You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@metron.apache.org by le...@apache.org on 2018/06/26 20:55:24 UTC

[1/9] metron git commit: METRON-1624 Set Profiler and Enrichment batch parameters in Ambari (nickwallen) closes apache/metron#1069

Repository: metron
Updated Branches:
  refs/heads/feature/METRON-1416-upgrade-solr 1767727a7 -> e0fc47582


METRON-1624 Set Profiler and Enrichment batch parameters in Ambari (nickwallen) closes apache/metron#1069


Project: http://git-wip-us.apache.org/repos/asf/metron/repo
Commit: http://git-wip-us.apache.org/repos/asf/metron/commit/b06bb5f4
Tree: http://git-wip-us.apache.org/repos/asf/metron/tree/b06bb5f4
Diff: http://git-wip-us.apache.org/repos/asf/metron/diff/b06bb5f4

Branch: refs/heads/feature/METRON-1416-upgrade-solr
Commit: b06bb5f4860c656023b9c357dfa83c2f0244b9ef
Parents: b575da1
Author: nickwallen <ni...@nickallen.org>
Authored: Fri Jun 22 16:19:37 2018 -0400
Committer: nickallen <ni...@apache.org>
Committed: Fri Jun 22 16:19:37 2018 -0400

----------------------------------------------------------------------
 .../configuration/metron-enrichment-env.xml     | 12 ++++++
 .../configuration/metron-profiler-env.xml       | 12 ++++++
 .../CURRENT/package/scripts/metron_service.py   | 20 ++++++++++
 .../package/scripts/params/params_linux.py      |  4 ++
 .../METRON/CURRENT/themes/metron_theme.json     | 41 +++++++++++++++++++-
 5 files changed, 88 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/metron/blob/b06bb5f4/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/configuration/metron-enrichment-env.xml
----------------------------------------------------------------------
diff --git a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/configuration/metron-enrichment-env.xml b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/configuration/metron-enrichment-env.xml
index 81b135c..b41c455 100644
--- a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/configuration/metron-enrichment-env.xml
+++ b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/configuration/metron-enrichment-env.xml
@@ -89,6 +89,18 @@
     <value>indexing</value>
     <display-name>Threat Intel Error Topic</display-name>
   </property>
+  <property>
+    <name>enrichment_kafka_writer_batch_size</name>
+    <value>15</value>
+    <description>The number of records to batch when writing to Kakfa.</description>
+    <display-name>Kafka Writer Batch Size</display-name>
+  </property>
+  <property>
+    <name>enrichment_kafka_writer_batch_timeout</name>
+    <value>0</value>
+    <description>The timeout in milliseconds after which a batch will be written to Kafka, even if the batch size has not been met.  If unspecified, or set to `0`, this defaults to a system-determined duration.</description>
+    <display-name>Kafka Writer Batch Timeout</display-name>
+  </property>
 
   <!--
     hbase parameters

http://git-wip-us.apache.org/repos/asf/metron/blob/b06bb5f4/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/configuration/metron-profiler-env.xml
----------------------------------------------------------------------
diff --git a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/configuration/metron-profiler-env.xml b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/configuration/metron-profiler-env.xml
index 8546b56..07b8d11 100644
--- a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/configuration/metron-profiler-env.xml
+++ b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/configuration/metron-profiler-env.xml
@@ -221,4 +221,16 @@
     <description>The profiler storm topology acker executors</description>
     <display-name>Number of Acker Executors</display-name>
   </property>
+  <property>
+    <name>profiler_kafka_writer_batch_size</name>
+    <value>15</value>
+    <description>The number of records to batch when writing to Kakfa.</description>
+    <display-name>Kafka Writer Batch Size</display-name>
+  </property>
+  <property>
+    <name>profiler_kafka_writer_batch_timeout</name>
+    <value>0</value>
+    <description>The timeout in milliseconds after which a batch will be written to Kafka, even if the batch size has not been met.  If unspecified, or set to `0`, this defaults to a system-determined duration.</description>
+    <display-name>Kafka Writer Batch Timeout</display-name>
+  </property>
 </configuration>

http://git-wip-us.apache.org/repos/asf/metron/blob/b06bb5f4/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/metron_service.py
----------------------------------------------------------------------
diff --git a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/metron_service.py b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/metron_service.py
index 1999992..e3e48ab 100644
--- a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/metron_service.py
+++ b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/metron_service.py
@@ -119,6 +119,26 @@ def build_global_config_patch(params, patch_file):
         "op": "add",
         "path": "/threat.triage.score.field",
         "value": "{{threat_triage_score_field}}"
+    },
+    {
+        "op": "add",
+        "path": "/enrichment.writer.batchSize",
+        "value": "{{enrichment_kafka_writer_batch_size}}"
+    },
+    {
+        "op": "add",
+        "path": "/enrichment.writer.batchTimeout",
+        "value": "{{enrichment_kafka_writer_batch_timeout}}"
+    },
+    {
+        "op": "add",
+        "path": "/profiler.writer.batchSize",
+        "value": "{{profiler_kafka_writer_batch_size}}"
+    },
+    {
+        "op": "add",
+        "path": "/profiler.writer.batchTimeout",
+        "value": "{{profiler_kafka_writer_batch_timeout}}"
     }
   ]
   """

http://git-wip-us.apache.org/repos/asf/metron/blob/b06bb5f4/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/params/params_linux.py
----------------------------------------------------------------------
diff --git a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/params/params_linux.py b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/params/params_linux.py
index f054c00..ec01292 100755
--- a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/params/params_linux.py
+++ b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/params/params_linux.py
@@ -268,6 +268,8 @@ enrichment_input_topic = status_params.enrichment_input_topic
 enrichment_output_topic = config['configurations']['metron-enrichment-env']['enrichment_output_topic']
 enrichment_error_topic = config['configurations']['metron-enrichment-env']['enrichment_error_topic']
 threatintel_error_topic = config['configurations']['metron-enrichment-env']['threatintel_error_topic']
+enrichment_kafka_writer_batch_size = config['configurations']['metron-enrichment-env']['enrichment_kafka_writer_batch_size']
+enrichment_kafka_writer_batch_timeout = config['configurations']['metron-enrichment-env']['enrichment_kafka_writer_batch_timeout']
 
 # Enrichment - Storm common parameters
 enrichment_workers = config['configurations']['metron-enrichment-env']['enrichment_workers']
@@ -328,6 +330,8 @@ profiler_window_lag=config['configurations']['metron-profiler-env']['profiler_wi
 profiler_window_lag_units=config['configurations']['metron-profiler-env']['profiler_window_lag_units']
 profiler_topology_message_timeout_secs=config['configurations']['metron-profiler-env']['profiler_topology_message_timeout_secs']
 profiler_topology_max_spout_pending=config['configurations']['metron-profiler-env']['profiler_topology_max_spout_pending']
+profiler_kafka_writer_batch_size = config['configurations']['metron-profiler-env']['profiler_kafka_writer_batch_size']
+profiler_kafka_writer_batch_timeout = config['configurations']['metron-profiler-env']['profiler_kafka_writer_batch_timeout']
 
 # Indexing
 ra_indexing_kafka_start = config['configurations']['metron-indexing-env']['ra_indexing_kafka_start']

http://git-wip-us.apache.org/repos/asf/metron/blob/b06bb5f4/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/themes/metron_theme.json
----------------------------------------------------------------------
diff --git a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/themes/metron_theme.json b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/themes/metron_theme.json
index d09f270..d757ec6 100644
--- a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/themes/metron_theme.json
+++ b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/themes/metron_theme.json
@@ -484,6 +484,14 @@
           "subsection-name": "subsection-enrichment-kafka"
         },
         {
+          "config": "metron-enrichment-env/enrichment_kafka_writer_batch_size",
+          "subsection-name": "subsection-enrichment-kafka"
+        },
+        {
+          "config": "metron-enrichment-env/enrichment_kafka_writer_batch_timeout",
+          "subsection-name": "subsection-enrichment-kafka"
+        },
+        {
           "config": "metron-enrichment-env/enrichment_workers",
           "subsection-name": "subsection-enrichment-storm"
         },
@@ -668,6 +676,14 @@
           "subsection-name": "subsection-profiler-kafka"
         },
         {
+          "config": "metron-profiler-env/profiler_kafka_writer_batch_size",
+          "subsection-name": "subsection-profiler-kafka"
+        },
+        {
+          "config": "metron-profiler-env/profiler_kafka_writer_batch_timeout",
+          "subsection-name": "subsection-profiler-kafka"
+        },
+        {
           "config": "metron-profiler-env/profiler_period_duration",
           "subsection-name": "subsection-profiler-setup"
         },
@@ -864,7 +880,6 @@
           "type": "text-field"
         }
       },
-
       {
         "config": "metron-enrichment-env/geoip_url",
         "widget": {
@@ -908,6 +923,18 @@
         }
       },
       {
+        "config": "metron-enrichment-env/enrichment_kafka_writer_batch_size",
+        "widget": {
+          "type": "text-field"
+        }
+      },
+      {
+        "config": "metron-enrichment-env/enrichment_kafka_writer_batch_timeout",
+        "widget": {
+          "type": "text-field"
+        }
+      },
+      {
         "config": "metron-enrichment-env/enrichment_workers",
         "widget": {
           "type": "text-field"
@@ -1186,6 +1213,18 @@
         }
       },
       {
+        "config": "metron-profiler-env/profiler_kafka_writer_batch_size",
+        "widget": {
+          "type": "text-field"
+        }
+      },
+      {
+        "config": "metron-profiler-env/profiler_kafka_writer_batch_timeout",
+        "widget": {
+          "type": "text-field"
+        }
+      },
+      {
         "config": "metron-profiler-env/profiler_period_duration",
         "widget": {
           "type": "text-field"


[4/9] metron git commit: METRON-1489 Retrofit UI tests to run reliably during nightly QE runs (sardell via nickwallen) closes apache/metron#1004

Posted by le...@apache.org.
http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/package-lock.json
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/package-lock.json b/metron-interface/metron-alerts/package-lock.json
index 39b3588..3ace2b7 100644
--- a/metron-interface/metron-alerts/package-lock.json
+++ b/metron-interface/metron-alerts/package-lock.json
@@ -1,18 +1,118 @@
 {
   "name": "metron-alerts",
-  "version": "0.0.0",
+  "version": "0.4.3",
   "lockfileVersion": 1,
+  "requires": true,
   "dependencies": {
     "@angular/cli": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-1.0.0.tgz",
-      "integrity": "sha1-e/3h58Xyi/W+1N2hNS7mfuiHMC8=",
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-1.2.4.tgz",
+      "integrity": "sha1-BPfA2aLuLP18wRo8Gom4fwPhT44=",
       "dev": true,
+      "requires": {
+        "@ngtools/json-schema": "1.1.0",
+        "@ngtools/webpack": "1.5.3",
+        "autoprefixer": "6.7.7",
+        "chalk": "2.3.0",
+        "circular-dependency-plugin": "3.0.0",
+        "common-tags": "1.5.1",
+        "core-object": "3.1.5",
+        "css-loader": "0.28.7",
+        "cssnano": "3.10.0",
+        "denodeify": "1.2.1",
+        "diff": "3.2.0",
+        "ember-cli-normalize-entity-name": "1.0.0",
+        "ember-cli-string-utils": "1.1.0",
+        "exports-loader": "0.6.4",
+        "extract-text-webpack-plugin": "2.1.2",
+        "file-loader": "0.10.1",
+        "fs-extra": "4.0.2",
+        "get-caller-file": "1.0.2",
+        "glob": "7.1.2",
+        "heimdalljs": "0.2.5",
+        "heimdalljs-logger": "0.1.9",
+        "html-webpack-plugin": "2.30.1",
+        "inflection": "1.12.0",
+        "inquirer": "3.3.0",
+        "isbinaryfile": "3.0.2",
+        "istanbul-instrumenter-loader": "2.0.0",
+        "json-loader": "0.5.7",
+        "karma-source-map-support": "1.2.0",
+        "less": "2.7.3",
+        "less-loader": "4.0.5",
+        "license-webpack-plugin": "0.4.3",
+        "lodash": "4.17.4",
+        "memory-fs": "0.4.1",
+        "minimatch": "3.0.4",
+        "node-modules-path": "1.0.1",
+        "node-sass": "4.5.3",
+        "nopt": "4.0.1",
+        "opn": "5.1.0",
+        "portfinder": "1.0.13",
+        "postcss-loader": "1.3.3",
+        "postcss-url": "5.1.2",
+        "raw-loader": "0.5.1",
+        "resolve": "1.3.3",
+        "rsvp": "3.6.2",
+        "rxjs": "5.4.0",
+        "sass-loader": "6.0.6",
+        "script-loader": "0.7.2",
+        "semver": "5.3.0",
+        "silent-error": "1.1.0",
+        "source-map-loader": "0.2.3",
+        "style-loader": "0.13.2",
+        "stylus": "0.54.5",
+        "stylus-loader": "3.0.1",
+        "temp": "0.8.3",
+        "typescript": "2.2.2",
+        "url-loader": "0.5.9",
+        "walk-sync": "0.3.2",
+        "webpack": "2.4.1",
+        "webpack-dev-middleware": "1.12.2",
+        "webpack-dev-server": "2.4.5",
+        "webpack-merge": "2.6.1",
+        "zone.js": "0.8.18"
+      },
       "dependencies": {
+        "ansi-styles": {
+          "version": "3.2.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz",
+          "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==",
+          "dev": true,
+          "requires": {
+            "color-convert": "1.9.1"
+          }
+        },
+        "chalk": {
+          "version": "2.3.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz",
+          "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "3.2.0",
+            "escape-string-regexp": "1.0.5",
+            "supports-color": "4.5.0"
+          }
+        },
+        "has-flag": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
+          "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "4.5.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz",
+          "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=",
+          "dev": true,
+          "requires": {
+            "has-flag": "2.0.0"
+          }
+        },
         "zone.js": {
-          "version": "0.7.8",
-          "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.7.8.tgz",
-          "integrity": "sha1-Tz/og01EWX8mOQU6D6Q43zT//e0=",
+          "version": "0.8.18",
+          "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.8.18.tgz",
+          "integrity": "sha512-knKOBQM0oea3/x9pdyDuDi7RhxDlJhOIkeixXSiTKWLgs4LpK37iBc+1HaHwzlciHUKT172CymJFKo8Xgh+44Q==",
           "dev": true
         }
       }
@@ -32,6 +132,11 @@
       "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-4.1.3.tgz",
       "integrity": "sha1-wjYv/fZXVkcUgfg5+rZ1vKwhP5Y=",
       "dev": true,
+      "requires": {
+        "@angular/tsc-wrapped": "4.1.3",
+        "minimist": "1.2.0",
+        "reflect-metadata": "0.1.10"
+      },
       "dependencies": {
         "minimist": {
           "version": "1.2.0",
@@ -75,19 +180,28 @@
       "version": "4.1.3",
       "resolved": "https://registry.npmjs.org/@angular/tsc-wrapped/-/tsc-wrapped-4.1.3.tgz",
       "integrity": "sha1-LWNyyRh78WIerNlguUs5xPlSk80=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "tsickle": "0.21.6"
+      }
     },
     "@ngtools/json-schema": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/@ngtools/json-schema/-/json-schema-1.0.5.tgz",
-      "integrity": "sha1-rTkDfHDIiyRaxyZ6cXd2RrYGPXc=",
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@ngtools/json-schema/-/json-schema-1.1.0.tgz",
+      "integrity": "sha1-w6DFRNYjkqzCgTpCyKDcb1j4aSI=",
       "dev": true
     },
     "@ngtools/webpack": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-1.3.0.tgz",
-      "integrity": "sha1-oQcSMJhTWOzfh7L6mHmubMY1XoM=",
-      "dev": true
+      "version": "1.5.3",
+      "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-1.5.3.tgz",
+      "integrity": "sha1-hsGDSxEFnpGkhUPonMaXrR9km9I=",
+      "dev": true,
+      "requires": {
+        "enhanced-resolve": "3.3.0",
+        "loader-utils": "1.1.0",
+        "magic-string": "0.22.4",
+        "source-map": "0.5.6"
+      }
     },
     "@types/ace": {
       "version": "0.0.32",
@@ -95,10 +209,10 @@
       "integrity": "sha1-1YSBOWBgdUDdsgLeiz4ilQTUXP8=",
       "dev": true
     },
-    "@types/bootstrap": {
-      "version": "3.3.33",
-      "resolved": "https://registry.npmjs.org/@types/bootstrap/-/bootstrap-3.3.33.tgz",
-      "integrity": "sha1-RIIg7bQq3QoLcC9xIl01kF8MuUg=",
+    "@types/es6-promise": {
+      "version": "0.0.33",
+      "resolved": "https://registry.npmjs.org/@types/es6-promise/-/es6-promise-0.0.33.tgz",
+      "integrity": "sha1-KApwfmKxtr7xqGzAhh7GPNBsf/M=",
       "dev": true
     },
     "@types/jasmine": {
@@ -107,11 +221,14 @@
       "integrity": "sha1-pDeRJMSSHU4h3lTsdGacnps1Zxc=",
       "dev": true
     },
-    "@types/jquery": {
-      "version": "2.0.46",
-      "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-2.0.46.tgz",
-      "integrity": "sha512-U64bkZqTfFi4HXHqOckD1Uxvg+oPooCjD5bQ10t9xOG5Ke6cR8tFnvERXrQtrRWvgS428nhAL1V8qv1b88kgyQ==",
-      "dev": true
+    "@types/moment": {
+      "version": "2.13.0",
+      "resolved": "https://registry.npmjs.org/@types/moment/-/moment-2.13.0.tgz",
+      "integrity": "sha1-YE69GJvDvDShVIaJQE5hoqSqyJY=",
+      "dev": true,
+      "requires": {
+        "moment": "2.19.2"
+      }
     },
     "@types/node": {
       "version": "6.0.78",
@@ -119,6 +236,15 @@
       "integrity": "sha512-+vD6E8ixntRzzZukoF3uP1iV+ZjVN3koTcaeK+BEoc/kSfGbLDIGC7RmCaUgVpUfN6cWvfczFRERCyKM9mkvXg==",
       "dev": true
     },
+    "@types/pikaday-time": {
+      "version": "1.4.5",
+      "resolved": "https://registry.npmjs.org/@types/pikaday-time/-/pikaday-time-1.4.5.tgz",
+      "integrity": "sha1-040HYaJnOzjAjgULvQieYcw8LRc=",
+      "dev": true,
+      "requires": {
+        "moment": "2.19.2"
+      }
+    },
     "@types/q": {
       "version": "0.0.32",
       "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz",
@@ -126,9 +252,9 @@
       "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=",
+      "version": "2.53.37",
+      "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-2.53.37.tgz",
+      "integrity": "sha1-NPdDwg5TrnEA7ekIcP3lVN8kR/g=",
       "dev": true
     },
     "abbrev": {
@@ -141,7 +267,11 @@
       "version": "1.3.3",
       "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz",
       "integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "mime-types": "2.1.15",
+        "negotiator": "0.6.1"
+      }
     },
     "ace-builds": {
       "version": "1.2.6",
@@ -149,16 +279,27 @@
       "integrity": "sha1-qSM8J8N7hJTyCvhJF+4WGUia9Ck="
     },
     "acorn": {
-      "version": "4.0.13",
-      "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz",
-      "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=",
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.2.1.tgz",
+      "integrity": "sha1-MXrHghgmwixwLWYYmrg1lnXxNdc=",
       "dev": true
     },
     "acorn-dynamic-import": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz",
       "integrity": "sha1-x1K9IQvvZ5UBtsbLf8hPj0cVjMQ=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "acorn": "4.0.13"
+      },
+      "dependencies": {
+        "acorn": {
+          "version": "4.0.13",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz",
+          "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=",
+          "dev": true
+        }
+      }
     },
     "adm-zip": {
       "version": "0.4.7",
@@ -177,6 +318,10 @@
       "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",
@@ -190,7 +335,11 @@
       "version": "4.11.8",
       "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz",
       "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "co": "4.6.0",
+        "json-stable-stringify": "1.0.1"
+      }
     },
     "ajv-keywords": {
       "version": "1.5.1",
@@ -202,7 +351,12 @@
       "version": "0.1.4",
       "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz",
       "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "kind-of": "3.2.2",
+        "longest": "1.0.1",
+        "repeat-string": "1.6.1"
+      }
     },
     "alphanum-sort": {
       "version": "1.0.2",
@@ -220,12 +374,15 @@
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz",
       "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "string-width": "2.0.0"
+      }
     },
     "ansi-escapes": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-2.0.0.tgz",
-      "integrity": "sha1-W65SvkJIeN2Xg+iRDj/Cki6DyBs=",
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.0.0.tgz",
+      "integrity": "sha1-7D6LTp+AZPwCw6ybZfHCdb2o75I=",
       "dev": true
     },
     "ansi-html": {
@@ -256,7 +413,11 @@
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.0.tgz",
       "integrity": "sha1-o+Uvo5FoyCX/V7AkgSbOWo/5VQc=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "arrify": "1.0.1",
+        "micromatch": "2.3.11"
+      }
     },
     "app-root-path": {
       "version": "2.0.1",
@@ -268,7 +429,10 @@
       "version": "0.4.0",
       "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-0.4.0.tgz",
       "integrity": "sha1-126/jKlNJ24keja61EpLdKthGZE=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "default-require-extensions": "1.0.0"
+      }
     },
     "aproba": {
       "version": "1.1.2",
@@ -280,19 +444,29 @@
       "version": "1.1.4",
       "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz",
       "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "delegates": "1.0.0",
+        "readable-stream": "2.2.11"
+      }
     },
     "argparse": {
       "version": "1.0.9",
       "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz",
       "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "sprintf-js": "1.0.3"
+      }
     },
     "arr-diff": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
       "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "arr-flatten": "1.0.3"
+      }
     },
     "arr-flatten": {
       "version": "1.0.3",
@@ -322,7 +496,10 @@
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
       "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "array-uniq": "1.0.3"
+      }
     },
     "array-uniq": {
       "version": "1.0.3",
@@ -349,9 +526,9 @@
       "dev": true
     },
     "asap": {
-      "version": "2.0.5",
-      "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.5.tgz",
-      "integrity": "sha1-UidltQw1EEkOUtfc/ghe+bqWlY8=",
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
+      "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=",
       "dev": true,
       "optional": true
     },
@@ -362,16 +539,24 @@
       "dev": true
     },
     "asn1.js": {
-      "version": "4.9.1",
-      "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.9.1.tgz",
-      "integrity": "sha1-SLokC0WpKA6UdImQull9IWYX/UA=",
-      "dev": true
+      "version": "4.9.2",
+      "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.9.2.tgz",
+      "integrity": "sha1-gRfvT37YfNj4kES1v/l6wkOhbJo=",
+      "dev": true,
+      "requires": {
+        "bn.js": "4.11.8",
+        "inherits": "2.0.3",
+        "minimalistic-assert": "1.0.0"
+      }
     },
     "assert": {
       "version": "1.4.1",
       "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz",
       "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "util": "0.10.3"
+      }
     },
     "assert-plus": {
       "version": "0.2.0",
@@ -383,7 +568,10 @@
       "version": "2.4.1",
       "resolved": "https://registry.npmjs.org/async/-/async-2.4.1.tgz",
       "integrity": "sha1-YqVrJ5yYoR0JhwlqAcw+6463u9c=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "lodash": "4.17.4"
+      }
     },
     "async-each": {
       "version": "1.0.1",
@@ -403,11 +591,24 @@
       "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
       "dev": true
     },
+    "atoa": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/atoa/-/atoa-1.0.0.tgz",
+      "integrity": "sha1-DMDpGkgOc4+SPrwQNnZHF3mzSkk="
+    },
     "autoprefixer": {
       "version": "6.7.7",
       "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-6.7.7.tgz",
       "integrity": "sha1-Hb0cg1ZY41zj+ZhAmdsAWFx4IBQ=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "browserslist": "1.7.7",
+        "caniuse-db": "1.0.30000772",
+        "normalize-range": "0.1.2",
+        "num2fraction": "1.2.2",
+        "postcss": "5.2.18",
+        "postcss-value-parser": "3.3.0"
+      }
     },
     "aws-sign2": {
       "version": "0.6.0",
@@ -425,13 +626,28 @@
       "version": "6.22.0",
       "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz",
       "integrity": "sha1-AnYgvuVnqIwyVhV05/0IAdMxGOQ=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "chalk": "1.1.3",
+        "esutils": "2.0.2",
+        "js-tokens": "3.0.1"
+      }
     },
     "babel-generator": {
       "version": "6.24.1",
       "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.24.1.tgz",
       "integrity": "sha1-5xX0hsWN7SVknYiJRNUqoHxdlJc=",
       "dev": true,
+      "requires": {
+        "babel-messages": "6.23.0",
+        "babel-runtime": "6.23.0",
+        "babel-types": "6.24.1",
+        "detect-indent": "4.0.0",
+        "jsesc": "1.3.0",
+        "lodash": "4.17.4",
+        "source-map": "0.5.6",
+        "trim-right": "1.0.1"
+      },
       "dependencies": {
         "jsesc": {
           "version": "1.3.0",
@@ -445,31 +661,62 @@
       "version": "6.23.0",
       "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
       "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "babel-runtime": "6.23.0"
+      }
     },
     "babel-runtime": {
       "version": "6.23.0",
       "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
       "integrity": "sha1-CpSJ8UTecO+zzkMArM2zKeL8VDs=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "core-js": "2.4.1",
+        "regenerator-runtime": "0.10.5"
+      }
     },
     "babel-template": {
       "version": "6.24.1",
       "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.24.1.tgz",
       "integrity": "sha1-BK5RTx+Ts6JTfyoPYKWkX7gwgzM=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "babel-runtime": "6.23.0",
+        "babel-traverse": "6.24.1",
+        "babel-types": "6.24.1",
+        "babylon": "6.17.2",
+        "lodash": "4.17.4"
+      }
     },
     "babel-traverse": {
       "version": "6.24.1",
       "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.24.1.tgz",
       "integrity": "sha1-qzZnP9NW+aCUhlnnszjV/q2zFpU=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "babel-code-frame": "6.22.0",
+        "babel-messages": "6.23.0",
+        "babel-runtime": "6.23.0",
+        "babel-types": "6.24.1",
+        "babylon": "6.17.2",
+        "debug": "2.6.8",
+        "globals": "9.18.0",
+        "invariant": "2.2.2",
+        "lodash": "4.17.4"
+      }
     },
     "babel-types": {
       "version": "6.24.1",
       "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.24.1.tgz",
       "integrity": "sha1-oTaHncFbNga9oNkMH8dDBML/CXU=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "babel-runtime": "6.23.0",
+        "esutils": "2.0.2",
+        "lodash": "4.17.4",
+        "to-fast-properties": "1.0.3"
+      }
     },
     "babylon": {
       "version": "6.17.2",
@@ -496,9 +743,9 @@
       "dev": true
     },
     "base64-js": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.0.tgz",
-      "integrity": "sha1-o5mS1yNYSBGYK+XikLtqU9hnAPE=",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz",
+      "integrity": "sha1-qRlH2h9KUW6jjltOwOw3c2deCIY=",
       "dev": true
     },
     "base64id": {
@@ -518,18 +765,24 @@
       "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz",
       "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=",
       "dev": true,
-      "optional": true
+      "optional": true,
+      "requires": {
+        "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=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "callsite": "1.0.0"
+      }
     },
     "big.js": {
-      "version": "3.1.3",
-      "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.1.3.tgz",
-      "integrity": "sha1-TK2iGTZS6zyp7I5VyQFWacmAaXg=",
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz",
+      "integrity": "sha1-pfwpi4G54Nyi5FiCR4S2XFK6WI4=",
       "dev": true
     },
     "binary-extensions": {
@@ -548,13 +801,19 @@
       "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
+      "dev": true,
+      "requires": {
+        "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=",
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-1.0.1.tgz",
+      "integrity": "sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA==",
       "dev": true,
+      "requires": {
+        "minimist": "1.2.0"
+      },
       "dependencies": {
         "minimist": {
           "version": "1.2.0",
@@ -571,9 +830,9 @@
       "dev": true
     },
     "bn.js": {
-      "version": "4.11.6",
-      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz",
-      "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=",
+      "version": "4.11.8",
+      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
+      "integrity": "sha1-LN4J617jQfSEdGuwMJsyU7GxRC8=",
       "dev": true
     },
     "body-parser": {
@@ -581,6 +840,18 @@
       "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.17.2.tgz",
       "integrity": "sha1-+IkqvI+eYn1Crtr7yma/WrmRBO4=",
       "dev": true,
+      "requires": {
+        "bytes": "2.4.0",
+        "content-type": "1.0.2",
+        "debug": "2.6.7",
+        "depd": "1.1.0",
+        "http-errors": "1.6.1",
+        "iconv-lite": "0.4.15",
+        "on-finished": "2.3.0",
+        "qs": "6.4.0",
+        "raw-body": "2.2.0",
+        "type-is": "1.6.15"
+      },
       "dependencies": {
         "bytes": {
           "version": "2.4.0",
@@ -592,7 +863,10 @@
           "version": "2.6.7",
           "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz",
           "integrity": "sha1-krrR9tBbu2u6Isyoi80OyJTChh4=",
-          "dev": true
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
         },
         "iconv-lite": {
           "version": "0.4.15",
@@ -612,18 +886,34 @@
       "version": "2.10.1",
       "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz",
       "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "hoek": "2.16.3"
+      }
     },
     "bootstrap": {
       "version": "4.0.0-alpha.6",
       "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.0.0-alpha.6.tgz",
-      "integrity": "sha1-T1TdM6wN6sOyhAe8LffsYIhpycg="
+      "integrity": "sha1-T1TdM6wN6sOyhAe8LffsYIhpycg=",
+      "requires": {
+        "jquery": "3.2.1",
+        "tether": "1.4.0"
+      }
     },
     "boxen": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.1.0.tgz",
       "integrity": "sha1-sbad1SIwXoB6md7ud329blFnsQI=",
       "dev": true,
+      "requires": {
+        "ansi-align": "2.0.0",
+        "camelcase": "4.1.0",
+        "chalk": "1.1.3",
+        "cli-boxes": "1.0.0",
+        "string-width": "2.0.0",
+        "term-size": "0.1.1",
+        "widest-line": "1.0.0"
+      },
       "dependencies": {
         "camelcase": {
           "version": "4.1.0",
@@ -637,13 +927,22 @@
       "version": "1.1.7",
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.7.tgz",
       "integrity": "sha1-Pv/DxQ4ABTH7cg6v+A8K6O8jz1k=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "balanced-match": "0.4.2",
+        "concat-map": "0.0.1"
+      }
     },
     "braces": {
       "version": "1.8.5",
       "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
       "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "expand-range": "1.8.2",
+        "preserve": "0.2.0",
+        "repeat-element": "1.1.2"
+      }
     },
     "brorand": {
       "version": "1.1.0",
@@ -652,52 +951,95 @@
       "dev": true
     },
     "browserify-aes": {
-      "version": "1.0.6",
-      "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.0.6.tgz",
-      "integrity": "sha1-Xncl297x/Vkw1OurSFZ85FHEigo=",
-      "dev": true
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.1.1.tgz",
+      "integrity": "sha1-OLerVe24Bv8tzaGn8WIHc6R3xJ8=",
+      "dev": true,
+      "requires": {
+        "buffer-xor": "1.0.3",
+        "cipher-base": "1.0.4",
+        "create-hash": "1.1.3",
+        "evp_bytestokey": "1.0.3",
+        "inherits": "2.0.3",
+        "safe-buffer": "5.0.1"
+      }
     },
     "browserify-cipher": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.0.tgz",
       "integrity": "sha1-mYgkSHS/XtTijalWZtzWasj8Njo=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "browserify-aes": "1.1.1",
+        "browserify-des": "1.0.0",
+        "evp_bytestokey": "1.0.3"
+      }
     },
     "browserify-des": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.0.tgz",
       "integrity": "sha1-2qJ3cXRwki7S/hhZQRihdUOXId0=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "cipher-base": "1.0.4",
+        "des.js": "1.0.0",
+        "inherits": "2.0.3"
+      }
     },
     "browserify-rsa": {
       "version": "4.0.1",
       "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
       "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "bn.js": "4.11.8",
+        "randombytes": "2.0.5"
+      }
     },
     "browserify-sign": {
       "version": "4.0.4",
       "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz",
       "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "bn.js": "4.11.8",
+        "browserify-rsa": "4.0.1",
+        "create-hash": "1.1.3",
+        "create-hmac": "1.1.6",
+        "elliptic": "6.4.0",
+        "inherits": "2.0.3",
+        "parse-asn1": "5.1.0"
+      }
     },
     "browserify-zlib": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz",
-      "integrity": "sha1-uzX4pRn2AOD6a4SFJByXnQFB+y0=",
-      "dev": true
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz",
+      "integrity": "sha1-KGlFnZqjviRf6P4sofRuLn9U1z8=",
+      "dev": true,
+      "requires": {
+        "pako": "1.0.6"
+      }
     },
     "browserslist": {
       "version": "1.7.7",
       "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz",
       "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "caniuse-db": "1.0.30000772",
+        "electron-to-chromium": "1.3.27"
+      }
     },
     "buffer": {
       "version": "4.9.1",
       "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
       "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "base64-js": "1.2.1",
+        "ieee754": "1.1.8",
+        "isarray": "1.0.0"
+      }
     },
     "buffer-xor": {
       "version": "1.0.3",
@@ -733,7 +1075,11 @@
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz",
       "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "no-case": "2.3.2",
+        "upper-case": "1.1.3"
+      }
     },
     "camelcase": {
       "version": "2.1.1",
@@ -745,18 +1091,28 @@
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
       "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "camelcase": "2.1.1",
+        "map-obj": "1.0.1"
+      }
     },
     "caniuse-api": {
       "version": "1.6.1",
       "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.6.1.tgz",
       "integrity": "sha1-tTTnxzTE+B7F++isoq0kNUuWLGw=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "browserslist": "1.7.7",
+        "caniuse-db": "1.0.30000772",
+        "lodash.memoize": "4.1.2",
+        "lodash.uniq": "4.5.0"
+      }
     },
     "caniuse-db": {
-      "version": "1.0.30000680",
-      "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000680.tgz",
-      "integrity": "sha1-126+quuC49mVK/3FwjHE+DzUgUQ=",
+      "version": "1.0.30000772",
+      "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000772.tgz",
+      "integrity": "sha1-UarokXaChureSj2DGep21qAbUSs=",
       "dev": true
     },
     "capture-stack-trace": {
@@ -775,13 +1131,24 @@
       "version": "0.1.3",
       "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz",
       "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=",
-      "dev": true
+      "dev": 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",
       "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
       "dev": true,
+      "requires": {
+        "ansi-styles": "2.2.1",
+        "escape-string-regexp": "1.0.5",
+        "has-ansi": "2.0.0",
+        "strip-ansi": "3.0.1",
+        "supports-color": "2.0.0"
+      },
       "dependencies": {
         "supports-color": {
           "version": "2.0.0",
@@ -791,29 +1158,62 @@
         }
       }
     },
+    "chardet": {
+      "version": "0.4.2",
+      "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz",
+      "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=",
+      "dev": true
+    },
     "chokidar": {
       "version": "1.7.0",
       "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz",
       "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "anymatch": "1.3.0",
+        "async-each": "1.0.1",
+        "fsevents": "1.1.1",
+        "glob-parent": "2.0.0",
+        "inherits": "2.0.3",
+        "is-binary-path": "1.0.1",
+        "is-glob": "2.0.1",
+        "path-is-absolute": "1.0.1",
+        "readdirp": "2.1.0"
+      }
     },
     "cipher-base": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.3.tgz",
-      "integrity": "sha1-7qvxlEGc6QDaMBjCB9IS8qbfCgc=",
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
+      "integrity": "sha1-h2Dk7MJy9MNjUy+SbYdKriwTl94=",
+      "dev": true,
+      "requires": {
+        "inherits": "2.0.3",
+        "safe-buffer": "5.0.1"
+      }
+    },
+    "circular-dependency-plugin": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/circular-dependency-plugin/-/circular-dependency-plugin-3.0.0.tgz",
+      "integrity": "sha1-m2hpLjWw41EJmNAWS2rlARvqV2A=",
       "dev": true
     },
     "clap": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/clap/-/clap-1.1.3.tgz",
-      "integrity": "sha1-s7026T3Uy/s5WjwmiWNSRFJlwFs=",
-      "dev": true
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/clap/-/clap-1.2.3.tgz",
+      "integrity": "sha1-TzZ0WzIAhJJVf0ZBLWbVDLmbzlE=",
+      "dev": true,
+      "requires": {
+        "chalk": "1.1.3"
+      }
     },
     "clean-css": {
-      "version": "4.1.3",
-      "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.1.3.tgz",
-      "integrity": "sha1-B8/omA7bINRV3cI6rc8eBMblCc4=",
-      "dev": true
+      "version": "4.1.9",
+      "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.1.9.tgz",
+      "integrity": "sha1-Nc7ornaHpJuYA09w3gDE7dOCYwE=",
+      "dev": true,
+      "requires": {
+        "source-map": "0.5.6"
+      }
     },
     "cli-boxes": {
       "version": "1.0.0",
@@ -825,12 +1225,15 @@
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
       "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "restore-cursor": "2.0.0"
+      }
     },
     "cli-width": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.1.0.tgz",
-      "integrity": "sha1-sjTKIJsp72b8UY2bmNWEewDt8Ao=",
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
+      "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=",
       "dev": true
     },
     "cliui": {
@@ -838,27 +1241,63 @@
       "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
       "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
       "dev": true,
+      "requires": {
+        "string-width": "1.0.2",
+        "strip-ansi": "3.0.1",
+        "wrap-ansi": "2.1.0"
+      },
       "dependencies": {
         "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=",
-          "dev": true
+          "dev": true,
+          "requires": {
+            "number-is-nan": "1.0.1"
+          }
         },
         "string-width": {
           "version": "1.0.2",
           "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
           "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
-          "dev": true
+          "dev": true,
+          "requires": {
+            "code-point-at": "1.1.0",
+            "is-fullwidth-code-point": "1.0.0",
+            "strip-ansi": "3.0.1"
+          }
         }
       }
     },
     "clone": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz",
-      "integrity": "sha1-Jgt6meux7f4kdTgXX3gyQ8sZ0Uk=",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.3.tgz",
+      "integrity": "sha1-KY1+IjFmD0DAA8LtMUDezz9TCF8=",
       "dev": true
     },
+    "clone-deep": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-0.3.0.tgz",
+      "integrity": "sha1-NIxhrpzb4O3+BT2R/0zFIdeQ7eg=",
+      "dev": true,
+      "requires": {
+        "for-own": "1.0.0",
+        "is-plain-object": "2.0.4",
+        "kind-of": "3.2.2",
+        "shallow-clone": "0.1.2"
+      },
+      "dependencies": {
+        "for-own": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz",
+          "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=",
+          "dev": true,
+          "requires": {
+            "for-in": "1.0.2"
+          }
+        }
+      }
+    },
     "co": {
       "version": "4.6.0",
       "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
@@ -866,10 +1305,13 @@
       "dev": true
     },
     "coa": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/coa/-/coa-1.0.2.tgz",
-      "integrity": "sha1-K6n+w7SqQ9eknX5sNWHpIGG2vOw=",
-      "dev": true
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/coa/-/coa-1.0.4.tgz",
+      "integrity": "sha1-qe8VNmDWqGqL3sAomlxoTSF0Mv0=",
+      "dev": true,
+      "requires": {
+        "q": "1.5.0"
+      }
     },
     "code-point-at": {
       "version": "1.1.0",
@@ -881,37 +1323,61 @@
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-2.0.1.tgz",
       "integrity": "sha1-0PcSH2eoQkyS0h07MfNkC4Pe+e0=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "app-root-path": "2.0.1",
+        "css-selector-tokenizer": "0.7.0",
+        "cssauron": "1.4.0",
+        "semver-dsl": "1.0.1",
+        "source-map": "0.5.6",
+        "sprintf-js": "1.0.3"
+      }
     },
     "color": {
       "version": "0.11.4",
       "resolved": "https://registry.npmjs.org/color/-/color-0.11.4.tgz",
       "integrity": "sha1-bXtcdPtl6EHNSHkq0e1eB7kE12Q=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "clone": "1.0.3",
+        "color-convert": "1.9.1",
+        "color-string": "0.3.0"
+      }
     },
     "color-convert": {
-      "version": "1.9.0",
-      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.0.tgz",
-      "integrity": "sha1-Gsz5fdc5uYO/mU1W/sj5WFNkG3o=",
-      "dev": true
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz",
+      "integrity": "sha1-wSYRB66y8pTr/+ye2eytUppgl+0=",
+      "dev": true,
+      "requires": {
+        "color-name": "1.1.3"
+      }
     },
     "color-name": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.2.tgz",
-      "integrity": "sha1-XIq3K2S9IhXWF66VWeuxSEdc+Y0=",
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
       "dev": true
     },
     "color-string": {
       "version": "0.3.0",
       "resolved": "https://registry.npmjs.org/color-string/-/color-string-0.3.0.tgz",
       "integrity": "sha1-J9RvtnAlxcL6JZk7+/V55HhBuZE=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "color-name": "1.1.3"
+      }
     },
     "colormin": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/colormin/-/colormin-1.1.2.tgz",
       "integrity": "sha1-6i90IKcrlogaOKrlnsEkpvcpgTM=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "color": "0.11.4",
+        "css-color-names": "0.0.4",
+        "has": "1.0.1"
+      }
     },
     "colors": {
       "version": "1.1.2",
@@ -923,25 +1389,52 @@
       "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
+      "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",
       "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "delayed-stream": "1.0.0"
+      }
     },
     "commander": {
-      "version": "2.9.0",
-      "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz",
-      "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=",
+      "version": "2.12.2",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-2.12.2.tgz",
+      "integrity": "sha1-D1lGxCftnsDZGka7ne9T5UZQ5VU=",
       "dev": true
     },
     "common-tags": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.4.0.tgz",
-      "integrity": "sha1-EYe+Tz1M8MBCfUP3Tu8fc1AWFMA=",
-      "dev": true
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.5.1.tgz",
+      "integrity": "sha1-4uOZMaATzQIlPe/u2Joa1hWifwc=",
+      "dev": true,
+      "requires": {
+        "babel-runtime": "6.26.0"
+      },
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.26.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+          "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
+          "dev": true,
+          "requires": {
+            "core-js": "2.4.1",
+            "regenerator-runtime": "0.11.0"
+          }
+        },
+        "regenerator-runtime": {
+          "version": "0.11.0",
+          "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz",
+          "integrity": "sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A==",
+          "dev": true
+        }
+      }
     },
     "component-bind": {
       "version": "1.0.0",
@@ -965,19 +1458,33 @@
       "version": "2.0.10",
       "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.10.tgz",
       "integrity": "sha1-/tocf3YXkScyspv4zyYlKiC57s0=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "mime-db": "1.27.0"
+      }
     },
     "compression": {
       "version": "1.6.2",
       "resolved": "https://registry.npmjs.org/compression/-/compression-1.6.2.tgz",
       "integrity": "sha1-zOsSHsydCcUtetDDNQ6pPd1AK8M=",
       "dev": true,
+      "requires": {
+        "accepts": "1.3.3",
+        "bytes": "2.3.0",
+        "compressible": "2.0.10",
+        "debug": "2.2.0",
+        "on-headers": "1.0.1",
+        "vary": "1.1.1"
+      },
       "dependencies": {
         "debug": {
           "version": "2.2.0",
           "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
           "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
-          "dev": true
+          "dev": true,
+          "requires": {
+            "ms": "0.7.1"
+          }
         },
         "ms": {
           "version": "0.7.1",
@@ -997,33 +1504,53 @@
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.0.tgz",
       "integrity": "sha1-Rd+QcHPibfoc9LLVL1tgVF6qEdE=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "dot-prop": "4.1.1",
+        "graceful-fs": "4.1.11",
+        "make-dir": "1.0.0",
+        "unique-string": "1.0.0",
+        "write-file-atomic": "2.1.0",
+        "xdg-basedir": "3.0.0"
+      }
     },
     "connect": {
       "version": "3.6.2",
       "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.2.tgz",
       "integrity": "sha1-aU6NIGgb/kkCgsiriGvpjwn0L+c=",
       "dev": true,
+      "requires": {
+        "debug": "2.6.7",
+        "finalhandler": "1.0.3",
+        "parseurl": "1.3.1",
+        "utils-merge": "1.0.0"
+      },
       "dependencies": {
         "debug": {
           "version": "2.6.7",
           "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz",
           "integrity": "sha1-krrR9tBbu2u6Isyoi80OyJTChh4=",
-          "dev": true
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
         }
       }
     },
     "connect-history-api-fallback": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.3.0.tgz",
-      "integrity": "sha1-5R0X+PDvDbkKZP20feMFFVbp8Wk=",
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz",
+      "integrity": "sha1-sGhzk0vF40T+9hGhlqb6rgruAVo=",
       "dev": true
     },
     "console-browserify": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz",
       "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "date-now": "0.1.4"
+      }
     },
     "console-control-strings": {
       "version": "1.1.0",
@@ -1049,10 +1576,19 @@
       "integrity": "sha1-t9ETrueo3Se9IRM8TcJSnfFyHu0=",
       "dev": true
     },
+    "contra": {
+      "version": "1.9.4",
+      "resolved": "https://registry.npmjs.org/contra/-/contra-1.9.4.tgz",
+      "integrity": "sha1-9TveQtfltZhcrk2ZqNYQUm3o8o0=",
+      "requires": {
+        "atoa": "1.0.0",
+        "ticky": "1.0.1"
+      }
+    },
     "convert-source-map": {
-      "version": "1.5.0",
-      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.0.tgz",
-      "integrity": "sha1-ms1whRxtXf3ZPZKC5e35SgP/RrU=",
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz",
+      "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=",
       "dev": true
     },
     "cookie": {
@@ -1072,59 +1608,181 @@
       "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz",
       "integrity": "sha1-TekR5mew6ukSTjQlS1OupvxhjT4="
     },
+    "core-object": {
+      "version": "3.1.5",
+      "resolved": "https://registry.npmjs.org/core-object/-/core-object-3.1.5.tgz",
+      "integrity": "sha1-+mJ7h1Aq3JgEXkRnjpqOw7nA0qk=",
+      "dev": true,
+      "requires": {
+        "chalk": "2.3.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "3.2.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz",
+          "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==",
+          "dev": true,
+          "requires": {
+            "color-convert": "1.9.1"
+          }
+        },
+        "chalk": {
+          "version": "2.3.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz",
+          "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "3.2.0",
+            "escape-string-regexp": "1.0.5",
+            "supports-color": "4.5.0"
+          }
+        },
+        "has-flag": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
+          "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "4.5.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz",
+          "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=",
+          "dev": true,
+          "requires": {
+            "has-flag": "2.0.0"
+          }
+        }
+      }
+    },
     "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
     },
+    "cosmiconfig": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-2.2.2.tgz",
+      "integrity": "sha1-YXPOvVb6wELB9DkO33r2wHx8uJI=",
+      "dev": true,
+      "requires": {
+        "is-directory": "0.3.1",
+        "js-yaml": "3.7.0",
+        "minimist": "1.2.0",
+        "object-assign": "4.1.1",
+        "os-homedir": "1.0.2",
+        "parse-json": "2.2.0",
+        "require-from-string": "1.2.1"
+      },
+      "dependencies": {
+        "minimist": {
+          "version": "1.2.0",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+          "dev": true
+        }
+      }
+    },
     "create-ecdh": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.0.tgz",
       "integrity": "sha1-iIxyNZbN92EvZJgjPuvXo1MBc30=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "bn.js": "4.11.8",
+        "elliptic": "6.4.0"
+      }
     },
     "create-error-class": {
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz",
       "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "capture-stack-trace": "1.0.0"
+      }
     },
     "create-hash": {
       "version": "1.1.3",
       "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz",
       "integrity": "sha1-YGBCrIuSYnUPSDyt2rD1gZFy2P0=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "cipher-base": "1.0.4",
+        "inherits": "2.0.3",
+        "ripemd160": "2.0.1",
+        "sha.js": "2.4.9"
+      }
     },
     "create-hmac": {
       "version": "1.1.6",
       "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.6.tgz",
       "integrity": "sha1-rLniIaThe9sHbpBlfEK5PjcmzwY=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "cipher-base": "1.0.4",
+        "create-hash": "1.1.3",
+        "inherits": "2.0.3",
+        "ripemd160": "2.0.1",
+        "safe-buffer": "5.0.1",
+        "sha.js": "2.4.9"
+      }
     },
     "cross-spawn": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz",
       "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "lru-cache": "4.1.0",
+        "which": "1.2.14"
+      }
     },
     "cross-spawn-async": {
       "version": "2.2.5",
       "resolved": "https://registry.npmjs.org/cross-spawn-async/-/cross-spawn-async-2.2.5.tgz",
       "integrity": "sha1-hF/wwINKPe2dFg2sptOQkGuyiMw=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "lru-cache": "4.1.0",
+        "which": "1.2.14"
+      }
+    },
+    "crossvent": {
+      "version": "1.5.4",
+      "resolved": "https://registry.npmjs.org/crossvent/-/crossvent-1.5.4.tgz",
+      "integrity": "sha1-2ixPj0DJR4JRe/K+7BBEFIGUq5I=",
+      "requires": {
+        "custom-event": "1.0.1"
+      }
     },
     "cryptiles": {
       "version": "2.0.5",
       "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz",
       "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "boom": "2.10.1"
+      }
     },
     "crypto-browserify": {
-      "version": "3.11.0",
-      "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.11.0.tgz",
-      "integrity": "sha1-NlKgkGq5sqfgw85mpAjpV6JIVSI=",
-      "dev": true
+      "version": "3.12.0",
+      "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz",
+      "integrity": "sha1-OWz58xN/A+S45TLFj2mCVOAPgOw=",
+      "dev": true,
+      "requires": {
+        "browserify-cipher": "1.0.0",
+        "browserify-sign": "4.0.4",
+        "create-ecdh": "4.0.0",
+        "create-hash": "1.1.3",
+        "create-hmac": "1.1.6",
+        "diffie-hellman": "5.0.2",
+        "inherits": "2.0.3",
+        "pbkdf2": "3.0.14",
+        "public-encrypt": "4.0.0",
+        "randombytes": "2.0.5",
+        "randomfill": "1.0.3"
+      }
     },
     "crypto-random-string": {
       "version": "1.0.0",
@@ -1139,10 +1797,26 @@
       "dev": true
     },
     "css-loader": {
-      "version": "0.26.4",
-      "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-0.26.4.tgz",
-      "integrity": "sha1-th6eMNuUMD5v/IkvEOzQmtAlof0=",
-      "dev": true
+      "version": "0.28.7",
+      "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-0.28.7.tgz",
+      "integrity": "sha1-Xy7pid0y7dkHcX+VMxdlYWCZnBs=",
+      "dev": true,
+      "requires": {
+        "babel-code-frame": "6.22.0",
+        "css-selector-tokenizer": "0.7.0",
+        "cssnano": "3.10.0",
+        "icss-utils": "2.1.0",
+        "loader-utils": "1.1.0",
+        "lodash.camelcase": "4.3.0",
+        "object-assign": "4.1.1",
+        "postcss": "5.2.18",
+        "postcss-modules-extract-imports": "1.1.0",
+        "postcss-modules-local-by-default": "1.2.0",
+        "postcss-modules-scope": "1.1.0",
+        "postcss-modules-values": "1.3.0",
+        "postcss-value-parser": "3.3.0",
+        "source-list-map": "2.0.0"
+      }
     },
     "css-parse": {
       "version": "1.7.0",
@@ -1154,13 +1828,24 @@
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
       "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "boolbase": "1.0.0",
+        "css-what": "2.1.0",
+        "domutils": "1.5.1",
+        "nth-check": "1.0.1"
+      }
     },
     "css-selector-tokenizer": {
       "version": "0.7.0",
       "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz",
       "integrity": "sha1-5piEdK6MlTR3v15+/s/OzNnPTIY=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "cssesc": "0.1.0",
+        "fastparse": "1.1.1",
+        "regexpu-core": "1.0.0"
+      }
     },
     "css-what": {
       "version": "2.1.0",
@@ -1172,7 +1857,10 @@
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz",
       "integrity": "sha1-pmAt/34EqDBtwNuaVR6S6LVmKtg=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "through": "2.3.8"
+      }
     },
     "cssesc": {
       "version": "0.1.0",
@@ -1184,31 +1872,74 @@
       "version": "3.10.0",
       "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-3.10.0.tgz",
       "integrity": "sha1-Tzj2zqK5sX+gFJDyPx3GjqZcHDg=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "autoprefixer": "6.7.7",
+        "decamelize": "1.2.0",
+        "defined": "1.0.0",
+        "has": "1.0.1",
+        "object-assign": "4.1.1",
+        "postcss": "5.2.18",
+        "postcss-calc": "5.3.1",
+        "postcss-colormin": "2.2.2",
+        "postcss-convert-values": "2.6.1",
+        "postcss-discard-comments": "2.0.4",
+        "postcss-discard-duplicates": "2.1.0",
+        "postcss-discard-empty": "2.1.0",
+        "postcss-discard-overridden": "0.1.1",
+        "postcss-discard-unused": "2.2.3",
+        "postcss-filter-plugins": "2.0.2",
+        "postcss-merge-idents": "2.1.7",
+        "postcss-merge-longhand": "2.0.2",
+        "postcss-merge-rules": "2.1.2",
+        "postcss-minify-font-values": "1.0.5",
+        "postcss-minify-gradients": "1.0.5",
+        "postcss-minify-params": "1.2.2",
+        "postcss-minify-selectors": "2.1.1",
+        "postcss-normalize-charset": "1.1.1",
+        "postcss-normalize-url": "3.0.8",
+        "postcss-ordered-values": "2.2.3",
+        "postcss-reduce-idents": "2.4.0",
+        "postcss-reduce-initial": "1.0.1",
+        "postcss-reduce-transforms": "1.0.4",
+        "postcss-svgo": "2.1.6",
+        "postcss-unique-selectors": "2.0.2",
+        "postcss-value-parser": "3.3.0",
+        "postcss-zindex": "2.2.0"
+      }
     },
     "csso": {
       "version": "2.3.2",
       "resolved": "https://registry.npmjs.org/csso/-/csso-2.3.2.tgz",
       "integrity": "sha1-3dUsWHAz9J6Utx/FVWnyUuj/X4U=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "clap": "1.2.3",
+        "source-map": "0.5.6"
+      }
     },
     "currently-unhandled": {
       "version": "0.4.1",
       "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
       "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "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
+      "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU="
     },
     "dashdash": {
       "version": "1.14.1",
       "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
       "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
       "dev": true,
+      "requires": {
+        "assert-plus": "1.0.0"
+      },
       "dependencies": {
         "assert-plus": {
           "version": "1.0.0",
@@ -1228,7 +1959,10 @@
       "version": "2.6.8",
       "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
       "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "ms": "2.0.0"
+      }
     },
     "decamelize": {
       "version": "1.2.0",
@@ -1246,7 +1980,10 @@
       "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
+      "dev": true,
+      "requires": {
+        "strip-bom": "2.0.0"
+      }
     },
     "defined": {
       "version": "1.0.0",
@@ -1258,7 +1995,16 @@
       "version": "2.2.2",
       "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz",
       "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=",
-      "dev": true
+      "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.1"
+      }
     },
     "delayed-stream": {
       "version": "1.0.0",
@@ -1288,7 +2034,11 @@
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz",
       "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "inherits": "2.0.3",
+        "minimalistic-assert": "1.0.0"
+      }
     },
     "destroy": {
       "version": "1.0.4",
@@ -1300,7 +2050,10 @@
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz",
       "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "repeating": "2.0.1"
+      }
     },
     "detect-node": {
       "version": "2.0.3",
@@ -1324,19 +2077,44 @@
       "version": "5.0.2",
       "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.2.tgz",
       "integrity": "sha1-tYNXOScM/ias9jIJn97SoH8gnl4=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "bn.js": "4.11.8",
+        "miller-rabin": "4.0.1",
+        "randombytes": "2.0.5"
+      }
     },
     "directory-encoder": {
       "version": "0.7.2",
       "resolved": "https://registry.npmjs.org/directory-encoder/-/directory-encoder-0.7.2.tgz",
       "integrity": "sha1-WbTiqk8lQi9sY7UntGL14tDdLFg=",
       "dev": true,
+      "requires": {
+        "fs-extra": "0.23.1",
+        "handlebars": "1.3.0",
+        "img-stats": "0.5.2"
+      },
       "dependencies": {
         "fs-extra": {
           "version": "0.23.1",
           "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.23.1.tgz",
           "integrity": "sha1-ZhHbpq3yq43Jxp+rN83fiBgVfj0=",
-          "dev": true
+          "dev": true,
+          "requires": {
+            "graceful-fs": "4.1.11",
+            "jsonfile": "2.4.0",
+            "path-is-absolute": "1.0.1",
+            "rimraf": "2.6.1"
+          }
+        },
+        "jsonfile": {
+          "version": "2.4.0",
+          "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
+          "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=",
+          "dev": true,
+          "requires": {
+            "graceful-fs": "4.1.11"
+          }
         }
       }
     },
@@ -1345,6 +2123,9 @@
       "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.1.4.tgz",
       "integrity": "sha1-pF71cnuJDJv/5tfIduexnLDhfzs=",
       "dev": true,
+      "requires": {
+        "utila": "0.3.3"
+      },
       "dependencies": {
         "utila": {
           "version": "0.3.3",
@@ -1358,13 +2139,23 @@
       "version": "2.2.1",
       "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz",
       "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "custom-event": "1.0.1",
+        "ent": "2.2.0",
+        "extend": "3.0.1",
+        "void-elements": "2.0.1"
+      }
     },
     "dom-serializer": {
       "version": "0.1.0",
       "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz",
       "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=",
       "dev": true,
+      "requires": {
+        "domelementtype": "1.1.3",
+        "entities": "1.1.1"
+      },
       "dependencies": {
         "domelementtype": {
           "version": "1.1.3",
@@ -1390,19 +2181,38 @@
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.1.0.tgz",
       "integrity": "sha1-0mRvXlf2w7qxHPbLBdPArPdBJZQ=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "domelementtype": "1.3.0"
+      }
     },
     "domutils": {
       "version": "1.5.1",
       "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
       "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "dom-serializer": "0.1.0",
+        "domelementtype": "1.3.0"
+      }
     },
     "dot-prop": {
       "version": "4.1.1",
       "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.1.1.tgz",
       "integrity": "sha1-qEk/C3te7sglJbXHWH+n3nyoWcE=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "is-obj": "1.0.1"
+      }
+    },
+    "dragula": {
+      "version": "3.7.2",
+      "resolved": "https://registry.npmjs.org/dragula/-/dragula-3.7.2.tgz",
+      "integrity": "sha1-SjXJ05gf+sGpScKcpyhQWOhzk84=",
+      "requires": {
+        "contra": "1.9.4",
+        "crossvent": "1.5.4"
+      }
     },
     "duplexer3": {
       "version": "0.1.4",
@@ -1415,7 +2225,10 @@
       "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
       "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=",
       "dev": true,
-      "optional": true
+      "optional": true,
+      "requires": {
+        "jsbn": "0.1.1"
+      }
     },
     "ee-first": {
       "version": "1.1.1",
@@ -1424,22 +2237,346 @@
       "dev": true
     },
     "electron-to-chromium": {
-      "version": "1.3.13",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.13.tgz",
-      "integrity": "sha1-GzperObgh7teJXoQCwy/6Bsokfw=",
+      "version": "1.3.27",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.27.tgz",
+      "integrity": "sha1-eOy4o5kGYYe7N07t412ccFZagD0=",
       "dev": true
     },
+    "elementor": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/elementor/-/elementor-2.1.0.tgz",
+      "integrity": "sha1-ELbxOHwDL+9gzFPlIRq/rim0L90=",
+      "dev": true,
+      "requires": {
+        "body-parser": "1.17.2",
+        "chalk": "1.1.3",
+        "express": "5.0.0-alpha.2",
+        "lodash": "4.17.4",
+        "minimist": "0.0.8",
+        "protractor": "4.0.14",
+        "q": "1.5.0",
+        "temp": "0.8.3"
+      },
+      "dependencies": {
+        "accepts": {
+          "version": "1.2.13",
+          "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.2.13.tgz",
+          "integrity": "sha1-5fHzkoxtlf2WVYw27D2dDeSm7Oo=",
+          "dev": true,
+          "requires": {
+            "mime-types": "2.1.15",
+            "negotiator": "0.5.3"
+          }
+        },
+        "array-flatten": {
+          "version": "1.1.0",
+          "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.0.tgz",
+          "integrity": "sha1-rD76xxew57vcd4zgvec4GsZgQ5M=",
+          "dev": true
+        },
+        "content-disposition": {
+          "version": "0.5.0",
+          "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.0.tgz",
+          "integrity": "sha1-QoT+auBjCHRjnkToCkGMKTQTXp4=",
+          "dev": true
+        },
+        "cookie": {
+          "version": "0.1.3",
+          "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.3.tgz",
+          "integrity": "sha1-5zSlwUF/zkctWu+Cw4HKu2TRpDU=",
+          "dev": true
+        },
+        "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"
+          }
+        },
+        "depd": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/depd/-/depd-1.0.1.tgz",
+          "integrity": "sha1-gK7GTJ1tl+ZcwqnKqTwKpqv3Oqo=",
+          "dev": true
+        },
+        "escape-html": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.2.tgz",
+          "integrity": "sha1-130y+pjjjC9BroXpJ44ODmuhAiw=",
+          "dev": true
+        },
+        "etag": {
+          "version": "1.7.0",
+          "resolved": "https://registry.npmjs.org/etag/-/etag-1.7.0.tgz",
+          "integrity": "sha1-A9MLX2fdbmMtKUXTDWZScxo01dg=",
+          "dev": true
+        },
+        "express": {
+          "version": "5.0.0-alpha.2",
+          "resolved": "https://registry.npmjs.org/express/-/express-5.0.0-alpha.2.tgz",
+          "integrity": "sha1-/VQXf2V7akxFQHJ3Au3Ry6o6asU=",
+          "dev": true,
+          "requires": {
+            "accepts": "1.2.13",
+            "array-flatten": "1.1.0",
+            "content-disposition": "0.5.0",
+            "content-type": "1.0.2",
+            "cookie": "0.1.3",
+            "cookie-signature": "1.0.6",
+            "debug": "2.2.0",
+            "depd": "1.0.1",
+            "escape-html": "1.0.2",
+            "etag": "1.7.0",
+            "finalhandler": "0.4.0",
+            "fresh": "0.3.0",
+            "merge-descriptors": "1.0.0",
+            "methods": "1.1.2",
+            "on-finished": "2.3.0",
+            "parseurl": "1.3.1",
+            "path-is-absolute": "1.0.0",
+            "path-to-regexp": "0.1.6",
+            "proxy-addr": "1.0.10",
+            "qs": "4.0.0",
+            "range-parser": "1.0.3",
+            "router": "1.1.5",
+            "send": "0.13.0",
+            "serve-static": "1.10.3",
+            "type-is": "1.6.15",
+            "utils-merge": "1.0.0",
+            "vary": "1.0.1"
+          }
+        },
+        "finalhandler": {
+          "version": "0.4.0",
+          "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.4.0.tgz",
+          "integrity": "sha1-llpS2ejQXSuFdUhUH7ibU6JJfZs=",
+          "dev": true,
+          "requires": {
+            "debug": "2.2.0",
+            "escape-html": "1.0.2",
+            "on-finished": "2.3.0",
+            "unpipe": "1.0.0"
+          }
+        },
+        "fresh": {
+          "version": "0.3.0",
+          "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.3.0.tgz",
+          "integrity": "sha1-ZR+DjiJCTnVm3hYdg1jKoZn4PU8=",
+          "dev": true
+        },
+        "http-errors": {
+          "version": "1.3.1",
+          "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.3.1.tgz",
+          "integrity": "sha1-GX4izevUGYWF6GlO9nhhl7ke2UI=",
+          "dev": true,
+          "requires": {
+            "inherits": "2.0.3",
+            "statuses": "1.2.1"
+          }
+        },
+        "ipaddr.js": {
+          "version": "1.0.5",
+          "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.0.5.tgz",
+          "integrity": "sha1-X6eM8wG4JceKvDBC2BJyMEnqI8c=",
+          "dev": true
+        },
+        "merge-descriptors": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.0.tgz",
+          "integrity": "sha1-IWnPdTjhsMyH+4jhUC2EdLv3mGQ=",
+          "dev": true
+        },
+        "mime": {
+          "version": "1.3.4",
+          "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz",
+          "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM=",
+          "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
+        },
+        "negotiator": {
+          "version": "0.5.3",
+          "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.5.3.tgz",
+          "integrity": "sha1-Jp1cR2gQ7JLtvntsLygxY4T5p+g=",
+          "dev": true
+        },
+        "path-is-absolute": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz",
+          "integrity": "sha1-Jj2tpmqz8vsQv3+dJN2PPlcO+RI=",
+          "dev": true
+        },
+        "path-to-regexp": {
+          "version": "0.1.6",
+          "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.6.tgz",
+          "integrity": "sha1-8B/Vc0BHtr+8XyCMYTWjPXrwnDY=",
+          "dev": true
+        },
+        "protractor": {
+          "version": "4.0.14",
+          "resolved": "https://registry.npmjs.org/protractor/-/protractor-4.0.14.tgz",
+          "integrity": "sha1-78Sod/rDoYKp3e0mzVhp9HYv0XI=",
+          "dev": true,
+          "requires": {
+            "@types/jasmine": "2.5.38",
+            "@types/node": "6.0.78",
+            "@types/q": "0.0.32",
+            "@types/selenium-webdriver": "2.53.37",
+            "adm-zip": "0.4.7",
+            "chalk": "1.1.3",
+            "glob": "7.1.2",
+            "jasmine": "2.4.1",
+            "jasminewd2": "0.0.10",
+            "optimist": "0.6.1",
+            "q": "1.4.1",
+            "saucelabs": "1.3.0",
+            "selenium-webdriver": "2.53.3",
+            "source-map-support": "0.4.15",
+            "webdriver-manager": "10.3.0"
+          },
+          "dependencies": {
+            "minimist": {
+              "version": "1.2.0",
+              "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+              "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+              "dev": true
+            },
+            "q": {
+              "version": "1.4.1",
+              "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz",
+              "integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=",
+              "dev": true
+            },
+            "webdriver-manager": {
+              "version": "10.3.0",
+              "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-10.3.0.tgz",
+              "integrity": "sha1-mTFFiKCx2+aIxEHXQojGyxh1+os=",
+              "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.81.0",
+                "rimraf": "2.6.1",
+                "semver": "5.3.0"
+              }
+            }
+          }
+        },
+        "proxy-addr": {
+          "version": "1.0.10",
+          "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.0.10.tgz",
+          "integrity": "sha1-DUCoL4Afw1VWfS7LZe/j8HfxIcU=",
+          "dev": true,
+          "requires": {
+            "forwarded": "0.1.0",
+            "ipaddr.js": "1.0.5"
+          }
+        },
+        "qs": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/qs/-/qs-4.0.0.tgz",
+          "integrity": "sha1-wx2bdOwn33XlQ6hseHKO2NRiNgc=",
+          "dev": true
+        },
+        "range-parser": {
+          "version": "1.0.3",
+          "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.0.3.tgz",
+          "integrity": "sha1-aHKCNTXGkuLCoBA4Jq/YLC4P8XU=",
+          "dev": true
+        },
+        "serve-static": {
+          "version": "1.10.3",
+          "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.10.3.tgz",
+          "integrity": "sha1-zlpuzTEB/tXsCYJ9rCKpwpv7BTU=",
+          "dev": true,
+          "requires": {
+            "escape-html": "1.0.3",
+            "parseurl": "1.3.1",
+            "send": "0.13.2"
+          },
+          "dependencies": {
+            "depd": {
+              "version": "1.1.1",
+              "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz",
+              "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=",
+              "dev": true
+            },
+            "escape-html": {
+              "version": "1.0.3",
+              "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+              "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=",
+              "dev": true
+            },
+            "send": {
+              "version": "0.13.2",
+              "resolved": "https://registry.npmjs.org/send/-/send-0.13.2.tgz",
+              "integrity": "sha1-dl52B8gFVFK7pvCwUllTUJhgNt4=",
+              "dev": true,
+              "requires": {
+                "debug": "2.2.0",
+                "depd": "1.1.1",
+                "destroy": "1.0.4",
+                "escape-html": "1.0.3",
+                "etag": "1.7.0",
+                "fresh": "0.3.0",
+                "http-errors": "1.3.1",
+                "mime": "1.3.4",
+                "ms": "0.7.1",
+                "on-finished": "2.3.0",
+                "range-parser": "1.0.3",
+                "statuses": "1.2.1"
+              }
+            }
+          }
+        },
+        "statuses": {
+          "version": "1.2.1",
+          "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.2.1.tgz",
+          "integrity": "sha1-3e1FzBglbVHtQK7BQkidXGECbSg=",
+          "dev": true
+        },
+        "vary": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/vary/-/vary-1.0.1.tgz",
+          "integrity": "sha1-meSYFWaihhGN+yuBc1ffeZM3bRA=",
+          "dev": true
+        }
+      }
+    },
     "elliptic": {
       "version": "6.4.0",
       "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz",
       "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "bn.js": "4.11.8",
+        "brorand": "1.1.0",
+        "hash.js": "1.1.3",
+        "hmac-drbg": "1.0.1",
+        "inherits": "2.0.3",
+        "minimalistic-assert": "1.0.0",
+        "minimalistic-crypto-utils": "1.0.1"
+      }
     },
     "ember-cli-normalize-entity-name": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/ember-cli-normalize-entity-name/-/ember-cli-normalize-entity-name-1.0.0.tgz",
       "integrity": "sha1-CxT3vLxZmqEXtf3cgeT9A8S61bc=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "silent-error": "1.1.0"
+      }
     },
     "ember-cli-string-utils": {
       "version": "1.1.0",
@@ -1464,12 +2601,23 @@
       "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": {
         "debug": {
           "version": "2.3.3",
           "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
           "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
-          "dev": true
+          "dev": true,
+          "requires": {
+            "ms": "0.7.2"
+          }
         },
         "ms": {
           "version": "0.7.2",
@@ -1484,6 +2632,20 @@
       "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",
@@ -1495,7 +2657,10 @@
           "version": "2.3.3",
           "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
           "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
-          "dev": true
+          "dev": true,
+          "requires": {
+            "ms": "0.7.2"
+          }
         },
         "ms": {
           "version": "0.7.2",
@@ -1509,13 +2674,27 @@
       "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
+      "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": "3.1.0",
-      "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-3.1.0.tgz",
-      "integrity": "sha1-n0tib1dyRe3PSyrYPYbhf09CHew=",
-      "dev": true
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-3.3.0.tgz",
+      "integrity": "sha1-lQlk7MfwMypCMhtnOzjcj/FVNbM=",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "4.1.11",
+        "memory-fs": "0.4.1",
+        "object-assign": "4.1.1",
+        "tapable": "0.2.8"
+      }
     },
     "ensure-posix-path": {
       "version": "1.0.2",
@@ -1539,12 +2718,24 @@
       "version": "0.1.4",
       "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.4.tgz",
       "integrity": "sha1-uJbiOp5ei6M4cfyZar02NfyaHH0=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "prr": "0.0.0"
+      }
     },
     "error-ex": {
       "version": "1.3.1",
       "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz",
       "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=",
+      "dev": true,
+      "requires": {
+        "is-arrayish": "0.2.1"
+      }
+    },
+    "es6-promise": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.0.2.tgz",
+      "integrity": "sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y=",
       "dev": true
     },
     "escape-html": {
@@ -1593,19 +2784,42 @@
       "version": "0.1.6",
       "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-0.1.6.tgz",
       "integrity": "sha1-Cs7ehJ7X3RzMMsgRuxG5RNTykjI=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "original": "1.0.0"
+      }
     },
     "evp_bytestokey": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.0.tgz",
-      "integrity": "sha1-SXtmrZ/vZc18CKYYCCS6FHa2blM=",
-      "dev": true
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
+      "integrity": "sha1-f8vbGY3HGVlDLv4ThCaE4FJaywI=",
+      "dev": true,
+      "requires": {
+        "md5.js": "1.3.4",
+        "safe-buffer": "5.1.1"
+      },
+      "dependencies": {
+        "safe-buffer": {
+          "version": "5.1.1",
+          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
+          "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
+          "dev": true
+        }
+      }
     },
     "execa": {
       "version": "0.4.0",
       "resolved": "https://registry.npmjs.org/execa/-/execa-0.4.0.tgz",
       "integrity": "sha1-TrZGejaglfq7KXD/nV4/t7zm68M=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "cross-spawn-async": "2.2.5",
+        "is-stream": "1.1.0",
+        "npm-run-path": "1.0.0",
+        "object-assign": "4.1.1",
+        "path-key": "1.0.0",
+        "strip-eof": "1.0.0"
+      }
     },
     "exit": {
       "version": "0.1.2",
@@ -1618,18 +2832,30 @@
       "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
+          "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
+          "dev": true,
+          "requires": {
+            "is-number": "0.1.1",
+            "repeat-string": "0.2.2"
+          }
         },
         "is-number": {
           "version": "0.1.1",
@@ -1649,31 +2875,107 @@
       "version": "0.1.5",
       "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
       "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "is-posix-bracket": "0.1.1"
+      }
     },
     "expand-range": {
       "version": "1.8.2",
       "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz",
       "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "fill-range": "2.2.3"
+      }
     },
     "exports-loader": {
       "version": "0.6.4",
       "resolved": "https://registry.npmjs.org/exports-loader/-/exports-loader-0.6.4.tgz",
       "integrity": "sha1-1w/GEhl1s1/BKDDPUnVL4nQPyIY=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "loader-utils": "1.1.0",
+        "source-map": "0.5.6"
+      }
     },
     "express": {
-      "version": "4.15.3",
-      "resolved": "https://registry.npmjs.org/express/-/express-4.15.3.tgz",
-      "integrity": "sha1-urZdDwOqgMNYQIly/HAPkWlEtmI=",
+      "version": "4.15.2",
+      "resolved": "https://registry.npmjs.org/express/-/express-4.15.2.tgz",
+      "integrity": "sha1-rxB/wUhQRFfy3Kmm8lcdcSm5ezU=",
       "dev": true,
+      "requires": {
+        "accepts": "1.3.3",
+        "array-flatten": "1.1.1",
+        "content-disposition": "0.5.2",
+        "content-type": "1.0.2",
+        "cookie": "0.3.1",
+        "cookie-signature": "1.0.6",
+        "debug": "2.6.1",
+        "depd": "1.1.0",
+        "encodeurl": "1.0.1",
+        "escape-html": "1.0.3",
+        "etag": "1.8.0",
+        "finalhandler": "1.0.3",
+        "fresh": "0.5.0",
+        "merge-descriptors": "1.0.1",
+        "methods": "1.1.2",
+        "on-finished": "2.3.0",
+        "parseurl": "1.3.1",
+        "path-to-regexp": "0.1.7",
+        "proxy-addr": "1.1.4",
+        "qs": "6.4.0",
+        "range-parser": "1.2.0",
+        "send": "0.15.1",
+        "serve-static": "1.12.1",
+        "setprototypeof": "1.0.3",
+        "statuses": "1.3.1",
+        "type-is": "1.6.15",
+        "utils-merge": "1.0.0",
+        "vary": "1.1.1"
+      },
       "dependencies": {
         "debug": {
-          "version": "2.6.7",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz",
-          "integrity": "sha1-krrR9tBbu2u6Isyoi80OyJTChh4=",
+          "version": "2.6.1",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.1.tgz",
+          "integrity": "sha1-eYVQkLosTjEVzH2HaUkdWPBJE1E=",
+          "dev": true,
+          "requires": {
+            "ms": "0.7.2"
+          }
+        },
+        "mime": {
+          "version": "1.3.4",
+          "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz",
+          "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM=",
+          "dev": true
+        },
+        "ms": {
+          "version": "0.7.2",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
+          "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=",
           "dev": true
+        },
+        "send": {
+          "version": "0.15.1",
+          "resolved": "https://registry.npmjs.org/send/-/send-0.15.1.tgz",
+          "integrity": "sha1-igI1TCbm9cynAAZfXwzeupDse18=",
+          "dev": true,
+          "requires": {
+            "debug": "2.6.1",
+            "depd": "1.1.0",
+            "destroy": "1.0.4",
+            "encodeurl": "1.0.1",
+            "escape-html": "1.0.3",
+            "etag": "1.8.0",
+            "fresh": "0.5.0",
+            "http-errors": "1.6.1",
+            "mime": "1.3.4",
+            "ms": "0.7.2",
+            "on-finished": "2.3.0",
+            "range-parser": "1.2.0",
+            "statuses": "1.3.1"
+          }
         }
       }
     },
@@ -1684,22 +2986,47 @@
       "dev": true
     },
     "external-editor": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.0.4.tgz",
-      "integrity": "sha1-HtkZnanL/i7y96MbL96LDRI2iXI=",
-      "dev": true
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.1.0.tgz",
+      "integrity": "sha1-PQJqIbf5W1cmOH1CAKwWDTcsO0g=",
+      "dev": true,
+      "requires": {
+        "chardet": "0.4.2",
+        "iconv-lite": "0.4.19",
+        "tmp": "0.0.33"
+      },
+      "dependencies": {
+        "tmp": {
+          "version": "0.0.33",
+          "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+          "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+          "dev": true,
+          "requires": {
+            "os-tmpdir": "1.0.2"
+          }
+        }
+      }
     },
     "extglob": {
       "version": "0.3.2",
       "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
       "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
-      "dev": true
+      "dev": true,
+      "requires": {
+        "is-extglob": "1.0.0"
+      }
     },
     "extract-text-webpack-plugin": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/extract-text-webpack-plugin/-/extract-text-webpack-plugin-2.0.0.tgz",
-      "integrity": "sha1-hkD3JgmACjUo8ToqljTVZqXBrmA=",
-      "dev": true
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/extract-text-webpack-plugin/-/extract-text-webpack-plugin-2.1.2.tgz",
+      "integrity": "sha1-dW7076gVXDaBgz+8NNpTuUF0bWw=",
+      "dev": true,
+      "requires": {
+        "async": "2.4.1",
+        "loader-utils": "1.1.0",
+        "schema-utils": "0.3.0",
+        "webpack-sources": "1.1.0"
+      }
     },
     "extsprintf": {
       "version": "1.0.2",
@@ -1707,6 +3034,18 @@
       "integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA=",
       "dev": true
     },
+    "fast-deep-equal": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz",
+      "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=",
+      "dev": true
+    },
+    "fast-json-stable-stringify": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringi

<TRUNCATED>

[7/9] metron git commit: METRON-1489 Retrofit UI tests to run reliably during nightly QE runs (sardell via nickwallen) closes apache/metron#1004

Posted by le...@apache.org.
METRON-1489 Retrofit UI tests to run reliably during nightly QE runs (sardell via nickwallen) closes apache/metron#1004


Project: http://git-wip-us.apache.org/repos/asf/metron/repo
Commit: http://git-wip-us.apache.org/repos/asf/metron/commit/436cec43
Tree: http://git-wip-us.apache.org/repos/asf/metron/tree/436cec43
Diff: http://git-wip-us.apache.org/repos/asf/metron/diff/436cec43

Branch: refs/heads/feature/METRON-1416-upgrade-solr
Commit: 436cec43737bf0e38659c598cc8098509763fedf
Parents: 2ee6cc7
Author: sardell <sa...@hortonworks.com>
Authored: Tue Jun 26 10:45:22 2018 -0400
Committer: nickallen <ni...@apache.org>
Committed: Tue Jun 26 10:45:22 2018 -0400

----------------------------------------------------------------------
 metron-interface/metron-alerts/README.md        |   19 +-
 .../e2e/alert-details/alert-details.po.ts       |   67 +-
 .../alert-details-status.e2e-spec.ts            |  168 +-
 .../alert-filters/alert-filters.e2e-spec.ts     |   78 +-
 .../alert-filters/alert-filters.po.ts           |   31 +-
 .../alert-status/alerts-list-status.e2e-spec.ts |  125 +-
 .../e2e/alerts-list/alerts-list.e2e-spec.ts     |  369 +-
 .../e2e/alerts-list/alerts-list.po.ts           |  308 +-
 .../configure-table/configure-table.e2e-spec.ts |   62 +-
 .../meta-alerts/meta-alert.e2e-spec.ts          |  248 +-
 .../alerts-list/meta-alerts/meta-alert.po.ts    |   21 +-
 .../save-search/save-search.e2e-spec.ts         |   93 +-
 .../alerts-list/tree-view/tree-view.e2e-spec.ts |  208 +-
 .../e2e/alerts-list/tree-view/tree-view.po.ts   |  170 +-
 .../metron-alerts/e2e/login/login.e2e-spec.ts   |   36 +-
 .../metron-alerts/e2e/login/login.po.ts         |   44 +-
 .../e2e/utils/clean_metron_update_table.ts      |   52 +
 .../metron-alerts/e2e/utils/e2e_util.ts         |  223 +-
 .../metron-alerts/package-lock.json             | 6163 +++++++++++++++---
 metron-interface/metron-alerts/package.json     |    8 +-
 .../metron-alerts/protractor.conf.js            |   31 +-
 .../alert-filters/alert-filters.component.ts    |    2 +-
 .../alerts-list/alerts-list.component.html      |    8 +-
 .../alerts-list/alerts-list.component.scss      |    3 +-
 .../alerts/alerts-list/alerts-list.component.ts |    4 +-
 .../tree-view/tree-view.component.html          |    4 +-
 .../configure-rows/configure-rows.component.ts  |    2 +-
 .../saved-searches.component.html               |    4 +-
 .../app/shared/group-by/group-by.component.html |    2 +-
 .../shared/time-range/time-range.component.html |   12 +-
 .../shared/time-range/time-range.component.scss |    4 +
 .../metron-alerts/src/app/utils/constants.ts    |    1 +
 .../src/environments/environment.e2e.ts         |    3 +-
 .../src/environments/environment.js             |    6 +-
 .../src/environments/environment.prod.ts        |    3 +-
 .../src/environments/environment.ts             |    3 +-
 metron-interface/metron-alerts/src/index.html   |    2 +-
 metron-interface/metron-alerts/src/styles.scss  |   10 +
 38 files changed, 6644 insertions(+), 1953 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/README.md
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/README.md b/metron-interface/metron-alerts/README.md
index 41052a7..ca6dcb7 100644
--- a/metron-interface/metron-alerts/README.md
+++ b/metron-interface/metron-alerts/README.md
@@ -136,20 +136,27 @@ The application will be available at http://host:4201 assuming the port is set t
 
 ## E2E Tests
 
-An expressjs server is available for mocking the elastic search api.
+### Caveats
+1. E2E tests uses data from full-dev wherever applicable. The tests assume rest-api's are available @http://node1:8082. It is recommended to shutdown all other Metron services while running the E2E tests including Parsers, Enrichment, Indexing and the Profiler.
 
-1. Run e2e webserver :
+1. E2E tests are run on headless chrome. To see the chrome browser in action, remove the '--headless' parameter of chromeOptions in metron/metron-interface/metron-alerts/protractor.conf.js file
+
+1. E2E tests delete all the data in HBase table 'metron_update' and Elastic search index 'meta_alerts_index' for testing against its test data
+
+1. E2E tests use [protractor-flake](https://github.com/NickTomlin/protractor-flake) to re-run flaky tests.
+
+### Steps to run
+
+1. An Express.js server is available for accessing the rest api. Run the e2e webserver:
     ```
     cd metron/metron-interface/metron-alerts
     sh ./scripts/start-server-for-e2e.sh
     ```
 
-1. run e2e test using the following command
+1. Run e2e tests using the following command:
     ```
     cd metron/metron-interface/metron-alerts
     npm run e2e
     ```
 
-1. E2E tests uses data from full-dev wherever applicable. The tests assume rest-api's are available @http://node1:8082
-
-**NOTE**: *e2e tests covers all the general workflows and we will extend them as we need*
+**NOTE**: *e2e tests cover all the general workflows and we will extend them as we need*

http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/e2e/alert-details/alert-details.po.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/e2e/alert-details/alert-details.po.ts b/metron-interface/metron-alerts/e2e/alert-details/alert-details.po.ts
index 18cb273..8279ad9 100644
--- a/metron-interface/metron-alerts/e2e/alert-details/alert-details.po.ts
+++ b/metron-interface/metron-alerts/e2e/alert-details/alert-details.po.ts
@@ -17,77 +17,84 @@
  */
 
 import {browser, element, by, protractor} from 'protractor';
-import {waitForElementInVisibility, waitForElementPresence, waitForElementVisibility} from '../utils/e2e_util';
+import {
+  scrollIntoView, waitForElementInVisibility, waitForElementPresence,
+  waitForElementVisibility, waitForStalenessOf
+} from '../utils/e2e_util';
 
 export class MetronAlertDetailsPage {
 
   navigateTo(alertId: string) {
-    browser.waitForAngularEnabled(false);
-    browser.get('/alerts-list(dialog:details/alerts_ui_e2e/'+ alertId +'/alerts_ui_e2e_index)');
-    browser.sleep(2000);
+    return browser.waitForAngularEnabled(false)
+    .then(() => browser.get('/alerts-list(dialog:details/alerts_ui_e2e/'+ alertId +'/alerts_ui_e2e_index)'))
+    .then(() => browser.sleep(1000));
   }
 
   addCommentAndSave(comment: string, index: number) {
     let textAreaElement = element(by.css('app-alert-details textarea'));
     let addCommentButtonElement = element(by.buttonText('ADD COMMENT'));
-    let latestCommentEle = element.all(by.css('.comment-container .comment')).get(index);
+    let latestCommentEle = element.all(by.cssContainingText('.comment-container .comment', comment));
 
-    textAreaElement.clear()
+    return textAreaElement.clear()
     .then(() => textAreaElement.sendKeys(comment))
     .then(() => addCommentButtonElement.click())
-    .then(() => waitForElementPresence(latestCommentEle));
+    .then(() => waitForElementVisibility(latestCommentEle));
   }
 
   clickNew() {
-    element.all(by.css('.metron-slider-pane-details table tbody tr')).get(1).all(by.css('td')).get(0).click();
+    return element.all(by.css('.metron-slider-pane-details table tbody tr')).get(1).all(by.css('td')).get(0).click();
   }
 
   clickOpen() {
-    element.all(by.css('.metron-slider-pane-details table tbody tr')).get(1).all(by.css('td')).get(1).click();
+    return element.all(by.css('.metron-slider-pane-details table tbody tr')).get(1).all(by.css('td')).get(1).click();
   }
 
   clickDismiss() {
-    element.all(by.css('.metron-slider-pane-details table tbody tr')).get(1).all(by.css('td')).get(2).click();
+    return element.all(by.css('.metron-slider-pane-details table tbody tr')).get(1).all(by.css('td')).get(2).click();
   }
 
   clickEscalate() {
-    element.all(by.css('.metron-slider-pane-details table tbody tr')).get(0).all(by.css('td')).get(1).click();
+    return element.all(by.css('.metron-slider-pane-details table tbody tr')).get(0).all(by.css('td')).get(1).click();
   }
 
   clickResolve() {
-    element.all(by.css('.metron-slider-pane-details table tbody tr')).get(2).all(by.css('td')).get(1).click();
+    return element.all(by.css('.metron-slider-pane-details table tbody tr')).get(2).all(by.css('td')).get(1).click();
   }
 
   clickCommentsInSideNav() {
-    return element(by.css('app-alert-details .fa.fa-comment')).click();
+    let commentIcon = element(by.css('app-alert-details .fa.fa-comment'));
+    return waitForElementVisibility(commentIcon)
+    .then(() => commentIcon.click())
+    .then(() => waitForElementVisibility(element(by.buttonText('ADD COMMENT'))));
   }
 
   clickNoForConfirmation() {
-    browser.sleep(1000);
-    let dialogElement = element(by.css('.metron-dialog .modal-header .close'));
-    let maskElement = element(by.css('.modal-backdrop.fade'));
-    waitForElementVisibility(dialogElement).then(() => element(by.css('.metron-dialog')).element(by.buttonText('Cancel')).click())
+    let cancelButton = element(by.css('.metron-dialog')).element(by.buttonText('Cancel'));
+    let maskElement = element(by.css('.modal-backdrop'));
+    waitForElementVisibility(cancelButton).then(() => element(by.css('.metron-dialog')).element(by.buttonText('Cancel')).click())
     .then(() => waitForElementInVisibility(maskElement));
   }
 
-  clickYesForConfirmation() {
-    browser.sleep(1000);
-    let dialogElement = element(by.css('.metron-dialog .modal-header .close'));
-    let maskElement = element(by.css('.modal-backdrop.fade'));
-    waitForElementVisibility(dialogElement).then(() => element(by.css('.metron-dialog')).element(by.buttonText('OK')).click())
+  clickYesForConfirmation(comment) {
+    let okButton = element(by.css('.metron-dialog')).element(by.buttonText('OK'));
+    let maskElement = element(by.css('.modal-backdrop'));
+    waitForElementVisibility(okButton).then(() => element(by.css('.metron-dialog')).element(by.buttonText('OK')).click())
     .then(() => waitForElementInVisibility(maskElement));
   }
 
   closeDetailPane() {
-    element(by.css('app-alert-details .close-button')).click();
-    browser.sleep(2000);
-  }
+  let dialogElement = element(by.css('.metron-dialog.modal.show'));
+  return waitForElementInVisibility(dialogElement).then(() => scrollIntoView(element(by.css('app-alert-details .close-button')), true)
+        .then(() => element(by.css('app-alert-details .close-button')).click())
+        .then(() => waitForElementInVisibility(element(by.css('app-alert-details')))));
+}
 
   deleteComment() {
     let scrollToEle = element.all(by.css('.comment-container')).get(0);
     let trashIcon = element.all(by.css('.fa.fa-trash-o')).get(0);
     browser.actions().mouseMove(scrollToEle).perform().then(() => waitForElementVisibility(trashIcon))
-    .then(() => element.all(by.css('.fa.fa-trash-o')).get(0).click());
+    .then(() => trashIcon.click())
+    .then(() => waitForElementVisibility(element(by.css('.modal-backdrop'))));
   }
 
   getAlertStatus(previousText) {
@@ -126,19 +133,19 @@ export class MetronAlertDetailsPage {
   }
 
   clickRenameMetaAlert() {
-    element(by.css('app-alert-details .editable-text')).click();
+    return element(by.css('app-alert-details .editable-text')).click();
   }
 
   renameMetaAlert(name: string) {
-    element(by.css('app-alert-details input.form-control')).sendKeys(name);
+    return element(by.css('app-alert-details input.form-control')).sendKeys(name);
   }
 
   cancelRename() {
-    element(by.css('app-alert-details .input-group .fa.fa-times')).click();
+    return element(by.css('app-alert-details .input-group .fa.fa-times')).click();
   }
 
   saveRename() {
-    element(by.css('app-alert-details .fa.fa-check')).click();
+    return element(by.css('app-alert-details .fa.fa-check')).click();
   }
 
   getAlertDetailsCount() {

http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/e2e/alert-details/alert-status/alert-details-status.e2e-spec.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/e2e/alert-details/alert-status/alert-details-status.e2e-spec.ts b/metron-interface/metron-alerts/e2e/alert-details/alert-status/alert-details-status.e2e-spec.ts
index d051a78..28d9ed0 100644
--- a/metron-interface/metron-alerts/e2e/alert-details/alert-status/alert-details-status.e2e-spec.ts
+++ b/metron-interface/metron-alerts/e2e/alert-details/alert-status/alert-details-status.e2e-spec.ts
@@ -23,24 +23,25 @@ import {loadTestData, deleteTestData} from '../../utils/e2e_util';
 import { MetronAlertsPage } from '../../alerts-list/alerts-list.po';
 import {TreeViewPage} from '../../alerts-list/tree-view/tree-view.po';
 
-describe('metron-alerts alert status', function() {
+describe('Test spec for metron details page', function() {
   let page: MetronAlertDetailsPage;
   let listPage: MetronAlertsPage;
   let treePage: TreeViewPage;
   let loginPage: LoginPage;
 
-  beforeAll(() => {
-    loadTestData();
+  beforeAll(async function() : Promise<any> {
     loginPage = new LoginPage();
     listPage = new MetronAlertsPage();
     treePage = new TreeViewPage();
-    loginPage.login();
+
+    await loadTestData();
+    await loginPage.login();
   });
 
-  afterAll(() => {
+  afterAll(async function() : Promise<any> {
     new MetronAlertsPage().navigateTo();
-    loginPage.logout();
-    deleteTestData();
+    await loginPage.logout();
+    await deleteTestData();
   });
 
   beforeEach(() => {
@@ -48,99 +49,104 @@ describe('metron-alerts alert status', function() {
     jasmine.addMatchers(customMatchers);
   });
 
-  it('should change alert statuses', () => {
-    let alertId = 'c4c5e418-3938-099e-bb0d-37028a98dca8';
-
-    page.navigateTo(alertId);
-    page.clickNew();
-    expect(page.getAlertStatus('ANY')).toEqual('NEW');
-    page.clickOpen();
-    expect(page.getAlertStatus('NEW')).toEqual('OPEN');
-    expect(listPage.getAlertStatusById(alertId)).toEqual('OPEN');
-    page.clickDismiss();
-    expect(page.getAlertStatus('OPEN')).toEqual('DISMISS');
-    expect(listPage.getAlertStatusById(alertId)).toEqual('DISMISS');
-    page.clickEscalate();
-    expect(page.getAlertStatus('DISMISS')).toEqual('ESCALATE');
-    expect(listPage.getAlertStatusById(alertId)).toEqual('ESCALATE');
-    page.clickResolve();
-    expect(page.getAlertStatus('ESCALATE')).toEqual('RESOLVE');
-    expect(listPage.getAlertStatusById(alertId)).toEqual('RESOLVE');
-    page.clickNew();
+  it('should change alert statuses', async function() : Promise<any> {
+    let alertId = '2cc174d7-c049-aaf4-d0d6-138073777309';
+
+    await page.navigateTo(alertId);
+    expect(await page.getAlertStatus('ANY')).toEqual('NEW');
+    await page.clickOpen();
+    expect(await page.getAlertStatus('NEW')).toEqual('OPEN');
+    expect(await listPage.getAlertStatusById(alertId)).toEqual('OPEN');
+    await page.clickDismiss();
+    expect(await page.getAlertStatus('OPEN')).toEqual('DISMISS');
+    expect(await listPage.getAlertStatusById(alertId)).toEqual('DISMISS');
+    await page.clickEscalate();
+    expect(await page.getAlertStatus('DISMISS')).toEqual('ESCALATE');
+    expect(await listPage.getAlertStatusById(alertId)).toEqual('ESCALATE');
+    await page.clickResolve();
+    expect(await page.getAlertStatus('ESCALATE')).toEqual('RESOLVE');
+    expect(await listPage.getAlertStatusById(alertId)).toEqual('RESOLVE');
+    await page.clickNew();
   });
 
-  it('should add comments for table view', () => {
-    let comment1 = 'This is a sample comment';
-    let comment2 = 'This is a sample comment again';
-    let userNameAndTimestamp = '- admin - a few seconds ago';
+  // The below code will fail until this issue is resolved in Protractor: https://github.com/angular/protractor/issues/4693
+  // This is because the connection resets before deleting the test comment, which causes the assertion to be false
 
-    page.clickCommentsInSideNav();
-    page.addCommentAndSave(comment1, 0);
+  // it('should add comments for table view', async function() : Promise<any> {
+  //   let comment1 = 'This is a sample comment';
+  //   let comment2 = 'This is a sample comment again';
+  //   let userNameAndTimestamp = '- admin - a few seconds ago';
+  //   let alertId = '2cc174d7-c049-aaf4-d0d6-138073777309';
 
-    expect(page.getCommentsText()).toEqual([comment1]);
-    expect(page.getCommentsUserNameAndTimeStamp()).toEqual([userNameAndTimestamp]);
+  //   page.navigateTo(alertId);
 
-    page.addCommentAndSave(comment2, 1);
-    expect(page.getCommentsText()).toEqual([comment2, comment1]);
-    expect(page.getCommentsUserNameAndTimeStamp()).toEqual([userNameAndTimestamp, userNameAndTimestamp]);
+  //   await page.clickCommentsInSideNav();
+  //   await page.addCommentAndSave(comment1, 0);
 
-    page.deleteComment();
-    page.clickNoForConfirmation();
-    expect(page.getCommentsText()).toEqual([comment2, comment1]);
+  //   expect(await page.getCommentsText()).toEqual([comment1]);
+  //   expect(await page.getCommentsUserNameAndTimeStamp()).toEqual([userNameAndTimestamp]);
 
-    page.deleteComment();
-    page.clickYesForConfirmation();
-    expect(page.getCommentsText()).toEqual([comment1]);
+  //   await page.addCommentAndSave(comment2, 0);
+  //   expect(await page.getCommentsText()).toEqual([comment2, comment1]);
+  //   expect(await page.getCommentsUserNameAndTimeStamp()).toEqual([userNameAndTimestamp, userNameAndTimestamp]);
 
-    expect(page.getCommentIconCountInListView()).toEqual(1);
+  //   await page.deleteComment();
+  //   await page.clickNoForConfirmation();
+  //   expect(await page.getCommentsText()).toEqual([comment2, comment1]);
 
-    page.deleteComment();
-    page.clickYesForConfirmation();
-    expect(page.getCommentsText()).toEqual([]);
+  //   await page.deleteComment();
+  //   await page.clickYesForConfirmation(comment2);
+  //   expect(await page.getCommentsText()).toEqual([comment1]);
 
-    page.closeDetailPane();
-  });
+  //   expect(await page.getCommentIconCountInListView()).toEqual(1);
 
-  it('should add comments for tree view', () => {
-    let comment1 = 'This is a sample comment';
-    let comment2 = 'This is a sample comment again';
-    let userNameAndTimestamp = '- admin - a few seconds ago';
+  //   await page.deleteComment();
+  //   await page.clickYesForConfirmation(comment1);
+  //   expect(await page.getCommentsText()).toEqual([]);
 
-    treePage.selectGroup('source:type');
-    treePage.expandDashGroup('alerts_ui_e2e');
+  //   await page.closeDetailPane();
+  // });
 
-    treePage.clickOnRow('acf5a641-9cdb-d7ec-c309-6ea316e14fbe');
-    page.clickCommentsInSideNav();
-    page.addCommentAndSave(comment1, 0);
+  // it('should add comments for tree view', async function(): Promise<any> {
+  //   let comment1 = 'This is a sample comment';
+  //   let comment2 = 'This is a sample comment again';
+  //   let userNameAndTimestamp = '- admin - a few seconds ago';
 
-    expect(page.getCommentsText()).toEqual([comment1]);
-    expect(page.getCommentsUserNameAndTimeStamp()).toEqual([userNameAndTimestamp]);
-    expect(page.getCommentIconCountInTreeView()).toEqual(1);
+  //   await treePage.navigateToAlertsList();
+  //   await treePage.selectGroup('source:type');
+  //   await treePage.expandDashGroup('alerts_ui_e2e');
 
-    page.deleteComment();
-    page.clickYesForConfirmation();
-    expect(page.getCommentsText()).toEqual([]);
-    page.closeDetailPane();
+  //   await treePage.clickOnRow('acf5a641-9cdb-d7ec-c309-6ea316e14fbe');
+  //   await page.clickCommentsInSideNav();
+  //   await page.addCommentAndSave(comment1, 0);
 
-    treePage.unGroup();
+  //   expect(await page.getCommentsText()).toEqual([comment1]);
+  //   expect(await page.getCommentsUserNameAndTimeStamp()).toEqual([userNameAndTimestamp]);
+  //   expect(await page.getCommentIconCountInTreeView()).toEqual(1);
 
-    treePage.selectGroup('source:type');
-    treePage.selectGroup('enrichments:geo:ip_dst_addr:country');
-    treePage.expandDashGroup('alerts_ui_e2e');
-    treePage.expandSubGroup('alerts_ui_e2e', 'FR');
+  //   await page.deleteComment();
+  //   await page.clickYesForConfirmation(comment1);
+  //   expect(await page.getCommentsText()).toEqual([]);
+  //   await page.closeDetailPane();
 
-    treePage.clickOnRow('7cd91565-132f-3340-db76-3ade5be54a6e');
-    page.clickCommentsInSideNav();
-    page.addCommentAndSave(comment2, 0);
+  //   await treePage.unGroup();
 
-    expect(page.getCommentsText()).toEqual([comment2]);
-    expect(page.getCommentsUserNameAndTimeStamp()).toEqual([userNameAndTimestamp]);
-    expect(page.getCommentIconCountInTreeView()).toEqual(1);
+  //   await treePage.selectGroup('source:type');
+  //   await treePage.selectGroup('enrichments:geo:ip_dst_addr:country');
+  //   await treePage.expandDashGroup('alerts_ui_e2e');
+  //   await treePage.expandSubGroup('alerts_ui_e2e', 'FR');
 
-    page.deleteComment();
-    page.clickYesForConfirmation();
-    expect(page.getCommentsText()).toEqual([]);
-    page.closeDetailPane();
-  });
+  //   await treePage.clickOnRow('07b29c29-9ab0-37dd-31d3-08ff19eaa888');
+  //   await page.clickCommentsInSideNav();
+  //   await page.addCommentAndSave(comment2, 0);
+
+  //   expect(await page.getCommentsText()).toEqual(comment2);
+  //   expect(await page.getCommentsUserNameAndTimeStamp()).toEqual(userNameAndTimestamp);
+  //   expect(await page.getCommentIconCountInTreeView()).toEqual(1);
+
+  //   await page.deleteComment();
+  //   await page.clickYesForConfirmation(comment2);
+  //   await page.closeDetailPane();
+  // });
 
 });

http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/e2e/alerts-list/alert-filters/alert-filters.e2e-spec.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/e2e/alerts-list/alert-filters/alert-filters.e2e-spec.ts b/metron-interface/metron-alerts/e2e/alerts-list/alert-filters/alert-filters.e2e-spec.ts
index b21e316..d9caf7c 100644
--- a/metron-interface/metron-alerts/e2e/alerts-list/alert-filters/alert-filters.e2e-spec.ts
+++ b/metron-interface/metron-alerts/e2e/alerts-list/alert-filters/alert-filters.e2e-spec.ts
@@ -21,20 +21,24 @@ import {customMatchers} from '../../matchers/custom-matchers';
 import {LoginPage} from '../../login/login.po';
 import {AlertFacetsPage} from './alert-filters.po';
 import {loadTestData, deleteTestData} from '../../utils/e2e_util';
+import {MetronAlertsPage} from '../alerts-list.po';
 
-describe('metron-alerts facets', function() {
+describe('Test spec for facet filters', function() {
   let page: AlertFacetsPage;
+  let tablePage: MetronAlertsPage;
   let loginPage: LoginPage;
 
-  beforeAll(() => {
-    loadTestData();
+  beforeAll(async function() : Promise<any> {
     loginPage = new LoginPage();
-    loginPage.login();
+    tablePage = new MetronAlertsPage();
+
+    await loadTestData();
+    await loginPage.login();
   });
 
-  afterAll(() => {
-    loginPage.logout();
-    deleteTestData();
+  afterAll(async function() : Promise<any> {
+    await loginPage.logout();
+    await deleteTestData();
   });
 
   beforeEach(() => {
@@ -42,63 +46,21 @@ describe('metron-alerts facets', function() {
     jasmine.addMatchers(customMatchers);
   });
 
-  it('should display facets data', () => {
+  it('should display facets data', async function() : Promise<any> {
     let facetValues = [ 'enrichm...:country 3', 'ip_dst_addr 8', 'ip_src_addr 2', 'source:type 1' ];
 
-    page.navgateToAlertList();
-    expect(page.getFacetsTitle()).toEqualBcoz(['Filters'], 'for Title as Filters');
-    expect(page.getFacetsValues()).toEqual(facetValues, 'for Facet values');
-  });
-
-  it('should expand all facets', () => {
-    expect(page.getFacetState(0)).toEqualBcoz('collapse', 'for first facet');
-    expect(page.getFacetState(1)).toEqualBcoz('collapse', 'for second facet');
-    expect(page.getFacetState(2)).toEqualBcoz('collapse', 'for third facet');
-    expect(page.getFacetState(3)).toEqualBcoz('collapse', 'for fourth facet');
-
-    page.toggleFacetState(0);
-    page.toggleFacetState(1);
-    page.toggleFacetState(2);
-    page.toggleFacetState(3);
-
-    expect(page.getFacetState(0)).toEqualBcoz('collapse show', 'for first facet');
-    expect(page.getFacetState(1)).toEqualBcoz('collapse show', 'for second facet');
-    expect(page.getFacetState(2)).toEqualBcoz('collapse show', 'for third facet');
-    expect(page.getFacetState(3)).toEqualBcoz('collapse show', 'for fourth facet');
-  });
-
-  it('should have all facet  values', () => {
-    let hostMap = {
-        'comarks...rity.com': '9' ,
-        '7oqnsnz...ysun.com': '44' ,
-        'node1': '36' ,
-        '62.75.195.236': '18' ,
-        'runlove.us': '13' ,
-        'ip-addr.es': '2' ,
-        'ubb67.3...grams.in': '1' ,
-        'r03afd2...grams.in': '3' ,
-        'va872g....grams.in': '1'
-    };
-
-    expect(page.getFacetValues(0)).toEqualBcoz({ US: '22', RU: '44', FR: '25' }, 'for enrichment facet');
-    expect(page.getFacetValues(3)).toEqual({ alerts_ui_e2e: '169' }, 'for source:type facet');
+    await page.navgateToAlertList();
+    expect(await page.getFacetsTitle()).toEqualBcoz('Filters', 'for Title as Filters');
+    expect(await page.getFacetsValues()).toEqual(facetValues, 'for Facet values');
   });
 
-  it('should collapse all facets', () => {
-    expect(page.getFacetState(0)).toEqualBcoz('collapse show', 'for first facet');
-    expect(page.getFacetState(1)).toEqualBcoz('collapse show', 'for second facet');
-    expect(page.getFacetState(2)).toEqualBcoz('collapse show', 'for third facet');
-    expect(page.getFacetState(3)).toEqualBcoz('collapse show', 'for fourth facet');
+  it('should search when facet is selected', async function() : Promise<any> {
+    await page.toggleFacetState(1);
+    expect(await page.getFacetState(1)).toEqualBcoz('collapse show', 'for second facet');
 
-    page.toggleFacetState(0);
-    page.toggleFacetState(1);
-    page.toggleFacetState(2);
-    page.toggleFacetState(3);
+    await page.selectFilter('95.163.121.204');
+    expect(await tablePage.getChangesAlertTableTitle('Alerts (169)')).toEqual('Alerts (44)');
 
-    expect(page.getFacetState(0)).toEqualBcoz('collapse', 'for first facet');
-    expect(page.getFacetState(1)).toEqualBcoz('collapse', 'for second facet');
-    expect(page.getFacetState(2)).toEqualBcoz('collapse', 'for third facet');
-    expect(page.getFacetState(3)).toEqualBcoz('collapse', 'for fourth facet');
   });
 });
 

http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/e2e/alerts-list/alert-filters/alert-filters.po.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/e2e/alerts-list/alert-filters/alert-filters.po.ts b/metron-interface/metron-alerts/e2e/alerts-list/alert-filters/alert-filters.po.ts
index 7d675e5..3d17db6 100644
--- a/metron-interface/metron-alerts/e2e/alerts-list/alert-filters/alert-filters.po.ts
+++ b/metron-interface/metron-alerts/e2e/alerts-list/alert-filters/alert-filters.po.ts
@@ -17,39 +17,43 @@
  */
 
 import {browser, element, by} from 'protractor';
-import {waitForElementPresence} from '../../utils/e2e_util';
+import {
+  reduce_for_get_all, waitForElementPresence,
+  waitForElementVisibility
+} from '../../utils/e2e_util';
 
 export class AlertFacetsPage {
 
   private sleepTime = 500;
 
   navgateToAlertList() {
-    browser.waitForAngularEnabled(false);
-    return browser.get('/alerts-list');
+    return browser.waitForAngularEnabled(false).then(() => browser.get('/alerts-list'));
   }
 
   getFacetsTitle() {
-    return waitForElementPresence(element.all(by.css('app-alert-filters metron-collapse'))).then(() => {
-      return element.all(by.css('app-alert-filters .title')).getText();
+    return waitForElementVisibility(element(by.css('app-alert-filters .title'))).then(() => {
+      return element(by.css('app-alert-filters .title')).getText();
     });
   }
 
   getFacetsValues() {
-    return element.all(by.css('app-alert-filters metron-collapse')).getText();
+    return waitForElementVisibility(element(by.css('app-alert-filters  metron-collapse:first-child'))).then(() => {
+      return element.all(by.css('app-alert-filters metron-collapse')).reduce(reduce_for_get_all(), []);
+    });
   }
 
   getFacetState(id: number) {
-    browser.sleep(this.sleepTime);
     let collpaseElement = element.all(by.css('metron-collapse')).get(id);
-    browser.actions().mouseMove(collpaseElement).perform();
-    return collpaseElement.element(by.css('div.collapse')).getAttribute('class');
+    return browser.actions().mouseMove(collpaseElement).perform()
+    .then(() => collpaseElement.element(by.css('div.collapse')).getAttribute('class'))
   }
 
   toggleFacetState(id: number) {
-    browser.sleep(this.sleepTime);
     let collpaseElement = element.all(by.css('metron-collapse')).get(id);
-    browser.actions().mouseMove(collpaseElement).perform();
-    return collpaseElement.element(by.css('a')).click();
+    return browser.actions().mouseMove(collpaseElement).perform()
+    .then(() => collpaseElement.element(by.css('a')).click())
+    .then(() => waitForElementVisibility(collpaseElement.element(by.css('div.collapse'))))
+
   }
 
   getFacetValues(id: number) {
@@ -64,5 +68,8 @@ export class AlertFacetsPage {
     });
   }
 
+  selectFilter(filterTitle: string) {
+    return element(by.css(`li[title="${filterTitle}"]`)).click();
+  }
 }
 

http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/e2e/alerts-list/alert-status/alerts-list-status.e2e-spec.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/e2e/alerts-list/alert-status/alerts-list-status.e2e-spec.ts b/metron-interface/metron-alerts/e2e/alerts-list/alert-status/alerts-list-status.e2e-spec.ts
index 828f290..e421c6e 100644
--- a/metron-interface/metron-alerts/e2e/alerts-list/alert-status/alerts-list-status.e2e-spec.ts
+++ b/metron-interface/metron-alerts/e2e/alerts-list/alert-status/alerts-list-status.e2e-spec.ts
@@ -22,20 +22,21 @@ import {LoginPage} from '../../login/login.po';
 import {loadTestData, deleteTestData} from '../../utils/e2e_util';
 import {TreeViewPage} from '../tree-view/tree-view.po';
 
-describe('metron-alerts alert status', function() {
+describe('Test spec for changing alert status in list view & tree view', function() {
   let page: MetronAlertsPage;
   let treePage: TreeViewPage;
   let loginPage: LoginPage;
 
-  beforeAll(() => {
-    loadTestData();
+  beforeAll(async function() : Promise<any> {
     loginPage = new LoginPage();
-    loginPage.login();
+
+    await loadTestData();
+    await loginPage.login();
   });
 
-  afterAll(() => {
-    loginPage.logout();
-    deleteTestData();
+  afterAll(async function() : Promise<any> {
+    await loginPage.logout();
+    await deleteTestData();
   });
 
   beforeEach(() => {
@@ -44,81 +45,81 @@ describe('metron-alerts alert status', function() {
     jasmine.addMatchers(customMatchers);
   });
 
-  it('should change alert status for multiple alerts to OPEN', () => {
-    page.navigateTo();
-    page.toggleAlertInList(0);
-    page.toggleAlertInList(1);
-    page.toggleAlertInList(2);
-    page.clickActionDropdownOption('Open');
-    expect(page.getAlertStatus(0, 'NEW')).toEqual('OPEN');
-    expect(page.getAlertStatus(1, 'NEW')).toEqual('OPEN');
-    expect(page.getAlertStatus(2, 'NEW')).toEqual('OPEN');
+  it('should change alert status for multiple alerts to OPEN', async function() : Promise<any> {
+    await page.navigateTo();
+    await page.toggleAlertInList(0);
+    await page.toggleAlertInList(1);
+    await page.toggleAlertInList(2);
+    await page.clickActionDropdownOption('Open');
+    expect(await page.getAlertStatus(0, 'NEW')).toEqual('OPEN');
+    expect(await page.getAlertStatus(1, 'NEW')).toEqual('OPEN');
+    expect(await page.getAlertStatus(2, 'NEW')).toEqual('OPEN');
   });
 
-  it('should change alert status for multiple alerts to DISMISS', () => {
-    page.toggleAlertInList(3);
-    page.toggleAlertInList(4);
-    page.toggleAlertInList(5);
-    page.clickActionDropdownOption('Dismiss');
-    expect(page.getAlertStatus(3, 'NEW')).toEqual('DISMISS');
-    expect(page.getAlertStatus(4, 'NEW')).toEqual('DISMISS');
-    expect(page.getAlertStatus(5, 'NEW')).toEqual('DISMISS');
+  it('should change alert status for multiple alerts to DISMISS', async function() : Promise<any> {
+    await page.toggleAlertInList(3);
+    await page.toggleAlertInList(4);
+    await page.toggleAlertInList(5);
+    await page.clickActionDropdownOption('Dismiss');
+    expect(await page.getAlertStatus(3, 'NEW')).toEqual('DISMISS');
+    expect(await page.getAlertStatus(4, 'NEW')).toEqual('DISMISS');
+    expect(await page.getAlertStatus(5, 'NEW')).toEqual('DISMISS');
   });
 
-  it('should change alert status for multiple alerts to ESCALATE', () => {
-    page.toggleAlertInList(6);
-    page.toggleAlertInList(7);
-    page.toggleAlertInList(8);
-    page.clickActionDropdownOption('Escalate');
-    expect(page.getAlertStatus(6, 'NEW')).toEqual('ESCALATE');
-    expect(page.getAlertStatus(7, 'NEW')).toEqual('ESCALATE');
-    expect(page.getAlertStatus(8, 'NEW')).toEqual('ESCALATE');
+  it('should change alert status for multiple alerts to ESCALATE', async function() : Promise<any> {
+    await page.toggleAlertInList(6);
+    await page.toggleAlertInList(7);
+    await page.toggleAlertInList(8);
+    await page.clickActionDropdownOption('Escalate');
+    expect(await page.getAlertStatus(6, 'NEW')).toEqual('ESCALATE');
+    expect(await page.getAlertStatus(7, 'NEW')).toEqual('ESCALATE');
+    expect(await page.getAlertStatus(8, 'NEW')).toEqual('ESCALATE');
   });
 
-  it('should change alert status for multiple alerts to RESOLVE', () => {
-    page.toggleAlertInList(9);
-    page.toggleAlertInList(10);
-    page.toggleAlertInList(11);
-    page.clickActionDropdownOption('Resolve');
-    expect(page.getAlertStatus(9, 'NEW')).toEqual('RESOLVE');
-    expect(page.getAlertStatus(10, 'NEW')).toEqual('RESOLVE');
-    expect(page.getAlertStatus(11, 'NEW')).toEqual('RESOLVE');
+  it('should change alert status for multiple alerts to RESOLVE', async function() : Promise<any> {
+    await page.toggleAlertInList(9);
+    await page.toggleAlertInList(10);
+    await page.toggleAlertInList(11);
+    await page.clickActionDropdownOption('Resolve');
+    expect(await page.getAlertStatus(9, 'NEW')).toEqual('RESOLVE');
+    expect(await page.getAlertStatus(10, 'NEW')).toEqual('RESOLVE');
+    expect(await page.getAlertStatus(11, 'NEW')).toEqual('RESOLVE');
   });
 
 
-  it('should change alert status for multiple alerts to OPEN in tree view', () => {
-    treePage.selectGroup('source:type');
-    treePage.selectGroup('enrichments:geo:ip_dst_addr:country');
-    
-    treePage.expandDashGroup('alerts_ui_e2e');
-    treePage.expandSubGroup('alerts_ui_e2e', 'US');
-    treePage.expandSubGroup('alerts_ui_e2e', 'RU');
-    treePage.expandSubGroup('alerts_ui_e2e', 'FR');
+  it('should change alert status for multiple alerts to OPEN in tree view', async function() : Promise<any> {
+    await treePage.selectGroup('source:type');
+    await treePage.selectGroup('enrichments:geo:ip_dst_addr:country');
+
+    await treePage.expandDashGroup('alerts_ui_e2e');
+    await treePage.expandSubGroup('alerts_ui_e2e', 'US');
+    await treePage.expandSubGroup('alerts_ui_e2e', 'RU');
+    await treePage.expandSubGroup('alerts_ui_e2e', 'FR');
 
-    treePage.toggleAlertInTree(1);
-    treePage.toggleAlertInTree(2);
-    treePage.toggleAlertInTree(3);
-    page.clickActionDropdownOption('Open');
+    await treePage.toggleAlertInTree(1);
+    await treePage.toggleAlertInTree(2);
+    await treePage.toggleAlertInTree(3);
+    await page.clickActionDropdownOption('Open');
     expect(treePage.getAlertStatusForTreeView(1, 'NEW')).toEqual('OPEN');
     expect(treePage.getAlertStatusForTreeView(2, 'NEW')).toEqual('OPEN');
     expect(treePage.getAlertStatusForTreeView(3, 'NEW')).toEqual('OPEN');
 
-    treePage.toggleAlertInTree(4);
-    treePage.toggleAlertInTree(5);
-    page.clickActionDropdownOption('Dismiss');
+    await treePage.toggleAlertInTree(4);
+    await treePage.toggleAlertInTree(5);
+    await page.clickActionDropdownOption('Dismiss');
     expect(treePage.getAlertStatusForTreeView(4, 'NEW')).toEqual('DISMISS');
     expect(treePage.getAlertStatusForTreeView(5, 'NEW')).toEqual('DISMISS');
 
-    treePage.toggleAlertInTree(8);
-    treePage.toggleAlertInTree(9);
-    page.clickActionDropdownOption('Escalate');
+    await treePage.toggleAlertInTree(8);
+    await treePage.toggleAlertInTree(9);
+    await page.clickActionDropdownOption('Escalate');
     expect(treePage.getAlertStatusForTreeView(8, 'NEW')).toEqual('ESCALATE');
     expect(treePage.getAlertStatusForTreeView(9, 'NEW')).toEqual('ESCALATE');
 
-    treePage.toggleAlertInTree(10);
-    treePage.toggleAlertInTree(11);
-    treePage.toggleAlertInTree(12);
-    page.clickActionDropdownOption('Resolve');
+    await treePage.toggleAlertInTree(10);
+    await treePage.toggleAlertInTree(11);
+    await treePage.toggleAlertInTree(12);
+    await page.clickActionDropdownOption('Resolve');
     expect(treePage.getAlertStatusForTreeView(10, 'NEW')).toEqual('RESOLVE');
     expect(treePage.getAlertStatusForTreeView(11, 'NEW')).toEqual('RESOLVE');
     expect(treePage.getAlertStatusForTreeView(12, 'NEW')).toEqual('RESOLVE');

http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/e2e/alerts-list/alerts-list.e2e-spec.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/e2e/alerts-list/alerts-list.e2e-spec.ts b/metron-interface/metron-alerts/e2e/alerts-list/alerts-list.e2e-spec.ts
index 358878d..e3709ab 100644
--- a/metron-interface/metron-alerts/e2e/alerts-list/alerts-list.e2e-spec.ts
+++ b/metron-interface/metron-alerts/e2e/alerts-list/alerts-list.e2e-spec.ts
@@ -21,7 +21,7 @@ import { customMatchers } from  '../matchers/custom-matchers';
 import { LoginPage } from '../login/login.po';
 import { loadTestData, deleteTestData } from '../utils/e2e_util';
 
-describe('metron-alerts App', function() {
+describe('Test spec for all ui elements & list view', function() {
   let page: MetronAlertsPage;
   let loginPage: LoginPage;
   let columnNames = [ '', 'Score', 'id', 'timestamp', 'source:type', 'ip_src_addr', 'enrichm...:country',
@@ -29,15 +29,16 @@ describe('metron-alerts App', function() {
   let colNamesColumnConfig = [ 'score', 'id', 'timestamp', 'source:type', 'ip_src_addr', 'enrichments:geo:ip_dst_addr:country',
                                 'ip_dst_addr', 'host', 'alert_status' ];
 
-  beforeAll(() => {
-    loadTestData();
+  beforeAll(async function() : Promise<any> {
     loginPage = new LoginPage();
-    loginPage.login();
+
+    await loadTestData();
+    await loginPage.login();
   });
 
-  afterAll(() => {
-    loginPage.logout();
-    deleteTestData();
+  afterAll(async function() : Promise<any> {
+    await loginPage.logout();
+    await deleteTestData();
   });
 
   beforeEach(() => {
@@ -45,110 +46,109 @@ describe('metron-alerts App', function() {
     jasmine.addMatchers(customMatchers);
   });
 
-  it('should have all the UI elements', () => {
-    page.navigateTo();
-    page.clearLocalStorage();
-
-    expect(page.isMetronLogoPresent()).toEqualBcoz(true, 'for Metron Logo');
-    expect(page.isSavedSearchButtonPresent()).toEqualBcoz(true, 'for SavedSearch Button');
-    expect(page.isClearSearchPresent()).toEqualBcoz(true, 'for Clear Search');
-    expect(page.isSearchButtonPresent()).toEqualBcoz(true, 'for Search Button');
-    expect(page.isSaveSearchButtonPresent()).toEqualBcoz(true, 'for Save Search Button');
-    expect(page.isTableSettingsButtonPresent()).toEqualBcoz(true, 'for table settings button');
-    expect(page.isPausePlayRefreshButtonPresent()).toEqualBcoz(true, 'for pause/play button');
-    expect(page.isConfigureTableColumnsPresent()).toEqualBcoz(true, 'for alerts table column configure button');
-
-    expect(page.getChangesAlertTableTitle('Alerts (0)')).toEqualBcoz('Alerts (169)', 'for alerts title');
-    expect(page.getActionDropdownItems()).toEqualBcoz([ 'Open', 'Dismiss', 'Escalate', 'Resolve', 'Add to Alert' ],
-                                                        'for default dropdown actions');
-    expect(page.getTableColumnNames()).toEqualBcoz(columnNames, 'for default column names for alert list table');
-  });
+  it('should have all the UI elements', async function() : Promise<any> {
+    await page.navigateTo();
+    await page.clearLocalStorage();
 
-  it('should have all pagination controls and they should be working', () => {
-    expect(page.isChevronLeftEnabled()).toEqualBcoz(false, 'for left chevron to be disabled for first page');
-    expect(page.getPaginationText()).toEqualBcoz('1 - 25 of 169', 'for pagination text');
-    expect(page.isChevronRightEnabled()).toEqualBcoz(true, 'for right chevron to be enabled for first page');
+    expect(await page.getChangesAlertTableTitle('Alerts (0)')).toEqualBcoz('Alerts (169)', 'for alerts title');
 
-    page.clickChevronRight();
+    expect(await page.isMetronLogoPresent()).toEqualBcoz(true, 'for Metron Logo');
+    expect(await page.isSavedSearchButtonPresent()).toEqualBcoz(true, 'for SavedSearch Button');
+    expect(await page.isClearSearchPresent()).toEqualBcoz(true, 'for Clear Search');
+    expect(await page.isSearchButtonPresent()).toEqualBcoz(true, 'for Search Button');
+    expect(await page.isSaveSearchButtonPresent()).toEqualBcoz(true, 'for Save Search Button');
+    expect(await page.isTableSettingsButtonPresent()).toEqualBcoz(true, 'for table settings button');
+    expect(await page.isPausePlayRefreshButtonPresent()).toEqualBcoz(true, 'for pause/play button');
+    expect(await page.isConfigureTableColumnsPresent()).toEqualBcoz(true, 'for alerts table column configure button');
 
-    expect(page.isChevronLeftEnabled()).toEqualBcoz(true, 'for left chevron to be enabled for second page');
-    expect(page.getPaginationText()).toEqualBcoz('26 - 50 of 169', 'for pagination text');
-    expect(page.isChevronRightEnabled()).toEqualBcoz(true, 'for right chevron to be enabled for second page');
+    expect(await page.getActionDropdownItems()).toEqualBcoz([ 'Open', 'Dismiss', 'Escalate', 'Resolve', 'Add to Alert' ],
+                                                        'for default dropdown actions');
+    expect(await page.getTableColumnNames()).toEqualBcoz(columnNames, 'for default column names for alert list table');
+  });
 
-    page.clickChevronRight();
+  it('should have all pagination controls and they should be working', async function() : Promise<any> {
 
-    expect(page.isChevronLeftEnabled()).toEqualBcoz(true, 'for left chevron to be enabled for third page');
-    expect(page.getPaginationText()).toEqualBcoz('51 - 75 of 169', 'for pagination text');
-    expect(page.isChevronRightEnabled()).toEqualBcoz(true, 'for right chevron to be enabled for third page');
+    await page.clickSettings();
+    await page.clickPageSize('100');
 
-    page.clickChevronRight(4);
+    expect(await page.getChangedPaginationText('1 - 25 of 169')).toEqualBcoz('1 - 100 of 169', 'for pagination text');
+    expect(await page.isChevronLeftEnabled()).toEqualBcoz(false, 'for left chevron to be disabled for first page');
+    expect(await page.isChevronRightEnabled()).toEqualBcoz(true, 'for right chevron to be enabled for first page');
 
-    expect(page.isChevronLeftEnabled()).toEqualBcoz(true, 'for left chevron to be enabled for last page');
-    expect(page.getPaginationText()).toEqualBcoz('151 - 169 of 169', 'for pagination text');
-    expect(page.isChevronRightEnabled()).toEqualBcoz(false, 'for right chevron to be disabled for last page');
+    await page.clickChevronRight();
+    expect(await page.getChangedPaginationText('1 - 100 of 169')).toEqualBcoz('101 - 169 of 169', 'for pagination text');
+    expect(await page.isChevronLeftEnabled()).toEqualBcoz(true, 'for left chevron to be disabled for first page');
+    expect(await page.isChevronRightEnabled()).toEqualBcoz(false, 'for right chevron to be enabled for first page');
 
-    page.clickChevronLeft(7);
+    await page.clickChevronLeft();
+    expect(await page.getChangedPaginationText('101 - 169 of 169')).toEqualBcoz('1 - 100 of 169', 'for pagination text');
+    expect(await page.isChevronLeftEnabled()).toEqualBcoz(false, 'for left chevron to be disabled for first page');
+    expect(await page.isChevronRightEnabled()).toEqualBcoz(true, 'for right chevron to be enabled for first page');
 
-    expect(page.isChevronLeftEnabled()).toEqualBcoz(false, 'for left chevron to be disabled for first page again');
-    expect(page.getPaginationText()).toEqualBcoz('1 - 25 of 169', 'for pagination text');
-    expect(page.isChevronRightEnabled()).toEqualBcoz(true, 'for right chevron to be enabled for first page again');
+    await page.clickSettings();
+    await page.clickPageSize('25');
+    expect(await page.getChangedPaginationText('1 - 100 of 169')).toEqualBcoz('1 - 25 of 169', 'for pagination text');
 
+    await page.clickSettings();
   });
 
-  it('should have all settings controls and they should be working', () => {
+  it('should have all settings controls and they should be working', async function() : Promise<any> {
     let settingsPaneLbelNames = [ 'REFRESH RATE', 'ROWS PER PAGE', 'HIDE Resolved Alerts', 'HIDE Dismissed Alerts' ];
     let settingPaneRefreshIntervals = [ '5s', '10s', '15s', '30s', '1m', '10m', '1h' ];
     let settingsPanePageSize = [ '10', '25', '50', '100', '250', '500', '1000' ];
 
-    page.clickSettings();
+    await page.clickSettings();
+
+    expect(await page.getSettingsLabels()).toEqualBcoz(settingsPaneLbelNames, 'for table settings labels');
 
-    expect(page.getSettingsLabels()).toEqualBcoz(settingsPaneLbelNames, 'for table settings labels');
+    expect(await page.getRefreshRateOptions()).toEqualBcoz(settingPaneRefreshIntervals, 'for table settings refresh rate labels');
+    expect(await page.getRefreshRateSelectedOption()).toEqualBcoz([ '1m' ], 'for table settings default refresh rate');
 
-    expect(page.getRefreshRateOptions()).toEqualBcoz(settingPaneRefreshIntervals, 'for table settings refresh rate labels');
-    expect(page.getRefreshRateSelectedOption()).toEqualBcoz([ '1m' ], 'for table settings default refresh rate');
+    await  page.clickRefreshInterval('10s');
+    expect(await page.getRefreshRateSelectedOption()).toEqualBcoz([ '10s' ], 'for refresh interval 10s');
 
-    page.clickRefreshInterval('10s');
-    expect(page.getRefreshRateSelectedOption()).toEqualBcoz([ '10s' ], 'for refresh interval 10s');
+    await page.clickRefreshInterval('1h');
+    expect(await page.getRefreshRateSelectedOption()).toEqualBcoz([ '1h' ], 'for refresh interval 1h');
 
-    page.clickRefreshInterval('1h');
-    expect(page.getRefreshRateSelectedOption()).toEqualBcoz([ '1h' ], 'for refresh interval 1h');
+    expect(await page.getPageSizeOptions()).toEqualBcoz(settingsPanePageSize, 'for table settings refresh rate labels');
+    expect(await page.getPageSizeSelectedOption()).toEqualBcoz([ '25' ], 'for table settings default page size');
 
-    expect(page.getPageSizeOptions()).toEqualBcoz(settingsPanePageSize, 'for table settings refresh rate labels');
-    expect(page.getPageSizeSelectedOption()).toEqualBcoz([ '25' ], 'for table settings default page size');
+    await page.clickPageSize('50');
+    expect(await page.getPageSizeSelectedOption()).toEqualBcoz([ '50' ], 'for page size 50');
 
-    page.clickPageSize('10');
-    expect(page.getPageSizeSelectedOption()).toEqualBcoz([ '10' ], 'for page size 10');
+    await page.clickPageSize('100');
+    expect(await page.getPageSizeSelectedOption()).toEqualBcoz([ '100' ], 'for page size 100');
 
-    page.clickPageSize('100');
-    expect(page.getPageSizeSelectedOption()).toEqualBcoz([ '100' ], 'for page size 100');
+    await page.clickPageSize('25');
+    expect(await page.getPageSizeSelectedOption()).toEqualBcoz([ '25' ], 'for page size 100');
 
-    page.clickSettings();
+    await page.clickSettings();
   });
 
-  it('play pause should start polling and stop polling ', () => {
-    expect(page.getPlayPauseState()).toEqual('fa fa-pause', 'for default pause option');
+  it('play pause should start polling and stop polling ', async function() : Promise<any> {
+    expect(await page.getPlayPauseState()).toEqual('fa fa-play', 'for default pause option');
 
-    page.clickPlayPause();
-    expect(page.getPlayPauseState()).toEqual('fa fa-play', 'for default pause option');
+    await page.clickPlayPause('fa-pause');
+    expect(await page.getPlayPauseState()).toEqual('fa fa-pause', 'for default pause option');
 
-    page.clickPlayPause();
-    expect(page.getPlayPauseState()).toEqual('fa fa-pause', 'for default pause option');
+    await page.clickPlayPause('fa-play');
+    expect(await page.getPlayPauseState()).toEqual('fa fa-play', 'for default pause option');
   });
 
-  it('should select columns from table configuration', () => {
+  it('should select columns from table configuration', async function() : Promise<any> {
     let newColNamesColumnConfig = [ 'score', 'timestamp', 'source:type', 'ip_src_addr', 'enrichments:geo:ip_dst_addr:country',
       'ip_dst_addr', 'host', 'alert_status', 'guid' ];
 
-    page.clickConfigureTable();
-    expect(page.getSelectedColumnNames()).toEqual(colNamesColumnConfig, 'for default selected column names');
-    page.toggleSelectCol('id');
-    page.toggleSelectCol('guid', 'method');
-    expect(page.getSelectedColumnNames()).toEqual(newColNamesColumnConfig, 'for guid added to selected column names');
-    page.saveConfigureColumns();
+    await page.clickConfigureTable();
+    expect(await page.getSelectedColumnNames()).toEqual(colNamesColumnConfig, 'for default selected column names');
+    await page.toggleSelectCol('id');
+    await page.toggleSelectCol('guid');
+    expect(await page.getSelectedColumnNames()).toEqual(newColNamesColumnConfig, 'for guid added to selected column names');
+    await page.saveConfigureColumns();
 
   });
 
-  it('should have all time-range controls', () => {
+  it('should have all time-range controls', async function() : Promise<any> {
     let quickRanges = [
       'Last 7 days', 'Last 30 days', 'Last 60 days', 'Last 90 days', 'Last 6 months', 'Last 1 year', 'Last 2 years', 'Last 5 years',
       'Yesterday', 'Day before yesterday', 'This day last week', 'Previous week', 'Previous month', 'Previous year', 'All time',
@@ -156,191 +156,168 @@ describe('metron-alerts App', function() {
       'Last 5 minutes', 'Last 15 minutes', 'Last 30 minutes', 'Last 1 hour', 'Last 3 hours', 'Last 6 hours', 'Last 12 hours', 'Last 24 hours'
     ];
 
-    page.clickDateSettings();
-    expect(page.getTimeRangeTitles()).toEqual(['Time Range', 'Quick Ranges']);
-    expect(page.getQuickTimeRanges()).toEqual(quickRanges);
-    expect(page.getValueForManualTimeRange()).toEqual([ 'now', 'now' ]);
-    expect(page.isManulaTimeRangeApplyButtonPresent()).toEqual(true);
-    expect(page.getTimeRangeButtonText()).toEqual('All time');
-    page.clickDateSettings();
+    await page.clickDateSettings();
+    expect(await page.getTimeRangeTitles()).toEqual(['Time Range', 'Quick Ranges']);
+    expect(await page.getQuickTimeRanges()).toEqual(quickRanges);
+    expect(await page.getValueForManualTimeRange()).toEqual([ 'now', 'now' ]);
+    expect(await page.isManulaTimeRangeApplyButtonPresent()).toEqual(true);
+    expect(await page.getTimeRangeButtonText()).toEqual('All time');
+    await page.hideDateSettings();
 
   });
 
-  it('should have all time range values populated - 1', () => {
+  it('should have all time range values populated - 1', async function() : Promise<any> {
     let secInADay = (24 * 60 * 60 * 1000);
 
-    page.clickClearSearch();
-    expect(page.getTimeRangeButtonAndSubText()).toEqualBcoz(['All time'], 'for all-time');
+    await page.clickDateSettings();
+    expect(await page.selectQuickTimeRangeAndGetTimeRangeAndTimeText('Last 7 days').catch(e => console.log(e))).toEqualBcoz(['Last 7 days', String(secInADay * 7)], 'for last 7 days');
 
-    page.clickDateSettings();
-    page.selectQuickTimeRange('Last 7 days');
-    expect(page.getTimeRangeButtonAndSubText()).toEqualBcoz(['Last 7 days', String(secInADay * 7)], 'for last 7 days');
+    await page.clickDateSettings();
+    expect(await page.selectQuickTimeRangeAndGetTimeRangeAndTimeText('Last 30 days').catch(e => console.log(e))).toEqualBcoz(['Last 30 days', String(secInADay * 30)], 'for last 30 days');
 
-    page.clickDateSettings();
-    page.selectQuickTimeRange('Last 30 days');
-    expect(page.getTimeRangeButtonAndSubText()).toEqualBcoz(['Last 30 days', String(secInADay * 30)], 'for last 30 days');
+    await page.clickDateSettings();
+    expect(await page.selectQuickTimeRangeAndGetTimeRangeAndTimeText('Last 60 days').catch(e => console.log(e))).toEqualBcoz(['Last 60 days', String(secInADay * 60)], 'for last 60 days');
 
-    page.clickDateSettings();
-    page.selectQuickTimeRange('Last 60 days');
-    expect(page.getTimeRangeButtonAndSubText()).toEqualBcoz(['Last 60 days', String(secInADay * 60)], 'for last 60 days');
+    await page.clickDateSettings();
+    expect(await page.selectQuickTimeRangeAndGetTimeRangeAndTimeText('Last 90 days').catch(e => console.log(e))).toEqualBcoz(['Last 90 days', String(secInADay * 90)], 'for last 90 days');
 
-    page.clickDateSettings();
-    page.selectQuickTimeRange('Last 90 days');
-    expect(page.getTimeRangeButtonAndSubText()).toEqualBcoz(['Last 90 days', String(secInADay * 90)], 'for last 90 days');
+    await page.clickDateSettings();
+    expect(await page.selectQuickTimeRangeAndGetTimeRangeAndTimeText('Last 1 year').catch(e => console.log(e))).toEqualBcoz(['Last 1 year', String(secInADay * 365)], 'for last 1 year');
 
+    await page.clickDateSettings();
+    expect(await page.selectQuickTimeRangeAndGetTimeRangeAndTimeText('Last 2 years').catch(e => console.log(e))).toEqualBcoz(['Last 2 years', String((secInADay * 365 * 2))], 'for last 2 years');
 
-    page.clickDateSettings();
-    page.selectQuickTimeRange('Last 1 year');
-    expect(page.getTimeRangeButtonAndSubText()).toEqualBcoz(['Last 1 year', String(secInADay * 365)], 'for last 1 year');
+    await page.clickDateSettings();
+    expect(await page.selectQuickTimeRangeAndGetTimeRangeAndTimeText('Last 5 years').catch(e => console.log(e))).toEqualBcoz(['Last 5 years', String((secInADay * 365 * 5) + secInADay)], 'for last 5 years');
 
-    page.clickDateSettings();
-    page.selectQuickTimeRange('Last 2 years');
-    expect(page.getTimeRangeButtonAndSubText()).toEqualBcoz(['Last 2 years', String((secInADay * 365 * 2) + secInADay)], 'for last 2 years');
-
-    page.clickDateSettings();
-    page.selectQuickTimeRange('Last 5 years');
-    expect(page.getTimeRangeButtonAndSubText()).toEqualBcoz(['Last 5 years', String((secInADay * 365 * 5) + secInADay)], 'for last 5 years');
-
-    page.clickClearSearch();
   });
 
-  it('should have all time range values populated - 2', () => {
+  it('should have all time range values populated - 2', async function() : Promise<any> {
     let secInADay = (24*60*60*1000);
 
-    page.clickDateSettings();
-    page.selectQuickTimeRange('Yesterday');
-    expect(page.getTimeRangeButtonAndSubText()).toEqualBcoz([ 'Yesterday', String(secInADay - 1000)], 'yesterday');
+    await page.clickDateSettings();
+    expect(await page.selectQuickTimeRangeAndGetTimeRangeAndTimeText('Yesterday').catch(e => console.log(e))).toEqualBcoz([ 'Yesterday', String(secInADay - 1000)], 'yesterday');
 
-    page.clickDateSettings();
-    page.selectQuickTimeRange('Day before yesterday');
-    expect(page.getTimeRangeButtonAndSubText()).toEqualBcoz([ 'Day before yesterday', String(secInADay - 1000)], 'day before yesterday');
+    await page.clickDateSettings();
+    expect(await page.selectQuickTimeRangeAndGetTimeRangeAndTimeText('Day before yesterday').catch(e => console.log(e))).toEqualBcoz([ 'Day before yesterday', String(secInADay - 1000)], 'day before yesterday');
 
-    page.clickDateSettings();
-    page.selectQuickTimeRange('This day last week');
-    expect(page.getTimeRangeButtonAndSubText()).toEqualBcoz([ 'This day last week', String(secInADay - 1000)], 'this day last week');
+    await page.clickDateSettings();
+    expect(await page.selectQuickTimeRangeAndGetTimeRangeAndTimeText('This day last week').catch(e => console.log(e))).toEqualBcoz([ 'This day last week', String(secInADay - 1000)], 'this day last week');
 
-    page.clickDateSettings();
-    page.selectQuickTimeRange('Previous week');
-    expect(page.getTimeRangeButtonAndSubText()).toEqualBcoz([ 'Previous week', String((secInADay * 7) - (1000))], 'for previous week');
+    await page.clickDateSettings();
+    expect(await page.selectQuickTimeRangeAndGetTimeRangeAndTimeText('Previous week').catch(e => console.log(e))).toEqualBcoz([ 'Previous week', String((secInADay * 7) - (1000))], 'for previous week');
 
-    page.clickClearSearch();
   });
 
-  it('should have all time range values populated - 3', () => {
+  it('should have all time range values populated - 3', async function() : Promise<any> {
     let secInADay = (24*60*60*1000);
 
-    page.clickDateSettings();
-    page.selectQuickTimeRange('Today');
-    expect(page.getTimeRangeButtonAndSubText()).toEqualBcoz([ 'Today', String(secInADay - 1000)], 'for today');
+    await page.clickDateSettings();
+    expect(await page.selectQuickTimeRangeAndGetTimeRangeAndTimeText('Today').catch(e => console.log(e))).toEqualBcoz([ 'Today', String(secInADay - 1000)], 'for today');
 
-    page.clickDateSettings();
-    page.selectQuickTimeRange('This week');
-    expect(page.getTimeRangeButtonAndSubText()).toEqualBcoz([ 'This week', String((secInADay*7) - 1000)], 'for this week');
+    await page.clickDateSettings();
+    expect(await page.selectQuickTimeRangeAndGetTimeRangeAndTimeText('This week').catch(e => console.log(e))).toEqualBcoz([ 'This week', String((secInADay*7) - 1000)], 'for this week');
 
-    page.clickClearSearch();
   });
 
-  it('should have all time range values populated - 4', () => {
-    let secInADay = (24*60*60*1000);
+  it('should have all time range values populated - 4', async function() : Promise<any> {
 
-    page.clickDateSettings();
-    page.selectQuickTimeRange('Last 5 minutes');
-    expect(page.getTimeRangeButtonAndSubText()).toEqualBcoz([ 'Last 5 minutes', String(5 * 60 * 1000)], 'for last 5 minutes');
+    await page.clickDateSettings();
+    expect(await page.selectQuickTimeRangeAndGetTimeRangeAndTimeText('Last 5 minutes').catch(e => console.log(e))).toEqualBcoz([ 'Last 5 minutes', String(5 * 60 * 1000)], 'for last 5 minutes');
 
-    page.clickDateSettings();
-    page.selectQuickTimeRange('Last 15 minutes');
-    expect(page.getTimeRangeButtonAndSubText()).toEqualBcoz([ 'Last 15 minutes', String(15 * 60 * 1000)], 'for last 15 minutes');
+    await page.clickDateSettings();
+    expect(await page.selectQuickTimeRangeAndGetTimeRangeAndTimeText('Last 15 minutes').catch(e => console.log(e))).toEqualBcoz([ 'Last 15 minutes', String(15 * 60 * 1000)], 'for last 15 minutes');
 
-    page.clickDateSettings();
-    page.selectQuickTimeRange('Last 30 minutes');
-    expect(page.getTimeRangeButtonAndSubText()).toEqualBcoz([ 'Last 30 minutes', String(30 * 60 * 1000)], 'for last 30 minutes');
+    await page.clickDateSettings();
+    expect(await page.selectQuickTimeRangeAndGetTimeRangeAndTimeText('Last 30 minutes').catch(e => console.log(e))).toEqualBcoz([ 'Last 30 minutes', String(30 * 60 * 1000)], 'for last 30 minutes');
 
-    page.clickDateSettings();
-    page.selectQuickTimeRange('Last 1 hour');
-    expect(page.getTimeRangeButtonAndSubText()).toEqualBcoz([ 'Last 1 hour', String(60 * 60 * 1000)], 'for last 1 hour');
+    await page.clickDateSettings();
+    expect(await page.selectQuickTimeRangeAndGetTimeRangeAndTimeText('Last 1 hour').catch(e => console.log(e))).toEqualBcoz([ 'Last 1 hour', String(60 * 60 * 1000)], 'for last 1 hour');
 
-    page.clickDateSettings();
-    page.selectQuickTimeRange('Last 3 hours');
-    expect(page.getTimeRangeButtonAndSubText()).toEqualBcoz([ 'Last 3 hours', String(3 * 60 * 60 * 1000)], 'for last 3 hours');
+    await page.clickDateSettings();
+    expect(await page.selectQuickTimeRangeAndGetTimeRangeAndTimeText('Last 3 hours').catch(e => console.log(e))).toEqualBcoz([ 'Last 3 hours', String(3 * 60 * 60 * 1000)], 'for last 3 hours');
 
-    page.clickDateSettings();
-    page.selectQuickTimeRange('Last 6 hours');
-    expect(page.getTimeRangeButtonAndSubText()).toEqualBcoz([ 'Last 6 hours', String(6 * 60 * 60 * 1000)], 'for last 6 hours');
+    await page.clickDateSettings();
+    expect(await page.selectQuickTimeRangeAndGetTimeRangeAndTimeText('Last 6 hours').catch(e => console.log(e))).toEqualBcoz([ 'Last 6 hours', String(6 * 60 * 60 * 1000)], 'for last 6 hours');
 
-    page.clickDateSettings();
-    page.selectQuickTimeRange('Last 12 hours');
-    expect(page.getTimeRangeButtonAndSubText()).toEqualBcoz([ 'Last 12 hours', String(12 * 60 * 60 * 1000)], 'for last 12 hours');
+    await page.clickDateSettings();
+    expect(await page.selectQuickTimeRangeAndGetTimeRangeAndTimeText('Last 12 hours').catch(e => console.log(e))).toEqualBcoz([ 'Last 12 hours', String(12 * 60 * 60 * 1000)], 'for last 12 hours');
 
-    page.clickDateSettings();
-    page.selectQuickTimeRange('Last 24 hours');
-    expect(page.getTimeRangeButtonAndSubText()).toEqualBcoz([ 'Last 24 hours', String(24 * 60 * 60 * 1000)], 'for last 24 hours');
+    await page.clickDateSettings();
+    expect(await page.selectQuickTimeRangeAndGetTimeRangeAndTimeText('Last 24 hours').catch(e => console.log(e))).toEqualBcoz([ 'Last 24 hours', String(24 * 60 * 60 * 1000)], 'for last 24 hours');
 
-    page.clickClearSearch();
   });
 
-  it('should disable date picker when timestamp is present in search', () => {
-    page.clickTableText('2017-09-13 18:02:20');
-    expect(page.isDateSeettingDisabled()).toEqual(true);
+  it('should disable date picker when timestamp is present in search', async function() : Promise<any> {
+    await page.setSearchText('timestamp:1505325740512');
+    expect(await page.getChangesAlertTableTitle('Alerts (169)')).toEqual('Alerts (1)');
+    expect(await page.isDateSeettingDisabled()).toEqual(true);
 
-    page.clickClearSearch();
-    expect(page.isDateSeettingDisabled()).toEqual(false);
+    await page.clickClearSearch();
+    expect(await page.getChangesAlertTableTitle('Alerts (1)')).toEqual('Alerts (169)');
+    expect(await page.isDateSeettingDisabled()).toEqual(false);
 
-    page.clickTableText('alerts_ui_e2e');
-    expect(page.isDateSeettingDisabled()).toEqual(false);
+    await expect(page.clickTableTextAndGetSearchText('FR', 'enrichments:geo:ip_dst_addr:country:FR')).toEqual('enrichments:geo:ip_dst_addr:country:FR');
+    expect(await page.getChangesAlertTableTitle('Alerts (169)')).toEqual('Alerts (25)');
+    expect(await page.isDateSeettingDisabled()).toEqual(false);
 
-    page.clickClearSearch();
+    await page.clickClearSearch();
+    expect(await page.getChangesAlertTableTitle('Alerts (25)')).toEqual('Alerts (169)');
   });
 
-  it('should have now included when to date is empty', () => {
-    page.clickDateSettings();
-    page.setDate(0, '2017', 'September', '13', '23', '29', '35');
-    page.selectTimeRangeApplyButton();
-    expect(page.getTimeRangeButtonTextForNow()).toEqual([ 'Date Range', '2017-09-13 23:29:35 to now' ]);
+  it('should have now included when to date is empty', async function() : Promise<any> {
+    await page.clickDateSettings();
+    await page.setDate(0, '2017', 'September', '13', '23', '29', '35');
+    await page.selectTimeRangeApplyButton();
+    expect(await page.getTimeRangeButtonTextForNow()).toEqual([ 'Date Range', '2017-09-13 23:29:35 to now' ]);
 
-    page.clickClearSearch();
+    await page.clickClearSearch();
   });
-  
-  it('should have all time-range included while searching', () => {
+
+  it('should have all time-range included while searching', async function() : Promise<any> {
     let startDate = new Date(1505325575000);
     let endDate = new Date(1505325580000);
 
-    page.clearLocalStorage();
-    page.clickDateSettings();
+    await page.clearLocalStorage();
+    await page.clickDateSettings();
 
     /* Select Last 5years for time range */
-    page.selectQuickTimeRange('Last 5 years');
-    expect(page.getTimeRangeButtonText()).toEqual('Last 5 years');
+    expect(await page.selectQuickTimeRangeAndGetTimeRangeText('Last 5 years')).toEqual('Last 5 years');
 
     /* Select custom date for time range */
-    page.clickDateSettings();
-    page.setDate(0, String(startDate.getFullYear()), startDate.toLocaleString('en-us', { month: "long" }), String(startDate.getDate()),
+    await page.clickDateSettings();
+    await page.setDate(0, String(startDate.getFullYear()), startDate.toLocaleString('en-us', { month: "long" }), String(startDate.getDate()),
                 String(startDate.getHours()), String(startDate.getMinutes()), String(startDate.getSeconds()));
-    page.setDate(1, String(endDate.getFullYear()), endDate.toLocaleString('en-us', { month: "long" }), String(endDate.getDate()),
+    await page.setDate(1, String(endDate.getFullYear()), endDate.toLocaleString('en-us', { month: "long" }), String(endDate.getDate()),
                 String(endDate.getHours()), String(endDate.getMinutes()), String(endDate.getSeconds()));
-    page.selectTimeRangeApplyButton();
-    expect(page.getChangesAlertTableTitle('Alerts (169)')).toEqual('Alerts (5)');
+    await page.selectTimeRangeApplyButton();
+    expect(await page.getChangesAlertTableTitle('Alerts (169)')).toEqual('Alerts (5)');
 
     /* Save custom date in saved searches */
-    page.saveSearch('e2e-2');
-    page.clickSavedSearch();
-    expect(page.getRecentSearchOptions()).toContain('timestamp:last-5-years', 'for recent search options');
-    expect(page.getSavedSearchOptions()).toEqual(['e2e-2'],
+    await page.saveSearch('e2e-2');
+    await page.clickSavedSearch();
+
+    // The below expect statement will fail until this issue is resolved in Protractor: https://github.com/angular/protractor/issues/4693
+    // This is because the connection resets before deleting the test comment, which causes the assertion to be false
+
+    // expect(await page.getRecentSearchOptions()).toContain('timestamp:last-5-years', 'for recent search options');
+    expect(await page.getSavedSearchOptions()).toEqual(['e2e-2'],
                                                     'for saved search options');
-    page.clickCloseSavedSearch();
+    await page.clickCloseSavedSearch();
 
     /* Clear Search should should show all rows */
-    page.clickClearSearch();
-    expect(page.getChangesAlertTableTitle('Alerts (5)')).toEqual('Alerts (169)');
+    await page.clickClearSearch();
+    expect(await page.getChangesAlertTableTitle('Alerts (5)')).toEqual('Alerts (169)');
 
     /* Load the saved search */
-    page.clickSavedSearch();
-    page.loadSavedSearch('e2e-2');
-    expect(page.getChangesAlertTableTitle('Alerts (169)')).toEqual('Alerts (5)');
+    await page.clickSavedSearch();
+    await page.loadSavedSearch('e2e-2');
+    expect(await page.getChangesAlertTableTitle('Alerts (169)')).toEqual('Alerts (5)');
 
     /* Load recent search */
-    page.clickSavedSearch();
-    page.loadRecentSearch('last-5-years');
-    expect(page.getChangesAlertTableTitle('Alerts (5)')).toEqual('Alerts (169)');
+    await page.clickSavedSearch();
+    await page.loadRecentSearch('last-5-years');
+    expect(await page.getChangesAlertTableTitle('Alerts (5)')).toEqual('Alerts (169)');
 
   });
 


[2/9] metron git commit: METRON-1637 Wrong path to escalate alert REST endpoint (merrimanr) closes apache/metron#1078

Posted by le...@apache.org.
METRON-1637 Wrong path to escalate alert REST endpoint (merrimanr) closes apache/metron#1078


Project: http://git-wip-us.apache.org/repos/asf/metron/repo
Commit: http://git-wip-us.apache.org/repos/asf/metron/commit/2ee6cc7e
Tree: http://git-wip-us.apache.org/repos/asf/metron/tree/2ee6cc7e
Diff: http://git-wip-us.apache.org/repos/asf/metron/diff/2ee6cc7e

Branch: refs/heads/feature/METRON-1416-upgrade-solr
Commit: 2ee6cc7e0b448d8d27f56f873e2c15a603c53917
Parents: b06bb5f
Author: merrimanr <me...@gmail.com>
Authored: Tue Jun 26 08:08:29 2018 -0500
Committer: merrimanr <me...@apache.org>
Committed: Tue Jun 26 08:08:29 2018 -0500

----------------------------------------------------------------------
 metron-interface/metron-alerts/src/app/service/alerts.service.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/metron/blob/2ee6cc7e/metron-interface/metron-alerts/src/app/service/alerts.service.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/src/app/service/alerts.service.ts b/metron-interface/metron-alerts/src/app/service/alerts.service.ts
index 7324a72..56939d8 100644
--- a/metron-interface/metron-alerts/src/app/service/alerts.service.ts
+++ b/metron-interface/metron-alerts/src/app/service/alerts.service.ts
@@ -30,7 +30,7 @@ export class AlertsService {
   }
 
   public escalate(alerts: Alert[]): Observable<null> {
-    return this.http.post('/api/v1/alert/escalate', alerts, new RequestOptions({headers: new Headers(this.defaultHeaders)}))
+    return this.http.post('/api/v1/alerts/ui/escalate', alerts, new RequestOptions({headers: new Headers(this.defaultHeaders)}))
     .catch(HttpUtil.handleError);
   }
 }


[5/9] metron git commit: METRON-1489 Retrofit UI tests to run reliably during nightly QE runs (sardell via nickwallen) closes apache/metron#1004

Posted by le...@apache.org.
http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/e2e/login/login.po.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/e2e/login/login.po.ts b/metron-interface/metron-alerts/e2e/login/login.po.ts
index 8d37800..3e42395 100644
--- a/metron-interface/metron-alerts/e2e/login/login.po.ts
+++ b/metron-interface/metron-alerts/e2e/login/login.po.ts
@@ -24,43 +24,47 @@ export class LoginPage {
     }
 
     login() {
-        this.navigateToLogin();
-        this.setUserNameAndPassword('admin', 'password');
-        this.submitLoginForm();
-        browser.waitForAngularEnabled(false);
-        browser.wait(function() {return element(by.css('.logout')).isPresent(); });
+        return this.navigateToLogin()
+        .then(() => this.setUserNameAndPassword('admin', 'password'))
+        .then(() => this.submitLoginForm())
+        .then(() => browser.waitForAngularEnabled(false))
+        .then(() => waitForElementVisibility(element(by.css('.logout-link'))))
+        .then(() => browser.executeScript("document.body.className += ' notransition';"));
     }
 
     logout() {
-        browser.waitForAngularEnabled(false);
-        element.all(by.css('.alert .close')).click();
-        element.all(by.css('.logout-link')).click();
-        waitForURL('http://localhost:4200/login');
+        return browser.waitForAngularEnabled(false)
+        .then(() => waitForElementVisibility(element(by.css('.logout-link'))))
+        .then(() => element(by.css('.logout-link')).click())
+        .then(() => waitForURL('http://localhost:4200/login'));
     }
 
     setUserNameAndPassword(userName: string, password: string) {
-        element.all(by.css('input.form-control')).get(0).sendKeys(userName);
-        element.all(by.css('input.form-control')).get(1).sendKeys(password);
+        return waitForElementVisibility(element(by.css('[name=user]')))
+        .then(() => waitForElementVisibility(element(by.css('[name=password]'))))
+        .then(() => element(by.css('[name=user]')).clear())
+        .then(() => element(by.css('[name=user]')).sendKeys(userName))
+        .then(() => element(by.css('[name=password]')).clear())
+        .then(() => element(by.css('[name=password]')).sendKeys(password));
     }
 
     submitLoginForm() {
-        return element.all(by.buttonText('LOG IN')).click();
+        return element(by.buttonText('LOG IN')).click();
     }
 
     getErrorMessage() {
-        browser.waitForAngularEnabled(false);
         let errElement = element(by.css('.login-failed-msg'));
-        return waitForElementVisibility(errElement).then(() => {
-            browser.sleep(1000);
-            return errElement.getText().then((message) => {
-                return message.replace(/\n/, '').replace(/LOG\ IN$/, '');
+        return browser.waitForAngularEnabled(false)
+                .then(() => waitForElementVisibility(errElement))
+                .then(() => {
+                        browser.sleep(1000);
+                    return errElement.getText().then((message) => {
+                        return message.replace(/\n/, '').replace(/LOG\ IN$/, '');
             });
         });
     }
 
     getLocation() {
-        return browser.getCurrentUrl().then(url => {
-            return url;
-        });
+        return browser.getCurrentUrl();
     }
 }

http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/e2e/utils/clean_metron_update_table.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/e2e/utils/clean_metron_update_table.ts b/metron-interface/metron-alerts/e2e/utils/clean_metron_update_table.ts
new file mode 100644
index 0000000..c6e99df
--- /dev/null
+++ b/metron-interface/metron-alerts/e2e/utils/clean_metron_update_table.ts
@@ -0,0 +1,52 @@
+declare var Promise: any;
+var chalk = require('chalk');
+var Client = require('ssh2').Client;
+var errorMsg = '';
+
+export function cleanMetronUpdateTable() {
+  return  new Promise(
+      function (resolve, reject) {
+        resolve();
+        // cleanupTable(resolve, reject);
+      }
+  );
+}
+
+function cleanupTable(resolve, reject) {
+  var conn = new Client();
+  conn.on('ready', function() {
+    console.log(chalk.bold.green('Connected to node1 as root'));
+    conn.shell(function(err, stream) {
+      if (err) throw err;
+      stream.on('close', function() {
+        if (errorMsg.length > 0) {
+          console.log(chalk.bold.red('Error is:') + errorMsg);
+          console.log(chalk.red.bgBlack.bold('Unable to truncate metron_update table in HBase. Most likely reason is HBase is down !!!'));
+          reject();
+        } else {
+          console.log(chalk.bold.green('Truncated metron_update table in HBase'));
+          resolve();
+        }
+        conn.end();
+      }).on('data', function(data) {
+        console.log('STDOUT: ' + data);
+        if (data.indexOf('ERROR') !== -1) {
+          errorMsg = data;
+        }
+      }).stderr.on('data', function(data) {
+        console.log('STDERR: ' + data);
+      });
+      var comands = [
+        'echo \'truncate "metron_update"\' | /usr/hdp/current/hbase-master/bin/hbase shell',
+        'exit',
+        ''
+      ];
+      stream.end(comands.join('\r\n'));
+    });
+  }).connect({
+    host: 'node1',
+    port: 22,
+    username: 'root',
+    password: 'vagrant'
+  });
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/e2e/utils/e2e_util.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/e2e/utils/e2e_util.ts b/metron-interface/metron-alerts/e2e/utils/e2e_util.ts
index 8ae1de1..9f9180c 100644
--- a/metron-interface/metron-alerts/e2e/utils/e2e_util.ts
+++ b/metron-interface/metron-alerts/e2e/utils/e2e_util.ts
@@ -1,7 +1,18 @@
-import { browser, protractor } from 'protractor';
+import { browser, protractor, by, element, ElementFinder } from 'protractor';
 import request = require('request');
 import fs = require('fs');
 
+export class UtilFun {
+  public static async waitForElementPresence(element: ElementFinder): Promise<void> {
+    let EC = protractor.ExpectedConditions;
+    await browser.wait(
+        EC.visibilityOf(element),
+        10000,
+        `${element.locator()} was expected to be visible`
+    );
+  }
+}
+
 export function changeURL(url: string) {
     return browser.get(url).then(() => {
         return browser.getCurrentUrl().then((newURL) => {
@@ -15,56 +26,186 @@ export function waitForURL(url: string) {
   return browser.wait(EC.urlIs(url));
 }
 
-export function waitForText(element, text) {
+export function waitForText(selector, text) {
   let EC = protractor.ExpectedConditions;
-  return browser.wait(EC.textToBePresentInElementValue(element, text));
+  return browser.wait(EC.textToBePresentInElement(element(by.css(selector)), text)).catch((error) => console.log(`waitForText:`, error));;
 }
 
 export function waitForTextChange(element, previousText) {
   let EC = protractor.ExpectedConditions;
-  return browser.wait(EC.not(EC.textToBePresentInElement(element, previousText)));
+  if (previousText.trim().length === 0) {
+    return waitForNonEmptyText(element);
+  }
+  return browser.wait(EC.not(EC.textToBePresentInElement(element, previousText))).catch((error) => console.log(`${element.locator()} waitForTextChange:`, error));
 }
 
 export function waitForElementInVisibility (_element ) {
     let EC = protractor.ExpectedConditions;
-    return browser.wait(EC.invisibilityOf(_element));
+    return browser.wait(EC.invisibilityOf(_element)).catch((error) => console.log(`${_element.locator()} waitForElementInVisibility:`, error));
 }
 
 export function waitForElementPresence (_element ) {
     let EC = protractor.ExpectedConditions;
-    return browser.wait(EC.presenceOf(_element));
+    return browser.wait(EC.presenceOf(_element)).catch((error) => console.log(`${_element.locator()} waitForElementPresence:`, error));
 }
 
 export function waitForElementVisibility (_element ) {
     let EC = protractor.ExpectedConditions;
-    return browser.wait(EC.visibilityOf(_element));
+    return browser.wait(EC.visibilityOf(_element)).catch((error) => console.log(`${_element.locator()} waitForElementVisibility:`, error));
+}
+
+export function waitForElementPresenceAndvisbility(selector) {
+  let EC = protractor.ExpectedConditions;
+  return browser.wait(EC.visibilityOf(element(by.css(selector)))).catch((error) => console.log(`waitForElementPresenceAndvisbility: `, error));
 }
 
 export function waitForStalenessOf (_element ) {
     let EC = protractor.ExpectedConditions;
-    return browser.wait(EC.stalenessOf(_element));
+    return browser.wait(EC.stalenessOf(_element)).catch((error) => console.log(`${_element.locator()} waitForStalenessOf: `, error));
+}
+
+export function waitForCssClass(elementFinder, desiredClass) {
+  function waitForCssClass$(elementFinder, desiredClass)
+  {
+    return function () {
+      return elementFinder.getAttribute('class').then(function (classValue) {
+        return classValue && classValue.indexOf(desiredClass) >= 0;
+      });
+    }
+  }
+  return browser.wait(waitForCssClass$(elementFinder, desiredClass)).catch((error) => console.log(`waitForCssClass:`, error));
+}
+
+export function waitForCssClassNotToBePresent(elementFinder, desiredClass) {
+  function waitForCssClassNotToBePresent$(elementFinder, desiredClass)
+  {
+    return function () {
+      return elementFinder.getAttribute('class').then(function (classValue) {
+        return classValue && classValue.indexOf(desiredClass) === -1;
+      }).catch((error) => console.log(`waitForCssClassNotToBePresent:`, error));;
+    }
+  }
+  return browser.wait(waitForCssClassNotToBePresent$(elementFinder, desiredClass)).catch((error) => console.log(`waitForCssClassNotToBePresent:`, error));
+}
+
+export function catchNoSuchElementError() {
+  return (err) => {
+    if (err.name === 'NoSuchElementError' || err.name === 'Error') {
+      return null;
+    }
+    throw err;
+  };
+}
+
+export function waitForNonEmptyTextAndGetText(elementFinder) {
+  function waitForNonEmptyText$(elementFinder)
+  {
+    return function () {
+      return elementFinder.getText().then(function (text) {
+        return text.trim().length > 0;
+      }).catch(catchNoSuchElementError());
+    }
+  }
+  return browser.wait(waitForNonEmptyText$(elementFinder))
+  .then(() => elementFinder.getText())
+  .catch( catchNoSuchElementError());
+}
+
+export function waitForNonEmptyText(elementFinder) {
+  function waitForNonEmptyText$(elementFinder)
+  {
+    return function () {
+      return elementFinder.getText().then(function (text) {
+        return text.trim().length > 0;
+      }).catch(catchNoSuchElementError());
+    }
+  }
+  return browser.wait(waitForNonEmptyText$(elementFinder)).catch(catchNoSuchElementError());
+}
+
+export function waitForElementCountGreaterThan(className, expectedCount) {
+  function waitForElementCountGreaterThan$()
+  {
+    return function () {
+      return element.all(by.css(className)).count().then(function (count) {
+        return count >= expectedCount;
+      }).catch((error) => console.log(`waitForElementCountGreaterThan:`, error));;
+    }
+  }
+
+  return browser.wait(waitForElementCountGreaterThan$()).catch((error) => console.log(`waitForElementCountGreaterThan: `, error));
+}
+
+export function scrollIntoView(element, eleToTopBottom){
+    return browser.executeScript(function(element, eleToTopBottom) {
+      element.scrollIntoView(eleToTopBottom);
+    },  element.getWebElement(), eleToTopBottom)
+    .catch((error) => console.log());
+}
+
+function promiseHandlerWithResponse(resolve, reject) {
+  return (response) => {
+    if (response && (response.statusCode === 200 || response.statusCode === 404)) {
+      resolve();
+    } else {
+      console.log(response.statusCode);
+      reject();
+    }
+  };
+}
+
+function promiseHandlerWithResponseAndBody(resolve, reject) {
+  return (error, response, body) => {
+    if (response && (response.statusCode === 200 || response.statusCode === 404)) {
+      resolve();
+    } else {
+      reject();
+    }
+  };
 }
 
 export function loadTestData() {
-  deleteTestData();
-
-  let template = fs.readFileSync('e2e/mock-data/alerts_ui_e2e_index.template', 'utf8');
-  request({
-    url: 'http://node1:9200/_template/alerts_ui_e2e_index',
-    method: 'POST',
-    body: template
-  }, function(error, response, body) {
-    // add logging if desired
+  let deleteIndex = function () {
+    return new Promise((resolve, reject) => {
+      request.delete('http://node1:9200/alerts_ui_e2e_index*')
+      .on('response', promiseHandlerWithResponse(resolve, reject));
+    });
+  };
+
+  let createTemplate = function () {
+    return new Promise((resolve, reject) => {
+      let template = fs.readFileSync('e2e/mock-data/alerts_ui_e2e_index.template', 'utf8');
+      request({
+        url: 'http://node1:9200/_template/alerts_ui_e2e_index',
+        method: 'POST',
+        body: template
+      },promiseHandlerWithResponseAndBody(resolve, reject));
+    });
+  };
+
+  let loadData = function () {
+    return new Promise((resolve, reject) => {
+      let data = fs.readFileSync('e2e/mock-data/alerts_ui_e2e_index.data', 'utf8');
+      request({
+        url: 'http://node1:9200/alerts_ui_e2e_index/alerts_ui_e2e_doc/_bulk',
+        method: 'POST',
+        body: data
+      }, promiseHandlerWithResponseAndBody(resolve, reject));
+    })
+  };
+
+  return deleteIndex().then(() => createTemplate()).then(() => loadData(), reason => {
+    console.error( 'Load test data failed ', reason );
   });
+}
 
-  let data = fs.readFileSync('e2e/mock-data/alerts_ui_e2e_index.data', 'utf8');
-  request({
-    url: 'http://node1:9200/alerts_ui_e2e_index/alerts_ui_e2e_doc/_bulk',
-    method: 'POST',
-    body: data
-  }, function(error, response, body) {
-    // add logging if desired
-  });
+export function reduce_for_get_all() {
+  return  (acc, elem) => {
+    return elem.getText().then(function(text) {
+      acc.push(text);
+      return acc;
+    }).catch(e => console.log(e));
+  };
 }
 
 export function deleteTestData() {
@@ -72,19 +213,29 @@ export function deleteTestData() {
 }
 
 export function createMetaAlertsIndex() {
-  deleteMetaAlertsIndex();
-
-  let template = fs.readFileSync('./../../metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/files/metaalert_index.template', 'utf8');
-  request({
-    url: 'http://node1:9200/_template/metaalert_index',
-    method: 'POST',
-    body: template
-  }, function(error, response, body) {
-    // add logging if desired
+  let deleteIndex = function () {
+    return new Promise((resolve, reject) => {
+      request.delete('http://node1:9200/metaalert_index*')
+            .on('response', promiseHandlerWithResponse(resolve, reject));
+    });
+  };
+
+  let createIndex = function () {
+    return new Promise((resolve, reject) => {
+      let template = fs.readFileSync('./../../metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/files/metaalert_index.template', 'utf8');
+      request({
+        url: 'http://node1:9200/_template/metaalert_index',
+        method: 'POST',
+        body: template
+      }, promiseHandlerWithResponseAndBody(resolve, reject));
+    });
+  };
+
+  return deleteIndex().then(() => createIndex(), reason => {
+    console.error( 'create Meta Alerts Index failed', reason );
   });
 }
 
 export function deleteMetaAlertsIndex() {
   request.delete('http://node1:9200/metaalert_index*');
-}
-
+}
\ No newline at end of file


[9/9] metron git commit: Merge branch 'master' into feature/METRON-1416-upgrade-solr

Posted by le...@apache.org.
Merge branch 'master' into feature/METRON-1416-upgrade-solr


Project: http://git-wip-us.apache.org/repos/asf/metron/repo
Commit: http://git-wip-us.apache.org/repos/asf/metron/commit/e0fc4758
Tree: http://git-wip-us.apache.org/repos/asf/metron/tree/e0fc4758
Diff: http://git-wip-us.apache.org/repos/asf/metron/diff/e0fc4758

Branch: refs/heads/feature/METRON-1416-upgrade-solr
Commit: e0fc47582e65e9daf1a0c85dc1b1657166ff14f5
Parents: 1767727 622d50a
Author: justinjleet <ju...@gmail.com>
Authored: Tue Jun 26 15:34:09 2018 -0400
Committer: justinjleet <ju...@gmail.com>
Committed: Tue Jun 26 16:07:29 2018 -0400

----------------------------------------------------------------------
 .../configuration/metron-enrichment-env.xml     |   12 +
 .../configuration/metron-profiler-env.xml       |   12 +
 .../CURRENT/package/scripts/metron_service.py   |   20 +
 .../package/scripts/params/params_linux.py      |    4 +
 .../METRON/CURRENT/themes/metron_theme.json     |   41 +-
 metron-interface/metron-alerts/README.md        |   19 +-
 .../e2e/alert-details/alert-details.po.ts       |   67 +-
 .../alert-details-status.e2e-spec.ts            |  168 +-
 .../alert-filters/alert-filters.e2e-spec.ts     |   78 +-
 .../alert-filters/alert-filters.po.ts           |   31 +-
 .../alert-status/alerts-list-status.e2e-spec.ts |  125 +-
 .../e2e/alerts-list/alerts-list.e2e-spec.ts     |  369 +-
 .../e2e/alerts-list/alerts-list.po.ts           |  308 +-
 .../configure-table/configure-table.e2e-spec.ts |   62 +-
 .../meta-alerts/meta-alert.e2e-spec.ts          |  248 +-
 .../alerts-list/meta-alerts/meta-alert.po.ts    |   21 +-
 .../save-search/save-search.e2e-spec.ts         |   93 +-
 .../alerts-list/tree-view/tree-view.e2e-spec.ts |  208 +-
 .../e2e/alerts-list/tree-view/tree-view.po.ts   |  170 +-
 .../metron-alerts/e2e/login/login.e2e-spec.ts   |   36 +-
 .../metron-alerts/e2e/login/login.po.ts         |   44 +-
 .../e2e/utils/clean_metron_update_table.ts      |   52 +
 .../metron-alerts/e2e/utils/e2e_util.ts         |  223 +-
 .../metron-alerts/package-lock.json             | 6163 +++++++++++++++---
 metron-interface/metron-alerts/package.json     |    8 +-
 .../metron-alerts/protractor.conf.js            |   31 +-
 .../alert-details/alert-details.component.ts    |   49 +-
 .../alert-filters/alert-filters.component.ts    |    2 +-
 .../alerts-list/alerts-list.component.html      |    8 +-
 .../alerts-list/alerts-list.component.scss      |    3 +-
 .../alerts/alerts-list/alerts-list.component.ts |    4 +-
 .../tree-view/tree-view.component.html          |    4 +-
 .../configure-rows/configure-rows.component.ts  |    2 +-
 .../saved-searches.component.html               |    4 +-
 .../app/shared/group-by/group-by.component.html |    2 +-
 .../shared/time-range/time-range.component.html |   12 +-
 .../shared/time-range/time-range.component.scss |    4 +
 .../metron-alerts/src/app/utils/constants.ts    |    1 +
 .../src/environments/environment.e2e.ts         |    3 +-
 .../src/environments/environment.js             |    6 +-
 .../src/environments/environment.prod.ts        |    3 +-
 .../src/environments/environment.ts             |    3 +-
 metron-interface/metron-alerts/src/index.html   |    2 +-
 metron-interface/metron-alerts/src/styles.scss  |   10 +
 44 files changed, 6761 insertions(+), 1974 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/metron/blob/e0fc4758/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/metron_service.py
----------------------------------------------------------------------
diff --cc metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/metron_service.py
index 58d581f,e3e48ab..9d15e93
--- a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/metron_service.py
+++ b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/metron_service.py
@@@ -148,15 -119,29 +148,35 @@@ def build_global_config_patch(params, p
          "op": "add",
          "path": "/threat.triage.score.field",
          "value": "{{threat_triage_score_field}}"
+     },
+     {
+         "op": "add",
+         "path": "/enrichment.writer.batchSize",
+         "value": "{{enrichment_kafka_writer_batch_size}}"
+     },
+     {
+         "op": "add",
+         "path": "/enrichment.writer.batchTimeout",
+         "value": "{{enrichment_kafka_writer_batch_timeout}}"
+     },
+     {
+         "op": "add",
+         "path": "/profiler.writer.batchSize",
+         "value": "{{profiler_kafka_writer_batch_size}}"
+     },
+     {
+         "op": "add",
+         "path": "/profiler.writer.batchTimeout",
+         "value": "{{profiler_kafka_writer_batch_timeout}}"
      }
 -  ]
    """
 +  patch_template = ambari_format(
 +  """
 +  [
 +    {indexing_patches},
 +    {other_patches}
 +  ]
 +  """)
    File(patch_file,
         content=InlineTemplate(patch_template),
         owner=params.metron_user,

http://git-wip-us.apache.org/repos/asf/metron/blob/e0fc4758/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/params/params_linux.py
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/metron/blob/e0fc4758/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/themes/metron_theme.json
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/metron/blob/e0fc4758/metron-interface/metron-alerts/README.md
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/metron/blob/e0fc4758/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.ts
----------------------------------------------------------------------
diff --cc metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.ts
index 39d47ac,efc7e84..e68a8e0
--- a/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.ts
+++ b/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.ts
@@@ -15,10 -15,10 +15,10 @@@
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
--import { Component, OnInit } from '@angular/core';
--import {Router, ActivatedRoute} from '@angular/router';
++import {Component, OnInit} from '@angular/core';
++import {ActivatedRoute, Router} from '@angular/router';
  import * as moment from 'moment/moment';
--import {Observable, Subscription} from 'rxjs/Rx';
++import {Subscription} from 'rxjs/Rx';
  
  import {SearchService} from '../../service/search.service';
  import {UpdateService} from '../../service/update.service';
@@@ -30,14 -30,13 +30,13 @@@ import {Patch} from '../../model/patch'
  import {AlertComment} from './alert-comment';
  import {AuthenticationService} from '../../service/authentication.service';
  import {MetronDialogBox} from '../../shared/metron-dialog-box';
 -import {META_ALERTS_INDEX, META_ALERTS_SENSOR_TYPE} from '../../utils/constants';
 -import { GlobalConfigService } from '../../service/global-config.service';
 +import {CommentAddRemoveRequest} from "../../model/comment-add-remove-request";
 +import {META_ALERTS_SENSOR_TYPE} from '../../utils/constants';
- import { GlobalConfigService } from '../../service/global-config.service';
++import {GlobalConfigService} from '../../service/global-config.service';
  
  export enum AlertState {
    NEW, OPEN, ESCALATE, DISMISS, RESOLVE
  }
--
  export enum Tabs {
    DETAILS, COMMENTS
  }
@@@ -222,18 -221,18 +220,26 @@@ export class AlertDetailsComponent impl
    }
  
    onAddComment() {
+     let newComment = new AlertComment(this.alertCommentStr, this.authenticationService.getCurrentUserName(), new Date().getTime());
+     let alertComments = this.alertCommentsWrapper.map(alertsWrapper => alertsWrapper.alertComment);
+     alertComments.unshift(newComment);
+     this.setComments(alertComments);
 -    this.patchAlert(new Patch('add', '/comments', alertComments), () => {
 -      let previousComments = this.alertCommentsWrapper.map(alertsWrapper => alertsWrapper.alertComment)
 -              .filter(alertComment => alertComment !== newComment);
 -      this.setComments(previousComments);
 -    });
 +    let commentRequest = new CommentAddRemoveRequest();
 +    commentRequest.guid = this.alertSource.guid;
 +    commentRequest.comment = this.alertCommentStr;
 +    commentRequest.username = this.authenticationService.getCurrentUserName();
 +    commentRequest.timestamp = new Date().getTime();
 +    commentRequest.sensorType = this.alertSourceType;
-     this.updateService.addComment(commentRequest).subscribe( () => {
-       this.getData(true);
-     });
++    this.updateService.addComment(commentRequest).subscribe(
++        () => {},
++        () => {
++          let previousComments = this.alertCommentsWrapper.map(alertsWrapper => alertsWrapper.alertComment)
++          .filter(alertComment => alertComment !== newComment);
++          this.setComments(previousComments);
++        });
    }
  
-   patchAlert(patch: Patch) {
+   patchAlert(patch: Patch, onPatchError) {
      let patchRequest = new PatchRequest();
      patchRequest.guid = this.alertSource.guid;
      patchRequest.index = this.alertIndex;
@@@ -255,18 -252,15 +259,23 @@@
  
      this.metronDialogBox.showConfirmationMessage(commentText).subscribe(response => {
        if (response) {
+         let deletedCommentWrapper = this.alertCommentsWrapper.splice(index, 1)[0];
 -        this.patchAlert(new Patch('add', '/comments', this.alertCommentsWrapper.map(alertsWrapper => alertsWrapper.alertComment)), () => {
 -          // add the deleted comment back
 -          this.alertCommentsWrapper.unshift(deletedCommentWrapper);
 -          this.alertCommentsWrapper.sort((a, b) => b.alertComment.timestamp - a.alertComment.timestamp);
 -        });
 +        let commentRequest = new CommentAddRemoveRequest();
 +        commentRequest.guid = this.alertSource.guid;
 +        commentRequest.comment = this.alertCommentsWrapper[index].alertComment.comment;
 +        commentRequest.username = this.alertCommentsWrapper[index].alertComment.username;
 +        commentRequest.timestamp = this.alertCommentsWrapper[index].alertComment.timestamp;
 +        commentRequest.sensorType = this.alertSourceType;
-         this.updateService.removeComment(commentRequest).subscribe( () => {
-           this.getData(true);
-         });
++        this.updateService.removeComment(commentRequest).subscribe(
++            () => {
++              this.alertCommentsWrapper.map(alertsWrapper => alertsWrapper.alertComment)
++            },
++            () => {
++              // add the deleted comment back
++              this.alertCommentsWrapper.unshift(deletedCommentWrapper);
++              this.alertCommentsWrapper.sort((a, b) => b.alertComment.timestamp - a.alertComment.timestamp);
++            });
        }
      });
    }
  }
--
--

http://git-wip-us.apache.org/repos/asf/metron/blob/e0fc4758/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.ts
----------------------------------------------------------------------
diff --cc metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.ts
index 07f7015,c13b7d4..ca1bd50
--- a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.ts
+++ b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.ts
@@@ -36,10 -36,10 +36,10 @@@ import {AlertSearchDirective} from '../
  import {SearchResponse} from '../../model/search-response';
  import {ElasticsearchUtils} from '../../utils/elasticsearch-utils';
  import {Filter} from '../../model/filter';
- import {TIMESTAMP_FIELD_NAME, ALL_TIME} from '../../utils/constants';
+ import { TIMESTAMP_FIELD_NAME, ALL_TIME, POLLING_DEFAULT_STATE } from '../../utils/constants';
  import {TableViewComponent} from './table-view/table-view.component';
  import {Pagination} from '../../model/pagination';
 -import {META_ALERTS_SENSOR_TYPE, META_ALERTS_INDEX} from '../../utils/constants';
 +import {META_ALERTS_SENSOR_TYPE} from '../../utils/constants';
  import {MetaAlertService} from '../../service/meta-alert.service';
  import {Facets} from '../../model/facets';
  import { GlobalConfigService } from '../../service/global-config.service';

http://git-wip-us.apache.org/repos/asf/metron/blob/e0fc4758/metron-interface/metron-alerts/src/app/utils/constants.ts
----------------------------------------------------------------------


[8/9] metron git commit: METRON-1634 Alerts UI add comment doesn' t immediately show up. (merrimanr) closes apache/metron#1077

Posted by le...@apache.org.
METRON-1634 Alerts UI add comment doesn&apos;t immediately show up. (merrimanr) closes apache/metron#1077


Project: http://git-wip-us.apache.org/repos/asf/metron/repo
Commit: http://git-wip-us.apache.org/repos/asf/metron/commit/622d50a1
Tree: http://git-wip-us.apache.org/repos/asf/metron/tree/622d50a1
Diff: http://git-wip-us.apache.org/repos/asf/metron/diff/622d50a1

Branch: refs/heads/feature/METRON-1416-upgrade-solr
Commit: 622d50a168ef7056377d3a3143bc47d2d57ad67f
Parents: 436cec4
Author: merrimanr <me...@gmail.com>
Authored: Tue Jun 26 10:42:06 2018 -0500
Committer: rmerriman <me...@gmail.com>
Committed: Tue Jun 26 10:42:06 2018 -0500

----------------------------------------------------------------------
 .../alert-details/alert-details.component.ts    | 32 ++++++++++++--------
 1 file changed, 19 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/metron/blob/622d50a1/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.ts b/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.ts
index c939f04..efc7e84 100644
--- a/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.ts
+++ b/metron-interface/metron-alerts/src/app/alerts/alert-details/alert-details.component.ts
@@ -99,7 +99,7 @@ export class AlertDetailsComponent implements OnInit {
       this.alertSource = alertSource;
       this.selectedAlertState = this.getAlertState(alertSource['alert_status']);
       this.alertSources = (alertSource.metron_alert && alertSource.metron_alert.length > 0) ? alertSource.metron_alert : [alertSource];
-      this.setComments(alertSource);
+      this.setComments(alertSource['comments'] || []);
 
       if (fireToggleEditor) {
         this.toggleNameEditor();
@@ -107,8 +107,7 @@ export class AlertDetailsComponent implements OnInit {
     });
   }
 
-  setComments(alert) {
-    let alertComments = alert['comments'] ? alert['comments'] : [];
+  setComments(alertComments) {
     this.alertCommentsWrapper = alertComments.map(alertComment =>
         new AlertCommentWrapper(alertComment, moment(new Date(alertComment.timestamp)).fromNow()));
   }
@@ -222,22 +221,25 @@ export class AlertDetailsComponent implements OnInit {
   }
 
   onAddComment() {
-    let alertComment = new AlertComment(this.alertCommentStr, this.authenticationService.getCurrentUserName(), new Date().getTime());
-    let tAlertComments = this.alertCommentsWrapper.map(alertsWrapper => alertsWrapper.alertComment);
-    tAlertComments.unshift(alertComment);
-    this.patchAlert(new Patch('add', '/comments', tAlertComments));
+    let newComment = new AlertComment(this.alertCommentStr, this.authenticationService.getCurrentUserName(), new Date().getTime());
+    let alertComments = this.alertCommentsWrapper.map(alertsWrapper => alertsWrapper.alertComment);
+    alertComments.unshift(newComment);
+    this.setComments(alertComments);
+    this.patchAlert(new Patch('add', '/comments', alertComments), () => {
+      let previousComments = this.alertCommentsWrapper.map(alertsWrapper => alertsWrapper.alertComment)
+              .filter(alertComment => alertComment !== newComment);
+      this.setComments(previousComments);
+    });
   }
 
-  patchAlert(patch: Patch) {
+  patchAlert(patch: Patch, onPatchError) {
     let patchRequest = new PatchRequest();
     patchRequest.guid = this.alertSource.guid;
     patchRequest.index = this.alertIndex;
     patchRequest.patch = [patch];
     patchRequest.sensorType = this.alertSourceType;
 
-    this.updateService.patch(patchRequest).subscribe(() => {
-      this.getData();
-    });
+    this.updateService.patch(patchRequest).subscribe(() => {}, onPatchError);
   }
 
   onDeleteComment(index: number) {
@@ -250,8 +252,12 @@ export class AlertDetailsComponent implements OnInit {
 
     this.metronDialogBox.showConfirmationMessage(commentText).subscribe(response => {
       if (response) {
-        this.alertCommentsWrapper.splice(index, 1);
-        this.patchAlert(new Patch('add', '/comments', this.alertCommentsWrapper.map(alertsWrapper => alertsWrapper.alertComment)));
+        let deletedCommentWrapper = this.alertCommentsWrapper.splice(index, 1)[0];
+        this.patchAlert(new Patch('add', '/comments', this.alertCommentsWrapper.map(alertsWrapper => alertsWrapper.alertComment)), () => {
+          // add the deleted comment back
+          this.alertCommentsWrapper.unshift(deletedCommentWrapper);
+          this.alertCommentsWrapper.sort((a, b) => b.alertComment.timestamp - a.alertComment.timestamp);
+        });
       }
     });
   }


[3/9] metron git commit: METRON-1489 Retrofit UI tests to run reliably during nightly QE runs (sardell via nickwallen) closes apache/metron#1004

Posted by le...@apache.org.
http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/package.json
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/package.json b/metron-interface/metron-alerts/package.json
index cb6f170..0a40f0d 100644
--- a/metron-interface/metron-alerts/package.json
+++ b/metron-interface/metron-alerts/package.json
@@ -9,7 +9,7 @@
     "lint": "tslint \"src/**/*.ts\"",
     "test": "./node_modules/@angular/cli/bin/ng test --watch=false",
     "pree2e": "webdriver-manager update",
-    "e2e": "protractor"
+    "e2e": "protractor-flake --protractor-path=./node_modules/.bin/protractor --max-attempts=3 -- ./protractor.conf.js"
   },
   "private": true,
   "dependencies": {
@@ -21,7 +21,6 @@
     "@angular/platform-browser": "^4.0.0",
     "@angular/platform-browser-dynamic": "^4.0.0",
     "@angular/router": "^4.0.0",
-    "@types/moment": "^2.13.0",
     "ace-builds": "^1.2.6",
     "bootstrap": "4.0.0-alpha.6",
     "core-js": "^2.4.1",
@@ -37,6 +36,7 @@
     "@angular/cli": "1.2.4",
     "@angular/compiler-cli": "^4.0.0",
     "@types/ace": "0.0.32",
+    "@types/es6-promise": "0.0.33",
     "@types/jasmine": "2.5.38",
     "@types/moment": "^2.13.0",
     "@types/node": "~6.0.60",
@@ -56,9 +56,11 @@
     "karma-jasmine-html-reporter": "^0.2.2",
     "node-sass": "^4.5.0",
     "optimist": "0.6.1",
-    "protractor": "~5.1.0",
+    "protractor": "5.3.0",
+    "protractor-flake": "^3.3.0",
     "serve-favicon": "2.4.2",
     "serve-static": "1.12.1",
+    "ssh2": "^0.5.5",
     "ts-node": "~2.0.0",
     "tslint": "~4.5.0",
     "typescript": "~2.2.0"

http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/protractor.conf.js
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/protractor.conf.js b/metron-interface/metron-alerts/protractor.conf.js
index 82f5c09..219a8b4 100644
--- a/metron-interface/metron-alerts/protractor.conf.js
+++ b/metron-interface/metron-alerts/protractor.conf.js
@@ -23,7 +23,7 @@
 var SpecReporter = require('jasmine-spec-reporter').SpecReporter;
 
 exports.config = {
-  allScriptsTimeout: 25000,
+  allScriptsTimeout: 15000,
   specs: [
     './e2e/login/login.e2e-spec.ts',
     './e2e/alerts-list/alerts-list.e2e-spec.ts',
@@ -38,6 +38,7 @@ exports.config = {
   capabilities: {
     'browserName': 'chrome',
     'chromeOptions': {
+      args: ["--disable-gpu", "--window-size=1435,850", "--headless" ],
       'prefs': {
         'credentials_enable_service': false,
         'profile': { 'password_manager_enabled': false}
@@ -50,27 +51,27 @@ exports.config = {
   jasmineNodeOpts: {
     showColors: true,
     defaultTimeoutInterval: 50000,
-    print: function() {}
+    includeStackTrace: true
   },
-  useAllAngular2AppRoots: true,
-  rootElement: 'metron-alerts-root',
   beforeLaunch: function() {
     require('ts-node').register({
       project: 'e2e'
     });
   },
   onPrepare: function() {
-    var createMetaAlertsIndex =  require('./e2e/utils/e2e_util').createMetaAlertsIndex;
-    createMetaAlertsIndex();
-    jasmine.getEnv().addReporter(new SpecReporter());
-    setTimeout(function() {
-      browser.driver.executeScript(function() {
-        return {
-          width: window.screen.availWidth,
-          height: window.screen.availHeight
-        };
-      }).then(function(result) {
-        browser.driver.manage().window().setSize(result.width, result.height);
+
+    jasmine.getEnv().addReporter(new SpecReporter({spec: {displayStacktrace: true}}));
+
+    return new Promise(function(resolve, reject) {
+      var cleanMetronUpdateTable = require('./e2e/utils/clean_metron_update_table').cleanMetronUpdateTable;
+      var createMetaAlertsIndex = require('./e2e/utils/e2e_util').createMetaAlertsIndex;
+      cleanMetronUpdateTable()
+      .then(function() {
+        createMetaAlertsIndex();
+        resolve();
+      })
+      .catch(function (error) {
+        reject();
       });
     });
   },

http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/src/app/alerts/alerts-list/alert-filters/alert-filters.component.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alert-filters/alert-filters.component.ts b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alert-filters/alert-filters.component.ts
index 12d98e7..a448e3e 100644
--- a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alert-filters/alert-filters.component.ts
+++ b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alert-filters/alert-filters.component.ts
@@ -52,4 +52,4 @@ export class AlertFiltersComponent implements OnChanges {
   onFacetFilterSelect($event) {
     this.facetFilterChange.emit($event);
   }
-}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.html
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.html b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.html
index adda4ab..77f24d5 100644
--- a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.html
+++ b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.html
@@ -46,15 +46,15 @@
                 <div class="btn cog">
                     <i class="fa fa-cog configure-table-icon" (click)="showConfigureTable()"></i>
                 </div>
-                <div class="btn settings">
-                    <i #settingsIcon class="fa fa-sliders" aria-hidden="true"></i>
+                <div #settingsIcon class="btn settings">
+                    <i class="fa fa-sliders" aria-hidden="true"></i>
                 </div>
                 <app-configure-rows [srcElement]="settingsIcon" [tableMetaData]="tableMetaData" [(interval)]="refreshInterval" [(size)]="tableMetaData.size" (configRowsChange)="onConfigRowsChange()" > </app-configure-rows>
                 <div class="btn  pause-play" (click)="onPausePlay()">
                     <i *ngIf="!pauseRefresh" class="fa fa-pause" aria-hidden="true"></i>
                     <i *ngIf="pauseRefresh" class="fa fa-play" aria-hidden="true"></i>
                 </div>
-                <div class="dropdown d-inline-block">
+                <div id="table-actions" class="dropdown d-inline-block">
                     <button class="btn btn-primary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">ACTIONS</button>
                     <div class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenuButton">
                         <span class="dropdown-item" [class.disabled]="selectedAlerts.length == 0" (click)="processOpen()">Open</span>
@@ -74,7 +74,7 @@
       <div class="px-0" style="width: 200px;max-width: 200px;">
         <app-alert-filters [facets]="searchResponse.facetCounts" (facetFilterChange)="onAddFacetFilter($event)"> </app-alert-filters>
       </div>
-      <div class="col px-0 ml-4">
+      <div class="col px-0 pl-4" style="overflow: auto;">
         <div class="col-xs-12 pl-0 pb-3">
           <app-group-by [facets]="groupFacets" (groupsChange)="onGroupsChange($event)"> </app-group-by>
         </div>

http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.scss
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.scss b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.scss
index 01b8f9a..fe2f54c 100644
--- a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.scss
+++ b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.scss
@@ -209,7 +209,8 @@ $searchbox-height: 42px;
   height: 38px;
   padding: 0px;
   line-height: 40px;
-  margin-left: 15px;
+  padding-left: 7px;
+  padding-right: 7px;
   color: $dove-grey-1;
   cursor: pointer;
 

http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.ts b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.ts
index 4496e37..c13b7d4 100644
--- a/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.ts
+++ b/metron-interface/metron-alerts/src/app/alerts/alerts-list/alerts-list.component.ts
@@ -36,7 +36,7 @@ import {AlertSearchDirective} from '../../shared/directives/alert-search.directi
 import {SearchResponse} from '../../model/search-response';
 import {ElasticsearchUtils} from '../../utils/elasticsearch-utils';
 import {Filter} from '../../model/filter';
-import {TIMESTAMP_FIELD_NAME, ALL_TIME} from '../../utils/constants';
+import { TIMESTAMP_FIELD_NAME, ALL_TIME, POLLING_DEFAULT_STATE } from '../../utils/constants';
 import {TableViewComponent} from './table-view/table-view.component';
 import {Pagination} from '../../model/pagination';
 import {META_ALERTS_SENSOR_TYPE, META_ALERTS_INDEX} from '../../utils/constants';
@@ -60,7 +60,7 @@ export class AlertsListComponent implements OnInit, OnDestroy {
   colNumberTimerId: number;
   refreshInterval = RefreshInterval.ONE_MIN;
   refreshTimer: Subscription;
-  pauseRefresh = false;
+  pauseRefresh = POLLING_DEFAULT_STATE;
   lastPauseRefreshValue = false;
   isMetaAlertPresentInSelectedAlerts = false;
   timeStampfilterPresent = false;

http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/src/app/alerts/alerts-list/tree-view/tree-view.component.html
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/src/app/alerts/alerts-list/tree-view/tree-view.component.html b/metron-interface/metron-alerts/src/app/alerts/alerts-list/tree-view/tree-view.component.html
index 34c0ad7..fa0baaa 100644
--- a/metron-interface/metron-alerts/src/app/alerts/alerts-list/tree-view/tree-view.component.html
+++ b/metron-interface/metron-alerts/src/app/alerts/alerts-list/tree-view/tree-view.component.html
@@ -44,7 +44,7 @@
                 <metron-config-sorter [type]="column.type" [sortBy]="column.name" title="{{column.name}}" [sortOnCol]="group.sortEvent.sortBy"  [sortOrder]="group.sortEvent.sortOrder"> {{ column.name | columnNameTranslate | centerEllipses:15 }}</metron-config-sorter>
               </th>
               <th style="width: 15px"></th>
-              <th style="width:25px"><input id="select-deselect-all-{{ group.key }}" class="fontawesome-checkbox" type="checkbox" (click)="selectAllGroupRows($event, group)">
+              <th style="width:15px"><input id="select-deselect-all-{{ group.key }}" class="fontawesome-checkbox" type="checkbox" (click)="selectAllGroupRows($event, group)">
                 <label for="select-deselect-all-{{ group.key }}"></label>
               </th>
             </tr>
@@ -81,7 +81,7 @@
                       <i class="fa" aria-hidden="true" [ngClass]="{'fa-caret-down': subGroup.expand, 'fa-caret-right': !subGroup.expand}"></i>
                     </span>
                     <span class="score" appAlertSeverity [severity]="subGroup.score"> {{ subGroup.score }} </span>
-                    <span class="group-value"> <span class="text-light"> {{ subGroup.key }} </span> ({{ subGroup.total}})</span>
+                    <span class="group-value"> <span class="text-light">{{ subGroup.key }}</span> ({{ subGroup.total }})</span>
                   </td>
                   <td>
                     <i style="color: #32ABDF;" class="fa fa-link" aria-hidden="true" (click)="createMetaAlert($event, subGroup, i)" data-animation="false" data-toggle="tooltip" data-placement="left"  title="Merge Alerts"></i>

http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/src/app/alerts/configure-rows/configure-rows.component.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/src/app/alerts/configure-rows/configure-rows.component.ts b/metron-interface/metron-alerts/src/app/alerts/configure-rows/configure-rows.component.ts
index 9204ebf..d5fb44d 100644
--- a/metron-interface/metron-alerts/src/app/alerts/configure-rows/configure-rows.component.ts
+++ b/metron-interface/metron-alerts/src/app/alerts/configure-rows/configure-rows.component.ts
@@ -70,7 +70,7 @@ export class ConfigureRowsComponent  {
       return;
     }
 
-    if (targetElement === this.srcElement) {
+    if (targetElement === this.srcElement || this.srcElement.contains(targetElement)) {
       this.showView = !this.showView;
       return;
     }

http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/src/app/alerts/saved-searches/saved-searches.component.html
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/src/app/alerts/saved-searches/saved-searches.component.html b/metron-interface/metron-alerts/src/app/alerts/saved-searches/saved-searches.component.html
index 6311817..71fb1db 100644
--- a/metron-interface/metron-alerts/src/app/alerts/saved-searches/saved-searches.component.html
+++ b/metron-interface/metron-alerts/src/app/alerts/saved-searches/saved-searches.component.html
@@ -21,9 +21,9 @@
     </div>
 
     <div>
-      <metron-collapse [data]="recentSearches" [fontSize]="15" [titleSeperator]="true"
+      <metron-collapse [data]="recentSearches" [fontSize]="15" [titleSeperator]="true" data-name="recent-searches"
                        (onSelect)="onSaveRecentSearchSelect($event)" (onDelete)="deleteRecentSearch($event)"> </metron-collapse>
-      <metron-collapse [data]="savedSearches" [fontSize]="15" [titleSeperator]="true" [deleteOption]="true"
+      <metron-collapse [data]="savedSearches" [fontSize]="15" [titleSeperator]="true" [deleteOption]="true" data-name="saved-searches"
                        (onSelect)="onSaveSearchSelect($event)" (onDelete)="deleteSearch($event)"> </metron-collapse>
     </div>
   </div>

http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/src/app/shared/group-by/group-by.component.html
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/src/app/shared/group-by/group-by.component.html b/metron-interface/metron-alerts/src/app/shared/group-by/group-by.component.html
index 3b12cd8..954c923 100644
--- a/metron-interface/metron-alerts/src/app/shared/group-by/group-by.component.html
+++ b/metron-interface/metron-alerts/src/app/shared/group-by/group-by.component.html
@@ -14,7 +14,7 @@
 <div class='wrapper'>
     <div class="mrow">
         <div class="group mr-2"> Group By </div>
-        <div class='container col mx-0 px-0' [dragula]='"group-bag"' [dragulaModel]='data' [dragulaOptions]="{direction: 'horizontal', removeOnSpill: false}">
+        <div class='container col mx-0 px-0' [dragula]='"group-bag"' [dragulaModel]='data' [dragulaOptions]="{direction: 'horizontal', removeOnSpill: false, ignoreInputTextSelection: false}">
             <div #dragEle class="group-by-items" *ngFor="let group of data" (click)="selectGroup(group)" [attr.data-name]="group.name"
                  data-animation="false" data-toggle="tooltip" data-placement="bottom" title="Drag to Sort"
                  [ngClass]="{'active': group.selected}">

http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/src/app/shared/time-range/time-range.component.html
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/src/app/shared/time-range/time-range.component.html b/metron-interface/metron-alerts/src/app/shared/time-range/time-range.component.html
index b65528d..fed679a 100644
--- a/metron-interface/metron-alerts/src/app/shared/time-range/time-range.component.html
+++ b/metron-interface/metron-alerts/src/app/shared/time-range/time-range.component.html
@@ -12,8 +12,8 @@
   the specific language governing permissions and limitations under the License.
   -->
 <button class="btn btn-secondary btn-search" [disabled]="disabled" type="button" data-animation="false"  data-toggle="collapse" data-target="#time-range" aria-expanded="false" aria-controls="time-range">
-  <span> {{selectedTimeRangeValue}} </span>
-  <br/> <span style="font-size: 8px;" *ngIf="selectedTimeRangeValue !== 'All time'"> {{fromDateStr}} to {{toDateStr}}</span>
+  <span class="time-range-text"> {{selectedTimeRangeValue}} </span>
+  <br/> <span class="time-range-value"> {{ selectedTimeRangeValue === 'All time' ? '' : fromDateStr +' to ' + toDateStr }}</span>
 </button>
 
 <div #datePicker class="collapse" id="time-range">
@@ -38,16 +38,16 @@
           <div class="title"> Quick Ranges </div> <br>
           <div class="row no-gutters">
             <div class="col-3">
-              <span *ngFor="let key of timeRangeMappingCol1 | mapKeys" (click)="selectTimeRange($event, timeRangeMappingCol1[key])">  {{ key }} </span> <br>
+              <span *ngFor="let key of timeRangeMappingCol1 | mapKeys" (click)="selectTimeRange($event, timeRangeMappingCol1[key])" [attr.id]="timeRangeMappingCol1[key]">  {{ key }} </span> <br>
             </div>
             <div class="col-3">
-              <span *ngFor="let key of timeRangeMappingCol2 | mapKeys" (click)="selectTimeRange($event, timeRangeMappingCol2[key])">  {{ key }} </span> <br>
+              <span *ngFor="let key of timeRangeMappingCol2 | mapKeys" (click)="selectTimeRange($event, timeRangeMappingCol2[key])" [attr.id]="timeRangeMappingCol2[key]">  {{ key }} </span> <br>
             </div>
             <div class="col-3">
-              <span *ngFor="let key of timeRangeMappingCol3 | mapKeys" (click)="selectTimeRange($event, timeRangeMappingCol3[key])">  {{ key }} </span> <br>
+              <span *ngFor="let key of timeRangeMappingCol3 | mapKeys" (click)="selectTimeRange($event, timeRangeMappingCol3[key])" [attr.id]="timeRangeMappingCol3[key]">  {{ key }} </span> <br>
             </div>
             <div class="col-3">
-              <span *ngFor="let key of timeRangeMappingCol4 | mapKeys" (click)="selectTimeRange($event, timeRangeMappingCol4[key])">  {{ key }} </span> <br>
+              <span *ngFor="let key of timeRangeMappingCol4 | mapKeys" (click)="selectTimeRange($event, timeRangeMappingCol4[key])" [attr.id]="timeRangeMappingCol4[key]">  {{ key }} </span> <br>
             </div>
           </div>
         </div>

http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/src/app/shared/time-range/time-range.component.scss
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/src/app/shared/time-range/time-range.component.scss b/metron-interface/metron-alerts/src/app/shared/time-range/time-range.component.scss
index 7f5faf0..ef75525 100644
--- a/metron-interface/metron-alerts/src/app/shared/time-range/time-range.component.scss
+++ b/metron-interface/metron-alerts/src/app/shared/time-range/time-range.component.scss
@@ -103,4 +103,8 @@
 
 form {
   margin-top: 5px;
+}
+
+.time-range-value {
+  font-size: 8px;
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/src/app/utils/constants.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/src/app/utils/constants.ts b/metron-interface/metron-alerts/src/app/utils/constants.ts
index ea50b14..bfa04bc 100644
--- a/metron-interface/metron-alerts/src/app/utils/constants.ts
+++ b/metron-interface/metron-alerts/src/app/utils/constants.ts
@@ -35,5 +35,6 @@ export let CUSTOMM_DATE_RANGE_LABEL = 'Date Range';
 
 export let TREE_SUB_GROUP_SIZE = 5;
 export let INDEXES =  environment.indices ? environment.indices.split(',') : [];
+export let POLLING_DEFAULT_STATE = environment.defaultPollingState;
 
 export let MAX_ALERTS_IN_META_ALERTS = 350;

http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/src/environments/environment.e2e.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/src/environments/environment.e2e.ts b/metron-interface/metron-alerts/src/environments/environment.e2e.ts
index df414b1..ebede73 100644
--- a/metron-interface/metron-alerts/src/environments/environment.e2e.ts
+++ b/metron-interface/metron-alerts/src/environments/environment.e2e.ts
@@ -17,5 +17,6 @@
  */
 export const environment = {
   production: false,
-  indices: 'alerts_ui_e2e,metaalert'
+  indices: 'alerts_ui_e2e,metaalert',
+  defaultPollingState: true
 };

http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/src/environments/environment.js
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/src/environments/environment.js b/metron-interface/metron-alerts/src/environments/environment.js
index acb2f54..29adadc 100644
--- a/metron-interface/metron-alerts/src/environments/environment.js
+++ b/metron-interface/metron-alerts/src/environments/environment.js
@@ -1,3 +1,4 @@
+"use strict";
 /**
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -19,7 +20,8 @@
 // The build system defaults to the dev environment which uses `environment.ts`, but if you do
 // `ng build --env=prod` then `environment.prod.ts` will be used instead.
 // The list of which env maps to which file can be found in `angular-cli.json`.
-"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
 exports.environment = {
-    production: false
+    production: false,
+    indices: null
 };

http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/src/environments/environment.prod.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/src/environments/environment.prod.ts b/metron-interface/metron-alerts/src/environments/environment.prod.ts
index 04e62a9..5f082a8 100644
--- a/metron-interface/metron-alerts/src/environments/environment.prod.ts
+++ b/metron-interface/metron-alerts/src/environments/environment.prod.ts
@@ -17,5 +17,6 @@
  */
 export const environment = {
   production: true,
-  indices: null
+  indices: null,
+  defaultPollingState: false
 };

http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/src/environments/environment.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/src/environments/environment.ts b/metron-interface/metron-alerts/src/environments/environment.ts
index 91fdbaf..b079ab8 100644
--- a/metron-interface/metron-alerts/src/environments/environment.ts
+++ b/metron-interface/metron-alerts/src/environments/environment.ts
@@ -22,5 +22,6 @@
 
 export const environment = {
   production: false,
-  indices: null
+  indices: null,
+  defaultPollingState: false
 };

http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/src/index.html
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/src/index.html b/metron-interface/metron-alerts/src/index.html
index 7795faa..e63e9bd 100644
--- a/metron-interface/metron-alerts/src/index.html
+++ b/metron-interface/metron-alerts/src/index.html
@@ -22,7 +22,7 @@
   <link rel="icon" type="image/x-icon" href="favicon.ico">
   <link rel="stylesheet" type="text/css" href="assets/fonts/font.css">
 </head>
-<body>
+<body class="notransition">
   <metron-alerts-root>Loading...</metron-alerts-root>
 </body>
 </html>

http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/src/styles.scss
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/src/styles.scss b/metron-interface/metron-alerts/src/styles.scss
index e9e1d51..687ad14 100644
--- a/metron-interface/metron-alerts/src/styles.scss
+++ b/metron-interface/metron-alerts/src/styles.scss
@@ -326,3 +326,13 @@ $background_color_3: #2196F3;
   }
 }
 
+.notransition * {
+  -webkit-transition: none !important;
+  -moz-transition: none !important;
+  -o-transition: none !important;
+  -ms-transition: none !important;
+  transition: none !important;
+
+  animation: none !important;
+}
+


[6/9] metron git commit: METRON-1489 Retrofit UI tests to run reliably during nightly QE runs (sardell via nickwallen) closes apache/metron#1004

Posted by le...@apache.org.
http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/e2e/alerts-list/alerts-list.po.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/e2e/alerts-list/alerts-list.po.ts b/metron-interface/metron-alerts/e2e/alerts-list/alerts-list.po.ts
index 45f4fee..13aeb27 100644
--- a/metron-interface/metron-alerts/e2e/alerts-list/alerts-list.po.ts
+++ b/metron-interface/metron-alerts/e2e/alerts-list/alerts-list.po.ts
@@ -18,16 +18,23 @@
 
 import {browser, element, by, protractor} from 'protractor';
 import * as moment from 'moment/moment';
-import {waitForElementVisibility, waitForElementPresence, waitForElementInVisibility} from '../utils/e2e_util';
+import {
+  waitForElementVisibility, waitForElementPresence, waitForElementInVisibility,
+  waitForText, waitForCssClass, waitForCssClassNotToBePresent, waitForTextChange,
+  waitForStalenessOf, reduce_for_get_all, waitForElementCountGreaterThan, scrollIntoView,
+  waitForNonEmptyText, catchNoSuchElementError
+} from '../utils/e2e_util';
 
 export class MetronAlertsPage {
+  private EC = protractor.ExpectedConditions;
+
   navigateTo() {
-    browser.waitForAngularEnabled(false);
-    return browser.get('/alerts-list');
+    return browser.waitForAngularEnabled(false)
+    .then(() => browser.get('/alerts-list'));
   }
 
   clearLocalStorage() {
-    browser.executeScript('window.localStorage.clear();');
+    return browser.executeScript('window.localStorage.clear();');
   }
 
   isMetronLogoPresent() {
@@ -72,23 +79,29 @@ export class MetronAlertsPage {
 
   clickActionDropdown() {
     let actionsDropDown = element(by.buttonText('ACTIONS'));
-    browser.actions().mouseMove(actionsDropDown).perform();
-    return actionsDropDown.click();
+    return scrollIntoView(actionsDropDown, true)
+    .then(() => actionsDropDown.click());
   }
 
   clickActionDropdownOption(option: string) {
-    this.clickActionDropdown().then(() => {
-      element(by.cssContainingText('.dropdown-menu span', option)).click();
-      browser.sleep(2000);
-    });
+    return this.clickActionDropdown()
+    .then(() => element(by.cssContainingText('.dropdown-menu span', option)).click())
+    .then(() => waitForCssClassNotToBePresent(element(by.css('#table-actions')), 'show'));
   }
 
   getActionDropdownItems() {
-    return this.clickActionDropdown().then(() => element.all(by.css('.dropdown-menu .dropdown-item.disabled')).getText());
+    return this.clickActionDropdown()
+    .then(() => element.all(by.css('.dropdown-menu .dropdown-item.disabled')).reduce(reduce_for_get_all(), []));
   }
 
   getTableColumnNames() {
-    return element.all(by.css('app-alerts-list .table th')).getText();
+    return element.all(by.css('app-alerts-list .table th')).reduce(reduce_for_get_all(), []);
+  }
+
+  getChangedPaginationText(previousText: string) {
+    let paginationElement = element(by.css('metron-table-pagination span'));
+    return waitForTextChange(paginationElement, previousText)
+    .then(() => paginationElement.getText());
   }
 
   getPaginationText() {
@@ -107,16 +120,18 @@ export class MetronAlertsPage {
     });
   }
 
-  clickChevronRight(times = 1) {
-    for (let i = 0; i < times; i++) {
-      element(by.css('metron-table-pagination .fa.fa-chevron-right')).click();
-    }
+  clickChevronRight() {
+    let paginationEle = element(by.css('metron-table-pagination .fa.fa-chevron-right'));
+    return waitForElementVisibility(paginationEle)
+    .then(() => browser.actions().mouseMove(paginationEle).perform())
+    .then(() => paginationEle.click())
   }
 
   clickChevronLeft(times = 1) {
-    for (let i = 0; i < times; i++) {
-      element(by.css('metron-table-pagination .fa.fa-chevron-left')).click();
-    }
+    let paginationEle = element(by.css('metron-table-pagination .fa.fa-chevron-left'));
+    return waitForElementVisibility(paginationEle)
+    .then(() => browser.actions().mouseMove(paginationEle).perform())
+    .then(() => paginationEle.click());
   }
 
   clickSettings() {
@@ -125,23 +140,23 @@ export class MetronAlertsPage {
   }
 
   getSettingsLabels() {
-    return element.all(by.css('app-configure-rows  form label:not(.switch)')).getText();
+    return element.all(by.css('app-configure-rows  form label:not(.switch)')).reduce(reduce_for_get_all() ,[]);
   }
 
   getRefreshRateOptions() {
-    return element.all(by.css('.preset-row.refresh-interval .preset-cell')).getText();
+    return element.all(by.css('.preset-row.refresh-interval .preset-cell')).reduce(reduce_for_get_all() ,[]);
   }
 
   getRefreshRateSelectedOption() {
-    return element.all(by.css('.preset-row.refresh-interval .preset-cell.is-active')).getText();
+    return element.all(by.css('.preset-row.refresh-interval .preset-cell.is-active')).reduce(reduce_for_get_all() ,[]);
   }
 
   getPageSizeOptions() {
-    return element.all(by.css('.preset-row.page-size .preset-cell')).getText();
+    return element.all(by.css('.preset-row.page-size .preset-cell')).reduce(reduce_for_get_all() ,[]);
   }
 
   getPageSizeSelectedOption() {
-    return element.all(by.css('.preset-row.page-size .preset-cell.is-active')).getText();
+    return element.all(by.css('.preset-row.page-size .preset-cell.is-active')).reduce(reduce_for_get_all() ,[]);
   }
 
   clickRefreshInterval(intervalText: string) {
@@ -154,30 +169,46 @@ export class MetronAlertsPage {
 
   clickConfigureTable() {
     let gearIcon = element(by.css('app-alerts-list .fa.fa-cog.configure-table-icon'));
-    waitForElementVisibility(gearIcon).then(() => gearIcon.click());
-    browser.sleep(1000);
+    return waitForElementVisibility(gearIcon)
+    .then(() => scrollIntoView(gearIcon, true))
+    .then(() => gearIcon.click())
+    .then(() => waitForElementCountGreaterThan('app-configure-table tr', 282));
   }
 
   clickCloseSavedSearch() {
-    element(by.css('app-saved-searches .close-button')).click();
-    browser.sleep(2000);
+    return element(by.css('app-saved-searches .close-button')).click()
+    .then(() => waitForStalenessOf(element(by.css('app-saved-searches'))));
   }
 
   clickSavedSearch() {
-    element(by.buttonText('Searches')).click();
-    browser.sleep(1000);
+    return element(by.buttonText('Searches')).click()
+    .then(() => waitForElementVisibility(element(by.css('app-saved-searches'))))
+    .then(() => browser.sleep(1000));
+  }
+
+  clickPlayPause(waitForPreviousClass: string) {
+    let playPauseButton = element(by.css('.btn.pause-play'));
+    return browser.actions().mouseMove(playPauseButton).perform()
+          .then(() => playPauseButton.click())
+          .then(() => waitForCssClass(element(by.css('.btn.pause-play i')), waitForPreviousClass));
   }
 
-  clickPlayPause() {
-    element(by.css('.btn.pause-play')).click();
+  clickTableTextAndGetSearchText(name: string, textToWaitFor: string) {
+    browser.sleep(500);
+    return waitForElementVisibility(element.all(by.cssContainingText('table tr td a', name)).get(0))
+          .then(() => element.all(by.cssContainingText('table tr td a', name)).get(0).click())
+          .then(() => waitForText('.ace_line', textToWaitFor))
+          .then(() => element(by.css('.ace_line')).getText());
   }
 
-  clickTableText(name: string) {
-    waitForElementPresence(element.all(by.linkText(name))).then(() => element.all(by.linkText(name)).get(0).click());
+  private clickTableText(name: string) {
+    waitForElementVisibility(element.all(by.linkText(name))).then(() => element.all(by.linkText(name)).get(0).click());
   }
 
-  clickClearSearch() {
-    element(by.css('.btn-search-clear')).click();
+  clickClearSearch(alertCount = '169') {
+    return element(by.css('.btn-search-clear')).click()
+    .then(() => waitForText('.ace_line', '*'))
+    .then(() => waitForText('.col-form-label-lg', `Alerts (${alertCount})`));
   }
 
   getSavedSearchTitle() {
@@ -197,36 +228,37 @@ export class MetronAlertsPage {
   }
 
   getRecentSearchOptions() {
-    browser.sleep(1000);
-    return element(by.linkText('Recent Searches')).element(by.xpath('..')).all(by.css('li')).getText();
+    return element.all(by.css('[data-name="recent-searches"] li')).getText();
   }
 
   getDefaultRecentSearchValue() {
-    browser.sleep(1000);
-    return element(by.linkText('Recent Searches')).element(by.xpath('..')).all(by.css('i')).getText();
+    return element.all(by.css('[data-name="recent-searches"] i')).getText();
   }
 
   getSavedSearchOptions() {
-    browser.sleep(1000);
-    return element(by.linkText('Saved Searches')).element(by.xpath('..')).all(by.css('li')).getText();
+    return element.all(by.css('[data-name="saved-searches"] li')).getText();
   }
 
   getDefaultSavedSearchValue() {
-    browser.sleep(1000);
-    return element(by.linkText('Saved Searches')).element(by.xpath('..')).all(by.css('i')).getText();
+    return element.all(by.css('[data-name="saved-searches"] i')).getText();
   }
 
   getSelectedColumnNames() {
-    return element.all(by.css('app-configure-table input[type="checkbox"]:checked')).map(ele => {
-      return ele.getAttribute('id').then(id => id.replace(/select-deselect-/, ''));
-    });
+    return element.all(by.css('app-configure-table input[type="checkbox"]:checked')).reduce((acc, ele) => {
+      return ele.getAttribute('id').then(id => {
+        acc.push(id.replace(/select-deselect-/, ''));
+        return acc;
+      })
+    }, []);
   }
 
-  toggleSelectCol(name: string, scrollTo = '') {
-    scrollTo = scrollTo === '' ? name : scrollTo;
-    let ele = element(by.css('app-configure-table label[for="select-deselect-' + name + '"]'));
-    let scrollToEle = element(by.css('app-configure-table label[for="select-deselect-' + scrollTo + '"]'));
-    browser.actions().mouseMove(scrollToEle).perform().then(() => ele.click());
+  toggleSelectCol(name: string) {
+    const selector = `app-configure-table label[for=\"select-deselect-${name}\"]`;
+    const ele = element(by.css(selector));
+    return waitForElementVisibility(ele)
+          .then(() => scrollIntoView(ele, true))
+          .then(() => (element(by.css(selector)).click()))
+          .catch(err => console.log(err));
   }
 
   saveSearch(name: string) {
@@ -235,28 +267,41 @@ export class MetronAlertsPage {
   }
 
   saveConfigureColumns() {
-    element(by.css('app-configure-table')).element(by.buttonText('SAVE')).click();
+    return element(by.css('app-configure-table')).element(by.buttonText('SAVE')).click();
   }
 
-  clickRemoveSearchChip() {
+  clickRemoveSearchChipAndGetSearchText(expectedSearchText: string) {
+    return this.clickRemoveSearchChip()
+    .then(() => waitForText('.ace_line', expectedSearchText))
+    .then(() => element(by.css('.ace_line')).getText())
+  }
+
+  private clickRemoveSearchChip(): any {
     let aceLine = element.all(by.css('.ace_keyword')).get(0);
     /* - Focus on the search text box by sending a empty string
        - move the mouse to the text in search bos so that delete buttons become visible
        - wait for delete buttons become visible
        - click on delete button
     */
-    element(by.css('app-alerts-list .ace_text-input')).sendKeys('')
+    return element(by.css('app-alerts-list .ace_text-input')).sendKeys('')
     .then(() => browser.actions().mouseMove(aceLine).perform())
     .then(() => this.waitForElementPresence(element(by.css('.ace_value i'))))
     .then(() => element.all(by.css('.ace_value i')).get(0).click());
   }
 
-  setSearchText(search: string) {
-    this.clickClearSearch();
-    element(by.css('app-alerts-list .ace_text-input')).sendKeys(protractor.Key.BACK_SPACE);
-    element(by.css('app-alerts-list .ace_text-input')).sendKeys(search);
-    element(by.css('app-alerts-list .ace_text-input')).sendKeys(protractor.Key.ENTER);
-    browser.sleep(2000);
+  setSearchText(search: string,  alertCount = '169') {
+    // It is required to click on a visible element of Ace editor in order to
+    // bring focus to the input: https://stackoverflow.com/questions/37809915/element-not-visible-error-not-able-to-click-an-element
+    let EC = protractor.ExpectedConditions;
+    let aceInput = element(by.css('app-alerts-list .ace_text-input'));
+    let aceScroller = element(by.css('app-alerts-list .ace_scroller'));
+    return this.clickClearSearch(alertCount)
+    .then(() => browser.wait(EC.presenceOf(aceScroller)))
+    .then(() => aceScroller.click())
+    .then(() => aceInput.sendKeys(protractor.Key.BACK_SPACE))
+    .then(() => aceInput.sendKeys(search))
+    .then(() => aceInput.sendKeys(protractor.Key.ENTER))
+    .then(() => browser.sleep(10000));
   }
 
   waitForElementPresence (element ) {
@@ -272,25 +317,31 @@ export class MetronAlertsPage {
   toggleAlertInList(index: number) {
     let selector = by.css('app-alerts-list tbody tr label');
     let checkbox = element.all(selector).get(index);
-    this.waitForElementPresence(checkbox).then(() => {
-      browser.actions().mouseMove(checkbox).perform().then(() => {
-        checkbox.click();
-      });
-    });
+    return this.waitForElementPresence(checkbox)
+    .then(() => scrollIntoView(checkbox, true))
+    .then(() => checkbox.click());
   }
 
   getAlertStatus(rowIndex: number, previousText: string, colIndex = 8) {
     let row = element.all(by.css('app-alerts-list tbody tr')).get(rowIndex);
     let column = row.all(by.css('td a')).get(colIndex);
-    return this.waitForTextChange(column, previousText).then(() => {
-      return column.getText();
-    });
+    return this.waitForTextChange(column, previousText).then(() => column.getText());
   }
 
-  waitForMetaAlert() {
-    browser.sleep(2000);
-    return element(by.css('button[data-name="search"]')).click()
-    .then(() => waitForElementPresence(element(by.css('.icon-cell.dropdown-cell'))));
+  waitForMetaAlert(expectedCount) {
+    let title = element(by.css('.col-form-label-lg'));
+    function waitForMetaAlert$()
+    {
+      return function () {
+        return browser.sleep(2000)
+        .then(() => element(by.css('button[data-name="search"]')).click())
+        .then(() => waitForTextChange(title, `Alerts (169)`))
+        .then(() => title.getText())
+        .then((text) => text === `Alerts (${expectedCount})`)
+        .catch(catchNoSuchElementError())
+      }
+    }
+    return browser.wait(waitForMetaAlert$()).catch(catchNoSuchElementError());
   }
 
   isDateSeettingDisabled() {
@@ -298,37 +349,74 @@ export class MetronAlertsPage {
   }
 
   clickDateSettings() {
-    element(by.css('app-time-range button.btn-search')).click();
-    browser.sleep(2000);
+    return scrollIntoView(element(by.css('app-time-range button.btn-search')), true)
+    .then(() => element(by.css('app-time-range button.btn-search')).click())
+    .then(() => waitForCssClass(element(by.css('app-time-range #time-range')), 'show'));
+  }
+
+  hideDateSettings() {
+    return element(by.css('app-time-range button.btn-search')).click()
+    .then(() => waitForCssClassNotToBePresent(element(by.css('app-time-range #time-range')), 'show'))
+    .then(() => waitForElementInVisibility(element(by.css('app-time-range #time-range'))));
   }
 
   getTimeRangeTitles() {
-    return element.all(by.css('app-time-range .title')).getText();
+    return element.all(by.css('app-time-range .title')).reduce(reduce_for_get_all(), []);
   }
 
   getQuickTimeRanges() {
-    return element.all(by.css('app-time-range .quick-ranges span')).getText();
+    return element.all(by.css('app-time-range .quick-ranges span')).reduce(reduce_for_get_all(), []);
   }
 
   getValueForManualTimeRange() {
-    return element.all(by.css('app-time-range input.form-control')). getAttribute('value');
+    return element.all(by.css('app-time-range input.form-control')).reduce((acc, ele) => {
+      return ele.getAttribute('value').then(value => {
+        acc.push(value);
+        return acc;
+      });
+    }, []);
   }
 
   isManulaTimeRangeApplyButtonPresent() {
     return element.all(by.css('app-time-range')).all(by.buttonText('APPLY')).count().then(count => count === 1);
   }
 
+  waitForTextAndSubTextInTimeRange(currentTimeRangeVal) {
+    return waitForTextChange(element(by.css('app-time-range .time-range-value')), currentTimeRangeVal[1])
+    .then(() => waitForTextChange(element(by.css('app-time-range .time-range-text')), currentTimeRangeVal[0]))
+  }
+
+  async selectQuickTimeRangeAndGetTimeRangeAndTimeText(quickRange: string) {
+    let currentTimeRangeVal: any = [];
+    let timeRangeVal = '', timeRangeText = '';
+    await element(by.css('app-time-range .time-range-value')).getText().then(text => timeRangeVal = text.trim());
+    await element(by.css('app-time-range .time-range-text')).getText().then(text => timeRangeText = text.trim());
+
+    await this.selectQuickTimeRange(quickRange);
+    await waitForCssClassNotToBePresent(element(by.css('app-time-range #time-range')), 'show');
+    await waitForTextChange(element(by.css('app-time-range .time-range-value')), timeRangeVal);
+    await waitForTextChange(element(by.css('app-time-range .time-range-text')), timeRangeText);
+
+    return this.getTimeRangeButtonAndSubText();
+  }
+
+  selectQuickTimeRangeAndGetTimeRangeText(quickRange: string) {
+    return this.selectQuickTimeRange(quickRange)
+    .then(() => waitForElementInVisibility(element(by.css('#time-range'))))
+    .then(() => browser.wait(this.EC.textToBePresentInElement(element(by.css('app-time-range .time-range-text')), quickRange)))
+    .then(() => element.all(by.css('app-time-range button span')).get(0).getText());
+  }
+
   selectQuickTimeRange(quickRange: string) {
-    element.all(by.cssContainingText('.quick-ranges span', quickRange)).get(0).click();
-    browser.sleep(2000);
+    return element(by.id(quickRange.toLowerCase().replace(/ /g,'-'))).click();
   }
 
   getTimeRangeButtonText() {
-    return element.all(by.css('app-time-range button.btn-search span')).get(0).getText();
+    return element(by.css('app-time-range .time-range-text')).getText();
   }
 
   setDate(index: number, year: string, month: string, day: string, hour: string, min: string, sec: string) {
-    element.all(by.css('app-time-range .calendar')).get(index).click()
+    return element.all(by.css('app-time-range .calendar')).get(index).click()
     .then(() => element.all(by.css('.pika-select.pika-select-hour')).get(index).click())
     .then(() => element.all(by.css('.pika-select.pika-select-hour')).get(index).element(by.cssContainingText('option', hour)).click())
     .then(() => element.all(by.css('.pika-select.pika-select-minute')).get(index).click())
@@ -341,8 +429,6 @@ export class MetronAlertsPage {
     .then(() => element.all(by.css('.pika-select.pika-select-month')).get(index).element(by.cssContainingText('option', month)).click())
     .then(() => element.all(by.css('.pika-table')).get(index).element(by.buttonText(day)).click())
     .then(() => waitForElementInVisibility(element.all(by.css('.pika-single')).get(index)));
-
-    browser.sleep(1000);
   }
 
   selectTimeRangeApplyButton() {
@@ -350,11 +436,9 @@ export class MetronAlertsPage {
   }
 
   getChangesAlertTableTitle(previousText: string) {
-    // browser.pause();
     let title = element(by.css('.col-form-label-lg'));
-    return this.waitForTextChange(title, previousText).then(() => {
-      return title.getText();
-    });
+    return waitForTextChange(title, previousText)
+    .then(() => title.getText());
   }
 
   getAlertStatusById(id: string) {
@@ -372,7 +456,7 @@ export class MetronAlertsPage {
   }
 
   expandMetaAlert(rowIndex: number) {
-    element.all(by.css('table tbody tr')).get(rowIndex).element(by.css('.icon-cell.dropdown-cell')).click();
+    return element.all(by.css('table tbody tr')).get(rowIndex).element(by.css('.icon-cell.dropdown-cell')).click();
   }
 
   getHiddenRowCount() {
@@ -388,8 +472,8 @@ export class MetronAlertsPage {
   }
 
   clickOnMetaAlertRow(rowIndex: number) {
-    element.all(by.css('table tbody tr')).get(rowIndex).all(by.css('td')).get(5).click();
-    browser.sleep(2000);
+    return element.all(by.css('table tbody tr')).get(rowIndex).all(by.css('td')).get(5).click()
+    .then(() => browser.sleep(2000));
   }
 
   removeAlert(rowIndex: number) {
@@ -397,42 +481,38 @@ export class MetronAlertsPage {
   }
 
   loadSavedSearch(name: string) {
-    element.all(by.css('app-saved-searches metron-collapse')).get(1).element(by.css('li[title="'+ name +'"]')).click();
-    browser.sleep(1000);
+    return element.all(by.css('app-saved-searches metron-collapse')).get(1).element(by.css('li[title="'+ name +'"]')).click();
   }
 
   loadRecentSearch(name: string) {
-    element.all(by.css('app-saved-searches metron-collapse')).get(0).all(by.css('li')).get(2).click();
-    browser.sleep(1000);
+    return element.all(by.css('app-saved-searches metron-collapse')).get(0).all(by.css('li')).get(2).click();
   }
 
   getTimeRangeButtonTextForNow() {
-    return element.all(by.css('app-time-range button span')).getText();
-  }
-
-  getTimeRangeButtonAndSubText() {
-    return waitForElementInVisibility(element(by.css('#time-range')))
-    .then(() => element.all(by.css('app-time-range button span')).getText())
-    .then(arr => {
-        let retArr = [arr[0]];
-        for (let i=1; i < arr.length; i++) {
-          let dateStr = arr[i].split(' to ');
-          let fromTime = moment.utc(dateStr[0], 'YYYY-MM-DD HH:mm:ss Z').unix() * 1000;
-          let toTime = moment.utc(dateStr[1], 'YYYY-MM-DD HH:mm:ss Z').unix() * 1000;
-          retArr.push((toTime - fromTime) + '');
-        }
-        return retArr;
-    });
+    return element.all(by.css('app-time-range button span')).reduce(reduce_for_get_all(), []);
+  }
+
+  async getTimeRangeButtonAndSubText() {
+    let timeRangetext = '', timeRangeValue = '';
+
+    await element(by.css('app-time-range .time-range-text')).getText().then(text => timeRangetext = text);
+    await element(by.css('app-time-range .time-range-value')).getText().then(text => timeRangeValue = text);
+
+    let retArr = [timeRangetext];
+    let dateStr = timeRangeValue.split(' to ');
+    let fromTime = moment.utc(dateStr[0], 'YYYY-MM-DD HH:mm:ss Z').unix() * 1000;
+    let toTime = moment.utc(dateStr[1], 'YYYY-MM-DD HH:mm:ss Z').unix() * 1000;
+    retArr.push((toTime - fromTime) + '');
+    return retArr;
   }
 
   renameColumn(name: string, value: string) {
-    element(by.cssContainingText('app-configure-table span', name))
+    return element(by.cssContainingText('app-configure-table span', name))
     .element(by.xpath('../..'))
     .element(by.css('.input')).sendKeys(value);
   }
 
   getTableCellValues(cellIndex: number, startRowIndex: number, endRowIndex: number): any {
-    return element.all(by.css('table tbody tr td:nth-child(' + cellIndex + ')')).getText()
-    .then(val => val.slice(startRowIndex, endRowIndex));
+    return element.all(by.css('table tbody tr td:nth-child(' + cellIndex + ')')).reduce(reduce_for_get_all(), [])
   }
 }

http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/e2e/alerts-list/configure-table/configure-table.e2e-spec.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/e2e/alerts-list/configure-table/configure-table.e2e-spec.ts b/metron-interface/metron-alerts/e2e/alerts-list/configure-table/configure-table.e2e-spec.ts
index 6741e2f..c3636f5 100644
--- a/metron-interface/metron-alerts/e2e/alerts-list/configure-table/configure-table.e2e-spec.ts
+++ b/metron-interface/metron-alerts/e2e/alerts-list/configure-table/configure-table.e2e-spec.ts
@@ -21,21 +21,22 @@ import {customMatchers} from '../../matchers/custom-matchers';
 import {LoginPage} from '../../login/login.po';
 import {loadTestData, deleteTestData} from '../../utils/e2e_util';
 
-describe('metron-alerts configure table', function() {
+describe('Test spec for table column configuration', function() {
   let page: MetronAlertsPage;
   let loginPage: LoginPage;
   let colNamesColumnConfig = [ 'score', 'id', 'timestamp', 'source:type', 'ip_src_addr', 'enrichments:geo:ip_dst_addr:country',
     'ip_dst_addr', 'host', 'alert_status' ];
 
-  beforeAll(() => {
-    loadTestData();
+  beforeAll(async function() : Promise<any> {
     loginPage = new LoginPage();
-    loginPage.login();
+
+    await loadTestData();
+    await loginPage.login();
   });
 
-  afterAll(() => {
-    loginPage.logout();
-    deleteTestData();
+  afterAll(async function() : Promise<any> {
+    await loginPage.logout();
+    await deleteTestData();
   });
 
   beforeEach(() => {
@@ -43,40 +44,39 @@ describe('metron-alerts configure table', function() {
     jasmine.addMatchers(customMatchers);
   });
 
-  it('should select columns from table configuration', () => {
+  it('should select columns from table configuration', async function() : Promise<any> {
     let newColNamesColumnConfig = [ 'score', 'timestamp', 'source:type', 'ip_src_addr', 'enrichments:geo:ip_dst_addr:country',
       'ip_dst_addr', 'host', 'alert_status', 'guid' ];
 
-    page.clearLocalStorage();
-    page.navigateTo();
+    await page.clearLocalStorage();
+    await page.navigateTo();
 
-    page.clickConfigureTable();
-    expect(page.getSelectedColumnNames()).toEqualBcoz(colNamesColumnConfig, 'for default selected column names');
-    page.toggleSelectCol('id');
-    page.toggleSelectCol('guid', 'method');
-    expect(page.getSelectedColumnNames()).toEqualBcoz(newColNamesColumnConfig, 'for guid added to selected column names');
-    page.saveConfigureColumns();
+    await  page.clickConfigureTable();
+    expect(await  page.getSelectedColumnNames()).toEqualBcoz(colNamesColumnConfig, 'for default selected column names');
+    await page.toggleSelectCol('id');
+    await page.toggleSelectCol('guid');
+    expect(await page.getSelectedColumnNames()).toEqualBcoz(newColNamesColumnConfig, 'for guid added to selected column names');
+    await page.saveConfigureColumns();
   });
 
-  it('should rename columns from table configuration', () => {
-    page.clearLocalStorage();
-    page.navigateTo();
+  it('should rename columns from table configuration', async function() : Promise<any> {
+    await page.clearLocalStorage();
+    await page.navigateTo();
 
-    page.clickConfigureTable();
-    page.renameColumn('enrichments:geo:ip_dst_addr:country', 'Country');
-    page.saveConfigureColumns();
+    await page.clickConfigureTable();
+    await page.renameColumn('enrichments:geo:ip_dst_addr:country', 'Country');
+    await page.saveConfigureColumns();
 
-    page.clickTableText('FR');
-    expect(page.getSearchText()).toEqual('Country:FR');
-    expect(page.getChangesAlertTableTitle('Alerts (169)')).toEqual('Alerts (25)');
-    page.clickClearSearch();
+    expect(await page.clickTableTextAndGetSearchText('FR', 'Country:FR')).toEqual('Country:FR');
+    expect(await page.getChangesAlertTableTitle('Alerts (169)')).toEqual('Alerts (25)');
+    await page.clickClearSearch();
 
-    expect(page.getChangesAlertTableTitle('Alerts (25)')).toEqual('Alerts (169)');
-    page.setSearchText('Country:FR');
-    expect(page.getChangesAlertTableTitle('Alerts (169)')).toEqual('Alerts (25)');
-    page.clickClearSearch();
+    expect(await page.getChangesAlertTableTitle('Alerts (25)')).toEqual('Alerts (169)');
+    await page.setSearchText('Country:FR');
+    expect(await page.getChangesAlertTableTitle('Alerts (169)')).toEqual('Alerts (25)');
+    await page.clickClearSearch();
 
-    expect(page.getTableColumnNames()).toContain('Country', 'for renamed column names for alert list table');
+    expect(await page.getTableColumnNames()).toContain('Country', 'for renamed column names for alert list table');
 
   });
 

http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/e2e/alerts-list/meta-alerts/meta-alert.e2e-spec.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/e2e/alerts-list/meta-alerts/meta-alert.e2e-spec.ts b/metron-interface/metron-alerts/e2e/alerts-list/meta-alerts/meta-alert.e2e-spec.ts
index 00d677e..5425523 100644
--- a/metron-interface/metron-alerts/e2e/alerts-list/meta-alerts/meta-alert.e2e-spec.ts
+++ b/metron-interface/metron-alerts/e2e/alerts-list/meta-alerts/meta-alert.e2e-spec.ts
@@ -19,13 +19,14 @@
 import { MetronAlertsPage } from '../alerts-list.po';
 import {customMatchers} from '../../matchers/custom-matchers';
 import {LoginPage} from '../../login/login.po';
-import {loadTestData, deleteTestData} from '../../utils/e2e_util';
+import {loadTestData, deleteTestData, createMetaAlertsIndex} from '../../utils/e2e_util';
 import {TreeViewPage} from '../tree-view/tree-view.po';
 import {MetronAlertDetailsPage} from '../../alert-details/alert-details.po';
 import {MetaAlertPage} from './meta-alert.po';
 import {AlertFacetsPage} from '../alert-filters/alert-filters.po';
+import {browser} from 'protractor';
 
-describe('meta-alerts workflow', function() {
+describe('Test spec for meta alerts workflow', function() {
   let detailsPage: MetronAlertDetailsPage;
   let tablePage: MetronAlertsPage;
   let metaAlertPage: MetaAlertPage;
@@ -33,122 +34,126 @@ describe('meta-alerts workflow', function() {
   let loginPage: LoginPage;
   let alertFacetsPage: AlertFacetsPage;
 
-  beforeAll(() => {
-    loadTestData();
-
+  beforeAll(async function() : Promise<any> {
     loginPage = new LoginPage();
-    loginPage.login();
     tablePage = new MetronAlertsPage();
     treePage = new TreeViewPage();
     tablePage = new MetronAlertsPage();
     metaAlertPage = new MetaAlertPage();
     detailsPage = new MetronAlertDetailsPage();
     alertFacetsPage = new AlertFacetsPage();
+
+    await createMetaAlertsIndex();
+    await loadTestData();
+    await loginPage.login();
   });
 
-  afterAll(() => {
-    loginPage.logout();
-    deleteTestData();
+  afterAll(async function() : Promise<any> {
+    await loginPage.logout();
+    await deleteTestData();
   });
 
   beforeEach(() => {
     jasmine.addMatchers(customMatchers);
   });
 
-  it('should have all the steps for meta alerts workflow', () => {
+  it('should have all the steps for meta alerts workflow', async function() : Promise<any> {
     let comment1 = 'This is a sample comment';
     let userNameAndTimestamp = '- admin - a few seconds ago';
-    let confirmText = 'Do you wish to create a meta alert with 113 selected alerts?';
+    let confirmText = 'Do you wish to create a meta alert with 22 selected alerts?';
     let dashRowValues = {
-      'firstDashRow': ['0', '192.168.138.158', 'ALERTS', '113'],
-      'secondDashRow': ['0', '192.168.66.1', 'ALERTS', '56']
+      'firstDashRow': ['0', '192.168.138.2', 'ALERTS', '22']
     };
 
-    tablePage.navigateTo();
+    await tablePage.navigateTo();
+    expect(await tablePage.getChangesAlertTableTitle('Alerts (0)')).toEqual('Alerts (169)');
 
     /* Create Meta Alert */
-    treePage.selectGroup('ip_src_addr');
-    expect(treePage.getDashGroupValues('192.168.138.158')).toEqualBcoz(dashRowValues.firstDashRow, 'First Dashrow to be present');
-    expect(treePage.getDashGroupValues('192.168.66.1')).toEqualBcoz(dashRowValues.secondDashRow, 'Second Dashrow to be present');
+    await treePage.selectGroup('ip_dst_addr');
+    // Test cannot pass until issue with missing dash score is resolved: https://issues.apache.org/jira/browse/METRON-1631
+    // expect(await treePage.getDashGroupValues('192.168.138.2')).toEqualBcoz(dashRowValues.firstDashRow, 'First Dashrow to be present');
 
-    treePage.clickOnMergeAlerts('192.168.138.158');
-    expect(treePage.getConfirmationText()).toEqualBcoz(confirmText, 'confirmation text to be present');
-    treePage.clickNoForConfirmation();
+    await treePage.clickOnMergeAlerts('192.168.138.2');
+    expect(await treePage.getConfirmationText()).toEqualBcoz(confirmText, 'confirmation text to be present');
+    await treePage.clickNoForConfirmation();
 
-    treePage.clickOnMergeAlerts('192.168.138.158');
-    treePage.clickYesForConfirmation();
+    await treePage.clickOnMergeAlerts('192.168.138.2');
+    await treePage.clickYesForConfirmation();
 
-    treePage.waitForElementToDisappear('192.168.138.158');
+    await treePage.waitForElementToDisappear('192.168.138.2');
 
-    treePage.unGroup();
+    await treePage.unGroup();
 
     /* Table should have all alerts */
-    tablePage.waitForMetaAlert();
-    expect(tablePage.getPaginationText()).toEqualBcoz('1 - 25 of 57', 'pagination text to be present');
-    expect(tablePage.getCellValue(0, 2, '(114)')).toContain('(113)', 'number of alerts in a meta alert should be correct');
-    expect(tablePage.getNonHiddenRowCount()).toEqualBcoz(25, '25 rows to be visible');
-    expect(tablePage.getAllRowsCount()).toEqualBcoz(138, '138 rows to be available');
-    expect(tablePage.getHiddenRowCount()).toEqualBcoz(113, '113 rows to be hidden');
-    tablePage.expandMetaAlert(0);
-    expect(tablePage.getNonHiddenRowCount()).toEqualBcoz(138, '138 rows to be visible after group expand');
-    expect(tablePage.getAllRowsCount()).toEqualBcoz(138, '138 rows to be available after group expand');
-    expect(tablePage.getHiddenRowCount()).toEqualBcoz(0, '0 rows to be hidden after group expand');
+    await tablePage.waitForMetaAlert(148);
+    expect(await tablePage.getChangedPaginationText('1 - 25 of 169')).toEqualBcoz('1 - 25 of 148', 'pagination text to be present');
+    expect(await tablePage.getCellValue(0, 2, '(14)')).toContain('(22)');
+    expect(await tablePage.getNonHiddenRowCount()).toEqualBcoz(25, '25 rows to be visible');
+    expect(await tablePage.getAllRowsCount()).toEqualBcoz(47, '47 rows to be available');
+    expect(await tablePage.getHiddenRowCount()).toEqualBcoz(22, '22 rows to be hidden');
+    await tablePage.expandMetaAlert(0);
+    expect(await tablePage.getNonHiddenRowCount()).toEqualBcoz(47, '47 rows to be visible after group expand');
+    expect(await tablePage.getAllRowsCount()).toEqualBcoz(47, '47 rows to be available after group expand');
+    expect(await tablePage.getHiddenRowCount()).toEqualBcoz(0, '0 rows to be hidden after group expand');
 
     /* Meta Alert Status Change */
-    tablePage.toggleAlertInList(0);
-    tablePage.clickActionDropdownOption('Open');
-    expect(tablePage.getAlertStatus(0, 'NEW', 2)).toEqual('OPEN');
-    expect(tablePage.getAlertStatus(1, 'NEW')).toEqual('OPEN');
-    expect(tablePage.getAlertStatus(2, 'NEW')).toEqual('OPEN');
-
-    /* Details Edit Should work - add comments - remove comments - multiple alerts */
-    tablePage.clickOnMetaAlertRow(0);
-    expect(detailsPage.getAlertDetailsCount()).toEqualBcoz(113, '113 alert details should be present');
-    detailsPage.clickRenameMetaAlert();
-    detailsPage.renameMetaAlert('e2e-meta-alert');
-    detailsPage.cancelRename();
-    expect(detailsPage.getAlertNameOrId()).not.toEqual('e2e-meta-alert');
-    detailsPage.clickRenameMetaAlert();
-    detailsPage.renameMetaAlert('e2e-meta-alert');
-    detailsPage.saveRename();
+    await tablePage.toggleAlertInList(0);
+    await tablePage.clickActionDropdownOption('Open');
+    expect(await tablePage.getAlertStatus(0, 'NEW', 2)).toEqual('OPEN');
+    expect(await tablePage.getAlertStatus(1, 'NEW')).toEqual('OPEN');
+    expect(await tablePage.getAlertStatus(2, 'NEW')).toEqual('OPEN');
+
+    /* Details Edit - add comments - remove comments - multiple alerts */
+    await tablePage.clickOnMetaAlertRow(0);
+    expect(await detailsPage.getAlertDetailsCount()).toEqualBcoz(22, '22 alert details should be present');
+    await detailsPage.clickRenameMetaAlert();
+    await detailsPage.renameMetaAlert('e2e-meta-alert');
+    await detailsPage.cancelRename();
+    expect(await detailsPage.getAlertNameOrId()).not.toEqual('e2e-meta-alert');
+    await detailsPage.clickRenameMetaAlert();
+    await detailsPage.renameMetaAlert('e2e-meta-alert');
+    await detailsPage.saveRename();
     expect(detailsPage.getAlertNameOrId()).toEqual('e2e-meta-alert');
 
-    detailsPage.clickCommentsInSideNav();
-    detailsPage.addCommentAndSave(comment1, 0);
-    expect(detailsPage.getCommentsText()).toEqual([comment1]);
-    expect(detailsPage.getCommentsUserNameAndTimeStamp()).toEqual([userNameAndTimestamp]);
-    expect(detailsPage.getCommentIconCountInListView()).toEqual(1);
+    // The below code will fail until this issue is resolved in Protractor: https://github.com/angular/protractor/issues/4693
+    // This is because the connection resets before deleting the test comment, which causes the assertion to be false
 
-    detailsPage.deleteComment();
-    detailsPage.clickYesForConfirmation();
+    // await detailsPage.clickCommentsInSideNav();
+    // await detailsPage.addCommentAndSave(comment1, 0);
+    // expect(await detailsPage.getCommentsText()).toEqual([comment1]);
+    // expect(await detailsPage.getCommentsUserNameAndTimeStamp()).toEqual([userNameAndTimestamp]);
+    // expect(await detailsPage.getCommentIconCountInListView()).toEqual(1);
 
-    detailsPage.closeDetailPane();
+    // await detailsPage.deleteComment();
+    // await detailsPage.clickYesForConfirmation(comment1);
+    await detailsPage.closeDetailPane();
 
     /* Add to alert */
-    tablePage.toggleAlertInList(3);
-    tablePage.clickActionDropdownOption('Add to Alert');
-    expect(metaAlertPage.getPageTitle()).toEqualBcoz('Add to Alert', 'Add Alert Title should be present');
-    expect(metaAlertPage.getMetaAlertsTitle()).toEqualBcoz('SELECT OPEN ALERT', 'select open alert title should be present');
-    expect(metaAlertPage.getAvailableMetaAlerts()).toEqualBcoz('e2e-meta-alert (113)', 'Meta alert should be present');
-    metaAlertPage.selectRadio();
-    metaAlertPage.addToMetaAlert();
-    expect(tablePage.getCellValue(0, 2, '(113')).toContain('(114)', 'alert count should be incremented');
-
-    /* Remove from alert */
+    await tablePage.toggleAlertInList(3);
+    await tablePage.clickActionDropdownOption('Add to Alert');
+    await metaAlertPage.waitForDialog();
+    expect(await metaAlertPage.getPageTitle()).toEqualBcoz('Add to Alert', 'Add Alert Title should be present');
+    expect(await metaAlertPage.getMetaAlertsTitle()).toEqualBcoz('SELECT OPEN ALERT', 'select open alert title should be present');
+    expect(await metaAlertPage.getAvailableMetaAlerts()).toEqualBcoz('e2e-meta-alert (22)', 'Meta alert should be present');
+    await metaAlertPage.selectRadio();
+    await metaAlertPage.addToMetaAlert();
+    expect(await tablePage.getCellValue(0, 2, '(22')).toContain('(23)', 'alert count should be incremented');
+
+    // /* Remove from alert */
     let removAlertConfirmText = 'Do you wish to remove the alert from the meta alert?';
-    tablePage.removeAlert(2);
-    expect(treePage.getConfirmationText()).toEqualBcoz(removAlertConfirmText, 'confirmation text to remove alert from meta alert');
-    treePage.clickYesForConfirmation();
-    expect(tablePage.getCellValue(0, 2, '(114')).toContain('(113)', 'alert count should be decremented');
+    await tablePage.removeAlert(2);
+    expect(await treePage.getConfirmationText()).toEqualBcoz(removAlertConfirmText, 'confirmation text to remove alert from meta alert');
+    await treePage.clickYesForConfirmation();
+    expect(await tablePage.getCellValue(0, 2, '(23')).toContain('(22)', 'alert count should be decremented');
 
-    /* Delete Meta Alert */
+    // /* Delete Meta Alert */
     let removeMetaAlertConfirmText = 'Do you wish to remove all the alerts from meta alert?';
-    tablePage.removeAlert(0);
-    expect(treePage.getConfirmationText()).toEqualBcoz(removeMetaAlertConfirmText, 'confirmation text to remove meta alert');
-    treePage.clickYesForConfirmation();
+    await tablePage.removeAlert(0);
+    expect(await treePage.getConfirmationText()).toEqualBcoz(removeMetaAlertConfirmText, 'confirmation text to remove meta alert');
+    await treePage.clickYesForConfirmation();
   });
 
-  it('should create a meta alert from nesting of more than one level', () => {
+  it('should create a meta alert from nesting of more than one level', async function() : Promise<any> {
     let groupByItems = {
       'source:type': '1',
       'ip_dst_addr': '7',
@@ -178,70 +183,73 @@ describe('meta-alerts workflow', function() {
       'a5e95569-a...0e2613b29a'
     ];
 
-    let alertsAfterDeletedInMetaAlerts = [
-      '82f8046d-d...03b17480dd',
+    let alertsAfterDeletedInMetaAlerts =  [ '3c346bf9-b...cb04b43210',
+      '42f4ce28-8...b3d575b507',
       '5c1825f6-7...da3abe3aec',
-      '9041285e-9...a04a885b53',
-      'ed906df7-2...91cc54c2f3',
-      'e63ff7ae-d...cddbe0c0b3',
-      '3c346bf9-b...cb04b43210',
-      'dcc483af-c...7bb802b652',
-      'b71f085d-6...a4904d8fcf',
       '754b4f63-3...b39678207f',
-      'd9430af3-e...9a18600ab2',
+      '82f8046d-d...03b17480dd',
+      '9041285e-9...a04a885b53',
       '9a943c94-c...3b9046b782',
-      'f39dc401-3...1f9cf02cd9',
-      'd887fe69-c...2fdba06dbc',
-      'e38be207-b...60a43e3378',
-      'eba8eccb-b...0005325a90',
+      'a5e95569-a...0e2613b29a',
       'adca96e3-1...979bf0b5f1',
-      '42f4ce28-8...b3d575b507',
       'aed3d10f-b...8b8a139f25',
-      'a5e95569-a...0e2613b29a'
-    ];
+      'b71f085d-6...a4904d8fcf',
+      'c894bbcf-3...74cf0cc1fe',
+      'd887fe69-c...2fdba06dbc',
+      'd9430af3-e...9a18600ab2',
+      'dcc483af-c...7bb802b652',
+      'e63ff7ae-d...cddbe0c0b3',
+      'eba8eccb-b...0005325a90',
+      'ed906df7-2...91cc54c2f3',
+      'f39dc401-3...1f9cf02cd9' ];
 
     // Create a meta alert from a group that is nested by more than 1 level
-    treePage.selectGroup('source:type');
-    treePage.selectGroup('ip_dst_addr');
-    treePage.expandDashGroup('alerts_ui_e2e');
+    await treePage.selectGroup('source:type');
+    await treePage.selectGroup('ip_dst_addr');
+    await treePage.expandDashGroup('alerts_ui_e2e');
 
-    treePage.clickOnMergeAlertsInTable('alerts_ui_e2e', '224.0.0.251', 0);
-    treePage.clickYesForConfirmation();
+    await treePage.clickOnMergeAlertsInTable('alerts_ui_e2e', '224.0.0.251', 0);
+    await treePage.clickYesForConfirmation();
 
-    treePage.unGroup();
-    tablePage.waitForMetaAlert();
+    await treePage.unGroup();
+    await tablePage.waitForMetaAlert(150);
 
-    expect(tablePage.getPaginationText()).toEqualBcoz('1 - 25 of 150', 'pagination text to be present');
+    expect(await tablePage.getChangedPaginationText('1 - 25 of 169')).toEqualBcoz('1 - 25 of 150', 'pagination text to be present');
 
     // Meta Alert should appear in Filters
-    alertFacetsPage.toggleFacetState(3);
-    expect(alertFacetsPage.getFacetValues(3)).toEqual({'metaalert': '1' }, 'for source:type facet');
+    await alertFacetsPage.toggleFacetState(3);
+    let facetValues = await alertFacetsPage.getFacetValues(3);
+    expect(await facetValues['metaalert']).toEqual('1', 'for source:type facet');
 
     // Meta Alert should not appear in Groups
-    expect(treePage.getGroupByItemNames()).toEqualBcoz(Object.keys(groupByItems), 'Group By Elements names should be present');
-    expect(treePage.getGroupByItemCounts()).toEqualBcoz(Object.keys(groupByItems).map(key => groupByItems[key]),
+    expect(await treePage.getGroupByItemNames()).toEqualBcoz(Object.keys(groupByItems), 'Group By Elements names should be present');
+    expect(await treePage.getGroupByItemCounts()).toEqualBcoz(Object.keys(groupByItems).map(key => groupByItems[key]),
         '5 Group By Elements values should be present');
 
 
-    tablePage.setSearchText('guid:c894bbcf-3195-0708-aebe-0574cf0cc1fe');
-    expect(tablePage.getChangesAlertTableTitle('Alerts (150)')).toEqual('Alerts (1)');
-    tablePage.expandMetaAlert(0);
-    expect(tablePage.getAllRowsCount()).toEqual(21);
-    tablePage.expandMetaAlert(0);
-    tablePage.clickClearSearch();
-    expect(tablePage.getChangesAlertTableTitle('Alerts (1)')).toEqual('Alerts (150)');
+    await tablePage.setSearchText('guid:c894bbcf-3195-0708-aebe-0574cf0cc1fe', '150');
+    expect(await tablePage.getChangesAlertTableTitle('Alerts (150)')).toEqual('Alerts (1)');
+    await tablePage.expandMetaAlert(0);
+    expect(await tablePage.getAllRowsCount()).toEqual(21);
+    await tablePage.expandMetaAlert(0);
+    await tablePage.clickClearSearch('150');
+    expect(await tablePage.getChangesAlertTableTitle('Alerts (1)')).toEqual('Alerts (150)');
 
     // Delete a meta alert from the middle and check the data
-    tablePage.expandMetaAlert(0);
-    expect(tablePage.getTableCellValues(3, 1, 21)).toEqual(alertsInMetaAlerts);
-    tablePage.removeAlert(5);
-    treePage.clickYesForConfirmation();
-    expect(tablePage.getCellValue(0, 2, '(20')).toContain('(19)', 'alert count should be decremented');
-    expect(tablePage.getTableCellValues(3, 1, 20)).toEqual(alertsAfterDeletedInMetaAlerts);
+    await tablePage.expandMetaAlert(0);
+    let guidValues = await tablePage.getTableCellValues(3, 1, 21);
+    guidValues = guidValues.slice(1, 21).sort();
+    expect(guidValues).toEqual(alertsInMetaAlerts.sort());
+    await tablePage.removeAlert(5);
+    await treePage.clickYesForConfirmation();
+    expect(await tablePage.getCellValue(0, 2, '(20')).toContain('(19)', 'alert count should be decremented');
+    let guidValuesAfterDeleteOp = await tablePage.getTableCellValues(3, 1, 20);
+    guidValuesAfterDeleteOp = guidValuesAfterDeleteOp.slice(1, 20).sort();
+    expect(guidValuesAfterDeleteOp).toEqual(alertsAfterDeletedInMetaAlerts.sort());
 
     //Remove the meta alert
-    tablePage.removeAlert(0);
-    treePage.clickYesForConfirmation();
+    await tablePage.removeAlert(0);
+    await treePage.clickYesForConfirmation();
   });
 
 });

http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/e2e/alerts-list/meta-alerts/meta-alert.po.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/e2e/alerts-list/meta-alerts/meta-alert.po.ts b/metron-interface/metron-alerts/e2e/alerts-list/meta-alerts/meta-alert.po.ts
index 762deb8..7f8f13e 100644
--- a/metron-interface/metron-alerts/e2e/alerts-list/meta-alerts/meta-alert.po.ts
+++ b/metron-interface/metron-alerts/e2e/alerts-list/meta-alerts/meta-alert.po.ts
@@ -17,27 +17,36 @@
  */
 
 import {browser, element, by} from 'protractor';
+import {waitForElementInVisibility, waitForElementVisibility} from '../../utils/e2e_util';
 
 export class MetaAlertPage {
 
+  waitForDialog() {
+    return waitForElementVisibility(element(by.css('app-meta-alerts')))
+        .then(() => browser.sleep(2000));
+  }
+
   getPageTitle() {
-    return element(by.css('app-meta-alerts .form-title')).getText();
+    let elementFinder = element(by.css('app-meta-alerts .form-title'));
+    return waitForElementVisibility(elementFinder).then(() => elementFinder.getText())
   }
 
   getMetaAlertsTitle() {
-    return element(by.css('app-meta-alerts .title')).getText();
+    let elementFinder = element(by.css('app-meta-alerts .title'));
+    return waitForElementVisibility(elementFinder).then(() => elementFinder.getText());
   }
 
   getAvailableMetaAlerts() {
-    return element(by.css('app-meta-alerts .guid-name-container div')).getText();
+    return waitForElementVisibility(element(by.css('app-meta-alerts .guid-name-container div')))
+    .then(() => element(by.css('app-meta-alerts .guid-name-container div')).getText());
   }
 
   selectRadio() {
-    return element.all(by.css('app-meta-alerts .checkmark')).click();
+    return element.all(by.css('app-meta-alerts .checkmark')).get(0).click();
   }
 
   addToMetaAlert() {
-    element.all(by.css('app-meta-alerts')).get(0).element(by.buttonText('ADD')).click();
-    browser.sleep(2000);
+    return element.all(by.css('app-meta-alerts')).get(0).element(by.buttonText('ADD')).click()
+    .then(() => waitForElementInVisibility(element(by.css('app-meta-alerts'))));
   }
 }

http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/e2e/alerts-list/save-search/save-search.e2e-spec.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/e2e/alerts-list/save-search/save-search.e2e-spec.ts b/metron-interface/metron-alerts/e2e/alerts-list/save-search/save-search.e2e-spec.ts
index 350f11e..cab8455 100644
--- a/metron-interface/metron-alerts/e2e/alerts-list/save-search/save-search.e2e-spec.ts
+++ b/metron-interface/metron-alerts/e2e/alerts-list/save-search/save-search.e2e-spec.ts
@@ -21,19 +21,20 @@ import {MetronAlertsPage} from '../alerts-list.po';
 import {LoginPage} from '../../login/login.po';
 import {loadTestData, deleteTestData} from '../../utils/e2e_util';
 
-describe('metron-alerts Search', function() {
+describe('Test spec for search and save search', function() {
   let page: MetronAlertsPage;
   let loginPage: LoginPage;
 
-  beforeAll(() => {
-    loadTestData();
+  beforeAll(async function() : Promise<any> {
     loginPage = new LoginPage();
-    loginPage.login();
+
+    await loadTestData();
+    await loginPage.login();
   });
 
-  afterAll(() => {
-    loginPage.logout();
-    deleteTestData();
+  afterAll(async function() : Promise<any> {
+    await loginPage.logout();
+    await deleteTestData();
   });
 
   beforeEach(() => {
@@ -41,57 +42,57 @@ describe('metron-alerts Search', function() {
     jasmine.addMatchers(customMatchers);
   });
 
-  it('should display all the default values for saved searches', () => {
-    page.clearLocalStorage();
-    page.navigateTo();
+  it('should display all the default values for saved searches', async function() : Promise<any> {
+    await page.clearLocalStorage();
+    await page.navigateTo();
 
-    page.clickSavedSearch();
-    expect(page.getSavedSearchTitle()).toEqualBcoz('Searches', 'for saved searches title');
-    expect(page.getRecentSearchOptions()).toEqualBcoz([], 'for recent search options');
-    expect(page.getSavedSearchOptions()).toEqualBcoz([], 'for saved search options');
-    expect(page.getDefaultRecentSearchValue()).toEqualBcoz([ 'No Recent Searches' ], 'for recent search default value');
-    expect(page.getDefaultSavedSearchValue()).toEqualBcoz([ 'No Saved Searches' ], 'for saved search default value');
-    page.clickCloseSavedSearch();
+    await page.clickSavedSearch();
+    expect(await page.getSavedSearchTitle()).toEqualBcoz('Searches', 'for saved searches title');
+    expect(await page.getRecentSearchOptions()).toEqualBcoz([], 'for recent search options');
+    expect(await page.getSavedSearchOptions()).toEqualBcoz([], 'for saved search options');
+    expect(await page.getDefaultRecentSearchValue()).toEqualBcoz([ 'No Recent Searches' ], 'for recent search default value');
+    expect(await page.getDefaultSavedSearchValue()).toEqualBcoz([ 'No Saved Searches' ], 'for saved search default value');
+    await page.clickCloseSavedSearch();
 
   });
 
-  it('should have all save search controls and they save search should be working', () => {
-    page.saveSearch('e2e-1');
-    page.clickSavedSearch();
-    expect(page.getSavedSearchOptions()).toEqualBcoz([ 'e2e-1' ], 'for saved search options e2e-1');
-    page.clickCloseSavedSearch();
+  it('should have all save search controls and they save search should be working', async function() : Promise<any> {
+    await page.saveSearch('e2e-1');
+    await page.clickSavedSearch();
+    expect(await page.getSavedSearchOptions()).toEqualBcoz([ 'e2e-1' ], 'for saved search options e2e-1');
+    await page.clickCloseSavedSearch();
   });
 
-  it('should populate search items when selected on table', () => {
-    page.clickTableText('US');
-    expect(page.getSearchText()).toEqualBcoz('enrichments:geo:ip_dst_addr:country:US', 'for search text ip_dst_addr_country US');
-    page.clickClearSearch();
-    expect(page.getSearchText()).toEqualBcoz('*', 'for clear search');
-  });
+  it('should delete search items from search box', async function() : Promise<any> {
+    await page.clickClearSearch();
+    expect(await page.getSearchText()).toEqual('*');
+    expect(await page.getChangesAlertTableTitle('')).toEqual('Alerts (169)');
 
-  it('should delete search items from search box', () => {
-    page.clickTableText('US');
-    expect(page.getSearchText()).toEqualBcoz('enrichments:geo:ip_dst_addr:country:US', 'for search text ip_dst_addr_country US');
-    page.clickRemoveSearchChip();
-    expect(page.getSearchText()).toEqualBcoz('*', 'for search chip remove');
+    expect(await page.clickTableTextAndGetSearchText('FR', 'enrichments:geo:ip_dst_addr:country:FR')).toEqualBcoz('enrichments:geo:ip_dst_addr:country:FR', 'for search text ip_dst_addr_country FR');
+    expect(await page.clickRemoveSearchChipAndGetSearchText('*')).toEqualBcoz('*', 'for search chip remove');
   });
 
-  it('should delete first search items from search box having multiple search fields', () => {
-    page.clickTableText('US');
-    page.clickTableText('alerts_ui_e2e');
-    expect(page.getSearchText()).toEqual('enrichments:geo:ip_dst_addr:country:US AND source:type:alerts_ui_e2e', 'for search text US and alerts_ui_e2e');
-    page.clickRemoveSearchChip();
-    expect(page.getSearchText()).toEqual('source:type:alerts_ui_e2e', 'for search text alerts_ui_e2e after US is removed');
-    page.clickRemoveSearchChip();
-    expect(page.getSearchText()).toEqualBcoz('*', 'for search chip remove for two search texts');
+  it('should delete first search items from search box having multiple search fields', async function() : Promise<any> {
+    await page.clickClearSearch();
+    expect(await page.getSearchText()).toEqual('*');
+    expect(await page.getChangesAlertTableTitle('')).toEqual('Alerts (169)');
+
+    expect(await page.clickTableTextAndGetSearchText('FR', 'enrichments:geo:ip_dst_addr:country:FR')).toEqual('enrichments:geo:ip_dst_addr:country:FR');
+    expect(await page.clickTableTextAndGetSearchText('alerts_ui_e2e', 'enrichments:geo:ip_dst_addr:country:FR AND source:type:alerts_ui_e2e')).toEqual('enrichments:geo:ip_dst_addr:country:FR AND source:type:alerts_ui_e2e');
+
+    expect(await page.clickRemoveSearchChipAndGetSearchText('source:type:alerts_ui_e2e')).toEqual('source:type:alerts_ui_e2e');
+    expect(await page.clickRemoveSearchChipAndGetSearchText('*')).toEqual('*');
   });
 
-  it('manually entering search queries to search box and pressing enter key should search', () => {
-    page.setSearchText('enrichments:geo:ip_dst_addr:country:US');
-    expect(page.getPaginationText()).toEqualBcoz('1 - 22 of 22',
+  it('manually entering search queries to search box and pressing enter key should search', async function() : Promise<any> {
+    await page.setSearchText('enrichments:geo:ip_dst_addr:country:US');
+    expect(await page.getChangesAlertTableTitle('Alerts (169)')).toEqual('Alerts (22)');
+    expect(await page.getPaginationText()).toEqualBcoz('1 - 22 of 22',
                                                 'for pagination text with search text enrichments:geo:ip_dst_addr:country:US');
-    page.setSearchText('enrichments:geo:ip_dst_addr:country:RU');
-    expect(page.getPaginationText()).toEqualBcoz('1 - 25 of 44',
+
+    await page.setSearchText('enrichments:geo:ip_dst_addr:country:RU');
+    expect(await page.getChangesAlertTableTitle('Alerts (169)')).toEqual('Alerts (44)');
+    expect(await page.getPaginationText()).toEqualBcoz('1 - 25 of 44',
                                                   'for pagination text with search text enrichments:geo:ip_dst_addr:country:RU as text');
   });
 

http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/e2e/alerts-list/tree-view/tree-view.e2e-spec.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/e2e/alerts-list/tree-view/tree-view.e2e-spec.ts b/metron-interface/metron-alerts/e2e/alerts-list/tree-view/tree-view.e2e-spec.ts
index 339b19f..3129674 100644
--- a/metron-interface/metron-alerts/e2e/alerts-list/tree-view/tree-view.e2e-spec.ts
+++ b/metron-interface/metron-alerts/e2e/alerts-list/tree-view/tree-view.e2e-spec.ts
@@ -19,46 +19,55 @@
 import {customMatchers} from  '../../matchers/custom-matchers';
 import {LoginPage} from '../../login/login.po';
 import {TreeViewPage} from './tree-view.po';
-import {loadTestData, deleteTestData} from '../../utils/e2e_util';
 import {MetronAlertsPage} from '../alerts-list.po';
 
-describe('metron-alerts tree view', function () {
+import {loadTestData, deleteTestData} from '../../utils/e2e_util';
+
+describe('Test spec for tree view', function () {
   let page: TreeViewPage;
   let listPage: MetronAlertsPage;
   let loginPage: LoginPage;
 
-  beforeAll(() => {
-    loadTestData();
+  beforeAll(async function() : Promise<any> {
     loginPage = new LoginPage();
     page = new TreeViewPage();
     listPage = new MetronAlertsPage();
-    loginPage.login();
-    page.navigateToAlertsList();
+
+    await loadTestData();
+    await loginPage.login();
+    jasmine.addMatchers(customMatchers);
   });
 
-  afterAll(() => {
-    loginPage.logout();
-    deleteTestData();
+
+  afterAll(async function() : Promise<any> {
+    await loginPage.logout();
+    await deleteTestData();
   });
 
   beforeEach(() => {
-    jasmine.addMatchers(customMatchers);
+
   });
 
-  it('should have all group by elements', () => {
+  it('should have all group by elements', async function() : Promise<any> {
     let groupByItems = {
       'source:type': '1',
       'ip_dst_addr': '8',
       'enrichm...:country': '3',
       'ip_src_addr': '2'
     };
-    expect(page.getGroupByCount()).toEqualBcoz(Object.keys(groupByItems).length, '4 Group By Elements should be present');
-    expect(page.getGroupByItemNames()).toEqualBcoz(Object.keys(groupByItems), 'Group By Elements names should be present');
-    expect(page.getGroupByItemCounts()).toEqualBcoz(Object.keys(groupByItems).map(key => groupByItems[key]),
+
+    expect(await listPage.getChangesAlertTableTitle('Alerts (0)')).toEqualBcoz('Alerts (169)', 'for alerts title');
+
+    expect(await page.getGroupByCount()).toEqualBcoz(Object.keys(groupByItems).length, '4 Group By Elements should be present');
+    expect(await page.getGroupByItemNames()).toEqualBcoz(Object.keys(groupByItems), 'Group By Elements names should be present');
+    expect(await page.getGroupByItemCounts()).toEqualBcoz(Object.keys(groupByItems).map(key => groupByItems[key]),
                                                     '4 Group By Elements values should be present');
   });
 
-  it('drag and drop should change group order', () => {
+//   HTML5 Drag and Drop with Selenium Webdriver issue effects this test:
+//   https://github.com/SeleniumHQ/selenium-google-code-issue-archive/issues/3604
+
+  xit('drag and drop should change group order',  async function() : Promise<any> {
     let before = {
       'firstDashRow': ['0', 'alerts_ui_e2e', 'ALERTS', '169'],
       'firstSubGroup': '0 US (22)',
@@ -75,105 +84,110 @@ describe('metron-alerts tree view', function () {
       'thirdDashSubGroup': '0 alerts_ui_e2e (25)'
     };
 
-    page.selectGroup('source:type');
-    page.selectGroup('enrichments:geo:ip_dst_addr:country');
-    page.expandDashGroup('alerts_ui_e2e');
-    expect(page.getDashGroupValues('alerts_ui_e2e')).toEqualBcoz(before.firstDashRow, 'First Dash Row should be correct');
-    expect(page.getSubGroupValues('alerts_ui_e2e', 'US')).toEqualBcoz(before.firstSubGroup,
+    await page.selectGroup('source:type');
+    await page.selectGroup('enrichments:geo:ip_dst_addr:country');
+    expect(await page.getDashGroupValues('alerts_ui_e2e')).toEqualBcoz(before.firstDashRow, 'First Dash Row should be correct');
+
+    await page.expandDashGroup('alerts_ui_e2e');
+    expect(await page.getSubGroupValues('alerts_ui_e2e', 'US')).toEqualBcoz(before.firstSubGroup,
         'Dash Group Values should be correct for US');
-    expect(page.getSubGroupValues('alerts_ui_e2e', 'RU')).toEqualBcoz(before.secondSubGroup,
+    expect(await page.getSubGroupValues('alerts_ui_e2e', 'RU')).toEqualBcoz(before.secondSubGroup,
         'Dash Group Values should be present for RU');
-    expect(page.getSubGroupValues('alerts_ui_e2e', 'FR')).toEqualBcoz(before.thirdSubGroup,
+    expect(await page.getSubGroupValues('alerts_ui_e2e', 'FR')).toEqualBcoz(before.thirdSubGroup,
         'Dash Group Values should be present for FR');
 
-    page.dragGroup('source:type', 'ip_src_addr');
-    //page.selectGroup('source:type');
-    expect(page.getDashGroupValues('US')).toEqualBcoz(after.firstDashRow, 'First Dash Row after ' +
+    await page.simulateDragAndDrop('source:type', 'ip_src_addr');
+
+    expect(await page.getDashGroupValues('US')).toEqualBcoz(after.firstDashRow, 'First Dash Row after ' +
         'reorder should be correct');
-    expect(page.getDashGroupValues('RU')).toEqualBcoz(after.secondDashRow, 'Second Dash Row after ' +
+    expect(await page.getDashGroupValues('RU')).toEqualBcoz(after.secondDashRow, 'Second Dash Row after ' +
         'reorder should be correct');
-    expect(page.getDashGroupValues('FR')).toEqualBcoz(after.thirdDashRow, 'Third Dash Row after ' +
+    expect(await page.getDashGroupValues('FR')).toEqualBcoz(after.thirdDashRow, 'Third Dash Row after ' +
         'reorder should be correct');
 
-    page.expandDashGroup('US');
-    expect(page.getSubGroupValues('US', 'alerts_ui_e2e')).toEqualBcoz(after.firstDashSubGroup,
+    await page.expandDashGroup('US');
+    expect(await page.getSubGroupValues('US', 'alerts_ui_e2e')).toEqualBcoz(after.firstDashSubGroup,
         'First Dash Group Values should be present for alerts_ui_e2e');
 
-    page.expandDashGroup('RU');
-    expect(page.getSubGroupValues('RU', 'alerts_ui_e2e')).toEqualBcoz(after.secondDashSubGroup,
+    await page.expandDashGroup('RU');
+    expect(await page.getSubGroupValues('RU', 'alerts_ui_e2e')).toEqualBcoz(after.secondDashSubGroup,
         'Second Dash Group Values should be present for alerts_ui_e2e');
 
-    page.expandDashGroup('FR');
-    expect(page.getSubGroupValues('FR', 'alerts_ui_e2e')).toEqualBcoz(after.thirdDashSubGroup,
+    await page.expandDashGroup('FR');
+    expect(await page.getSubGroupValues('FR', 'alerts_ui_e2e')).toEqualBcoz(after.thirdDashSubGroup,
         'Third Dash Group Values should be present for alerts_ui_e2e');
 
-    page.dragGroup('source:type', 'ip_dst_addr');
-    page.unGroup();
+    await page.simulateDragAndDrop('source:type', 'ip_dst_addr');
+    await page.unGroup();
+
   });
 
-  it('should have group details for single group by', () => {
+  // Test cannot pass until issue with missing dash score is resolved: https://issues.apache.org/jira/browse/METRON-1631
+  xit('should have group details for single group by', async function() : Promise<any> {
     let dashRowValues = ['0', 'alerts_ui_e2e', 'ALERTS', '169'];
-    let row1_page1 = ['-', 'dcda4423-7...0962fafc47', '2017-09-13 17:59:32', 'alerts_ui_e2e',
-      '192.168.138.158', 'US', '72.34.49.86', 'comarksecurity.com', 'NEW', '', ''];
-    let row1_page2 = ['-', '07b29c29-9...ff19eaa888', '2017-09-13 17:59:37', 'alerts_ui_e2e',
-      '192.168.138.158', 'FR', '62.75.195.236', '62.75.195.236', 'NEW', '', ''];
+    let row1_page1 = ['-','acf5a641-9...a316e14fbe', '2017-09-13 17:59:35', 'alerts_ui_e2e',
+                        '192.168.66.1', '', '192.168.66.121', 'node1', 'NEW'];
+    let row1_page2 = ['-', '3097a3d9-f...1cfb870355', '2017-09-13 18:00:22', 'alerts_ui_e2e',
+                        '192.168.66.1', '','192.168.66.121', 'node1', 'NEW'];
 
-    page.selectGroup('source:type');
-    expect(page.getActiveGroups()).toEqualBcoz(['source:type'], 'only source type group should be selected');
-    expect(page.getDashGroupValues('alerts_ui_e2e')).toEqualBcoz(dashRowValues, 'Dash Group Values should be present');
+    await page.unGroup();
+    await page.selectGroup('source:type');
+    expect(await page.getActiveGroups()).toEqualBcoz(['source:type'], 'only source type group should be selected');
+    expect(await page.getDashGroupValues('alerts_ui_e2e')).toEqualBcoz(dashRowValues, 'Dash Group Values should be present');
 
-    page.expandDashGroup('alerts_ui_e2e');
-    expect(page.getDashGroupTableValuesForRow('alerts_ui_e2e', 0)).toEqualBcoz(row1_page1, 'Dash Group Values should be present');
+    await page.expandDashGroup('alerts_ui_e2e');
+    expect(await page.getTableValuesByRowId('alerts_ui_e2e', 0, 'acf5a641-9...a316e14fbe')).toEqualBcoz(row1_page1, 'Dash Group Values should be present');
 
-    page.clickOnNextPage('alerts_ui_e2e');
-    expect(page.getTableValuesByRowId('alerts_ui_e2e', 0, 'FR')).toEqualBcoz(row1_page2, 'Dash Group Values should be present');
+    await page.clickOnNextPage('alerts_ui_e2e');
+    expect(await page.getTableValuesByRowId('alerts_ui_e2e', 0, '3097a3d9-f...1cfb870355')).toEqualBcoz(row1_page2, 'Dash Group Values should be present');
 
-    page.unGroup();
-    expect(page.getActiveGroups()).toEqualBcoz([], 'no groups should be selected');
+    await page.unGroup();
+    expect(await page.getActiveGroups()).toEqualBcoz([], 'no groups should be selected');
   });
 
-  it('should have group details for multiple group by', () => {
+  it('should have group details for multiple group by', async function() : Promise<any> {
 
-    let usGroupIds = ['9a969c64-b...001cb011a3','a651f7c3-1...a97d4966c9','afc36901-3...d931231ab2','d860ac35-1...f9e282d571','04a5c3d0-9...af17c06fbc'];
-    let frGroupIds = ['07b29c29-9...ff19eaa888','7cd91565-1...de5be54a6e','ca5bde58-a...f3a88d2df4','5d6faf83-8...b88a407647','e2883424-f...79bb8b0606'];
+    let usGroupIds = ['a651f7c3-1...a97d4966c9', '5cfff1c7-6...ef3d766fc7', '7022e863-5...3c1fb629ed', '5404950f-9...86ce704b22', '8eb077ae-3...b77fed1ab4'];
+    let frGroupIds = ['07b29c29-9...ff19eaa888', 'c27f0bd2-3...697eaf8692', 'ba44eb73-6...6f9c15b261', '6a437817-e...dd0b37d280', '48fc3a55-4...3479974d34'];
 
-    page.selectGroup('source:type');
-    page.selectGroup('ip_dst_addr');
-    page.selectGroup('enrichments:geo:ip_dst_addr:country');
-    expect(page.getActiveGroups()).toEqualBcoz(['source:type', 'ip_dst_addr', 'enrichments:geo:ip_dst_addr:country'], '3 groups should be selected');
+    await page.unGroup();
+    await page.selectGroup('source:type');
+    await page.selectGroup('ip_dst_addr');
+    await page.selectGroup('enrichments:geo:ip_dst_addr:country');
+    expect(await page.getActiveGroups()).toEqualBcoz(['source:type', 'ip_dst_addr', 'enrichm...:country'], '3 groups should be selected');
 
-    expect(page.getDashGroupValues('alerts_ui_e2e')).toEqualBcoz(['0', 'alerts_ui_e2e', 'ALERTS', '169'],
+    expect(await page.getDashGroupValues('alerts_ui_e2e')).toEqualBcoz(['0', 'alerts_ui_e2e', 'ALERTS', '169'],
                                                               'Top Level Group Values should be present for alerts_ui_e2e');
 
-    page.expandDashGroup('alerts_ui_e2e');
-    expect(page.getSubGroupValuesByPosition('alerts_ui_e2e', '204.152.254.221', 0)).toEqualBcoz('0 204.152.254.221 (13)',
+    await page.expandDashGroup('alerts_ui_e2e');
+    expect(await page.getSubGroupValuesByPosition('alerts_ui_e2e', '204.152.254.221', 0)).toEqualBcoz('0 204.152.254.221 (13)',
                                                                     'Second Level Group Values should be present for 204.152.254.221');
 
-    page.expandSubGroupByPosition('alerts_ui_e2e', '204.152.254.221', 0);
-    expect(page.getSubGroupValuesByPosition('alerts_ui_e2e', 'US', 0)).toEqualBcoz('0 US (13)',
+    await page.expandSubGroupByPosition('alerts_ui_e2e', '204.152.254.221', 0);
+    expect(await page.getSubGroupValuesByPosition('alerts_ui_e2e', 'US', 0)).toEqualBcoz('0 US (13)',
         'Third Level Group Values should be present for US');
 
-    page.expandSubGroup('alerts_ui_e2e', 'US');
-    expect(page.getSubGroupValuesByPosition('alerts_ui_e2e', 'US', 0)).toEqualBcoz('0 US (13)',
+    await page.expandSubGroup('alerts_ui_e2e', 'US');
+    expect(await page.getSubGroupValuesByPosition('alerts_ui_e2e', 'US', 0)).toEqualBcoz('0 US (13)',
         'Third Level Group Values should not change when expanded for US');
-    expect(page.getCellValuesFromTable('alerts_ui_e2e', 'id', '04a5c3d0-9...af17c06fbc')).toEqual(usGroupIds, 'rows should be present for US');
+    expect(await page.getCellValuesFromTable('alerts_ui_e2e', 'id', 'a651f7c3-1...a97d4966c9')).toEqual(usGroupIds, 'rows should be present for US');
 
 
-    page.expandSubGroup('alerts_ui_e2e', '62.75.195.236');
-    expect(page.getSubGroupValuesByPosition('alerts_ui_e2e', 'FR', 1)).toEqualBcoz('0 FR (23)',
+    await page.expandSubGroup('alerts_ui_e2e', '62.75.195.236');
+    expect(await page.getSubGroupValuesByPosition('alerts_ui_e2e', 'FR', 1)).toEqualBcoz('0 FR (23)',
         'Third Level Group Values should be present for FR');
 
-    page.expandSubGroupByPosition('alerts_ui_e2e', 'FR', 1);
-    expect(page.getSubGroupValuesByPosition('alerts_ui_e2e', 'FR', 1)).toEqualBcoz('0 FR (23)',
+    await page.expandSubGroupByPosition('alerts_ui_e2e', 'FR', 1);
+    expect(await page.getSubGroupValuesByPosition('alerts_ui_e2e', 'FR', 1)).toEqualBcoz('0 FR (23)',
         'Third Level Group Values should not change when expanded for FR');
-    expect(page.getCellValuesFromTable('alerts_ui_e2e', 'id', 'e2883424-f...79bb8b0606')).toEqual(usGroupIds.concat(frGroupIds), 'rows should be present for FR');
-    
-    page.unGroup();
-    expect(page.getActiveGroups()).toEqualBcoz([], 'no groups should be selected');
+    expect(await page.getCellValuesFromTable('alerts_ui_e2e', 'id', '07b29c29-9...ff19eaa888')).toEqual(usGroupIds.concat(frGroupIds), 'rows should be present for FR');
+
+    await page.unGroup();
+    expect(await page.getActiveGroups()).toEqualBcoz([], 'no groups should be selected');
   });
 
 
-  it('should have sort working for group details for multiple sub groups', () => {
+  it('should have sort working for group details for multiple sub groups', async function() : Promise<any> {
 
     let usTSCol = ['2017-09-13 17:59:32', '2017-09-13 17:59:42', '2017-09-13 17:59:53', '2017-09-13 18:00:02', '2017-09-13 18:00:14'];
     let ruTSCol = ['2017-09-13 17:59:33', '2017-09-13 17:59:48', '2017-09-13 17:59:51', '2017-09-13 17:59:54', '2017-09-13 17:59:57'];
@@ -183,50 +197,52 @@ describe('metron-alerts tree view', function () {
     let ruSortedTSCol = ['2017-09-14 06:29:40', '2017-09-14 06:29:40', '2017-09-14 06:29:40', '2017-09-14 06:29:40', '2017-09-13 18:02:13'];
     let frSortedTSCol = ['2017-09-14 06:29:40', '2017-09-14 04:29:40', '2017-09-13 18:02:20', '2017-09-13 18:02:05', '2017-09-13 18:02:04'];
 
-    page.selectGroup('source:type');
-    page.selectGroup('enrichments:geo:ip_dst_addr:country');
+    await page.unGroup();
+    await page.selectGroup('source:type');
+    await page.selectGroup('enrichments:geo:ip_dst_addr:country');
 
-    page.expandDashGroup('alerts_ui_e2e');
-    page.expandSubGroup('alerts_ui_e2e', 'US');
-    page.expandSubGroup('alerts_ui_e2e', 'RU');
-    page.expandSubGroup('alerts_ui_e2e', 'FR');
+    await page.expandDashGroup('alerts_ui_e2e');
+    await page.expandSubGroup('alerts_ui_e2e', 'US');
+    await page.expandSubGroup('alerts_ui_e2e', 'RU');
+    await page.expandSubGroup('alerts_ui_e2e', 'FR');
 
     let unsortedTS = [...usTSCol, ...ruTSCol, ...frTSCol];
     let sortedTS = [...usSortedTSCol, ...ruSortedTSCol, ...frSortedTSCol];
 
-    page.sortSubGroup('alerts_ui_e2e', 'timestamp');
+    await page.sortSubGroup('alerts_ui_e2e', 'timestamp');
 
-    expect(page.getCellValuesFromTable('alerts_ui_e2e', 'timestamp', '2017-09-13 18:00:37')).toEqual(unsortedTS,
+    expect(await page.getCellValuesFromTable('alerts_ui_e2e', 'timestamp', '2017-09-13 18:00:37')).toEqual(unsortedTS,
                                                                                                       'timestamp should be sorted asc');
 
-    page.sortSubGroup('alerts_ui_e2e', 'timestamp');
+    await page.sortSubGroup('alerts_ui_e2e', 'timestamp');
 
-    expect(page.getCellValuesFromTable('alerts_ui_e2e', 'timestamp', '2017-09-13 18:02:04')).toEqual(sortedTS,
+    expect(await page.getCellValuesFromTable('alerts_ui_e2e', 'timestamp', '2017-09-13 18:02:04')).toEqual(sortedTS,
                                                                                                       'timestamp should be sorted dsc');
 
-    page.unGroup();
+    await page.unGroup();
     expect(page.getActiveGroups()).toEqualBcoz([], 'no groups should be selected');
   });
 
-  it('should have search working for group details for multiple sub groups', () => {
+  it('should have search working for group details for multiple sub groups', async function() : Promise<any> {
+
+    await page.unGroup();
+    await listPage.setSearchText('enrichments:geo:ip_dst_addr:country:FR');
+
+    expect(await listPage.getChangesAlertTableTitle('Alerts (169)')).toEqual('Alerts (25)');
 
-    page.selectGroup('source:type');
-    page.selectGroup('enrichments:geo:ip_dst_addr:country');
+    await page.selectGroup('source:type');
+    await page.selectGroup('enrichments:geo:ip_dst_addr:country');
 
-    page.expandDashGroup('alerts_ui_e2e');
-    expect(page.getNumOfSubGroups('alerts_ui_e2e')).toEqual(3, 'three sub groups should be present');
+    await page.expandDashGroup('alerts_ui_e2e');
+    expect(await page.getNumOfSubGroups('alerts_ui_e2e')).toEqual(1, 'three sub groups should be present');
 
-    listPage.setSearchText('enrichments:geo:ip_dst_addr:country:FR');
 
-    expect(page.getNumOfSubGroups('alerts_ui_e2e')).toEqual(1, 'one sub groups should be present');
-    page.expandSubGroup('alerts_ui_e2e', 'FR');
+    await page.expandSubGroup('alerts_ui_e2e', 'FR');
 
     let expected = ['FR', 'FR', 'FR', 'FR', 'FR'];
-    expect(page.getCellValuesFromTable('alerts_ui_e2e', 'enrichments:geo:ip_dst_addr:country', 'FR')).toEqual(expected,
+    expect(await page.getCellValuesFromTable('alerts_ui_e2e', 'enrichments:geo:ip_dst_addr:country', 'FR')).toEqual(expected,
                                                                                                               'id should be sorted');
-
-    page.unGroup();
-    expect(page.getActiveGroups()).toEqualBcoz([], 'no groups should be selected');
+    await page.unGroup();
   });
 
 });

http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/e2e/alerts-list/tree-view/tree-view.po.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/e2e/alerts-list/tree-view/tree-view.po.ts b/metron-interface/metron-alerts/e2e/alerts-list/tree-view/tree-view.po.ts
index 368f709..047578a 100644
--- a/metron-interface/metron-alerts/e2e/alerts-list/tree-view/tree-view.po.ts
+++ b/metron-interface/metron-alerts/e2e/alerts-list/tree-view/tree-view.po.ts
@@ -16,42 +16,47 @@
  * limitations under the License.
  */
 
-import {browser, element, by} from 'protractor';
+import { browser, element, by } from 'protractor';
 import {
   waitForElementPresence, waitForTextChange, waitForElementVisibility,
-  waitForElementInVisibility
+  waitForElementInVisibility, waitForCssClass, waitForStalenessOf,
+  waitForElementCountGreaterThan, reduce_for_get_all, scrollIntoView
 } from '../../utils/e2e_util';
 
 export class TreeViewPage {
   navigateToAlertsList() {
-    browser.waitForAngularEnabled(false);
     return browser.get('/alerts-list');
   }
 
   clickOnRow(id: string) {
     let idElement = element(by.css('a[title="' + id +'"]'));
-    waitForElementPresence(idElement)
+    let td = idElement.element(by.xpath('../..')).all(by.css('td')).get(9);
+    let detailsPane = element(by.css('.metron-slider-pane-details'));
+    return waitForElementPresence(idElement)
     .then(() => browser.actions().mouseMove(idElement).perform())
-    .then(() => idElement.element(by.xpath('../..')).all(by.css('td')).get(9).click());
-    browser.sleep(2000);
+    .then(() => browser.actions().mouseMove(td).perform())
+    .then(() => browser.actions().click().perform())
+    .then(() => waitForElementVisibility(detailsPane))
+    .then(() => browser.sleep(2000));
   }
 
   getActiveGroups() {
-    return element.all(by.css('app-group-by .group-by-items.active')).getAttribute('data-name');
+    return waitForElementCountGreaterThan('app-group-by .group-by-items .name', 4)
+    .then(() => element.all(by.css('app-group-by .group-by-items.active .name')).reduce(reduce_for_get_all(), []));
   }
 
   getGroupByCount() {
-    return waitForElementPresence(element.all(by.css('app-group-by .group-by-items'))).then(() => {
+    return waitForElementPresence(element(by.css('app-group-by .group-by-items'))).then(() => {
       return element.all(by.css('app-group-by .group-by-items')).count();
     });
   }
 
   getGroupByItemNames() {
-    return element.all(by.css('app-group-by .group-by-items .name')).getText();
+    return element.all(by.css('app-group-by .group-by-items .name')).reduce(reduce_for_get_all(), []);
   }
 
   getGroupByItemCounts() {
-    return element.all(by.css('app-group-by .group-by-items .count')).getText();
+    return element.all(by.css('app-group-by .group-by-items .count')).reduce(reduce_for_get_all(), []);
   }
 
   getSubGroupValues(name: string, rowName: string) {
@@ -63,31 +68,79 @@ export class TreeViewPage {
   }
 
   selectGroup(name: string) {
-    return element(by.css('app-group-by div[data-name="' + name + '"]')).click();
-  }
-
-  dragGroup(from: string, to: string) {
-    browser.actions().dragAndDrop(
-        element(by.css('app-group-by div[data-name="' + from + '"]')),
-        element(by.css('app-group-by div[data-name="' + to + '"]'))
-    ).perform();
-  }
-
-  getDashGroupValues(name: string) {
-    return waitForElementPresence(element(by.css('[data-name="' + name + '"] .card-header span'))).then(() => {
-      return element.all(by.css('[data-name="' + name + '"] .card-header span')).getText();
-    });
+    return element(by.css('app-group-by div[data-name="' + name + '"]')).click()
+    .then(() => waitForCssClass(element(by.css('app-group-by div[data-name="' + name + '"]')), 'active'))
+    .then(() => browser.waitForAngular());
+  }
+
+  async simulateDragAndDrop(target: string, destination: string) {
+    target = `app-group-by div[data-name=\"${target}\"]`;
+    destination = `app-group-by div[data-name=\"${destination}\"]`;
+    return  await browser.executeScript((target, destination) => {
+      let getEventOptions = (el, relatedElement) => {
+        //coordinates from destination element
+        const coords = el.getBoundingClientRect();
+        const x = coords.x || coords.left;
+        const y = coords.y || coords.top;
+        return {
+          x: x,
+          y: y,
+          clientX: x,
+          clientY: y,
+          screenX: x,
+          screenY: y,
+          //target reference
+          relatedTarget: relatedElement
+        };
+      };
+
+      let raise = (el, type, options?) => {
+        const o = options || { which: 1 };
+        const e = document.createEvent('Event');
+        e.initEvent(type, true, true);
+        Object.keys(o).forEach(apply);
+        el.dispatchEvent(e);
+        function apply(key) {
+          e[key] = o[key];
+        }
+      };
+
+
+      let targetEl = document.querySelector(target);
+      let destinationEl = document.querySelector(destination);
+      let options = getEventOptions(destinationEl, targetEl);
+
+      //start drag
+      raise(targetEl, 'mousedown');
+      raise(targetEl, 'mousemove');
+      //set event on location
+      raise(destinationEl, 'mousemove', options);
+      //drop
+      raise(destinationEl, 'mouseup', options);
+
+    }, target, destination);
+  }
+
+  async getDashGroupValues(name: string) {
+      let dashScore = await element(by.css('[data-name="' + name + '"] .dash-score')).getText();
+      let groupName = await element(by.css('[data-name="' + name + '"] .text-light.severity-padding .title')).getText();
+      let title = await element(by.css('[data-name="' + name + '"] .text-light.two-line .text-dark')).getText();
+      let count = await element(by.css('[data-name="' + name + '"] .text-light.two-line .title')).getText();
+
+      return Promise.all([dashScore, groupName, title, count]);
   }
 
   expandDashGroup(name: string) {
     let cardElement = element(by.css('.card[data-name="' + name +'"]'));
-    let downArrowElement = element(by.css('.card[data-name="' + name + '"] .mrow.top-group'));
+    let cardHeader = element(by.css('.card[data-name="' + name + '"] .card-header'));
+    let cardBody = element(by.css('.card[data-name="' + name + '"] .collapse'));
 
-    return waitForElementVisibility(cardElement)
-    .then(() => browser.actions().mouseMove(cardElement).perform())
-    .then(() => waitForElementVisibility(downArrowElement))
-    .then(() => downArrowElement.click())
-    .then(() => browser.sleep(2000));
+    return waitForElementPresence(cardBody)
+    .then(() => waitForElementVisibility(cardHeader))
+    .then(() => browser.actions().mouseMove(element(by.css('.card[data-name="' + name + '"] .card-header .down-arrow'))).perform())
+    .then(() => cardHeader.click())
+    .then(() => waitForCssClass(cardBody, 'show'))
+    .then(() => waitForElementVisibility(element(by.css('.card[data-name="' + name + '"] .collapse table tbody tr:nth-child(1)'))));
   }
 
   expandSubGroup(groupName: string, rowName: string) {
@@ -97,21 +150,14 @@ export class TreeViewPage {
   expandSubGroupByPosition(groupName: string, rowName: string, position: number) {
     let subGroupElement = element.all(by.css('[data-name="' + groupName + '"] tr[data-name="' + rowName + '"]')).get(position);
     return waitForElementVisibility(subGroupElement)
-    .then(() => browser.actions().mouseMove(subGroupElement).perform())
-    .then(() => subGroupElement.click());
-  }
-
-  getDashGroupTableValuesForRow(name: string, rowId: number) {
-    this.scrollToDashRow(name);
-    return waitForElementPresence(element(by.css('[data-name="' + name + '"] table tbody tr'))).then(() => {
-      return element.all(by.css('[data-name="' + name + '"] table tbody tr')).get(rowId).all(by.css('td')).getText();
-    });
+    .then(() => scrollIntoView(subGroupElement.element(by.css('.fa-caret-right')), true))
+    .then(() => subGroupElement.click())
+    .then(() => waitForElementVisibility(subGroupElement.element(by.css('.fa-caret-down'))));
   }
 
-  getTableValuesByRowId(name: string, rowId: number, waitForAnchor: string) {
-    return waitForElementPresence(element(by. cssContainingText('[data-name="' + name + '"] a', waitForAnchor))).then(() => {
-      return element.all(by.css('[data-name="' + name + '"] table tbody tr')).get(rowId).all(by.css('td')).getText();
-    });
+  async getTableValuesByRowId(name: string, rowId: number, waitForAnchor: string) {
+    await waitForElementPresence(element(by. cssContainingText('[data-name="' + name + '"] a', waitForAnchor)));
+    return element.all(by.css('[data-name="' + name + '"] table tbody tr')).get(rowId).all(by.css('td a')).reduce(reduce_for_get_all(), []);
   }
 
   getTableValuesForRow(name: string, rowName: string, waitForAnchor: string) {
@@ -122,9 +168,7 @@ export class TreeViewPage {
 
   scrollToDashRow(name: string) {
     let scrollToEle = element(by.css('[data-name="' + name + '"] .card-header'));
-    waitForElementPresence(scrollToEle).then(() => {
-      return browser.actions().mouseMove(scrollToEle).perform();
-    });
+    return scrollIntoView(scrollToEle, true);
   }
 
   clickOnNextPage(name: string) {
@@ -132,12 +176,12 @@ export class TreeViewPage {
   }
 
   unGroup() {
-    return element(by.css('app-group-by .ungroup-button')).click();
+    return element(by.css('app-group-by .ungroup-button')).click()
+    .then(() => waitForStalenessOf(element(by.css('app-tree-view'))));
   }
 
   getIdOfAllExpandedRows() {
     return element.all(by.css('[data-name="' + name + '"] table tbody tr')).then(row => {
-      browser.pause();
     });
   }
 
@@ -146,26 +190,23 @@ export class TreeViewPage {
   }
 
   getCellValuesFromTable(groupName: string, cellName: string, waitForAnchor: string) {
-    return waitForElementPresence(element(by.cssContainingText('[data-name="' + cellName + '"] a', waitForAnchor))).then(() => {
-      return element.all(by.css('[data-name="' + groupName + '"] table tbody [data-name="' + cellName + '"]')).map(element => {
-        browser.actions().mouseMove(element).perform();
-        return (element.getText());
-      });
-    });
+    let waitForEle = element.all(by.cssContainingText(`[data-name="${cellName}"] a`, waitForAnchor)).get(0);
+    return waitForElementPresence(waitForEle)
+          .then(() => scrollIntoView(waitForEle, true))
+          .then(() => element.all(by.css(`[data-name="${groupName}"] [data-name="${cellName}"]`)).reduce(reduce_for_get_all(), []))
   }
 
   sortSubGroup(groupName: string, colName: string) {
-    return element.all(by.css('[data-name="' + groupName + '"] metron-config-sorter[title="' + colName + '"]')).click();
+    return element(by.css(`[data-name="${groupName}"] metron-config-sorter[title="${colName}"]`)).click();
   }
 
   toggleAlertInTree(index: number) {
     let selector = by.css('app-tree-view tbody tr');
     let checkbox = element.all(selector).get(index).element(by.css('label'));
-    waitForElementPresence(checkbox).then(() => {
-      browser.actions().mouseMove(checkbox).perform().then(() => {
-        checkbox.click();
-      });
-    });
+
+    return waitForElementPresence(checkbox)
+            .then(() => browser.actions().mouseMove(checkbox).perform())
+            .then(() => checkbox.click());
   }
 
   getAlertStatusForTreeView(rowIndex: number, previousText) {
@@ -195,7 +236,7 @@ export class TreeViewPage {
   clickNoForConfirmation() {
     let maskElement = element(by.className('modal-backdrop'));
     let closeButton = element(by.css('.metron-dialog')).element(by.buttonText('Cancel'));
-    waitForElementVisibility(maskElement)
+    return waitForElementVisibility(maskElement)
     .then(() => closeButton.click())
     .then(() => waitForElementInVisibility(maskElement));
   }
@@ -203,7 +244,7 @@ export class TreeViewPage {
   clickYesForConfirmation() {
     let okButton = element(by.css('.metron-dialog')).element(by.buttonText('OK'));
     let maskElement = element(by.className('modal-backdrop'));
-    waitForElementVisibility(maskElement)
+    return waitForElementVisibility(maskElement)
     .then(() => okButton.click())
     .then(() => waitForElementInVisibility(maskElement));
   }
@@ -211,4 +252,9 @@ export class TreeViewPage {
   waitForElementToDisappear(groupName: string) {
     return waitForElementInVisibility(element.all(by.css('[data-name="' + groupName + '"]')));
   }
+
+  waitForTextChangeAndExpand(groupName: string, subGroupName: string, previousValue: string) {
+    return waitForTextChange(element(by.css(`[data-name="${subGroupName}"] .group-value`)), previousValue)
+    .then(() => this.expandSubGroup(groupName, subGroupName));
+  }
 }

http://git-wip-us.apache.org/repos/asf/metron/blob/436cec43/metron-interface/metron-alerts/e2e/login/login.e2e-spec.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/e2e/login/login.e2e-spec.ts b/metron-interface/metron-alerts/e2e/login/login.e2e-spec.ts
index dc53889..337f286 100644
--- a/metron-interface/metron-alerts/e2e/login/login.e2e-spec.ts
+++ b/metron-interface/metron-alerts/e2e/login/login.e2e-spec.ts
@@ -16,29 +16,35 @@
  * limitations under the License.
  */
 import { LoginPage } from './login.po';
+import {deleteTestData, loadTestData} from '../utils/e2e_util';
 
-describe('login to application', function() {
+describe('Test spec for login page', function() {
     let page: LoginPage;
 
-    beforeEach(() => {
-        page = new LoginPage();
+    beforeAll(async function() : Promise<any> {
+      page = new LoginPage();
+      await loadTestData();
     });
 
-    it('should display error message for invalid credentials', () => {
-        page.navigateToLogin();
-        page.setUserNameAndPassword('admin', 'admin');
-        page.submitLoginForm();
-        expect(page.getErrorMessage()).toEqual('Login failed for admin');
+    afterAll(async function() : Promise<any> {
+        await deleteTestData();
     });
 
-    it('should login for valid credentials', () => {
-        page.navigateToLogin();
-        page.setUserNameAndPassword('admin', 'password');
-        page.submitLoginForm();
+    it('should display error message for invalid credentials', async function() : Promise<any> {
+        await page.navigateToLogin();
+        await page.setUserNameAndPassword('admin', 'admin');
+        await page.submitLoginForm();
+        expect(await page.getErrorMessage()).toEqual('Login failed for admin');
     });
 
-    it('should logout', () => {
-        page.logout();
-        expect(page.getLocation()).toEqual('http://localhost:4200/login');
+    it('should login for valid credentials', async function() : Promise<any> {
+        await page.navigateToLogin();
+        await page.setUserNameAndPassword('admin', 'password');
+        await page.submitLoginForm();
+    });
+
+    it('should logout', async function() : Promise<any> {
+        await page.logout();
+        expect(await page.getLocation()).toEqual('http://localhost:4200/login');
     });
 });