<NME> upbat.test.js
<BEF> 'use strict';

require('should');
const fs = require('fs');

var levels = require('../lib/levels');

describe('Uploader Battery', function ( ) {
    var sandbox = require('../lib/sandbox')();
    var ctx = {
      settings: {}
    };
    var sbx = sandbox.clientInit(ctx, Date.now(), data);

    sbx.offerProperty = function mockedOfferProperty (name, setter) {
    var sandbox = require('../lib/sandbox')(ctx);
    
    var sbx = sandbox.clientInit(ctx, Date.now(), data);

    sbx.offerProperty = function mockedOfferProperty (name, setter) {
      name.should.equal('upbat');
      done();
    };

    var upbat = require('../lib/plugins/upbat')();
    upbat.setProperties(sbx);

  });

    var upbat = require('../lib/plugins/upbat')(ctx);
    upbat.setProperties(sbx);

  });

  it('set a pill to the uploader battery status', function (done) {
    var ctx = {
      settings: {}
          done();
        }
      }
    };

    var sandbox = require('../lib/sandbox')();
    var sbx = sandbox.clientInit(ctx, Date.now(), data);
    var upbat = require('../lib/plugins/upbat')();
    upbat.setProperties(sbx);
    upbat.updateVisualisation(sbx);

    var sandbox = require('../lib/sandbox')();
    var sbx = sandbox.clientInit(ctx, Date.now(), data);
    var upbat = require('../lib/plugins/upbat')(ctx);
    upbat.setProperties(sbx);
    upbat.updateVisualisation(sbx);

  });

          done();
        }
      }
    };

    var sandbox = require('../lib/sandbox')();
    var sbx = sandbox.clientInit(ctx, Date.now(), {});
    var upbat = require('../lib/plugins/upbat')();
    upbat.setProperties(sbx);
    upbat.updateVisualisation(sbx);
  });

    var sandbox = require('../lib/sandbox')();
    var sbx = sandbox.clientInit(ctx, Date.now(), {});
    var upbat = require('../lib/plugins/upbat')(ctx);
    upbat.setProperties(sbx);
    upbat.updateVisualisation(sbx);
          options.hide.should.equal(true);
          done();
        }
      }
    };

    var sandbox = require('../lib/sandbox')();
    var sbx = sandbox.clientInit(ctx, Date.now(), {devicestatus: [{uploader: {battery: -1}}]});
    var upbat = require('../lib/plugins/upbat')();
    upbat.setProperties(sbx);
    upbat.updateVisualisation(sbx);
  });
    ctx.language.set('en');


    var ctx = {
      settings: {}
    };

    var sandbox = require('../lib/sandbox')();
    var sbx = sandbox.clientInit(ctx, Date.now(), data);
    var upbat = require('../lib/plugins/upbat')();
    upbat.setProperties(sbx);

    upbat.alexa.intentHandlers.length.should.equal(1);
    };
    ctx.language.set('en');

    var sandbox = require('../lib/sandbox')();
    var sbx = sandbox.clientInit(ctx, Date.now(), data);
    var upbat = require('../lib/plugins/upbat')(ctx);
    upbat.setProperties(sbx);

    upbat.virtAsst.intentHandlers.length.should.equal(2);

    upbat.virtAsst.intentHandlers[0].intentHandler(function next(title, response) {
      title.should.equal('Uploader Battery');
      response.should.equal('Your uploader battery is at 20%');
      
      upbat.virtAsst.intentHandlers[1].intentHandler(function next(title, response) {
        title.should.equal('Uploader Battery');
        response.should.equal('Your uploader battery is at 20%');

        done();
      }, [], sbx);
      
    }, [], sbx);

  });

});

<MSG> Merge pull request #8 from nightscout/dev

Refresh dev from nightscout
<DFF> @@ -9,7 +9,9 @@ describe('Uploader Battery', function ( ) {
     var sandbox = require('../lib/sandbox')();
     var ctx = {
       settings: {}
+      , language: require('../lib/language')()
     };
+    ctx.language.set('en');
     var sbx = sandbox.clientInit(ctx, Date.now(), data);
 
     sbx.offerProperty = function mockedOfferProperty (name, setter) {
@@ -22,7 +24,7 @@ describe('Uploader Battery', function ( ) {
       done();
     };
 
-    var upbat = require('../lib/plugins/upbat')();
+    var upbat = require('../lib/plugins/upbat')(ctx);
     upbat.setProperties(sbx);
 
   });
@@ -38,11 +40,13 @@ describe('Uploader Battery', function ( ) {
           done();
         }
       }
+      , language: require('../lib/language')()
     };
+    ctx.language.set('en');
 
     var sandbox = require('../lib/sandbox')();
     var sbx = sandbox.clientInit(ctx, Date.now(), data);
-    var upbat = require('../lib/plugins/upbat')();
+    var upbat = require('../lib/plugins/upbat')(ctx);
     upbat.setProperties(sbx);
     upbat.updateVisualisation(sbx);
 
@@ -57,11 +61,13 @@ describe('Uploader Battery', function ( ) {
           done();
         }
       }
+      , language: require('../lib/language')()
     };
+    ctx.language.set('en');
 
     var sandbox = require('../lib/sandbox')();
     var sbx = sandbox.clientInit(ctx, Date.now(), {});
-    var upbat = require('../lib/plugins/upbat')();
+    var upbat = require('../lib/plugins/upbat')(ctx);
     upbat.setProperties(sbx);
     upbat.updateVisualisation(sbx);
   });
@@ -74,12 +80,13 @@ describe('Uploader Battery', function ( ) {
           options.hide.should.equal(true);
           done();
         }
-      }
+      }, language: require('../lib/language')()
     };
+    ctx.language.set('en');
 
     var sandbox = require('../lib/sandbox')();
     var sbx = sandbox.clientInit(ctx, Date.now(), {devicestatus: [{uploader: {battery: -1}}]});
-    var upbat = require('../lib/plugins/upbat')();
+    var upbat = require('../lib/plugins/upbat')(ctx);
     upbat.setProperties(sbx);
     upbat.updateVisualisation(sbx);
   });
@@ -88,11 +95,13 @@ describe('Uploader Battery', function ( ) {
 
     var ctx = {
       settings: {}
+      , language: require('../lib/language')()
     };
+    ctx.language.set('en');
 
     var sandbox = require('../lib/sandbox')();
     var sbx = sandbox.clientInit(ctx, Date.now(), data);
-    var upbat = require('../lib/plugins/upbat')();
+    var upbat = require('../lib/plugins/upbat')(ctx);
     upbat.setProperties(sbx);
 
     upbat.alexa.intentHandlers.length.should.equal(1);

{'commit': 'diff --git a/.travis.yml b/.travis.yml\nindex 14a3dfe5..d7513af2 100644\n--- a/.travis.yml\n+++ b/.travis.yml\n@@ -2,8 +2,9 @@ language: node_js\n sudo: required\n dist: trusty\n node_js:\n-  - "8.9.3"\n-before_install: if [[ `npm --version` != "5.6" ]]; then npm install -g npm@latest; npm --version; fi\n+  - "8"\n+  - "9"\n+before_install: if [[ `npm --version` != "5.8.0" ]]; then npm install -g npm@latest; npm --version; fi\n matrix:\n   fast_finish: true\n services:\ndiff --git a/README.md b/README.md\nindex 0dd62cf7..e5b3b037 100644\n--- a/README.md\n+++ b/README.md\n@@ -106,7 +106,8 @@ Community maintained fork of the\n \n Requirements:\n \n-- [Node.js](http://nodejs.org/) 8.9.0 LTS (use [Install instructions for Node](https://nodejs.org/en/download/package-manager/) or `setup.sh`)\n+- [Node.js](http://nodejs.org/) 8.11.0 LTS or later or [Node.js](http://nodejs.org/) 9.10.0 or later. Use [Install instructions for Node](https://nodejs.org/en/download/package-manager/) or `setup.sh`)\n+- [MongoDB](https://www.mongodb.com/download-center?jmp=nav#community) 3.x. MongoDB 2.4 is only supported for Raspberry Pi.\n \n Clone this repo then install dependencies into the root of the project:\n \n@@ -215,6 +216,7 @@ To learn more about the Nightscout API, visit https://YOUR-SITE.com/api-docs.htm\n   * `MONGO_DEVICESTATUS_COLLECTION`(`devicestatus`) - The collection used to store device status information such as uploader battery\n   * `MONGO_PROFILE_COLLECTION`(`profile`) - The collection used to store your profiles\n   * `MONGO_FOOD_COLLECTION`(`food`) - The collection used to store your food database\n+  * `MONGO_ACTIVITY_COLLECTION`(`activity`) - The collection used to store activity data\n   * `PORT` (`1337`) - The port that the node.js application will listen on.\n   * `HOSTNAME` - The hostname that the node.js application will listen on, null by default for any hostname for IPv6 you may need to use `::`.\n   * `SSL_KEY` - Path to your ssl key file, so that ssl(https) can be enabled directly in node.js\ndiff --git a/app.js b/app.js\nindex a073eff8..1d8f30b9 100644\n--- a/app.js\n+++ b/app.js\n@@ -101,9 +101,9 @@ function create(env, ctx) {\n     // pebble data\n     app.get(\'/pebble\', ctx.pebble);\n \n-    // expose swagger.yaml\n-    app.get(\'/swagger.yaml\', function(req, res) {\n-        res.sendFile(__dirname + \'/swagger.yaml\');\n+    // expose swagger.json\n+    app.get(\'/swagger.json\', function(req, res) {\n+        res.sendFile(__dirname + \'/swagger.json\');\n     });\n \n /*\n@@ -141,6 +141,13 @@ function create(env, ctx) {\n     // serve the static content\n     app.use(staticFiles);\n \n+    var swaggerFiles = express.static(env.swagger_files, {\n+        maxAge: maxAge\n+    });\n+\n+    // serve the static content\n+    app.use(\'/swagger-ui-dist\', swaggerFiles);\n+\n     var tmpFiles = express.static(\'tmp\', {\n         maxAge: maxAge\n     });\ndiff --git a/bundle/bundle.source.js b/bundle/bundle.source.js\nindex 9124fceb..f3d0c7ce 100644\n--- a/bundle/bundle.source.js\n+++ b/bundle/bundle.source.js\n@@ -1,7 +1,7 @@\n import \'../static/css/drawer.css\';\n import \'../static/css/dropdown.css\';\n import \'../static/css/sgv.css\';\n-import \'../node_modules/jquery.tipsy/src/jquery.tipsy.css\';\n+import \'../node_modules/jquery.tooltips/css/jquery.tooltips.css\';\n \n \n $ = require("jquery");\n@@ -11,7 +11,7 @@ require(\'jquery-ui-bundle\');\n window._ = require(\'lodash\');\n window.d3 = require(\'d3\');\n \n-require(\'jquery.tipsy\');\n+require(\'jquery.tooltips\');\n \n window.Storage = require(\'js-storage\');\n \ndiff --git a/env.js b/env.js\nindex b347d385..66286fad 100644\n--- a/env.js\n+++ b/env.js\n@@ -20,6 +20,7 @@ function config ( ) {\n   env.HOSTNAME = readENV(\'HOSTNAME\', null);\n   env.IMPORT_CONFIG = readENV(\'IMPORT_CONFIG\', null);\n   env.static_files = readENV(\'NIGHTSCOUT_STATIC_FILES\', __dirname + \'/static/\');\n+  env.swagger_files = readENV(\'NIGHTSCOUT_SWAGGER_FILES\',  __dirname + \'/node_modules/swagger-ui-dist/\');\n   env.debug = {\n     minify: readENVTruthy(\'DEBUG_MINIFY\', true)\n   };\n@@ -105,6 +106,7 @@ function setStorage() {\n   env.profile_collection = readENV(\'MONGO_PROFILE_COLLECTION\', \'profile\');\n   env.devicestatus_collection = readENV(\'MONGO_DEVICESTATUS_COLLECTION\', \'devicestatus\');\n   env.food_collection = readENV(\'MONGO_FOOD_COLLECTION\', \'food\');\n+  env.activity_collection = readENV(\'MONGO_ACTIVITY_COLLECTION\', \'activity\');\n \n   // TODO: clean up a bit\n   // Some people prefer to use a json configuration file instead.\ndiff --git a/lib/api/activity/index.js b/lib/api/activity/index.js\nnew file mode 100644\nindex 00000000..772a437c\n--- /dev/null\n+++ b/lib/api/activity/index.js\n@@ -0,0 +1,127 @@\n+\'use strict\';\n+\n+var _ = require(\'lodash\');\n+var consts = require(\'../../constants\');\n+var moment = require(\'moment\');\n+\n+function configure(app, wares, ctx) {\n+    var express = require(\'express\')\n+        , api = express.Router();\n+\n+    api.use(wares.compression());\n+    api.use(wares.bodyParser({\n+        limit: 1048576 * 50\n+    }));\n+    // text body types get handled as raw buffer stream\n+    api.use(wares.bodyParser.raw({\n+        limit: 1048576\n+    }));\n+    // json body types get handled as parsed json\n+    api.use(wares.bodyParser.json({\n+        limit: 1048576\n+    }));\n+    // also support url-encoded content-type\n+    api.use(wares.bodyParser.urlencoded({\n+        limit: 1048576\n+        , extended: true\n+    }));\n+    // invoke common middleware\n+    api.use(wares.sendJSONStatus);\n+\n+    api.use(ctx.authorization.isPermitted(\'api:activity:read\'));\n+\n+    // List activity data available\n+    api.get(\'/activity\', function(req, res) {\n+        var ifModifiedSince = req.get(\'If-Modified-Since\');\n+        ctx.activity.list(req.query, function(err, results) {\n+            var d1 = null;\n+            \n+            _.forEach(results, function clean(t) {\n+\n+                var d2 = null;\n+                \n+                if (t.hasOwnProperty(\'created_at\')) {\n+                  d2 = new Date(t.created_at);\n+                } else {\n+                  if (t.hasOwnProperty(\'timestamp\')) {\n+                    d2 = new Date(t.timestamp);\n+                  }\n+                }\n+                \n+                if (d2 == null) { return; }\n+                                \n+                if (d1 == null ||\xa0d2.getTime() > d1.getTime()) {\n+                    d1 = d2;\n+                }\n+            });\n+            \n+            if (!_.isNil(d1)) res.setHeader(\'Last-Modified\', d1.toUTCString());\n+\n+            if (ifModifiedSince && d1.getTime() <= moment(ifModifiedSince).valueOf()) {\n+                res.status(304).send({\n+                    status: 304\n+                    , message: \'Not modified\'\n+                    , type: \'internal\'\n+                });\n+                return;\n+            } else {\n+                return res.json(results);\n+            }\n+        });\n+    });\n+\n+    function config_authed(app, api, wares, ctx) {\n+\n+        function post_response(req, res) {\n+            var activity = req.body;\n+\n+            if (!_.isArray(activity)) {\n+                activity = [activity];\n+            };\n+\n+            ctx.activity.create(activity, function(err, created) {\n+                if (err) {\n+                    console.log(\'Error adding activity data\', err);\n+                    res.sendJSONStatus(res, consts.HTTP_INTERNAL_ERROR, \'Mongo Error\', err);\n+                } else {\n+                    console.log(\'Activity measure created\');\n+                    res.json(created);\n+                }\n+            });\n+        }\n+\n+        api.post(\'/activity/\', wares.bodyParser({\n+            limit: 1048576 * 50\n+        }), ctx.authorization.isPermitted(\'api:activity:create\'), post_response);\n+\n+        api.delete(\'/activity/:_id\', ctx.authorization.isPermitted(\'api:activity:delete\'), function(req, res) {\n+            ctx.activity.remove(req.params._id, function() {\n+                res.json({});\n+            });\n+        });\n+\n+        // update record\n+        api.put(\'/activity/\', ctx.authorization.isPermitted(\'api:activity:update\'), function(req, res) {\n+            var data = req.body;\n+            ctx.activity.save(data, function(err, created) {\n+                if (err) {\n+                    res.sendJSONStatus(res, consts.HTTP_INTERNAL_ERROR, \'Mongo Error\', err);\n+                    console.log(\'Error saving activity\');\n+                    console.log(err);\n+                } else {\n+                    res.json(created);\n+                    console.log(\'Activity measure saved\', data);\n+                }\n+            });\n+        });\n+    }\n+\n+    if (app.enabled(\'api\') && app.enabled(\'careportal\')) {\n+        config_authed(app, api, wares, ctx);\n+    }\n+\n+    return api;\n+}\n+\n+module.exports = configure;\n+\ndiff --git a/lib/api/entries/index.js b/lib/api/entries/index.js\nindex 19bcfed9..dea493ef 100644\n--- a/lib/api/entries/index.js\n+++ b/lib/api/entries/index.js\n@@ -83,9 +83,11 @@ function configure (app, wares, ctx) {\n         res.setHeader(\'Last-Modified\', lastEntryDate.toUTCString());\n       }\n       \n-      var ifModifiedSince = req.get(\'If-Modified-Since\');\n+      var ifModifiedSince = req.get(\'If-Modified-Since\');\t\n       if (!ifModifiedSince) { return next(); }\n       \n+      console.log("CGM Entry request with If-Modified-Since: ", ifModifiedSince);\n+      \n       if (lastEntryDate.getTime() <= new Date(ifModifiedSince).getTime()) {\n         res.status(304).send({status:304, message: \'Not modified\', type:\'internal\'});\n         return;\n@@ -114,6 +116,40 @@ function configure (app, wares, ctx) {\n       if (res.entries_err) {\n         return res.sendJSONStatus(res, consts.HTTP_INTERNAL_ERROR, \'Mongo Error\', res.entries_err);\n       }\n+      \n+      // IF-Modified-Since support\n+      \n+      function compare(a,b) {\n+         var a_field = a.mills ? a.mills : a.date;\n+         var b_field = b.mills ? b.mills : b.date;\n+         \n+ \t\t if (a_field < b_field)\n+  \t\t  return -1;\n+    \t if (a_field > b_field)\n+\t\t    return 1;\n+\t    return 0;\n+\t  }\n+\n+  \tres.entries.sort(compare);\n+      \n+      var lastEntry = _.last(res.entries);\n+      var lastEntryDate = null;\n+      \n+      if (!_.isNil(lastEntry)) {\n+      \tif (lastEntry.mills) lastEntryDate = new Date(lastEntry.mills);\n+      \tif (!lastEntry.mills && lastEntry.date ) lastEntryDate = new Date(lastEntry.date);\n+        res.setHeader(\'Last-Modified\', lastEntryDate.toUTCString());\n+      }\n+      \n+      var ifModifiedSince = req.get(\'If-Modified-Since\');\n+      \n+      console.log(\'If-Modified-Since: \' + new Date(ifModifiedSince) + \' Last-Modified\', lastEntryDate);\n+\n+      if (lastEntryDate !== null && ifModifiedSince !== null && lastEntryDate.getTime() <= new Date(ifModifiedSince).getTime()) {\n+        res.status(304).send({status:304, message: \'Not modified\', type:\'internal\'});\n+        return;\n+      }\n+      \n       // if no error, format the payload\n       // The general pattern here is to create an output stream that reformats\n       // the data correctly into the desired representation.\ndiff --git a/lib/api/index.js b/lib/api/index.js\nindex 4f4239c5..57c24975 100644\n--- a/lib/api/index.js\n+++ b/lib/api/index.js\n@@ -53,6 +53,8 @@ function create (env, ctx) {\n   app.all(\'/devicestatus*\', require(\'./devicestatus/\')(app, wares, ctx));\n   app.all(\'/notifications*\', require(\'./notifications-api\')(app, wares, ctx));\n \n+  app.all(\'/activity*\', require(\'./activity/\')(app, wares, ctx));\n+  \n   app.use(\'/\', wares.sendJSONStatus, require(\'./verifyauth\')(ctx));\n   app.all(\'/food*\', require(\'./food/\')(app, wares, ctx));\n \ndiff --git a/lib/authorization/storage.js b/lib/authorization/storage.js\nindex d90c2135..41969be1 100644\n--- a/lib/authorization/storage.js\n+++ b/lib/authorization/storage.js\n@@ -114,6 +114,7 @@ function init (env, ctx) {\n     , { name: \'readable\', permissions: [ \'*:*:read\' ] }\n     , { name: \'careportal\', permissions: [ \'api:treatments:create\' ] }\n     , { name: \'devicestatus-upload\', permissions: [ \'api:devicestatus:create\' ] }\n+    , { name: \'activity\', permissions: [ \'api:activity:create\' ] }\n   ];\n \n   storage.reload = function reload (callback) {\ndiff --git a/lib/client/browser-utils.js b/lib/client/browser-utils.js\nindex 6ce7d246..fc9a983d 100644\n--- a/lib/client/browser-utils.js\n+++ b/lib/client/browser-utils.js\n@@ -7,12 +7,12 @@ function init ($) {\n \n   // Tooltips can remain in the way on touch screens.\n   if (!isTouch()) {\n-    $(\'.tip\').tipsy();\n+    $(\'.tip\').tooltip();\n   } else {\n     // Drawer info tips should be displayed on touchscreens.\n-    $(\'#drawer\').find(\'.tip\').tipsy();\n+    $(\'#drawer\').find(\'.tip\').tooltip();\n   }\n-  $.fn.tipsy.defaults = {\n+  $.fn.tooltip.defaults = {\n     fade: true,\n     gravity: \'n\',\n     opacity: 0.75\ndiff --git a/lib/client/renderer.js b/lib/client/renderer.js\nindex f0666277..a333769a 100644\n--- a/lib/client/renderer.js\n+++ b/lib/client/renderer.js\n@@ -881,6 +881,7 @@ function init (client, d3) {\n   renderer.drawTreatments = function drawTreatments(client) {\n   \n     var treatmentCount = 0;\n+    chart().focus.selectAll(\'.draggable-treatment\').remove();\n     \n     _.forEach(client.ddata.treatments, function eachTreatment (d) {\n     \tif (Number(d.insulin) > 0 ||\xa0Number(d.carbs) > 0) { treatmentCount += 1; };\ndiff --git a/lib/data/dataloader.js b/lib/data/dataloader.js\nindex c6ab99df..714d7144 100644\n--- a/lib/data/dataloader.js\n+++ b/lib/data/dataloader.js\n@@ -5,301 +5,382 @@ var async = require(\'async\');\n var times = require(\'../times\');\n var fitTreatmentsToBGCurve = require(\'./treatmenttocurve\');\n \n-var ONE_DAY = 86400000\n-  , TWO_DAYS = 172800000;\n+var ONE_DAY = 86400000,\n+    TWO_DAYS = 172800000;\n \n function uniq(a) {\n-  var seen = {};\n-  return a.filter(function (item) {\n-    return seen.hasOwnProperty(item.mills) ? false : (seen[item.mills] = true);\n-  });\n+    var seen = {};\n+    return a.filter(function(item) {\n+        return seen.hasOwnProperty(item.mills) ? false : (seen[item.mills] = true);\n+    });\n }\n \n function init(env, ctx) {\n \n-  var dataloader = { };\n+    var dataloader = {};\n \n-  dataloader.update = function update(ddata, opts, done) {\n-        \n-    if (opts && done == null && opts.call) {\n-      done = opts;\n-      opts = { lastUpdated: Date.now( ), frame: false };\n-    }\n+    dataloader.update = function update(ddata, opts, done) {\n \n-    if (opts.frame) {\n-      ddata.page = {\n-        frame: true\n-        , after: opts.lastUpdated\n-        // , before: opts.\n-      };\n-    }\n-    ddata.lastUpdated = opts.lastUpdated;\n-    // console.log(\'LOOKING SINCE\', (new Date(ddata.lastUpdated)));\n-\n-    function loadComplete (err, result) {\n-      ddata.treatments = _.uniq(ddata.treatments, false, function (item) { return item._id.toString(); });\n-      //sort treatments so the last is the most recent\n-      ddata.treatments = _.sortBy(ddata.treatments, function (item) { return item.mills; });\n-      fitTreatmentsToBGCurve(ddata, env, ctx);\n-      if (err) {\n-        console.error(err);\n-      }\n-      ddata.processTreatments(true);\n-\n-      var counts = [];\n-      _.forIn(ddata, function each (value, key) {\n-        if (_.isArray(value) && value.length > 0) {\n-          counts.push(key + \':\' + value.length);\n+        //console.log("Database is connected: " + ctx.store.client.isConnected());\n+\n+        if (opts && done == null && opts.call) {\n+            done = opts;\n+            opts = {\n+                lastUpdated: Date.now(),\n+                frame: false\n+            };\n         }\n-      });\n \n-      console.info(\'Load Complete:\\n\\t\', counts.join(\', \'));\n+        if (opts.frame) {\n+            ddata.page = {\n+                frame: true,\n+                after: opts.lastUpdated\n+                    // , before: opts.\n+            };\n+        }\n+        ddata.lastUpdated = opts.lastUpdated;\n+        // console.log(\'LOOKING SINCE\', (new Date(ddata.lastUpdated)));\n \n-      done(err, result);\n-    }\n+        function loadComplete(err, result) {\n+            ddata.treatments = _.uniq(ddata.treatments, false, function(item) {\n+                return item._id.toString();\n+            });\n+            //sort treatments so the last is the most recent\n+            ddata.treatments = _.sortBy(ddata.treatments, function(item) {\n+                return item.mills;\n+            });\n+            fitTreatmentsToBGCurve(ddata, env, ctx);\n+            if (err) {\n+                console.error(err);\n+            }\n+            ddata.processTreatments(true);\n+\n+            var counts = [];\n+            _.forIn(ddata, function each(value, key) {\n+                if (_.isArray(value) && value.length > 0) {\n+                    counts.push(key + \':\' + value.length);\n+                }\n+            });\n \n-    // clear treatments, we\'re going to merge from more queries\n-    ddata.treatments = [];\n+            console.info(\'Load Complete:\\n\\t\', counts.join(\', \'));\n \n-    async.parallel([\n-      loadEntries.bind(null, ddata, ctx)\n-      , loadTreatments.bind(null, ddata, ctx)\n-      , loadProfileSwitchTreatments.bind(null, ddata, ctx)\n-      , loadSensorAndInsulinTreatments.bind(null, ddata, ctx)\n-      , loadProfile.bind(null, ddata, ctx)\n-      , loadFood.bind(null, ddata, ctx)\n-      , loadDeviceStatus.bind(null, ddata, env, ctx)\n-    ], loadComplete);\n+            done(err, result);\n+        }\n+\n+        // clear treatments, we\'re going to merge from more queries\n+        ddata.treatments = [];\n+\n+        async.parallel([\n+            loadEntries.bind(null, ddata, ctx)\n+            , loadTreatments.bind(null, ddata, ctx)\n+            , loadProfileSwitchTreatments.bind(null, ddata, ctx)\n+            , loadSensorAndInsulinTreatments.bind(null, ddata, ctx)\n+            , loadProfile.bind(null, ddata, ctx)\n+            , loadFood.bind(null, ddata, ctx)\n+            , loadDeviceStatus.bind(null, ddata, env, ctx)\n+            , loadActivity.bind(null, ddata, ctx)\n+        ], loadComplete);\n \n-  };\n+    };\n \n-  return dataloader;\n+    return dataloader;\n \n }\n \n-function loadEntries (ddata, ctx, callback) {\n-  var dateRange = {\n-    $gte: ddata.lastUpdated - TWO_DAYS\n-  };\n-  if (ddata.page && ddata.page.frame) {\n-    dateRange[\'$lte\'] = ddata.lastUpdated;\n-  }\n-  var q = {\n-    find: {\n-      date: dateRange\n+function loadEntries(ddata, ctx, callback) {\n+    var dateRange = {\n+        $gte: ddata.lastUpdated - TWO_DAYS\n+    };\n+    if (ddata.page && ddata.page.frame) {\n+        dateRange[\'$lte\'] = ddata.lastUpdated;\n     }\n-    , sort: {date: 1}\n-  };\n-\n-  ctx.entries.list(q, function (err, results) {\n-  \n-    if (err) { console.log("Problem loading entries"); }\n-  \n-    if (!err && results) {\n-      var mbgs = [];\n-      var sgvs = [];\n-      var cals = [];\n-      results.forEach(function (element) {\n-        if (element) {\n-          if (element.mbg) {\n-            mbgs.push({\n-              mgdl: Number(element.mbg), mills: element.date, device: element.device\n-            });\n-          } else if (element.sgv) {\n-            sgvs.push({\n-              mgdl: Number(element.sgv), mills: element.date, device: element.device, direction: element.direction, filtered: element.filtered, unfiltered: element.unfiltered, noise: element.noise, rssi: element.rssi\n-            });\n-          } else if (element.type === \'cal\') {\n-            cals.push({\n-              mills: element.date, scale: element.scale, intercept: element.intercept, slope: element.slope\n-            });\n-          }\n+    var q = {\n+        find: {\n+            date: dateRange\n+        },\n+        sort: {\n+            date: 1\n         }\n-      });\n+    };\n \n-      //stop using uniq for SGVs since we use buckets, also enables more detailed monitoring\n-      ddata.sgvs = sgvs;\n+    ctx.entries.list(q, function(err, results) {\n \n-      ddata.mbgs = uniq(mbgs);\n-      ddata.cals = uniq(cals);\n-    }\n-    callback();\n-  });\n+        if (err) {\n+            console.log("Problem loading entries");\n+        }\n+\n+        if (!err && results) {\n+            var mbgs = [];\n+            var sgvs = [];\n+            var cals = [];\n+            results.forEach(function(element) {\n+                if (element) {\n+                    if (element.mbg) {\n+                        mbgs.push({\n+                            mgdl: Number(element.mbg),\n+                            mills: element.date,\n+                            device: element.device\n+                        });\n+                    } else if (element.sgv) {\n+                        sgvs.push({\n+                            mgdl: Number(element.sgv),\n+                            mills: element.date,\n+                            device: element.device,\n+                            direction: element.direction,\n+                            filtered: element.filtered,\n+                            unfiltered: element.unfiltered,\n+                            noise: element.noise,\n+                            rssi: element.rssi\n+                        });\n+                    } else if (element.type === \'cal\') {\n+                        cals.push({\n+                            mills: element.date,\n+                            scale: element.scale,\n+                            intercept: element.intercept,\n+                            slope: element.slope\n+                        });\n+                    }\n+                }\n+            });\n+\n+            //stop using uniq for SGVs since we use buckets, also enables more detailed monitoring\n+            ddata.sgvs = sgvs;\n+\n+            ddata.mbgs = uniq(mbgs);\n+            ddata.cals = uniq(cals);\n+        }\n+        callback();\n+    });\n }\n \n-function mergeToTreatments (ddata, results) {\n-  var filtered = _.filter(results, function hasId (treatment) {\n-    return !_.isEmpty(treatment._id);\n-  });\n-\n-  var treatments = _.map(filtered, function update (treatment) {\n-    treatment.mills = new Date(treatment.created_at).getTime();\n-    return treatment;\n-  });\n-\n-  //filter out temps older than a day and an hour ago since we don\'t display them\n-  var oldestAgo = ddata.lastUpdated - TWO_DAYS - times.hour().msecs;\n-  treatments = _.filter(treatments, function noOldTemps (treatment) {\n-    return !treatment.eventType || treatment.eventType.indexOf(\'Temp Basal\') === -1 || treatment.mills > oldestAgo;\n-  });\n-\n-  ddata.treatments = _.unionWith(ddata.treatments, treatments, function (a, b) {\n-    return a._id.toString() == b._id.toString();\n-  });\n+function mergeToTreatments(ddata, results) {\n+    var filtered = _.filter(results, function hasId(treatment) {\n+        return !_.isEmpty(treatment._id);\n+    });\n+\n+    var treatments = _.map(filtered, function update(treatment) {\n+        treatment.mills = new Date(treatment.created_at).getTime();\n+        return treatment;\n+    });\n+\n+    //filter out temps older than a day and an hour ago since we don\'t display them\n+    var oldestAgo = ddata.lastUpdated - TWO_DAYS - times.hour().msecs;\n+    treatments = _.filter(treatments, function noOldTemps(treatment) {\n+        return !treatment.eventType || treatment.eventType.indexOf(\'Temp Basal\') === -1 || treatment.mills > oldestAgo;\n+    });\n+\n+    ddata.treatments = _.unionWith(ddata.treatments, treatments, function(a, b) {\n+        return a._id.toString() == b._id.toString();\n+    });\n }\n \n-function loadTreatments (ddata, ctx, callback) {\n-  var dateRange = {\n-    $gte: new Date(ddata.lastUpdated - (ONE_DAY * 8)).toISOString()\n-  };\n-  if (ddata.page && ddata.page.frame) {\n-    dateRange[\'$lte\'] = new Date(ddata.lastUpdated).toISOString( );\n-  }\n-  var tq = {\n-    find: {\n-      created_at: dateRange\n-    }\n-    , sort: {created_at: 1}\n-  };\n \n-  console.log(\'searching treatments q\', tq);\n-  ctx.treatments.list(tq, function (err, results) {\n-    if (!err && results) {\n-      mergeToTreatments(ddata, results);\n+function loadActivity(ddata, ctx, callback) {\n+    var dateRange = {\n+        $gte: new Date(ddata.lastUpdated - (ONE_DAY * 2)).toISOString()\n+    };\n+    if (ddata.page && ddata.page.frame) {\n+        dateRange[\'$lte\'] = new Date(ddata.lastUpdated).toISOString();\n     }\n \n-    callback();\n-  });\n-}\n+    var q = {\n+        find: {\n+            created_at: dateRange\n+        },\n+        sort: {\n+            created_at: 1\n+        }\n+    };\n \n-function loadProfileSwitchTreatments (ddata, ctx, callback) {\n-  var dateRange = {\n-    $gte: new Date(ddata.lastUpdated - (ONE_DAY * 31 * 12)).toISOString()\n-  };\n+    var activity = [];\n+    ctx.activity.list(q, function(err, results) {\n \n-  if (ddata.page && ddata.page.frame) {\n-    dateRange[\'$lte\'] = new Date(ddata.lastUpdated).toISOString( );\n-  }\n+        if (err) {\n+            console.log("Problem loading activity data");\n+        }\n \n-  var tq = {\n-    find: {\n-      eventType: \'Profile Switch\'\n-      , created_at: dateRange\n-    }\n-    , sort: {created_at: -1}\n-  };\n+        if (!err && results) {\n+            var activity = [];\n+            results.forEach(function(element) {\n+                if (element) {\n+                    if (element.created_at) {\n+                        var d = new Date(element.created_at);\n+                        activity.push({\n+                            mills: d,\n+                            heartrate: element.heartrate,\n+                            steps: element.steps,\n+                            activitylevel: element.activitylevel\n+                        });\n+                    }\n+                }\n+            });\n+\n+            ddata.activity = uniq(activity);\n+        }\n+        callback();\n+    });\n+}\n \n-  ctx.treatments.list(tq, function (err, results) {\n-    if (!err && results) {\n-      mergeToTreatments(ddata, results);\n+function loadTreatments(ddata, ctx, callback) {\n+    var dateRange = {\n+        $gte: new Date(ddata.lastUpdated - (ONE_DAY * 8)).toISOString()\n+    };\n+    if (ddata.page && ddata.page.frame) {\n+        dateRange[\'$lte\'] = new Date(ddata.lastUpdated).toISOString();\n     }\n+    var tq = {\n+        find: {\n+            created_at: dateRange\n+        },\n+        sort: {\n+            created_at: 1\n+        }\n+    };\n \n-    // Store last profile switch\n-    if (results) {\n-      ddata.lastProfileFromSwitch = null;\n-      var now = new Date().getTime();\n-      for (var p = 0; p < results.length; p++ ) {\n-        var pdate = new Date(results[p].created_at).getTime();\n-        if (pdate < now) {\n-          ddata.lastProfileFromSwitch = results[p].profile;\n-          break;\n+    console.log(\'searching treatments q\', tq);\n+    ctx.treatments.list(tq, function(err, results) {\n+        if (!err && results) {\n+            mergeToTreatments(ddata, results);\n         }\n-      }\n-    }\n \n-    callback();\n-  });\n+        callback();\n+    });\n }\n \n-function loadSensorAndInsulinTreatments (ddata, ctx, callback) {\n-  var dateRange = {\n-    $gte: new Date(ddata.lastUpdated - (ONE_DAY * 32)).toISOString()\n-  };\n-\n-  if (ddata.page && ddata.page.frame) {\n-    dateRange[\'$lte\'] = new Date(ddata.lastUpdated).toISOString( );\n-  }\n-\n-  var tq = {\n-    find: {\n-      eventType: {\n-        $in: [ \'Sensor Start\', \'Sensor Change\', \'Insulin Change\', \'Pump Battery Change\']\n-      }\n-      , created_at: dateRange\n+function loadProfileSwitchTreatments(ddata, ctx, callback) {\n+    var dateRange = {\n+        $gte: new Date(ddata.lastUpdated - (ONE_DAY * 31 * 12)).toISOString()\n+    };\n+\n+    if (ddata.page && ddata.page.frame) {\n+        dateRange[\'$lte\'] = new Date(ddata.lastUpdated).toISOString();\n     }\n-    , sort: {created_at: -1}\n-  };\n \n-  ctx.treatments.list(tq, function (err, results) {\n-    if (!err && results) {\n-      mergeToTreatments(ddata, results);\n+    var tq = {\n+        find: {\n+            eventType: \'Profile Switch\',\n+            created_at: dateRange\n+        },\n+        sort: {\n+            created_at: -1\n+        }\n+    };\n+\n+    ctx.treatments.list(tq, function(err, results) {\n+        if (!err && results) {\n+            mergeToTreatments(ddata, results);\n+        }\n+\n+        // Store last profile switch\n+        if (results) {\n+            ddata.lastProfileFromSwitch = null;\n+            var now = new Date().getTime();\n+            for (var p = 0; p < results.length; p++) {\n+                var pdate = new Date(results[p].created_at).getTime();\n+                if (pdate < now) {\n+                    ddata.lastProfileFromSwitch = results[p].profile;\n+                    break;\n+                }\n+            }\n+        }\n+\n+        callback();\n+    });\n+}\n+\n+function loadSensorAndInsulinTreatments(ddata, ctx, callback) {\n+    var dateRange = {\n+        $gte: new Date(ddata.lastUpdated - (ONE_DAY * 32)).toISOString()\n+    };\n+\n+    if (ddata.page && ddata.page.frame) {\n+        dateRange[\'$lte\'] = new Date(ddata.lastUpdated).toISOString();\n     }\n \n-    callback();\n-  });\n+    var tq = {\n+        find: {\n+            eventType: {\n+                $in: [\'Sensor Start\', \'Sensor Change\', \'Insulin Change\', \'Pump Battery Change\']\n+            },\n+            created_at: dateRange\n+        },\n+        sort: {\n+            created_at: -1\n+        }\n+    };\n+\n+    ctx.treatments.list(tq, function(err, results) {\n+        if (!err && results) {\n+            mergeToTreatments(ddata, results);\n+        }\n+\n+        callback();\n+    });\n }\n \n-function loadProfile (ddata, ctx, callback) {\n-  ctx.profile.last(function (err, results) {\n-    if (!err && results) {\n-      var profiles = [];\n-      results.forEach(function (element) {\n-        if (element) {\n-            profiles[0] = element;\n+function loadProfile(ddata, ctx, callback) {\n+    ctx.profile.last(function(err, results) {\n+        if (!err && results) {\n+            var profiles = [];\n+            results.forEach(function(element) {\n+                if (element) {\n+                    profiles[0] = element;\n+                }\n+            });\n+            ddata.profiles = profiles;\n         }\n-      });\n-      ddata.profiles = profiles;\n-    }\n-    callback();\n-  });\n+        callback();\n+    });\n }\n \n-  function loadFood (ddata, ctx, callback) {\n-    ctx.food.list(function (err, results) {\n-      if (!err && results) {\n-        ddata.food = results;\n-      }\n-      callback();\n+function loadFood(ddata, ctx, callback) {\n+    ctx.food.list(function(err, results) {\n+        if (!err && results) {\n+            ddata.food = results;\n+        }\n+        callback();\n     });\n-  }\n-\n-  function loadDeviceStatus (ddata, env, ctx, callback) {\n-  var dateRange = {\n-    $gte: new Date(ddata.lastUpdated - ONE_DAY).toISOString()\n-  };\n-  if (ddata.page && ddata.page.frame) {\n-    dateRange[\'$lte\'] = new Date(ddata.lastUpdated).toISOString( );\n-  }\n-  var opts = {\n-    find: {\n-      created_at: dateRange\n+}\n+\n+function loadDeviceStatus(ddata, env, ctx, callback) {\n+    var dateRange = {\n+        $gte: new Date(ddata.lastUpdated - ONE_DAY).toISOString()\n+    };\n+    if (ddata.page && ddata.page.frame) {\n+        dateRange[\'$lte\'] = new Date(ddata.lastUpdated).toISOString();\n     }\n-    , sort: {created_at: -1}\n-  };\n-\n-  if (env.extendedSettings.devicestatus && env.extendedSettings.devicestatus.advanced) {\n-    //not adding count: 1 restriction\n-  } else {\n-    opts.count = 1;\n-  }\n-\n-  ctx.devicestatus.list(opts, function (err, results) {\n-    if (!err && results) {\n-      ddata.devicestatus = _.map(results, function eachStatus (result) {\n-        result.mills = new Date(result.created_at).getTime();\n-        if (\'uploaderBattery\' in result) {\n-          result.uploader = {\n-            battery: result.uploaderBattery\n-          };\n-          delete result.uploaderBattery;\n+    var opts = {\n+        find: {\n+            created_at: dateRange\n+        },\n+        sort: {\n+            created_at: -1\n         }\n-        return result;\n-      }).reverse();\n+    };\n+\n+    if (env.extendedSettings.devicestatus && env.extendedSettings.devicestatus.advanced) {\n+        //not adding count: 1 restriction\n     } else {\n-      ddata.devicestatus = [];\n+        opts.count = 1;\n     }\n-    callback();\n-  });\n+\n+    ctx.devicestatus.list(opts, function(err, results) {\n+        if (!err && results) {\n+            ddata.devicestatus = _.map(results, function eachStatus(result) {\n+                result.mills = new Date(result.created_at).getTime();\n+                if (\'uploaderBattery\' in result) {\n+                    result.uploader = {\n+                        battery: result.uploaderBattery\n+                    };\n+                    delete result.uploaderBattery;\n+                }\n+                return result;\n+            }).reverse();\n+        } else {\n+            ddata.devicestatus = [];\n+        }\n+        callback();\n+    });\n }\n \n-module.exports = init;\n+module.exports = init;\n\\ No newline at end of file\ndiff --git a/lib/data/ddata.js b/lib/data/ddata.js\nindex 49f874cb..1b799427 100644\n--- a/lib/data/ddata.js\n+++ b/lib/data/ddata.js\n@@ -15,6 +15,7 @@ function init( ) {\n     , profiles: []\n     , devicestatus: []\n     , food: []\n+    , activity: []\n     , lastUpdated: 0\n   };\n \n@@ -36,7 +37,7 @@ function init( ) {\n       first: { }\n       , rest: { }\n     };\n-    \n+\n     function recent (item) {\n       return item.mills >= time - cutoff;\n     }\n@@ -44,7 +45,7 @@ function init( ) {\n     function filterMax(item) {\n       return item.mills >= time - max;\n     }\n-      \n+\n     function partition (field, filter) {\n       var data;\n       if (filter) {\n@@ -52,7 +53,7 @@ function init( ) {\n       } else {\n         data = ddata[field];\n       }\n-      \n+\n       var parts = _.partition(data, recent);\n       result.first[field] = parts[0];\n       result.rest[field] = parts[1];\n@@ -64,7 +65,7 @@ function init( ) {\n \n     result.first.sgvs = ddata.sgvs.filter(filterMax);\n     result.first.cals = ddata.cals;\n-    \n+\n     var profiles = _.cloneDeep(ddata.profiles);\n     if (profiles && profiles[0])\n       for (var k in profiles[0].store) {\n@@ -78,6 +79,7 @@ function init( ) {\n \n     result.rest.mbgs = ddata.mbgs.filter(filterMax);\n     result.rest.food = ddata.food;\n+    result.rest.activity = ddata.activity;\n \n      console.log(\'results.first size\', JSON.stringify(result.first).length,\'bytes\');\n      console.log(\'results.rest size\', JSON.stringify(result.rest).length,\'bytes\');\n@@ -127,7 +129,7 @@ function init( ) {\n       .value();\n \n   };\n-  \n+\n   ddata.processDurations = function processDurations (treatments, keepzeroduration) {\n \n     treatments = _.uniqBy(treatments, \'mills\');\n@@ -186,7 +188,12 @@ function init( ) {\n     ddata.insulinchangeTreatments = ddata.treatments.filter( function filterInsulin (t) {\n       return t.eventType.indexOf(\'Insulin Change\') > -1;\n     }).sort(function (a,b) { return a.mills > b.mills; });\n-\n+      \n+    // filter & prepare \'Pump Battery Change\' events\n+    ddata.batteryTreatments = ddata.treatments.filter( function filterSensor (t) {\n+      return t.eventType.indexOf(\'Pump Battery Change\') > -1;\n+    }).sort(function (a,b) { return a.mills > b.mills; });\n+      \n     // filter & prepare \'Sensor\' events\n     ddata.sensorTreatments = ddata.treatments.filter( function filterSensor (t) {\n       return t.eventType.indexOf(\'Sensor\') > -1;\n@@ -215,6 +222,17 @@ function init( ) {\n \n     // filter temp target\n     var tempTargetTreatments = ddata.treatments.filter( function filterTargets (t) {\n+      //check for a units being sent\n+      if (t.units){\n+        if (t.units == \'mmol\'){\n+          //convert to mgdl\n+          t.targetTop = t.targetTop * 18;\n+          t.targetBottom = t.targetBottom * 18;\n+        }\n+      }\n+      //if we have a temp target thats below 20, assume its mmol and convert to mgdl for safety.\n+      if ( t.targetTop < 20 ) { t.targetTop = t.targetTop * 18; }\n+      if ( t.targetBottom < 20 ) { t.targetBottom = t.targetBottom * 18; }\n       return t.eventType && t.eventType.indexOf(\'Temporary Target\') > -1;\n     });\n     if (preserveOrignalTreatments)\n@@ -227,4 +245,4 @@ function init( ) {\n \n }\n \n-module.exports = init;\n\\ No newline at end of file\n+module.exports = init;\ndiff --git a/lib/language.js b/lib/language.js\nindex 3216c53d..4888ed45 100644\n--- a/lib/language.js\n+++ b/lib/language.js\n@@ -49,7 +49,6 @@ function init() {\n       ,bg: \'Активиране на порта\'\n       ,hr: \'Slušanje na portu\'\n       ,it: \'Porta in ascolto\'\n-      ,dk: \'Lytter på port\'\n       ,fi: \'Kuuntelen porttia\'\n       ,nb: \'Lytter på port\'\n       ,he: \'מקשיב על פתחה\'\n@@ -2041,7 +2040,6 @@ function init() {\n     ,\'No API secret hash stored yet. You need to enter API secret.\' : {\n       cs: \'Není uložený žádný hash API hesla. Musíte zadat API heslo.\'\n       ,de: \'Keine API-Prüfsumme gespeichert. Bitte API-Prüfsumme eingeben.\'\n-      ,es: \'No se ha almacenado ningún hash todavía. Debe introducir su API secreto.\'\n       ,es: \'No se ha almacenado ningún hash todavía. Debe introducir su secreto API.\'\n       ,fr: \'Pas de secret API existant. Vous devez en entrer un.\'\n       ,el: \'Δεν υπάρχει αποθηκευμένο συνθηματικό API. Πρέπει να εισάγετε το συνθηματικό API\'\n@@ -4355,6 +4353,29 @@ function init() {\n       ,zh_cn: \'静音2小时\'\n       ,zh_tw: \'靜音2小時\'\n       }\n+    ,\'2HR\' : {\n+      cs: \'2hod\'\n+      ,de: \'2h\'\n+      ,es: \'2h\'\n+      ,fr: \'2hr\'\n+      ,el: \'2 ώρες\'\n+      ,pt: \'2h\'\n+      ,sv: \'2tim\'\n+      ,ro: \'2h\'\n+      ,bg: \'2часа\'\n+      ,hr: \'2h\'\n+      ,it: \'2ORE\'\n+      ,dk: \'2t\'\n+      ,fi: \'2h\'\n+      ,nb: \'2t\'\n+      ,pl: \'2h\'\n+      ,ru: \'2ч\'\n+      ,sk: \'2 hod\'\n+      ,nl: \'2 uur\'\n+      ,ko: \'2시간\'\n+      ,zh_cn: \'2小时\'\n+      ,zh_tw: \'2小時\'\n+      }\n     ,\'3HR\' : {\n       cs: \'3hod\'\n       ,de: \'3h\'\n@@ -6603,7 +6624,7 @@ function init() {\n       ,fr: \'Cet outil cherche et efface les valeurs CGM dont la date est dans le futur\'\n       ,el: \'Αυτή η ενέργεια αφαιρεί δεδομένα αιθητήρα τα οποία εισήχθησαν με λάθος ημερομηνία και ώρα, από τη βάση δεδομένων\'\n       ,de: \'Finde und entferne CGM Daten in der Zukunft, die vom Uploader mit falschem Datum/Uhrzeit erstellt wurden.\'\n-      ,es: \'Este comando encuentra y elimina datos del sensor futuros creados por actualizaciones con errores en fecha/hora\' \n+      ,es: \'Este comando encuentra y elimina datos del sensor futuros creados por actualizaciones con errores en fecha/hora\'\n       ,dk: \'Denne handling finder og fjerner CGM data i fremtiden forårsaget af indlæsning med forkert dato/tid.\'\n       ,bg: \'Тази опция ще намери и премахне данни от сензора в бъдещето, създадени поради грешна дата/време.\'\n       ,ro: \'Instrument de căutare și eliminare a datelor din viitor, create de uploader cu ora setată greșit\'\n@@ -7654,7 +7675,7 @@ function init() {\n       ,fr: \'mg/dL ou mmol/l par unité d\\\'insuline. Le rapport représentant la modification de la glycémie résultant de l\\\'administration d\\\'une unité d\\\'insuline.\'\n       ,el: \'mg/dl ή mmol/L ανά μονάδα U ινσουλίνης. Το πόσες μονάδες ρίχνει τη γλυκόζη αίματος μία μονάδα U ινσουλίνης\'\n       ,de: \'mg/dL oder mmol/L pro Einheit Insulin. Verhältnis von BG-Veränderung je Einheit Korrekturinsulin.\'\n-      ,es: \'mg/dl o mmol/L por unidad Insulina. La relación de la caída de glucosa y cada unidad de insulina de corrección administrada.\' \n+      ,es: \'mg/dl o mmol/L por unidad Insulina. La relación de la caída de glucosa y cada unidad de insulina de corrección administrada.\'\n       ,sv: \'mg/dl eller mmol per enhet insulin. Hur varje enhet insulin sänker blodsockret\'\n       ,nb: \'mg/dl eller mmol/l per enhet insulin.  Beskriver hvor mye blodsukkeret senkes per enhet insulin.\'\n       ,fi: \'mg/dL tai mmol/L / 1 yksikkö insuliinia. Suhde, joka kertoo montako yksikköä verensokeria yksi yksikkö insuliinia laskee.\'\n@@ -8184,7 +8205,7 @@ function init() {\n       ,sk: \'Operácia\'\n       ,pl: \'Operacja\'\n       ,pt: \'Operação\'\n-      ,nl: \'Operatie\' \n+      ,nl: \'Operatie\'\n       ,ko: \'동작\'\n       ,it: \'Operazione\'\n       ,zh_cn: \'操作\'\n@@ -9796,7 +9817,7 @@ function init() {\n       ,ro: \'Ignoră alarma de hiper deoarece este suficientă insulină activă IOB\'\n       ,fr: \'Alarme haute ignorée car suffisamment d\\\'insuline à bord (IOB)\'\n       ,bg: \'Изключване на аларма за висока КЗ, тъй като има достатъчно IOB\'\n-      ,es: \'Ignorar alarma de Hiperglucemia al tener suficiente insulina activa\' \n+      ,es: \'Ignorar alarma de Hiperglucemia al tener suficiente insulina activa\'\n       ,ru: \'Отключение предупреждение о высоком СК ввиду достаточности инсулина в организме\'\n       ,sv: \'Snoozar höglarm då aktivt insulin är tillräckligt\'\n       ,nb: \'Utsetter høyalarm siden det er nok aktivt insulin\'\n@@ -9818,7 +9839,7 @@ function init() {\n       ,nb: \'Sjekk blodsukker, på tide med bolus?\'\n       ,fi: \'Tarkista VS, aika bolustaa?\'\n       ,pt: \'Meça a glicemia, hora de bolus de correção?\'\n-      ,es: \'Controle su glucemia, ¿quizás un bolo Insulina?\' \n+      ,es: \'Controle su glucemia, ¿quizás un bolo Insulina?\'\n       ,sk: \'Skontrolovať glykémiu, čas na bolus?\'\n       ,it: \'Controllare BG, il tempo del bolo?\'\n       ,nl: \'Controleer BG, tijd om te bolussen?\'\n@@ -11326,6 +11347,46 @@ function init() {\n         , sv: \'no\'\n         , zh_cn: \'no\'\n         , zh_tw: \'no\'\n+    },\n+      \'alexaUploadBattery\': {\n+          en: \'Your uploader battery is at %1\'\n+          , de: \'Der Akku deines Uploader Handys ist bei %1\'\n+      },\n+      \'alexaReservoir\': {\n+          en: \'You have %1 units remaining\'\n+          , de: \'Du hast %1 Einheiten übrig\'\n+      },\n+      \'alexaPumpBattery\': {\n+        en: \'Your pump battery is at %1 %2\'\n+        , de: \'Der Batteriestand deiner Pumpe ist bei %1 %2\'\n+      },\n+      \'alexaLastLoop\': {\n+        en: \'The last successful loop was %1\'\n+        , de: \'Der letzte erfolgreiche Loop war vor %1\'\n+      },\n+    \'alexaLoopNotAvailable\': {\n+      en: \'Loop plugin does not seem to be enabled\'\n+      , de: \'Das Loop Plugin scheint nicht aktiviert zu sein\'\n+    },\n+    \'alexaLoopForecast\': {\n+      en: \'According to the loop forecast you are expected to be %1 over the next %2\'\n+      , de: \'Entsprechend der Loop Vorhersage landest du bei %1 während der nächsten %2\'\n+    },\n+    \'alexaForecastUnavailable\': {\n+      en: \'Unable to forecast with the data that is available\',\n+      de: \'Mit den verfügbaren Daten ist eine Loop Vorhersage nicht möglich\'\n+    },\n+    \'alexaRawBG\': {\n+      en: \'Your raw bg is %1\'\n+      , de: \'Dein Rohblutzucker ist %1\'\n+    },\n+    \'alexaOpenAPSForecast\': {\n+      en: \'The OpenAPS Eventual BG is %1\'\n+      , de: \'Der von OpenAPS vorhergesagte Blutzucker ist %1\'\n+    },\n+    \'alexaCOB\': {\n+      en: \'%1 %2 carbohydrates on board\'\n+      , de: \'%1 %2 Gramm Kohlenhydrate wirkend.\'\n     },\n     \'Fat [g]\': {\n         cs: \'Tuk [g]\'\ndiff --git a/lib/plugins/batteryage.js b/lib/plugins/batteryage.js\nnew file mode 100644\nindex 00000000..ffdb51bc\n--- /dev/null\n+++ b/lib/plugins/batteryage.js\n@@ -0,0 +1,156 @@\n+\'use strict\';\n+\n+var _ = require(\'lodash\');\n+var moment = require(\'moment\');\n+var levels = require(\'../levels\');\n+\n+function init(ctx) {\n+    var translate = ctx.language.translate;\n+    \n+    var bage = {\n+    name: \'bage\'\n+        , label: \'Pump Battery Change\'\n+        , pluginType: \'pill-minor\'\n+    };\n+    \n+    bage.getPrefs = function getPrefs(sbx) {\n+        return {\n+        info: sbx.extendedSettings.info || 312\n+            , warn: sbx.extendedSettings.warn || 336\n+            , urgent: sbx.extendedSettings.urgent || 360\n+            , display: sbx.extendedSettings.display ? sbx.extendedSettings.display : \'days\'\n+            , enableAlerts: sbx.extendedSettings.enableAlerts || false\n+        };\n+    };\n+    \n+    bage.setProperties = function setProperties (sbx) {\n+        sbx.offerProperty(\'bage\', function setProp ( ) {\n+                          return bage.findLatestTimeChange(sbx);\n+                          });\n+    };\n+    \n+    bage.checkNotifications = function checkNotifications(sbx) {\n+        var batteryInfo = sbx.properties.bage;\n+        \n+        if (batteryInfo.notification) {\n+            var notification = _.extend({}, batteryInfo.notification, {\n+                                        plugin: bage\n+                                        , debug: {\n+                                        age: batteryInfo.age\n+                                        }\n+                                        });\n+            sbx.notifications.requestNotify(notification);\n+        }\n+    };\n+    \n+    bage.findLatestTimeChange = function findLatestTimeChange(sbx) {\n+        \n+        var prefs = bage.getPrefs(sbx);\n+        \n+        var batteryInfo = {\n+        found: false\n+            , age: 0\n+            , treatmentDate: null\n+            , checkForAlert: false\n+        };\n+        \n+        var prevDate = 0;\n+        \n+        _.each(sbx.data.batteryTreatments, function eachTreatment (treatment) {\n+               var treatmentDate = treatment.mills;\n+               if (treatmentDate > prevDate && treatmentDate <= sbx.time) {\n+               \n+               prevDate = treatmentDate;\n+               batteryInfo.treatmentDate = treatmentDate;\n+               \n+               var a = moment(sbx.time);\n+               var b = moment(batteryInfo.treatmentDate);\n+               var days = a.diff(b,\'days\');\n+               var hours = a.diff(b,\'hours\') - days * 24;\n+               var age = a.diff(b,\'hours\');\n+               \n+               if (!batteryInfo.found || (age >= 0 && age < batteryInfo.age)) {\n+               batteryInfo.found = true;\n+               batteryInfo.age = age;\n+               batteryInfo.days = days;\n+               batteryInfo.hours = hours;\n+               batteryInfo.notes = treatment.notes;\n+               batteryInfo.minFractions = a.diff(b,\'minutes\') - age * 60;\n+               }\n+               }\n+               });\n+        \n+        \n+        batteryInfo.level = levels.NONE;\n+        \n+        var sound = \'incoming\';\n+        var message;\n+        var sendNotification = false;\n+        \n+        if (batteryInfo.age >= prefs.urgent) {\n+            sendNotification = batteryInfo.age === prefs.urgent;\n+            message = translate(\'Pump Battery change overdue!\');\n+            sound = \'persistent\';\n+            batteryInfo.level = levels.URGENT;\n+        } else if (batteryInfo.age >= prefs.warn) {\n+            sendNotification = batteryInfo.age === prefs.warn;\n+            message = translate(\'Time to change pump battery\');\n+            batteryInfo.level = levels.WARN;\n+        } else  if (batteryInfo.age >= prefs.info) {\n+            sendNotification = batteryInfo.age === prefs.info;\n+            message = \'Change pump battery soon\';\n+            batteryInfo.level = levels.INFO;\n+        }\n+        \n+        if (prefs.display === \'days\' && batteryInfo.found) {\n+            batteryInfo.display = \'\';\n+            if (batteryInfo.age >= 24) {\n+                batteryInfo.display += batteryInfo.days + \'d\';\n+            }\n+            batteryInfo.display += batteryInfo.hours + \'h\';\n+        } else {\n+            batteryInfo.display = batteryInfo.found ? batteryInfo.age + \'h\' : \'n/a \';\n+        }\n+        \n+        //allow for 20 minute period after a full hour during which we\'ll alert the user\n+        if (prefs.enableAlerts && sendNotification && batteryInfo.minFractions <= 20) {\n+            batteryInfo.notification = {\n+            title: translate(\'Pump battery age %1 hours\', { params: [batteryInfo.age] })\n+                , message: message\n+                , pushoverSound: sound\n+                , level: batteryInfo.level\n+                , group: \'BAGE\'\n+            };\n+        }\n+        \n+        return batteryInfo;\n+    };\n+    \n+    bage.updateVisualisation = function updateVisualisation (sbx) {\n+        \n+        var batteryInfo = sbx.properties.bage;\n+        \n+        var info = [{ label: translate(\'Inserted\'), value: new Date(batteryInfo.treatmentDate).toLocaleString() }];\n+        \n+        if (!_.isEmpty(batteryInfo.notes)) {\n+            info.push({label: translate(\'Notes\') + \':\', value: batteryInfo.notes});\n+        }\n+        \n+        var statusClass = null;\n+        if (batteryInfo.level === levels.URGENT) {\n+            statusClass = \'urgent\';\n+        } else if (batteryInfo.level === levels.WARN) {\n+            statusClass = \'warn\';\n+        }\n+        \n+        sbx.pluginBase.updatePillText(bage, {\n+                                      value: batteryInfo.display\n+                                      , label: translate(\'BAGE\')\n+                                      , info: info\n+                                      , pillClass: statusClass\n+                                      });\n+    };\n+    return bage;\n+}\n+\n+module.exports = init;\ndiff --git a/lib/plugins/careportal.js b/lib/plugins/careportal.js\nindex e6527707..b30a5153 100644\n--- a/lib/plugins/careportal.js\n+++ b/lib/plugins/careportal.js\n@@ -69,6 +69,10 @@ function init() {\n         , name: \'CGM Sensor Insert\'\n         , bg: true,  insulin: false, carbs: false, prebolus: false, duration: false, percent: false, absolute: false, profile: false, split: false\n       }\n+      , { val: \'Pump Battery Change\'\n+        , name: \'Pump Battery Change\'\n+        , bg: true,  insulin: false, carbs: false, prebolus: false, duration: false, percent: false, absolute: false, profile: false, split: false\n+            }\n       , { val: \'Insulin Change\'\n         , name: \'Insulin Cartridge Change\'\n         , bg: true,  insulin: false, carbs: false, prebolus: false, duration: false, percent: false, absolute: false, profile: false, split: false\n@@ -96,4 +100,4 @@ function init() {\n   return careportal;\n }\n \n-module.exports = init;\n\\ No newline at end of file\n+module.exports = init;\ndiff --git a/lib/plugins/index.js b/lib/plugins/index.js\nindex c874d968..acb7ab22 100644\n--- a/lib/plugins/index.js\n+++ b/lib/plugins/index.js\n@@ -35,6 +35,7 @@ function init (ctx) {\n     , require(\'./cannulaage\')(ctx)\n     , require(\'./sensorage\')(ctx)\n     , require(\'./insulinage\')(ctx)\n+    , require(\'./batteryage\')(ctx)\n     , require(\'./basalprofile\')(ctx)\n     , require(\'./boluscalc\')(ctx)  // fake plugin to show/hide\n     , require(\'./profile\')(ctx)    // fake plugin to hold extended settings\n@@ -57,6 +58,7 @@ function init (ctx) {\n     , require(\'./cannulaage\')(ctx)\n     , require(\'./sensorage\')(ctx)\n     , require(\'./insulinage\')(ctx)\n+    , require(\'./batteryage\')(ctx)\n     , require(\'./treatmentnotify\')(ctx)\n     , require(\'./timeago\')(ctx)\n     , require(\'./basalprofile\')(ctx)\ndiff --git a/lib/plugins/openaps.js b/lib/plugins/openaps.js\nindex 136e901c..e43af9bf 100644\n--- a/lib/plugins/openaps.js\n+++ b/lib/plugins/openaps.js\n@@ -9,13 +9,12 @@ var levels = require(\'../levels\');\n \n function init(ctx) {\n   var utils = require(\'../utils\')(ctx);\n-\n   var openaps = {\n     name: \'openaps\'\n     , label: \'OpenAPS\'\n     , pluginType: \'pill-status\'\n   };\n-\n+  var translate = ctx.language.translate;\n   var firstPrefs = true;\n \n   openaps.getPrefs = function getPrefs(sbx) {\n@@ -450,14 +449,22 @@ function init(ctx) {\n \n   function alexaForecastHandler (next, slots, sbx) {\n     if (sbx.properties.openaps && sbx.properties.openaps.lastEventualBG) {\n-      var response = \'The OpenAPS Eventual BG is \' + sbx.properties.openaps.lastEventualBG;\n+      var response = translate(\'alexaOpenAPSForecast\', {\n+        params: [\n+          sbx.properties.openaps.lastEventualBG\n+        ]}\n+      );\n       next(\'Loop Forecast\', response);\n     }\n   }\n \n   function alexaLastLoopHandler (next, slots, sbx) {\n     console.log(JSON.stringify(sbx.properties.openaps.lastLoopMoment));\n-    var response = \'The last successful loop was \' + moment(sbx.properties.openaps.lastLoopMoment).from(moment(sbx.time));\n+    var response = translate(\'alexaLastLoop\', {\n+      params: [\n+        moment(sbx.properties.openaps.lastLoopMoment).from(moment(sbx.time))\n+      ]\n+    });\n     next(\'Last loop\', response);\n   }\n \ndiff --git a/lib/plugins/pump.js b/lib/plugins/pump.js\nindex 1f8dd958..ff9e4f98 100644\n--- a/lib/plugins/pump.js\n+++ b/lib/plugins/pump.js\n@@ -136,14 +136,23 @@ function init (ctx) {\n   };\n \n   function alexaReservoirHandler (next, slots, sbx) {\n-    var response = \'You have \' + sbx.properties.pump.pump.reservoir + \' units remaining\';\n+      var response = translate(\'alexaReservoir\', {\n+        params: [\n+            sbx.properties.pump.pump.reservoir\n+        ]\n+    });\n     next(\'Remaining insulin\', response);\n   }\n \n   function alexaBatteryHandler (next, slots, sbx) {\n     var battery = _.get(sbx, \'properties.pump.data.battery\');\n     if (battery) {\n-      var response = \'Your battery is at \' + battery.value + \' \' + battery.unit;\n+      var response = translate(\'alexaPumpBattery\', {\n+              params: [\n+                  battery.value,\n+                  battery.unit\n+              ]\n+          });\n       next(\'Pump battery\', response);\n     } else {\n       next();\ndiff --git a/lib/plugins/treatmentnotify.js b/lib/plugins/treatmentnotify.js\nindex 98d609bf..88aa8f8d 100644\n--- a/lib/plugins/treatmentnotify.js\n+++ b/lib/plugins/treatmentnotify.js\n@@ -15,13 +15,13 @@ function init() {\n     , pluginType: \'notification\'\n   };\n \n-  //automated treatments from OpenAPS shouldn\'t trigger notifications or snooze alarms\n+  //automated treatments from OpenAPS or Loop shouldn\'t trigger notifications or snooze alarms\n   function filterTreatments (sbx) {\n     var treatments = sbx.data.treatments;\n \n     treatments = _.filter(treatments, function notOpenAPS (treatment) {\n       var ok = true;\n-      if (treatment.enteredBy && treatment.enteredBy.indexOf(\'openaps://\') === 0) {\n+      if (treatment.enteredBy && treatment.enteredBy.indexOf(\'openaps://\' || \'loop://\') === 0) {\n         ok = _.indexOf(OPENAPS_WHITELIST, treatment.eventType) >= 0;\n       }\n       return ok;\ndiff --git a/lib/server/activity.js b/lib/server/activity.js\nnew file mode 100644\nindex 00000000..f7df9f48\n--- /dev/null\n+++ b/lib/server/activity.js\n@@ -0,0 +1,79 @@\n+\'use strict\';\n+\n+var find_options = require(\'./query\');\n+\n+\n+function storage (env, ctx) {\n+   var ObjectID = require(\'mongodb\').ObjectID;\n+\n+  function create (obj, fn) {\n+    obj.created_at = (new Date( )).toISOString( );\n+    api().insert(obj, function (err, doc) {\n+      fn(null, doc.ops);\n+    });\n+  }\n+\n+  function save (obj, fn) {\n+    obj._id = new ObjectID(obj._id);\n+    obj.created_at = (new Date( )).toISOString( );\n+    api().save(obj, function (err, doc) {\n+      fn(err, doc);\n+    });\n+  }\n+\n+  function query_for (opts) {\n+    return find_options(opts, storage.queryOpts);\n+  }\n+\n+  function list(opts, fn) {\n+    // these functions, find, sort, and limit, are used to\n+    // dynamically configure the request, based on the options we\'ve\n+    // been given\n+\n+    // determine sort options\n+    function sort ( ) {\n+      return opts && opts.sort || {created_at: -1};\n+    }\n+\n+    // configure the limit portion of the current query\n+    function limit ( ) {\n+      if (opts && opts.count) {\n+        return this.limit(parseInt(opts.count));\n+      }\n+      return this;\n+    }\n+\n+    // handle all the results\n+    function toArray (err, entries) {\n+      fn(err, entries);\n+    }\n+\n+    // now just stitch them all together\n+    limit.call(api( )\n+        .find(query_for(opts))\n+        .sort(sort( ))\n+    ).toArray(toArray);\n+  }\n+  \n+  function remove (_id, fn) {\n+    return api( ).remove({ \'_id\': new ObjectID(_id) }, fn);\n+  }\n+\n+  function api ( ) {\n+    return ctx.store.collection(env.activity_collection);\n+  }\n+  \n+  api.list = list;\n+  api.create = create;\n+  api.query_for = query_for;\n+  api.save = save;\n+  api.remove = remove;\n+  api.indexedFields = [\'created_at\'];\n+  return api;\n+}\n+\n+module.exports = storage;\n+\n+storage.queryOpts = {\n+  dateField: \'created_at\'\n+};\ndiff --git a/lib/server/bootevent.js b/lib/server/bootevent.js\nindex e5f1e508..1d23ae27 100644\n--- a/lib/server/bootevent.js\n+++ b/lib/server/bootevent.js\n@@ -118,6 +118,7 @@ function boot (env, language) {\n     ctx.maker = require(\'../plugins/maker\')(env);\n     ctx.pushnotify = require(\'./pushnotify\')(env, ctx);\n \n+    ctx.activity = require(\'./activity\')(env, ctx);\n     ctx.entries = require(\'./entries\')(env, ctx);\n     ctx.treatments = require(\'./treatments\')(env, ctx);\n     ctx.devicestatus = require(\'./devicestatus\')(env.devicestatus_collection, ctx);\n@@ -148,6 +149,7 @@ function boot (env, language) {\n     ctx.store.ensureIndexes(ctx.devicestatus( ), ctx.devicestatus.indexedFields);\n     ctx.store.ensureIndexes(ctx.profile( ), ctx.profile.indexedFields);\n     ctx.store.ensureIndexes(ctx.food( ), ctx.food.indexedFields);\n+    ctx.store.ensureIndexes(ctx.activity( ), ctx.activity.indexedFields);\n \n     next( );\n   }\ndiff --git a/lib/server/websocket.js b/lib/server/websocket.js\nindex 65c088e1..aa2eaad8 100644\n--- a/lib/server/websocket.js\n+++ b/lib/server/websocket.js\n@@ -4,7 +4,7 @@ var levels = require(\'../levels\');\n var times = require(\'../times\');\n var calcData = require(\'../data/calcdelta\');\n var ObjectID = require(\'mongodb\').ObjectID;\n-       \n+\n function init (env, ctx, server) {\n \n   function websocket ( ) {\n@@ -17,19 +17,20 @@ function init (env, ctx, server) {\n   var log_reset = \'\\x1B[0m\';\n   var LOG_WS = log_green + \'WS: \' + log_reset;\n   var LOG_DEDUP = log_magenta + \'DEDUPE: \' + log_reset;\n-  \n+\n   var io;\n   var watchers = 0;\n   var lastData = {};\n   var lastProfileSwitch = null;\n \n   // TODO: this would be better to have somehow integrated/improved\n-  var supportedCollections = { \n-  \'treatments\' : env.treatments_collection, \n+  var supportedCollections = {\n+  \'treatments\' : env.treatments_collection,\n   \'entries\': env.entries_collection,\n   \'devicestatus\': env.devicestatus_collection, \n   \'profile\': env.profile_collection, \n-  \'food\': env.food_collection\n+  \'food\': env.food_collection,\n+  \'activity\': env.activity_collection\n   };\n \n   // This is little ugly copy but I was unable to pass testa after making module from status and share with /api/v1/status\n@@ -40,10 +41,10 @@ function init (env, ctx, server) {\n       versionNum = 10000 * parseInt(verParse[1]) + 100 * parseInt(verParse[2]) + 1 * parseInt(verParse[3]) ;\n     }\n     var apiEnabled = env.api_secret ? true : false;\n-    \n+\n     var activeProfile = ctx.ddata.lastProfileFromSwitch;\n-    \n-    var info = { \n+\n+    var info = {\n       status: \'ok\'\n       , name: env.name\n       , version: env.version\n@@ -55,7 +56,7 @@ function init (env, ctx, server) {\n       , settings: env.settings\n       , extendedSettings: ctx.plugins && ctx.plugins.extendedClientSettings ? ctx.plugins.extendedClientSettings(env.extendedSettings) : {}\n     };\n-    \n+\n     if (activeProfile) {\n       info.activeProfile = activeProfile;\n     }\n@@ -124,7 +125,7 @@ function init (env, ctx, server) {\n         console.log(LOG_WS + \'Disconnected client ID: \',socket.client.id);\n       });\n \n-      \n+\n       function checkConditions (action, data) {\n         var collection = supportedCollections[data.collection];\n         if (!collection) {\n@@ -148,7 +149,7 @@ function init (env, ctx, server) {\n             return { result: \'Not permitted\' };\n           }\n         }\n-        \n+\n         if (action === \'dbUpdate\' && !data._id) {\n           console.log(\'WS dbUpdate/dbAddnot sure abou documentati call: \', \'Missing _id\', data);\n           return { result: \'Missing _id\' };\n@@ -178,7 +179,7 @@ function init (env, ctx, server) {\n       socket.on(\'dbUpdate\', function dbUpdate (data, callback) {\n        console.log(LOG_WS + \'dbUpdate client ID: \', socket.client.id, \' data: \', data);\n        var collection = supportedCollections[data.collection];\n-        \n+\n         var check = checkConditions(\'dbUpdate\', data);\n         if (check) {\n          if (callback) {\n@@ -186,19 +187,25 @@ function init (env, ctx, server) {\n           }\n           return;\n         }\n-        \n+        var id ;\n+        try {\n+            id = new ObjectID(data._id);\n+        } catch (err){\n+            console.error(err);\n+          id = new ObjectID();\n+        }\n         ctx.store.collection(collection).update(\n-          { \'_id\': new ObjectID(data._id) },\n+          { \'_id\': id },\n           { $set: data.data }\n         );\n-          \n+\n         if (callback) {\n           callback( { result: \'success\' } );\n         }\n         ctx.bus.emit(\'data-received\');\n       });\n-      \n-      // dbUpdateUnset message  \n+\n+      // dbUpdateUnset message\n       //  {\n       //    collection: treatments\n       //    _id: \'some mongo record id\'\n@@ -210,7 +217,7 @@ function init (env, ctx, server) {\n       socket.on(\'dbUpdateUnset\', function dbUpdateUnset (data, callback) {\n        console.log(LOG_WS + \'dbUpdateUnset client ID: \', socket.client.id, \' data: \', data);\n        var collection = supportedCollections[data.collection];\n-        \n+\n         var check = checkConditions(\'dbUpdate\', data);\n         if (check) {\n          if (callback) {\n@@ -218,19 +225,19 @@ function init (env, ctx, server) {\n           }\n           return;\n         }\n-        \n+\n         ctx.store.collection(collection).update(\n           { \'_id\': new ObjectID(data._id) },\n           { $unset: data.data }\n         );\n-          \n+\n         if (callback) {\n           callback( { result: \'success\' } );\n         }\n         ctx.bus.emit(\'data-received\');\n       });\n-      \n-      // dbAdd message  \n+\n+      // dbAdd message\n       //  {\n       //    collection: treatments\n       //    data: {\n@@ -242,7 +249,7 @@ function init (env, ctx, server) {\n        console.log(LOG_WS + \'dbAdd client ID: \', socket.client.id, \' data: \', data);\n         var collection = supportedCollections[data.collection];\n         var maxtimediff = times.mins(1).msecs;\n-        \n+\n         var check = checkConditions(\'dbAdd\', data);\n         if (check) {\n          if (callback) {\n@@ -250,14 +257,14 @@ function init (env, ctx, server) {\n           }\n           return;\n         }\n-        \n+\n         if (data.collection === \'treatments\' && !(\'eventType\' in data.data)) {\n           data.data.eventType = \'<none>\';\n         }\n         if (!(\'created_at\' in data.data)) {\n           data.data.created_at = new Date().toISOString();\n         }\n-        \n+\n         // treatments deduping\n         if (data.collection === \'treatments\') {\n           var query;\n@@ -279,7 +286,7 @@ function init (env, ctx, server) {\n                 }\n                 return;\n             }\n-                \n+\n             var  selected = false;\n             var query_similiar  = {\n               created_at: {$gte: new Date(new Date(data.data.created_at).getTime() - maxtimediff).toISOString(), $lte: new Date(new Date(data.data.created_at).getTime() + maxtimediff).toISOString()}\n@@ -374,7 +381,7 @@ function init (env, ctx, server) {\n           });\n         }\n       });\n-      // dbRemove message  \n+      // dbRemove message\n       //  {\n       //    collection: treatments\n       //    _id: \'some mongo record id\'\n@@ -382,7 +389,7 @@ function init (env, ctx, server) {\n       socket.on(\'dbRemove\', function dbRemove (data, callback) {\n        console.log(LOG_WS + \'dbRemove client ID: \', socket.client.id, \' data: \', data);\n        var collection = supportedCollections[data.collection];\n-        \n+\n         var check = checkConditions(\'dbUpdate\', data);\n         if (check) {\n          if (callback) {\n@@ -390,20 +397,20 @@ function init (env, ctx, server) {\n           }\n           return;\n         }\n-        \n+\n         ctx.store.collection(collection).remove(\n           { \'_id\': new ObjectID(data._id) }\n         );\n-          \n+\n         if (callback) {\n           callback( { result: \'success\' } );\n         }\n         ctx.bus.emit(\'data-received\');\n       });\n-      \n+\n       // Authorization message\n       // {\n-      //  client: \'web\' | \'phone\' | \'pump\'  \n+      //  client: \'web\' | \'phone\' | \'pump\'\n       //  , secret: \'secret_hash\'\n       //  [, history : history_in_hours ]\n       //  [, status : true ]\n@@ -446,10 +453,10 @@ function init (env, ctx, server) {\n           }\n         });\n       });\n-      \n+\n       // Pind message\n       // {\n-      //  mills: <local_time_in_milliseconds>  \n+      //  mills: <local_time_in_milliseconds>\n       // }\n       socket.on(\'nsping\', function ping (message, callback) {\n         var clientTime = message.mills;\n@@ -490,7 +497,7 @@ function init (env, ctx, server) {\n       console.info(LOG_WS + \'emitted announcement to all clients\');\n     }\n   };\n-  \n+\n   start( );\n   listeners( );\n \ndiff --git a/lib/storage/mongo-storage.js b/lib/storage/mongo-storage.js\nindex 622748f2..72728e53 100644\n--- a/lib/storage/mongo-storage.js\n+++ b/lib/storage/mongo-storage.js\n@@ -30,18 +30,22 @@ function init (env, cb, forceNewConnection) {\n       var connect_with_retry = function(i) {\n         return MongoClient.connect(env.storageURI, options, function connected(err, client) {\n           if (err) {\n-            if (err.includes(\'Invalid schema\')) { throw new Error(\'MongoDB connection string seems invalid\'); }\n-            if (i>20) {\n-              // Abort after retrying for more than 10 minutes\n-              throw \'Error connecting to MongoDB, stopping the retry loop and aborting...\';\n+            //console.log(\'err=\', err)\n+            if (err.name && err.name === "MongoNetworkError") {\n+                if (i>20) {\n+                   // Abort after retrying for more than 10 minutes\n+                   throw \'Error connecting to MongoDB, stopping the retry loop and aborting...\';\n+                }\n+                console.log(\'Error connecting to MongoDB: %j - retrying in \' + i*3 + \' sec\', err);\n+                setTimeout(connect_with_retry, i*3000, i+1);\n+            } else if (err.message) {\n+                throw new Error(\'MongoDB connection string \'+env.storageURI+\' seems invalid: \'+err.message) ; \n             }\n-            console.log(\'Error connecting to MongoDB: %j - retrying in \' + i*3 + \' sec\', err);\n-            setTimeout(connect_with_retry, i*3000, i+1);\n           } else {\n             console.log(\'Successfully established a connected to MongoDB\');\n             \n-            var dbName = env.storageURI.split(\'?\').pop().split(\'/\');\n-            dbName = dbName[dbName.length -1];\n+            var dbName = env.storageURI.split(\'/\').pop().split(\'?\');\n+            dbName=dbName[0]; // drop Connection Options\n             mongo.db = client.db(dbName);\n             connection = mongo.db;\n             mongo.client = client;\ndiff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json\nindex 0263db9d..ac20968a 100644\n--- a/npm-shrinkwrap.json\n+++ b/npm-shrinkwrap.json\n@@ -4,12 +4,27 @@\n   "lockfileVersion": 1,\n   "requires": true,\n   "dependencies": {\n+    "@braintree/sanitize-url": {\n+      "version": "2.1.0",\n+      "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-2.1.0.tgz",\n+      "integrity": "sha1-VJqdH5I8m8eVOlhdPpqpQpvo/ig="\n+    },\n+    "@types/inline-style-prefixer": {\n+      "version": "3.0.1",\n+      "resolved": "https://registry.npmjs.org/@types/inline-style-prefixer/-/inline-style-prefixer-3.0.1.tgz",\n+      "integrity": "sha512-+kbOcYW1/noncDwRryRoB9tH87IYcMfdBGvw98iocK39LtTA2DFL7agmk4UHW/GxjzVfwrxfjlLrqrgA7MCtmg=="\n+    },\n     "@types/node": {\n       "version": "6.0.83",\n       "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.83.tgz",\n       "integrity": "sha512-Q92+tkWnX7nmT0ZG+/wFxzJr+idr00T12MgsY3p0sZIu8nfvYF8i5pbY3BVZw6ad6yS2MLF71sfMr+ySatc2Gw==",\n       "dev": true\n     },\n+    "@types/react": {\n+      "version": "16.0.38",\n+      "resolved": "https://registry.npmjs.org/@types/react/-/react-16.0.38.tgz",\n+      "integrity": "sha512-t0XJHNrlzLiVAKCWxS9zzAadoQO8zGFpHsrvNVk7QmrDXnm3cPFy2wFcHGNbKjntBiXznL6qQkh+a1Wxu21+dA=="\n+    },\n     "abab": {\n       "version": "1.0.3",\n       "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.3.tgz",\n@@ -58,11 +73,10 @@\n       "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8="\n     },\n     "ajv": {\n-      "version": "5.5.1",\n-      "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.1.tgz",\n-      "integrity": "sha1-s4u4h22ehr7plJVqBOch6IskjrI=",\n+      "version": "6.1.1",\n+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.1.1.tgz",\n+      "integrity": "sha1-l41Zf7wrfQ5aXD3esUmmgvKr+g4=",\n       "requires": {\n-        "co": "4.6.0",\n         "fast-deep-equal": "1.0.0",\n         "fast-json-stable-stringify": "2.0.0",\n         "json-schema-traverse": "0.3.1"\n@@ -100,6 +114,12 @@\n       "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",\n       "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU="\n     },\n+    "ansi-html": {\n+      "version": "0.0.7",\n+      "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz",\n+      "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=",\n+      "optional": true\n+    },\n     "ansi-regex": {\n       "version": "2.1.1",\n       "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",\n@@ -162,6 +182,12 @@\n       "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=",\n       "dev": true\n     },\n+    "array-find-index": {\n+      "version": "1.0.2",\n+      "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",\n+      "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=",\n+      "optional": true\n+    },\n     "array-flatten": {\n       "version": "1.1.1",\n       "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",\n@@ -172,6 +198,20 @@\n       "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz",\n       "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU="\n     },\n+    "array-union": {\n+      "version": "1.0.2",\n+      "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",\n+      "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",\n+      "optional": true,\n+      "requires": {\n+        "array-uniq": "1.0.3"\n+      }\n+    },\n+    "array-uniq": {\n+      "version": "1.0.3",\n+      "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",\n+      "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY="\n+    },\n     "array-unique": {\n       "version": "0.2.1",\n       "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",\n@@ -187,6 +227,11 @@\n       "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",\n       "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0="\n     },\n+    "asap": {\n+      "version": "2.0.6",\n+      "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",\n+      "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="\n+    },\n     "ascli": {\n       "version": "1.0.1",\n       "resolved": "https://registry.npmjs.org/ascli/-/ascli-1.0.1.tgz",\n@@ -202,9 +247,9 @@\n       "integrity": "sha1-VZvhg3bQik7E2+gId9J4GGObLfc="\n     },\n     "asn1.js": {\n-      "version": "4.9.2",\n-      "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.9.2.tgz",\n-      "integrity": "sha512-b/OsSjvWEo8Pi8H0zsDd2P6Uqo2TK2pH8gNLSJtNLM2Db0v2QaAZ0pBQJXVjAn4gBuugeVDr7s63ZogpUIwWDg==",\n+      "version": "4.10.1",\n+      "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz",\n+      "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==",\n       "requires": {\n         "bn.js": "4.11.8",\n         "inherits": "2.0.3",\n@@ -245,6 +290,11 @@\n       "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",\n       "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="\n     },\n+    "autolinker": {\n+      "version": "0.15.3",\n+      "resolved": "https://registry.npmjs.org/autolinker/-/autolinker-0.15.3.tgz",\n+      "integrity": "sha1-NCQX2PLzRhsUzwkIjV7fh5HcmDI="\n+    },\n     "autoprefixer": {\n       "version": "6.7.7",\n       "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-6.7.7.tgz",\n@@ -278,6 +328,15 @@\n         "js-tokens": "3.0.2"\n       }\n     },\n+    "babel-runtime": {\n+      "version": "6.26.0",\n+      "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",\n+      "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",\n+      "requires": {\n+        "core-js": "2.5.3",\n+        "regenerator-runtime": "0.11.1"\n+      }\n+    },\n     "backo2": {\n       "version": "1.0.2",\n       "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",\n@@ -294,9 +353,9 @@\n       "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg="\n     },\n     "base64-js": {\n-      "version": "1.2.1",\n-      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz",\n-      "integrity": "sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw=="\n+      "version": "1.2.3",\n+      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.3.tgz",\n+      "integrity": "sha512-MsAhsUW1GxCdgYSO6tAfZrNapmUKk7mWx/k5mFY/A1gBtkaCaNapTg+FExCw1r9yeaZhqx/xPg43xgTFH6KL5w=="\n     },\n     "base64id": {\n       "version": "1.0.0",\n@@ -308,6 +367,12 @@\n       "resolved": "https://registry.npmjs.org/base64url/-/base64url-2.0.0.tgz",\n       "integrity": "sha1-6sFuA+oUOO/5Qj1puqNiYu0fcLs="\n     },\n+    "batch": {\n+      "version": "0.6.1",\n+      "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",\n+      "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=",\n+      "optional": true\n+    },\n     "bcrypt-pbkdf": {\n       "version": "1.0.1",\n       "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz",\n@@ -335,6 +400,25 @@\n         "callsite": "1.0.0"\n       }\n     },\n+    "bfj-node4": {\n+      "version": "5.2.1",\n+      "resolved": "https://registry.npmjs.org/bfj-node4/-/bfj-node4-5.2.1.tgz",\n+      "integrity": "sha512-w+OTPD/R0AvDVR/sy/uVUVeoCpEgUoYj9/1P2zB6mR1yx7F/ADzLX4nlvZ/91WWzGgdZnuLxWP/J89D7ZDt0DA==",\n+      "dev": true,\n+      "requires": {\n+        "bluebird": "3.5.1",\n+        "check-types": "7.3.0",\n+        "tryer": "1.0.0"\n+      },\n+      "dependencies": {\n+        "bluebird": {\n+          "version": "3.5.1",\n+          "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",\n+          "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==",\n+          "dev": true\n+        }\n+      }\n+    },\n     "big.js": {\n       "version": "3.1.3",\n       "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.1.3.tgz",\n@@ -428,6 +512,28 @@\n         }\n       }\n     },\n+    "bonjour": {\n+      "version": "3.5.0",\n+      "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz",\n+      "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=",\n+      "optional": true,\n+      "requires": {\n+        "array-flatten": "2.1.1",\n+        "deep-equal": "1.0.1",\n+        "dns-equal": "1.0.0",\n+        "dns-txt": "2.0.2",\n+        "multicast-dns": "6.2.3",\n+        "multicast-dns-service-types": "1.1.0"\n+      },\n+      "dependencies": {\n+        "array-flatten": {\n+          "version": "2.1.1",\n+          "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.1.tgz",\n+          "integrity": "sha1-Qmu52oQJDBg42BLIFQryCoMx4pY=",\n+          "optional": true\n+        }\n+      }\n+    },\n     "boom": {\n       "version": "2.10.1",\n       "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz",\n@@ -444,6 +550,19 @@\n         "chainsaw": "0.1.0"\n       }\n     },\n+    "bowser": {\n+      "version": "1.9.2",\n+      "resolved": "https://registry.npmjs.org/bowser/-/bowser-1.9.2.tgz",\n+      "integrity": "sha512-fuiANC1Bqbqa/S4gmvfCt7bGBmNELMsGZj4Wg3PrP6esP66Ttoj1JSlzFlXtHyduMv07kDNmDsX6VsMWT/MLGg=="\n+    },\n+    "brace": {\n+      "version": "0.7.0",\n+      "resolved": "https://registry.npmjs.org/brace/-/brace-0.7.0.tgz",\n+      "integrity": "sha1-kGUdpb1Ibtu0GIjex4r9zQc3WyE=",\n+      "requires": {\n+        "w3c-blob": "0.0.1"\n+      }\n+    },\n     "brace-expansion": {\n       "version": "1.1.8",\n       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz",\n@@ -558,7 +677,7 @@\n       "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",\n       "requires": {\n         "bn.js": "4.11.8",\n-        "randombytes": "2.0.5"\n+        "randombytes": "2.0.6"\n       }\n     },\n     "browserify-sign": {\n@@ -597,12 +716,17 @@\n       "resolved": "https://registry.npmjs.org/bson/-/bson-1.0.4.tgz",\n       "integrity": "sha1-k8ENOeqltYQVy8QFLz5T5WKwtyw="\n     },\n+    "btoa": {\n+      "version": "1.1.2",\n+      "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.1.2.tgz",\n+      "integrity": "sha1-PkC4FmP4HS3WWWpMtxSo3BbPq+A="\n+    },\n     "buffer": {\n       "version": "4.9.1",\n       "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",\n       "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=",\n       "requires": {\n-        "base64-js": "1.2.1",\n+        "base64-js": "1.2.3",\n         "ieee754": "1.1.8",\n         "isarray": "1.0.0"\n       }\n@@ -612,6 +736,12 @@\n       "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",\n       "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="\n     },\n+    "buffer-indexof": {\n+      "version": "1.1.1",\n+      "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz",\n+      "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==",\n+      "optional": true\n+    },\n     "buffer-xor": {\n       "version": "1.0.3",\n       "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",\n@@ -695,6 +825,24 @@\n       "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz",\n       "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk="\n     },\n+    "camelcase-keys": {\n+      "version": "2.1.0",\n+      "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",\n+      "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",\n+      "optional": true,\n+      "requires": {\n+        "camelcase": "2.1.1",\n+        "map-obj": "1.0.1"\n+      },\n+      "dependencies": {\n+        "camelcase": {\n+          "version": "2.1.1",\n+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz",\n+          "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=",\n+          "optional": true\n+        }\n+      }\n+    },\n     "caniuse-api": {\n       "version": "1.6.1",\n       "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.6.1.tgz",\n@@ -752,6 +900,12 @@\n         "supports-color": "2.0.0"\n       }\n     },\n+    "check-types": {\n+      "version": "7.3.0",\n+      "resolved": "https://registry.npmjs.org/check-types/-/check-types-7.3.0.tgz",\n+      "integrity": "sha1-Ro9XGkQ1wkJI9f0MsOjYfDw0Hn0=",\n+      "dev": true\n+    },\n     "chokidar": {\n       "version": "1.7.0",\n       "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz",\n@@ -785,6 +939,11 @@\n         "chalk": "1.1.3"\n       }\n     },\n+    "classnames": {\n+      "version": "2.2.5",\n+      "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.5.tgz",\n+      "integrity": "sha1-+zgB1FNGdknvNgPH1hoCvRKb3m0="\n+    },\n     "clear-require": {\n       "version": "2.0.0",\n       "resolved": "https://registry.npmjs.org/clear-require/-/clear-require-2.0.0.tgz",\n@@ -921,11 +1080,48 @@\n       "resolved": "https://registry.npmjs.org/common/-/common-0.2.5.tgz",\n       "integrity": "sha1-PHGC9ni9HjaBzVzDSMdZ/o3SI5Q="\n     },\n+    "commonmark": {\n+      "version": "0.28.1",\n+      "resolved": "https://registry.npmjs.org/commonmark/-/commonmark-0.28.1.tgz",\n+      "integrity": "sha1-Buq41SM4uDn6Gi11rwCF7tGxvq4=",\n+      "requires": {\n+        "entities": "1.1.1",\n+        "mdurl": "1.0.1",\n+        "minimist": "1.2.0",\n+        "string.prototype.repeat": "0.2.0"\n+      },\n+      "dependencies": {\n+        "minimist": {\n+          "version": "1.2.0",\n+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",\n+          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="\n+        }\n+      }\n+    },\n+    "commonmark-react-renderer": {\n+      "version": "4.3.4",\n+      "resolved": "https://registry.npmjs.org/commonmark-react-renderer/-/commonmark-react-renderer-4.3.4.tgz",\n+      "integrity": "sha512-+/Rzo3sI37NR8LaVdkUiqBH3+CEW75hc86shwY4E9eEERg78VCy4rSkaP/p7OG5bTvosUMkvhn5d1ZJ5iyt/ag==",\n+      "requires": {\n+        "lodash.assign": "4.2.0",\n+        "lodash.isplainobject": "4.0.6",\n+        "pascalcase": "0.1.1",\n+        "xss-filters": "1.2.7"\n+      }\n+    },\n     "component-bind": {\n       "version": "1.0.0",\n       "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz",\n       "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E="\n     },\n+    "component-clone": {\n+      "version": "0.2.2",\n+      "resolved": "https://registry.npmjs.org/component-clone/-/component-clone-0.2.2.tgz",\n+      "integrity": "sha1-x/WXmCKID62M+wliuikYbQYe4E8=",\n+      "requires": {\n+        "component-type": "1.1.0"\n+      }\n+    },\n     "component-emitter": {\n       "version": "1.1.2",\n       "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz",\n@@ -936,6 +1132,34 @@\n       "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz",\n       "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM="\n     },\n+    "component-raf": {\n+      "version": "1.2.0",\n+      "resolved": "https://registry.npmjs.org/component-raf/-/component-raf-1.2.0.tgz",\n+      "integrity": "sha1-srxy1D8bAU/eeks8RHx2S8c8y6o="\n+    },\n+    "component-tween": {\n+      "version": "1.2.0",\n+      "resolved": "https://registry.npmjs.org/component-tween/-/component-tween-1.2.0.tgz",\n+      "integrity": "sha1-zDnOXbqwW1KCX0HRlHY4oLAbK4o=",\n+      "requires": {\n+        "component-clone": "0.2.2",\n+        "component-emitter": "1.2.0",\n+        "component-type": "1.1.0",\n+        "ease-component": "1.0.0"\n+      },\n+      "dependencies": {\n+        "component-emitter": {\n+          "version": "1.2.0",\n+          "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.0.tgz",\n+          "integrity": "sha1-zNETqGOI0GSC0D3j/H35hSa6jv4="\n+        }\n+      }\n+    },\n+    "component-type": {\n+      "version": "1.1.0",\n+      "resolved": "https://registry.npmjs.org/component-type/-/component-type-1.1.0.tgz",\n+      "integrity": "sha1-lbZmqtU+XI0fK+E1xFtdSZGXwMU="\n+    },\n     "compressible": {\n       "version": "2.0.11",\n       "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.11.tgz",\n@@ -1002,6 +1226,12 @@\n       "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",\n       "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="\n     },\n+    "connect-history-api-fallback": {\n+      "version": "1.5.0",\n+      "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz",\n+      "integrity": "sha1-sGhzk0vF40T+9hGhlqb6rgruAVo=",\n+      "optional": true\n+    },\n     "console-browserify": {\n       "version": "1.1.0",\n       "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz",\n@@ -1052,6 +1282,11 @@\n       "integrity": "sha1-Qa1XsbVVlR7BcUEqgZQrHoIA00o=",\n       "dev": true\n     },\n+    "core-js": {\n+      "version": "2.5.3",\n+      "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.3.tgz",\n+      "integrity": "sha1-isw4NFgk8W2DZbfJtCWRaOjtYD4="\n+    },\n     "core-util-is": {\n       "version": "1.0.2",\n       "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",\n@@ -1074,7 +1309,7 @@\n         "cipher-base": "1.0.4",\n         "inherits": "2.0.3",\n         "ripemd160": "2.0.1",\n-        "sha.js": "2.4.9"\n+        "sha.js": "2.4.10"\n       }\n     },\n     "create-hmac": {\n@@ -1087,7 +1322,33 @@\n         "inherits": "2.0.3",\n         "ripemd160": "2.0.1",\n         "safe-buffer": "5.1.1",\n-        "sha.js": "2.4.9"\n+        "sha.js": "2.4.10"\n+      }\n+    },\n+    "create-react-class": {\n+      "version": "15.6.3",\n+      "resolved": "https://registry.npmjs.org/create-react-class/-/create-react-class-15.6.3.tgz",\n+      "integrity": "sha512-M+/3Q6E6DLO6Yx3OwrWjwHBnvfXXYA7W+dFjt/ZDBemHO1DDZhsalX/NUtnTYclN6GfnBDRh4qRHjcDHmlJBJg==",\n+      "requires": {\n+        "fbjs": "0.8.16",\n+        "loose-envify": "1.3.1",\n+        "object-assign": "4.1.1"\n+      }\n+    },\n+    "cross-fetch": {\n+      "version": "0.0.8",\n+      "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-0.0.8.tgz",\n+      "integrity": "sha1-Ae2U3EB98sAPGAf95wCnz6SKIFw=",\n+      "requires": {\n+        "node-fetch": "1.7.3",\n+        "whatwg-fetch": "2.0.3"\n+      },\n+      "dependencies": {\n+        "whatwg-fetch": {\n+          "version": "2.0.3",\n+          "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz",\n+          "integrity": "sha1-nITsLc9oGH/wC8ZOEnS0QhduHIQ="\n+        }\n       }\n     },\n     "cross-spawn": {\n@@ -1122,8 +1383,8 @@\n         "inherits": "2.0.3",\n         "pbkdf2": "3.0.14",\n         "public-encrypt": "4.0.0",\n-        "randombytes": "2.0.5",\n-        "randomfill": "1.0.3"\n+        "randombytes": "2.0.6",\n+        "randomfill": "1.0.4"\n       }\n     },\n     "css-color-names": {\n@@ -1131,6 +1392,14 @@\n       "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz",\n       "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA="\n     },\n+    "css-in-js-utils": {\n+      "version": "2.0.0",\n+      "resolved": "https://registry.npmjs.org/css-in-js-utils/-/css-in-js-utils-2.0.0.tgz",\n+      "integrity": "sha512-yuWmPMD9FLi50Xf3k8W8oO3WM1eVnxEGCldCLyfusQ+CgivFk0s23yst4ooW6tfxMuSa03S6uUEga9UhX6GRrA==",\n+      "requires": {\n+        "hyphenate-style-name": "1.0.2"\n+      }\n+    },\n     "css-loader": {\n       "version": "0.28.9",\n       "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-0.28.9.tgz",\n@@ -1162,6 +1431,11 @@\n         "regexpu-core": "1.0.0"\n       }\n     },\n+    "css.escape": {\n+      "version": "1.5.1",\n+      "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz",\n+      "integrity": "sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s="\n+    },\n     "cssesc": {\n       "version": "0.1.0",\n       "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-0.1.0.tgz",\n@@ -1240,6 +1514,15 @@\n       "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz",\n       "integrity": "sha1-gsGMJGH3QRTvFsE1IkrQuRRMoS8="\n     },\n+    "currently-unhandled": {\n+      "version": "0.4.1",\n+      "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",\n+      "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=",\n+      "optional": true,\n+      "requires": {\n+        "array-find-index": "1.0.2"\n+      }\n+    },\n     "cycle": {\n       "version": "1.0.3",\n       "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz",\n@@ -1250,7 +1533,7 @@\n       "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz",\n       "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=",\n       "requires": {\n-        "es5-ext": "0.10.37"\n+        "es5-ext": "0.10.39"\n       }\n     },\n     "d3": {\n@@ -1291,6 +1574,11 @@\n       "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",\n       "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="\n     },\n+    "deep-diff": {\n+      "version": "0.3.8",\n+      "resolved": "https://registry.npmjs.org/deep-diff/-/deep-diff-0.3.8.tgz",\n+      "integrity": "sha1-wB3mPvsO7JeYgB1Ax+Da4ltYLIQ="\n+    },\n     "deep-equal": {\n       "version": "1.0.1",\n       "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",\n@@ -1299,8 +1587,7 @@\n     "deep-extend": {\n       "version": "0.4.2",\n       "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz",\n-      "integrity": "sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8=",\n-      "optional": true\n+      "integrity": "sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8="\n     },\n     "deep-is": {\n       "version": "0.1.3",\n@@ -1308,11 +1595,34 @@\n       "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",\n       "dev": true\n     },\n+    "define-properties": {\n+      "version": "1.1.2",\n+      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz",\n+      "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=",\n+      "requires": {\n+        "foreach": "2.0.5",\n+        "object-keys": "1.0.11"\n+      }\n+    },\n     "defined": {\n       "version": "1.0.0",\n       "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",\n       "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM="\n     },\n+    "del": {\n+      "version": "3.0.0",\n+      "resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz",\n+      "integrity": "sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=",\n+      "optional": true,\n+      "requires": {\n+        "globby": "6.1.0",\n+        "is-path-cwd": "1.0.0",\n+        "is-path-in-cwd": "1.0.0",\n+        "p-map": "1.2.0",\n+        "pify": "3.0.0",\n+        "rimraf": "2.6.1"\n+      }\n+    },\n     "delayed-stream": {\n       "version": "1.0.0",\n       "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",\n@@ -1349,6 +1659,12 @@\n       "integrity": "sha1-ca1dIEvxempsqPRQxhRUBm70YeE=",\n       "optional": true\n     },\n+    "detect-node": {\n+      "version": "2.0.3",\n+      "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.3.tgz",\n+      "integrity": "sha1-ogM8CcyOFY03dI+951B4Mr1s4Sc=",\n+      "optional": true\n+    },\n     "diff": {\n       "version": "1.4.0",\n       "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz",\n@@ -1362,7 +1678,7 @@\n       "requires": {\n         "bn.js": "4.11.8",\n         "miller-rabin": "4.0.1",\n-        "randombytes": "2.0.5"\n+        "randombytes": "2.0.6"\n       }\n     },\n     "director": {\n@@ -1370,16 +1686,84 @@\n       "resolved": "https://registry.npmjs.org/director/-/director-1.2.7.tgz",\n       "integrity": "sha1-v9N0EHX9f7GlsuE2WMX0vsd3NvM="\n     },\n+    "dns-equal": {\n+      "version": "1.0.0",\n+      "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",\n+      "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=",\n+      "optional": true\n+    },\n+    "dns-packet": {\n+      "version": "1.3.1",\n+      "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz",\n+      "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==",\n+      "optional": true,\n+      "requires": {\n+        "ip": "1.1.5",\n+        "safe-buffer": "5.1.1"\n+      }\n+    },\n+    "dns-txt": {\n+      "version": "2.0.2",\n+      "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz",\n+      "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=",\n+      "optional": true,\n+      "requires": {\n+        "buffer-indexof": "1.1.1"\n+      }\n+    },\n+    "dom-serializer": {\n+      "version": "0.1.0",\n+      "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz",\n+      "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=",\n+      "requires": {\n+        "domelementtype": "1.1.3",\n+        "entities": "1.1.1"\n+      },\n+      "dependencies": {\n+        "domelementtype": {\n+          "version": "1.1.3",\n+          "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz",\n+          "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs="\n+        }\n+      }\n+    },\n     "domain-browser": {\n-      "version": "1.1.7",\n-      "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz",\n-      "integrity": "sha1-hnqksJP6oF8d4IwG9NeyH9+GmLw="\n+      "version": "1.2.0",\n+      "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz",\n+      "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA=="\n+    },\n+    "domelementtype": {\n+      "version": "1.3.0",\n+      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz",\n+      "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI="\n+    },\n+    "domhandler": {\n+      "version": "2.4.1",\n+      "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.1.tgz",\n+      "integrity": "sha1-iS5HAAqZvlW783dP/qBWHYh5wlk=",\n+      "requires": {\n+        "domelementtype": "1.3.0"\n+      }\n+    },\n+    "domutils": {\n+      "version": "1.7.0",\n+      "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",\n+      "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==",\n+      "requires": {\n+        "dom-serializer": "0.1.0",\n+        "domelementtype": "1.3.0"\n+      }\n     },\n     "duplexer": {\n       "version": "0.1.1",\n       "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",\n       "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E="\n     },\n+    "ease-component": {\n+      "version": "1.0.0",\n+      "resolved": "https://registry.npmjs.org/ease-component/-/ease-component-1.0.0.tgz",\n+      "integrity": "sha1-s3VybbC1sEWVt3RAOW/sfapdd8k="\n+    },\n     "ecc-jsbn": {\n       "version": "0.1.1",\n       "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",\n@@ -1432,11 +1816,24 @@\n       "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz",\n       "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k="\n     },\n+    "encode-3986": {\n+      "version": "1.0.0",\n+      "resolved": "https://registry.npmjs.org/encode-3986/-/encode-3986-1.0.0.tgz",\n+      "integrity": "sha1-lA1RSY+HQa3hhLda0UObMXwMemA="\n+    },\n     "encodeurl": {\n       "version": "1.0.1",\n       "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz",\n       "integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA="\n     },\n+    "encoding": {\n+      "version": "0.1.12",\n+      "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",\n+      "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=",\n+      "requires": {\n+        "iconv-lite": "0.4.19"\n+      }\n+    },\n     "engine.io": {\n       "version": "1.8.4",\n       "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-1.8.4.tgz",\n@@ -1537,12 +1934,17 @@\n         "tapable": "0.2.8"\n       }\n     },\n+    "entities": {\n+      "version": "1.1.1",\n+      "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz",\n+      "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA="\n+    },\n     "errno": {\n-      "version": "0.1.4",\n-      "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.4.tgz",\n-      "integrity": "sha1-uJbiOp5ei6M4cfyZar02NfyaHH0=",\n+      "version": "0.1.7",\n+      "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz",\n+      "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==",\n       "requires": {\n-        "prr": "0.0.0"\n+        "prr": "1.0.1"\n       }\n     },\n     "error-ex": {\n@@ -1562,10 +1964,32 @@\n         "escape-html": "1.0.3"\n       }\n     },\n+    "es-abstract": {\n+      "version": "1.10.0",\n+      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.10.0.tgz",\n+      "integrity": "sha512-/uh/DhdqIOSkAWifU+8nG78vlQxdLckUdI/sPgy0VhuXi2qJ7T8czBmqIYtLQVpCIFYafChnsRsB5pyb1JdmCQ==",\n+      "requires": {\n+        "es-to-primitive": "1.1.1",\n+        "function-bind": "1.1.1",\n+        "has": "1.0.1",\n+        "is-callable": "1.1.3",\n+        "is-regex": "1.0.4"\n+      }\n+    },\n+    "es-to-primitive": {\n+      "version": "1.1.1",\n+      "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz",\n+      "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=",\n+      "requires": {\n+        "is-callable": "1.1.3",\n+        "is-date-object": "1.0.1",\n+        "is-symbol": "1.0.1"\n+      }\n+    },\n     "es5-ext": {\n-      "version": "0.10.37",\n-      "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.37.tgz",\n-      "integrity": "sha1-DudB0Ui4AGm6J9AgOTdWryV978M=",\n+      "version": "0.10.39",\n+      "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.39.tgz",\n+      "integrity": "sha512-AlaXZhPHl0po/uxMx1tyrlt1O86M6D5iVaDH8UgLfgek4kXTX6vzsRfJQWC2Ku+aG8pkw1XWzh9eTkwfVrsD5g==",\n       "requires": {\n         "es6-iterator": "2.0.3",\n         "es6-symbol": "3.1.1"\n@@ -1577,7 +2001,7 @@\n       "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=",\n       "requires": {\n         "d": "1.0.0",\n-        "es5-ext": "0.10.37",\n+        "es5-ext": "0.10.39",\n         "es6-symbol": "3.1.1"\n       }\n     },\n@@ -1587,7 +2011,7 @@\n       "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=",\n       "requires": {\n         "d": "1.0.0",\n-        "es5-ext": "0.10.37",\n+        "es5-ext": "0.10.39",\n         "es6-iterator": "2.0.3",\n         "es6-set": "0.1.5",\n         "es6-symbol": "3.1.1",\n@@ -1600,7 +2024,7 @@\n       "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=",\n       "requires": {\n         "d": "1.0.0",\n-        "es5-ext": "0.10.37",\n+        "es5-ext": "0.10.39",\n         "es6-iterator": "2.0.3",\n         "es6-symbol": "3.1.1",\n         "event-emitter": "0.3.5"\n@@ -1612,7 +2036,7 @@\n       "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=",\n       "requires": {\n         "d": "1.0.0",\n-        "es5-ext": "0.10.37"\n+        "es5-ext": "0.10.39"\n       }\n     },\n     "es6-weak-map": {\n@@ -1621,7 +2045,7 @@\n       "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=",\n       "requires": {\n         "d": "1.0.0",\n-        "es5-ext": "0.10.37",\n+        "es5-ext": "0.10.39",\n         "es6-iterator": "2.0.3",\n         "es6-symbol": "3.1.1"\n       }\n@@ -1713,7 +2137,7 @@\n       "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=",\n       "requires": {\n         "d": "1.0.0",\n-        "es5-ext": "0.10.37"\n+        "es5-ext": "0.10.39"\n       }\n     },\n     "event-stream": {\n@@ -1735,11 +2159,26 @@\n       "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz",\n       "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas="\n     },\n+    "eventemitter3": {\n+      "version": "1.2.0",\n+      "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz",\n+      "integrity": "sha1-HIaZHYFq0eUEdQ5zh0Ik7PO+xQg=",\n+      "optional": true\n+    },\n     "events": {\n       "version": "1.1.1",\n       "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",\n       "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ="\n     },\n+    "eventsource": {\n+      "version": "0.1.6",\n+      "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-0.1.6.tgz",\n+      "integrity": "sha1-Cs7ehJ7X3RzMMsgRuxG5RNTykjI=",\n+      "optional": true,\n+      "requires": {\n+        "original": "1.0.0"\n+      }\n+    },\n     "evp_bytestokey": {\n       "version": "1.0.3",\n       "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",\n@@ -1790,6 +2229,20 @@\n         "repeat-string": "0.2.2"\n       }\n     },\n+    "expect": {\n+      "version": "1.20.2",\n+      "resolved": "https://registry.npmjs.org/expect/-/expect-1.20.2.tgz",\n+      "integrity": "sha1-1Fj+TFYAQDa64yMkFqP2Nh8E+WU=",\n+      "requires": {\n+        "define-properties": "1.1.2",\n+        "has": "1.0.1",\n+        "is-equal": "1.5.5",\n+        "is-regex": "1.0.4",\n+        "object-inspect": "1.5.0",\n+        "object-keys": "1.0.11",\n+        "tmatch": "2.0.1"\n+      }\n+    },\n     "expose-loader": {\n       "version": "0.7.4",\n       "resolved": "https://registry.npmjs.org/expose-loader/-/expose-loader-0.7.4.tgz",\n@@ -1944,6 +2397,11 @@\n       "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz",\n       "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8="\n     },\n+    "fast-json-patch": {\n+      "version": "1.2.2",\n+      "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-1.2.2.tgz",\n+      "integrity": "sha1-03fZfGkR290qHIC/rNoEik+Du/k="\n+    },\n     "fast-json-stable-stringify": {\n       "version": "2.0.0",\n       "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",\n@@ -1960,6 +2418,36 @@\n       "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.1.tgz",\n       "integrity": "sha1-0eJkOzipTXWDtHkGDmxK/8lAcfg="\n     },\n+    "faye-websocket": {\n+      "version": "0.10.0",\n+      "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz",\n+      "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=",\n+      "optional": true,\n+      "requires": {\n+        "websocket-driver": "0.7.0"\n+      }\n+    },\n+    "fbjs": {\n+      "version": "0.8.16",\n+      "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.16.tgz",\n+      "integrity": "sha1-XmdDL1UNxBtXK/VYR7ispk5TN9s=",\n+      "requires": {\n+        "core-js": "1.2.7",\n+        "isomorphic-fetch": "2.2.1",\n+        "loose-envify": "1.3.1",\n+        "object-assign": "4.1.1",\n+        "promise": "7.3.1",\n+        "setimmediate": "1.0.5",\n+        "ua-parser-js": "0.7.17"\n+      },\n+      "dependencies": {\n+        "core-js": {\n+          "version": "1.2.7",\n+          "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",\n+          "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY="\n+        }\n+      }\n+    },\n     "file-loader": {\n       "version": "1.1.6",\n       "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-1.1.6.tgz",\n@@ -1974,7 +2462,20 @@\n           "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz",\n           "integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=",\n           "requires": {\n-            "ajv": "5.5.1"\n+            "ajv": "5.5.2"\n+          },\n+          "dependencies": {\n+            "ajv": {\n+              "version": "5.5.2",\n+              "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",\n+              "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",\n+              "requires": {\n+                "co": "4.6.0",\n+                "fast-deep-equal": "1.0.0",\n+                "fast-json-stable-stringify": "2.0.0",\n+                "json-schema-traverse": "0.3.1"\n+              }\n+            }\n           }\n         }\n       }\n@@ -1985,9 +2486,9 @@\n       "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY="\n     },\n     "filesize": {\n-      "version": "3.5.11",\n-      "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.5.11.tgz",\n-      "integrity": "sha512-ZH7loueKBoDb7yG9esn1U+fgq7BzlzW6NRi5/rMdxIZ05dj7GFD/Xc5rq2CDt5Yq86CyfSYVyx4242QQNZbx1g==",\n+      "version": "3.6.0",\n+      "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.0.tgz",\n+      "integrity": "sha512-g5OWtoZWcPI56js1DFhIEqyG9tnu/7sG3foHwgS9KGYFMfsYguI3E+PRVCmtmE96VajQIEMRU2OhN+ME589Gdw==",\n       "dev": true\n     },\n     "fill-range": {\n@@ -2047,11 +2548,12 @@\n       }\n     },\n     "find-up": {\n-      "version": "2.1.0",\n-      "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",\n-      "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",\n+      "version": "1.1.2",\n+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",\n+      "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",\n       "requires": {\n-        "locate-path": "2.0.0"\n+        "path-exists": "2.1.0",\n+        "pinkie-promise": "2.0.1"\n       }\n     },\n     "flatiron": {\n@@ -2099,6 +2601,11 @@\n         "for-in": "1.0.2"\n       }\n     },\n+    "foreach": {\n+      "version": "2.0.5",\n+      "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz",\n+      "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k="\n+    },\n     "forever": {\n       "version": "0.15.3",\n       "resolved": "https://registry.npmjs.org/forever/-/forever-0.15.3.tgz",\n@@ -2165,7 +2672,7 @@\n           "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz",\n           "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==",\n           "requires": {\n-            "lodash": "4.17.4"\n+            "lodash": "4.17.5"\n           }\n         }\n       }\n@@ -2429,11 +2936,22 @@\n       "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz",\n       "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U="\n     },\n+    "get-stdin": {\n+      "version": "4.0.1",\n+      "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",\n+      "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=",\n+      "optional": true\n+    },\n     "get-stream": {\n       "version": "3.0.0",\n       "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",\n       "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="\n     },\n+    "getbase": {\n+      "version": "2.8.2",\n+      "resolved": "https://registry.npmjs.org/getbase/-/getbase-2.8.2.tgz",\n+      "integrity": "sha1-ytdX/7K19THTKtb6xIceYmpMCcs="\n+    },\n     "getpass": {\n       "version": "0.1.7",\n       "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",\n@@ -2479,6 +2997,27 @@\n         "is-glob": "2.0.1"\n       }\n     },\n+    "globby": {\n+      "version": "6.1.0",\n+      "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",\n+      "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=",\n+      "optional": true,\n+      "requires": {\n+        "array-union": "1.0.2",\n+        "glob": "7.1.2",\n+        "object-assign": "4.1.1",\n+        "pify": "2.3.0",\n+        "pinkie-promise": "2.0.1"\n+      },\n+      "dependencies": {\n+        "pify": {\n+          "version": "2.3.0",\n+          "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",\n+          "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",\n+          "optional": true\n+        }\n+      }\n+    },\n     "graceful-fs": {\n       "version": "4.1.11",\n       "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",\n@@ -2497,14 +3036,21 @@\n       "dev": true\n     },\n     "gzip-size": {\n-      "version": "3.0.0",\n-      "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-3.0.0.tgz",\n-      "integrity": "sha1-VGGI6b3DN/Zzdy+BZgRks4nc5SA=",\n+      "version": "4.1.0",\n+      "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-4.1.0.tgz",\n+      "integrity": "sha1-iuCWJX6r59acRb4rZ8RIEk/7UXw=",\n       "dev": true,\n       "requires": {\n-        "duplexer": "0.1.1"\n+        "duplexer": "0.1.1",\n+        "pify": "3.0.0"\n       }\n     },\n+    "handle-thing": {\n+      "version": "1.2.5",\n+      "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-1.2.5.tgz",\n+      "integrity": "sha1-/Xqtcmvxpf0W38KbL3pmAdJxOcQ=",\n+      "optional": true\n+    },\n     "handlebars": {\n       "version": "4.0.10",\n       "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.10.tgz",\n@@ -2661,11 +3207,28 @@\n       "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",\n       "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0="\n     },\n+    "hoist-non-react-statics": {\n+      "version": "1.2.0",\n+      "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz",\n+      "integrity": "sha1-qkSM8JhtVcxAdzsXF0t90GbLfPs="\n+    },\n     "hosted-git-info": {\n       "version": "2.5.0",\n       "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz",\n       "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg=="\n     },\n+    "hpack.js": {\n+      "version": "2.1.6",\n+      "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz",\n+      "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=",\n+      "optional": true,\n+      "requires": {\n+        "inherits": "2.0.3",\n+        "obuf": "1.1.1",\n+        "readable-stream": "2.3.3",\n+        "wbuf": "1.7.2"\n+      }\n+    },\n     "html-comment-regex": {\n       "version": "1.1.1",\n       "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.1.tgz",\n@@ -2680,6 +3243,31 @@\n         "whatwg-encoding": "1.0.1"\n       }\n     },\n+    "html-entities": {\n+      "version": "1.2.1",\n+      "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz",\n+      "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=",\n+      "optional": true\n+    },\n+    "htmlparser2": {\n+      "version": "3.9.2",\n+      "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz",\n+      "integrity": "sha1-G9+HrMoPP55T+k/M6w9LTLsAszg=",\n+      "requires": {\n+        "domelementtype": "1.3.0",\n+        "domhandler": "2.4.1",\n+        "domutils": "1.7.0",\n+        "entities": "1.1.1",\n+        "inherits": "2.0.3",\n+        "readable-stream": "2.3.3"\n+      }\n+    },\n+    "http-deceiver": {\n+      "version": "1.2.7",\n+      "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz",\n+      "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=",\n+      "optional": true\n+    },\n     "http-errors": {\n       "version": "1.6.2",\n       "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz",\n@@ -2691,6 +3279,50 @@\n         "statuses": "1.4.0"\n       }\n     },\n+    "http-parser-js": {\n+      "version": "0.4.10",\n+      "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.10.tgz",\n+      "integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q="\n+    },\n+    "http-proxy": {\n+      "version": "1.16.2",\n+      "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.16.2.tgz",\n+      "integrity": "sha1-Bt/ykpUr9k2+hHH6nfcwZtTzd0I=",\n+      "optional": true,\n+      "requires": {\n+        "eventemitter3": "1.2.0",\n+        "requires-port": "1.0.0"\n+      }\n+    },\n+    "http-proxy-middleware": {\n+      "version": "0.17.4",\n+      "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.17.4.tgz",\n+      "integrity": "sha1-ZC6ISIUdZvCdTxJJEoRtuutBuDM=",\n+      "optional": true,\n+      "requires": {\n+        "http-proxy": "1.16.2",\n+        "is-glob": "3.1.0",\n+        "lodash": "4.17.5",\n+        "micromatch": "2.3.11"\n+      },\n+      "dependencies": {\n+        "is-extglob": {\n+          "version": "2.1.1",\n+          "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",\n+          "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",\n+          "optional": true\n+        },\n+        "is-glob": {\n+          "version": "3.1.0",\n+          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",\n+          "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",\n+          "optional": true,\n+          "requires": {\n+            "is-extglob": "2.1.1"\n+          }\n+        }\n+      }\n+    },\n     "http-signature": {\n       "version": "0.11.0",\n       "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.11.0.tgz",\n@@ -2706,6 +3338,11 @@\n       "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",\n       "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM="\n     },\n+    "hyphenate-style-name": {\n+      "version": "1.0.2",\n+      "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz",\n+      "integrity": "sha1-MRYKNpMK2vH8BMYHT360FGXU7Es="\n+    },\n     "i": {\n       "version": "0.3.6",\n       "resolved": "https://registry.npmjs.org/i/-/i-0.3.6.tgz",\n@@ -2792,6 +3429,25 @@\n       "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz",\n       "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q="\n     },\n+    "immediate": {\n+      "version": "3.0.6",\n+      "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",\n+      "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps="\n+    },\n+    "immutable": {\n+      "version": "3.8.2",\n+      "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz",\n+      "integrity": "sha1-wkOZUUVbs5kT2vKBN28VMOEErfM="\n+    },\n+    "indent-string": {\n+      "version": "2.1.0",\n+      "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",\n+      "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=",\n+      "optional": true,\n+      "requires": {\n+        "repeating": "2.0.1"\n+      }\n+    },\n     "indexes-of": {\n       "version": "1.0.1",\n       "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz",\n@@ -2821,16 +3477,48 @@\n       "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz",\n       "integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4="\n     },\n+    "inline-style-prefixer": {\n+      "version": "3.0.8",\n+      "resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-3.0.8.tgz",\n+      "integrity": "sha1-hVG45bTVcyROZqNLBPfTIHaitTQ=",\n+      "requires": {\n+        "bowser": "1.9.2",\n+        "css-in-js-utils": "2.0.0"\n+      }\n+    },\n+    "internal-ip": {\n+      "version": "1.2.0",\n+      "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-1.2.0.tgz",\n+      "integrity": "sha1-rp+/k7mEh4eF1QqN4bNWlWBYz1w=",\n+      "optional": true,\n+      "requires": {\n+        "meow": "3.7.0"\n+      }\n+    },\n     "interpret": {\n       "version": "1.1.0",\n       "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz",\n       "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ="\n     },\n+    "invariant": {\n+      "version": "2.2.2",\n+      "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz",\n+      "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=",\n+      "requires": {\n+        "loose-envify": "1.3.1"\n+      }\n+    },\n     "invert-kv": {\n       "version": "1.0.0",\n       "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",\n       "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY="\n     },\n+    "ip": {\n+      "version": "1.1.5",\n+      "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",\n+      "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=",\n+      "optional": true\n+    },\n     "ipaddr.js": {\n       "version": "1.5.2",\n       "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.5.2.tgz",\n@@ -2846,6 +3534,14 @@\n       "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",\n       "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0="\n     },\n+    "is-arrow-function": {\n+      "version": "2.0.3",\n+      "resolved": "https://registry.npmjs.org/is-arrow-function/-/is-arrow-function-2.0.3.tgz",\n+      "integrity": "sha1-Kb4sLY2UUIUri7r7Y1unuNjofsI=",\n+      "requires": {\n+        "is-callable": "1.1.3"\n+      }\n+    },\n     "is-binary-path": {\n       "version": "1.0.1",\n       "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",\n@@ -2854,6 +3550,11 @@\n         "binary-extensions": "1.8.0"\n       }\n     },\n+    "is-boolean-object": {\n+      "version": "1.0.0",\n+      "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.0.0.tgz",\n+      "integrity": "sha1-mPiygDBoQhmpXzdc+9iM40Bd/5M="\n+    },\n     "is-buffer": {\n       "version": "1.1.5",\n       "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz",\n@@ -2867,11 +3568,39 @@\n         "builtin-modules": "1.1.1"\n       }\n     },\n+    "is-callable": {\n+      "version": "1.1.3",\n+      "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz",\n+      "integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI="\n+    },\n+    "is-date-object": {\n+      "version": "1.0.1",\n+      "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",\n+      "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY="\n+    },\n     "is-dotfile": {\n       "version": "1.0.3",\n       "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz",\n       "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE="\n     },\n+    "is-equal": {\n+      "version": "1.5.5",\n+      "resolved": "https://registry.npmjs.org/is-equal/-/is-equal-1.5.5.tgz",\n+      "integrity": "sha1-XoXxlX4FKIMkf+s4aWWju6Ffuz0=",\n+      "requires": {\n+        "has": "1.0.1",\n+        "is-arrow-function": "2.0.3",\n+        "is-boolean-object": "1.0.0",\n+        "is-callable": "1.1.3",\n+        "is-date-object": "1.0.1",\n+        "is-generator-function": "1.0.7",\n+        "is-number-object": "1.0.3",\n+        "is-regex": "1.0.4",\n+        "is-string": "1.0.4",\n+        "is-symbol": "1.0.1",\n+        "object.entries": "1.0.4"\n+      }\n+    },\n     "is-equal-shallow": {\n       "version": "0.1.3",\n       "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz",\n@@ -2890,6 +3619,15 @@\n       "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",\n       "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA="\n     },\n+    "is-finite": {\n+      "version": "1.0.2",\n+      "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz",\n+      "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=",\n+      "optional": true,\n+      "requires": {\n+        "number-is-nan": "1.0.1"\n+      }\n+    },\n     "is-fullwidth-code-point": {\n       "version": "1.0.0",\n       "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",\n@@ -2898,6 +3636,11 @@\n         "number-is-nan": "1.0.1"\n       }\n     },\n+    "is-generator-function": {\n+      "version": "1.0.7",\n+      "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.7.tgz",\n+      "integrity": "sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw=="\n+    },\n     "is-glob": {\n       "version": "2.0.1",\n       "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",\n@@ -2922,6 +3665,35 @@\n       "resolved": "https://registry.npmjs.org/is-number/-/is-number-0.1.1.tgz",\n       "integrity": "sha1-aaevEWlj1HIG7JvZtIoUIW8eOAY="\n     },\n+    "is-number-object": {\n+      "version": "1.0.3",\n+      "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.3.tgz",\n+      "integrity": "sha1-8mWrian0RQNO9q/xWo8AsA9VF5k="\n+    },\n+    "is-path-cwd": {\n+      "version": "1.0.0",\n+      "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz",\n+      "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=",\n+      "optional": true\n+    },\n+    "is-path-in-cwd": {\n+      "version": "1.0.0",\n+      "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz",\n+      "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=",\n+      "optional": true,\n+      "requires": {\n+        "is-path-inside": "1.0.1"\n+      }\n+    },\n+    "is-path-inside": {\n+      "version": "1.0.1",\n+      "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz",\n+      "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=",\n+      "optional": true,\n+      "requires": {\n+        "path-is-inside": "1.0.2"\n+      }\n+    },\n     "is-plain-obj": {\n       "version": "1.1.0",\n       "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",\n@@ -2937,16 +3709,34 @@\n       "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz",\n       "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU="\n     },\n+    "is-promise": {\n+      "version": "2.1.0",\n+      "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",\n+      "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o="\n+    },\n     "is-property": {\n       "version": "1.0.2",\n       "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",\n       "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ="\n     },\n+    "is-regex": {\n+      "version": "1.0.4",\n+      "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",\n+      "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=",\n+      "requires": {\n+        "has": "1.0.1"\n+      }\n+    },\n     "is-stream": {\n       "version": "1.1.0",\n       "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",\n       "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="\n     },\n+    "is-string": {\n+      "version": "1.0.4",\n+      "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.4.tgz",\n+      "integrity": "sha1-zDqbaYV9Yh6WNyWiTK7shzuCbmQ="\n+    },\n     "is-svg": {\n       "version": "2.1.0",\n       "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-2.1.0.tgz",\n@@ -2955,21 +3745,26 @@\n         "html-comment-regex": "1.1.1"\n       }\n     },\n+    "is-symbol": {\n+      "version": "1.0.1",\n+      "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz",\n+      "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI="\n+    },\n     "is-typedarray": {\n       "version": "1.0.0",\n       "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",\n       "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="\n     },\n+    "is-utf8": {\n+      "version": "0.2.1",\n+      "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",\n+      "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI="\n+    },\n     "isarray": {\n       "version": "1.0.0",\n       "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",\n       "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="\n     },\n-    "isemail": {\n-      "version": "1.2.0",\n-      "resolved": "https://registry.npmjs.org/isemail/-/isemail-1.2.0.tgz",\n-      "integrity": "sha1-vgPfjMPineTSxd9lASY/H6RZXpo="\n-    },\n     "isexe": {\n       "version": "2.0.0",\n       "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",\n@@ -2983,6 +3778,23 @@\n         "isarray": "1.0.0"\n       }\n     },\n+    "isomorphic-fetch": {\n+      "version": "2.2.1",\n+      "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz",\n+      "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=",\n+      "requires": {\n+        "node-fetch": "1.7.3",\n+        "whatwg-fetch": "0.11.1"\n+      }\n+    },\n+    "isomorphic-form-data": {\n+      "version": "0.0.1",\n+      "resolved": "https://registry.npmjs.org/isomorphic-form-data/-/isomorphic-form-data-0.0.1.tgz",\n+      "integrity": "sha1-Am9ifgMrDNhBPsyHVZKLlKRosGI=",\n+      "requires": {\n+        "form-data": "1.0.1"\n+      }\n+    },\n     "isstream": {\n       "version": "0.1.2",\n       "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",\n@@ -3059,17 +3871,6 @@\n         }\n       }\n     },\n-    "joi": {\n-      "version": "6.10.1",\n-      "resolved": "https://registry.npmjs.org/joi/-/joi-6.10.1.tgz",\n-      "integrity": "sha1-TVDDGAeRIgAP5fFq8f+OGRe3fgY=",\n-      "requires": {\n-        "hoek": "2.16.3",\n-        "isemail": "1.2.0",\n-        "moment": "2.19.3",\n-        "topo": "1.1.0"\n-      }\n-    },\n     "jquery": {\n       "version": "2.2.4",\n       "resolved": "https://registry.npmjs.org/jquery/-/jquery-2.2.4.tgz",\n@@ -3107,7 +3908,6 @@\n       "version": "3.9.0",\n       "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.9.0.tgz",\n       "integrity": "sha512-0LoUNELX4S+iofCT8f4uEHIiRBR+c2AINyC8qRWfC6QNruLtxVZRJaPcu/xwMgFIgDxF25tGHaDjvxzJCNE9yw==",\n-      "dev": true,\n       "requires": {\n         "argparse": "1.0.9",\n         "esprima": "4.0.0"\n@@ -3116,8 +3916,7 @@\n         "esprima": {\n           "version": "4.0.0",\n           "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz",\n-          "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==",\n-          "dev": true\n+          "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw=="\n         }\n       }\n     },\n@@ -3217,15 +4016,27 @@\n       "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk="\n     },\n     "jsonwebtoken": {\n-      "version": "7.4.3",\n-      "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-7.4.3.tgz",\n-      "integrity": "sha1-d/UCHeBYtgWheD+hKD6ZgS5kVjg=",\n+      "version": "8.1.1",\n+      "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.1.1.tgz",\n+      "integrity": "sha512-+ijVOtfLMlCII8LJkvabaKX3+8tGrGjiCTfzoed2D1b/ebKTO1hIYBQUJHbd9dJ9Fa4kH+dhYEd1qDwyzDLUUw==",\n       "requires": {\n-        "joi": "6.10.1",\n         "jws": "3.1.4",\n+        "lodash.includes": "4.3.0",\n+        "lodash.isboolean": "3.0.3",\n+        "lodash.isinteger": "4.0.4",\n+        "lodash.isnumber": "3.0.3",\n+        "lodash.isplainobject": "4.0.6",\n+        "lodash.isstring": "4.0.1",\n         "lodash.once": "4.1.1",\n-        "ms": "2.0.0",\n+        "ms": "2.1.1",\n         "xtend": "4.0.1"\n+      },\n+      "dependencies": {\n+        "ms": {\n+          "version": "2.1.1",\n+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",\n+          "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="\n+        }\n       }\n     },\n     "jsprim": {\n@@ -3303,15 +4114,31 @@\n         "type-check": "0.3.2"\n       }\n     },\n+    "lie": {\n+      "version": "3.2.0",\n+      "resolved": "https://registry.npmjs.org/lie/-/lie-3.2.0.tgz",\n+      "integrity": "sha512-VhoCwA12FP8oixbhyjg1leSNePhF3y966Xdo3o0wAMQUoQ4g9a9vt3o6I3ob3PrNx4MCBJtHXEY+UpVZKhiscQ==",\n+      "requires": {\n+        "immediate": "3.0.6"\n+      }\n+    },\n     "load-json-file": {\n-      "version": "2.0.0",\n-      "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",\n-      "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=",\n+      "version": "1.1.0",\n+      "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",\n+      "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",\n       "requires": {\n         "graceful-fs": "4.1.11",\n         "parse-json": "2.2.0",\n         "pify": "2.3.0",\n-        "strip-bom": "3.0.0"\n+        "pinkie-promise": "2.0.1",\n+        "strip-bom": "2.0.0"\n+      },\n+      "dependencies": {\n+        "pify": {\n+          "version": "2.3.0",\n+          "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",\n+          "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="\n+        }\n       }\n     },\n     "loader-runner": {\n@@ -3336,12 +4163,24 @@\n       "requires": {\n         "p-locate": "2.0.0",\n         "path-exists": "3.0.0"\n+      },\n+      "dependencies": {\n+        "path-exists": {\n+          "version": "3.0.0",\n+          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",\n+          "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="\n+        }\n       }\n     },\n     "lodash": {\n-      "version": "4.17.4",\n-      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",\n-      "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4="\n+      "version": "4.17.5",\n+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz",\n+      "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw=="\n+    },\n+    "lodash-es": {\n+      "version": "4.17.5",\n+      "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.5.tgz",\n+      "integrity": "sha512-Ez3ONp3TK9gX1HYKp6IhetcVybD+2F+Yp6GS9dfH8ue6EOCEzQtQEh4K0FYWBP9qLv+lzeQAYXw+3ySfxyZqkw=="\n     },\n     "lodash._baseassign": {\n       "version": "3.2.0",\n@@ -3368,8 +4207,7 @@\n     "lodash._getnative": {\n       "version": "3.9.1",\n       "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz",\n-      "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=",\n-      "dev": true\n+      "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U="\n     },\n     "lodash._isiterateecall": {\n       "version": "3.0.9",\n@@ -3377,11 +4215,21 @@\n       "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=",\n       "dev": true\n     },\n+    "lodash.assign": {\n+      "version": "4.2.0",\n+      "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz",\n+      "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc="\n+    },\n     "lodash.camelcase": {\n       "version": "4.3.0",\n       "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",\n       "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY="\n     },\n+    "lodash.clonedeep": {\n+      "version": "4.5.0",\n+      "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",\n+      "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8="\n+    },\n     "lodash.create": {\n       "version": "3.1.1",\n       "resolved": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz",\n@@ -3393,23 +4241,55 @@\n         "lodash._isiterateecall": "3.0.9"\n       }\n     },\n+    "lodash.escaperegexp": {\n+      "version": "4.1.2",\n+      "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz",\n+      "integrity": "sha1-ZHYsSGGAglGKw99Mz11YhtriA0c="\n+    },\n+    "lodash.includes": {\n+      "version": "4.3.0",\n+      "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",\n+      "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8="\n+    },\n     "lodash.isarguments": {\n       "version": "3.1.0",\n       "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",\n-      "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=",\n-      "dev": true\n+      "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo="\n     },\n     "lodash.isarray": {\n       "version": "3.0.4",\n       "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz",\n-      "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=",\n-      "dev": true\n+      "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U="\n+    },\n+    "lodash.isboolean": {\n+      "version": "3.0.3",\n+      "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",\n+      "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY="\n+    },\n+    "lodash.isinteger": {\n+      "version": "4.0.4",\n+      "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",\n+      "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M="\n+    },\n+    "lodash.isnumber": {\n+      "version": "3.0.3",\n+      "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",\n+      "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w="\n+    },\n+    "lodash.isplainobject": {\n+      "version": "4.0.6",\n+      "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",\n+      "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs="\n+    },\n+    "lodash.isstring": {\n+      "version": "4.0.1",\n+      "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",\n+      "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE="\n     },\n     "lodash.keys": {\n       "version": "3.1.2",\n       "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz",\n       "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=",\n-      "dev": true,\n       "requires": {\n         "lodash._getnative": "3.9.1",\n         "lodash.isarguments": "3.1.0",\n@@ -3421,6 +4301,11 @@\n       "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",\n       "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4="\n     },\n+    "lodash.mergewith": {\n+      "version": "4.6.1",\n+      "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz",\n+      "integrity": "sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ=="\n+    },\n     "lodash.once": {\n       "version": "4.1.1",\n       "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",\n@@ -3447,6 +4332,24 @@\n       "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",\n       "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc="\n     },\n+    "loose-envify": {\n+      "version": "1.3.1",\n+      "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz",\n+      "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=",\n+      "requires": {\n+        "js-tokens": "3.0.2"\n+      }\n+    },\n+    "loud-rejection": {\n+      "version": "1.6.0",\n+      "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",\n+      "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=",\n+      "optional": true,\n+      "requires": {\n+        "currently-unhandled": "0.4.1",\n+        "signal-exit": "3.0.2"\n+      }\n+    },\n     "lru-cache": {\n       "version": "4.1.1",\n       "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz",\n@@ -3456,16 +4359,37 @@\n         "yallist": "2.1.2"\n       }\n     },\n+    "lru-queue": {\n+      "version": "0.1.0",\n+      "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz",\n+      "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=",\n+      "requires": {\n+        "es5-ext": "0.10.39"\n+      }\n+    },\n     "macaddress": {\n       "version": "0.2.8",\n       "resolved": "https://registry.npmjs.org/macaddress/-/macaddress-0.2.8.tgz",\n       "integrity": "sha1-WQTcU3w57G2+/q6QIycTX6hRHxI="\n     },\n+    "map-obj": {\n+      "version": "1.0.1",\n+      "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",\n+      "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0="\n+    },\n     "map-stream": {\n       "version": "0.1.0",\n       "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz",\n       "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ="\n     },\n+    "matcher": {\n+      "version": "0.1.2",\n+      "resolved": "https://registry.npmjs.org/matcher/-/matcher-0.1.2.tgz",\n+      "integrity": "sha1-7yDL3mTCTFDMYa9bg+4LG4/wAQE=",\n+      "requires": {\n+        "escape-string-regexp": "1.0.5"\n+      }\n+    },\n     "math-expression-evaluator": {\n       "version": "1.2.17",\n       "resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz",\n@@ -3491,6 +4415,11 @@\n         }\n       }\n     },\n+    "mdurl": {\n+      "version": "1.0.1",\n+      "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",\n+      "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4="\n+    },\n     "media-typer": {\n       "version": "0.3.0",\n       "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",\n@@ -3501,7 +4430,22 @@\n       "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz",\n       "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=",\n       "requires": {\n-        "mimic-fn": "1.1.0"\n+        "mimic-fn": "1.2.0"\n+      }\n+    },\n+    "memoizee": {\n+      "version": "0.4.1",\n+      "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.1.tgz",\n+      "integrity": "sha1-aT9TgM2ASjmR662gAXnGtWWjr6s=",\n+      "requires": {\n+        "d": "1.0.0",\n+        "es5-ext": "0.10.39",\n+        "es6-weak-map": "2.0.2",\n+        "event-emitter": "0.3.5",\n+        "is-promise": "2.1.0",\n+        "lru-queue": "0.1.0",\n+        "next-tick": "1.0.0",\n+        "timers-ext": "0.1.2"\n       }\n     },\n     "memory-fs": {\n@@ -3509,10 +4453,36 @@\n       "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",\n       "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=",\n       "requires": {\n-        "errno": "0.1.4",\n+        "errno": "0.1.7",\n         "readable-stream": "2.3.3"\n       }\n     },\n+    "meow": {\n+      "version": "3.7.0",\n+      "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",\n+      "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",\n+      "optional": true,\n+      "requires": {\n+        "camelcase-keys": "2.1.0",\n+        "decamelize": "1.2.0",\n+        "loud-rejection": "1.6.0",\n+        "map-obj": "1.0.1",\n+        "minimist": "1.2.0",\n+        "normalize-package-data": "2.4.0",\n+        "object-assign": "4.1.1",\n+        "read-pkg-up": "1.0.1",\n+        "redent": "1.0.0",\n+        "trim-newlines": "1.0.0"\n+      },\n+      "dependencies": {\n+        "minimist": {\n+          "version": "1.2.0",\n+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",\n+          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",\n+          "optional": true\n+        }\n+      }\n+    },\n     "merge-descriptors": {\n       "version": "1.0.1",\n       "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",\n@@ -3523,6 +4493,11 @@\n       "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",\n       "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="\n     },\n+    "mfb": {\n+      "version": "0.12.0",\n+      "resolved": "https://registry.npmjs.org/mfb/-/mfb-0.12.0.tgz",\n+      "integrity": "sha1-E+HUekDyF04sLEcFJKh8BNXKY38="\n+    },\n     "micromatch": {\n       "version": "2.3.11",\n       "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",\n@@ -3592,9 +4567,9 @@\n       }\n     },\n     "mimic-fn": {\n-      "version": "1.1.0",\n-      "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz",\n-      "integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg="\n+      "version": "1.2.0",\n+      "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",\n+      "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="\n     },\n     "minimalistic-assert": {\n       "version": "1.0.0",\n@@ -3749,16 +4724,16 @@\n       }\n     },\n     "moment": {\n-      "version": "2.19.3",\n-      "resolved": "https://registry.npmjs.org/moment/-/moment-2.19.3.tgz",\n-      "integrity": "sha1-vbmdJw1tf9p4zA+6zoVeJ/59pp8="\n+      "version": "2.20.1",\n+      "resolved": "https://registry.npmjs.org/moment/-/moment-2.20.1.tgz",\n+      "integrity": "sha512-Yh9y73JRljxW5QxN08Fner68eFLxM5ynNOAw2LbIB1YAGeQzZT8QFSUvkAz609Zf+IHhhaUxqZK8dG3W/+HEvg=="\n     },\n     "moment-timezone": {\n       "version": "0.5.14",\n       "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.14.tgz",\n       "integrity": "sha1-TrOP+VOLgBCLpGekWPPtQmjM/LE=",\n       "requires": {\n-        "moment": "2.19.3"\n+        "moment": "2.20.1"\n       }\n     },\n     "mongodb": {\n@@ -3822,6 +4797,22 @@\n       "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",\n       "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="\n     },\n+    "multicast-dns": {\n+      "version": "6.2.3",\n+      "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz",\n+      "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==",\n+      "optional": true,\n+      "requires": {\n+        "dns-packet": "1.3.1",\n+        "thunky": "1.0.2"\n+      }\n+    },\n+    "multicast-dns-service-types": {\n+      "version": "1.1.0",\n+      "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz",\n+      "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=",\n+      "optional": true\n+    },\n     "mute-stream": {\n       "version": "0.0.7",\n       "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",\n@@ -3869,13 +4860,18 @@\n       "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",\n       "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk="\n     },\n+    "next-tick": {\n+      "version": "1.0.0",\n+      "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",\n+      "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw="\n+    },\n     "node-cache": {\n       "version": "4.1.1",\n       "resolved": "https://registry.npmjs.org/node-cache/-/node-cache-4.1.1.tgz",\n       "integrity": "sha1-CFJGRe5AOd7cPcwd18a5eeBhnkQ=",\n       "requires": {\n         "clone": "2.1.1",\n-        "lodash": "4.17.4"\n+        "lodash": "4.17.5"\n       },\n       "dependencies": {\n         "clone": {\n@@ -3885,6 +4881,21 @@\n         }\n       }\n     },\n+    "node-fetch": {\n+      "version": "1.7.3",\n+      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",\n+      "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==",\n+      "requires": {\n+        "encoding": "0.1.12",\n+        "is-stream": "1.1.0"\n+      }\n+    },\n+    "node-forge": {\n+      "version": "0.7.1",\n+      "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.1.tgz",\n+      "integrity": "sha1-naYR6giYL0uUIGs760zJZl8gwwA=",\n+      "optional": true\n+    },\n     "node-libs-browser": {\n       "version": "2.1.0",\n       "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.1.0.tgz",\n@@ -3896,7 +4907,7 @@\n         "console-browserify": "1.1.0",\n         "constants-browserify": "1.0.0",\n         "crypto-browserify": "3.12.0",\n-        "domain-browser": "1.1.7",\n+        "domain-browser": "1.2.0",\n         "events": "1.1.1",\n         "https-browserify": "1.0.0",\n         "os-browserify": "0.3.0",\n@@ -3906,9 +4917,9 @@\n         "querystring-es3": "0.2.1",\n         "readable-stream": "2.3.3",\n         "stream-browserify": "2.0.1",\n-        "stream-http": "2.7.2",\n+        "stream-http": "2.8.0",\n         "string_decoder": "1.0.3",\n-        "timers-browserify": "2.0.4",\n+        "timers-browserify": "2.0.6",\n         "tty-browserify": "0.0.0",\n         "url": "0.11.0",\n         "util": "0.10.3",\n@@ -4166,6 +5177,27 @@\n       "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz",\n       "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE="\n     },\n+    "object-inspect": {\n+      "version": "1.5.0",\n+      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.5.0.tgz",\n+      "integrity": "sha512-UmOFbHbwvv+XHj7BerrhVq+knjceBdkvU5AriwLMvhv2qi+e7DJzxfBeFpILEjVzCp+xA+W/pIf06RGPWlZNfw=="\n+    },\n+    "object-keys": {\n+      "version": "1.0.11",\n+      "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz",\n+      "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0="\n+    },\n+    "object.entries": {\n+      "version": "1.0.4",\n+      "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.0.4.tgz",\n+      "integrity": "sha1-G/mk3SKI9bM/Opk9JXZh8F0WGl8=",\n+      "requires": {\n+        "define-properties": "1.1.2",\n+        "es-abstract": "1.10.0",\n+        "function-bind": "1.1.1",\n+        "has": "1.0.1"\n+      }\n+    },\n     "object.omit": {\n       "version": "2.0.1",\n       "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz",\n@@ -4175,6 +5207,11 @@\n         "is-extendable": "0.1.1"\n       }\n     },\n+    "obuf": {\n+      "version": "1.1.1",\n+      "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.1.tgz",\n+      "integrity": "sha1-EEEktsYCxnlogaBCVB0220OlJk4="\n+    },\n     "on-finished": {\n       "version": "2.3.0",\n       "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",\n@@ -4202,6 +5239,16 @@\n       "integrity": "sha1-XG2ixdflgx6P+jlklQ+NZnSskLg=",\n       "dev": true\n     },\n+    "opn": {\n+      "version": "4.0.2",\n+      "resolved": "https://registry.npmjs.org/opn/-/opn-4.0.2.tgz",\n+      "integrity": "sha1-erwi5kTf9jsKltWrfyeQwPAavJU=",\n+      "optional": true,\n+      "requires": {\n+        "object-assign": "4.1.1",\n+        "pinkie-promise": "2.0.1"\n+      }\n+    },\n     "optimist": {\n       "version": "0.6.1",\n       "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",\n@@ -4243,24 +5290,50 @@\n       "resolved": "https://registry.npmjs.org/optjs/-/optjs-3.2.2.tgz",\n       "integrity": "sha1-aabOicRCpEQDFBrS+bNwvVu29O4="\n     },\n-    "os-browserify": {\n-      "version": "0.3.0",\n-      "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",\n-      "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc="\n-    },\n-    "os-homedir": {\n+    "original": {\n+      "version": "1.0.0",\n+      "resolved": "https://registry.npmjs.org/original/-/original-1.0.0.tgz",\n+      "integrity": "sha1-kUf5P6FpbQS+YeAb1QuurKZWvTs=",\n+      "optional": true,\n+      "requires": {\n+        "url-parse": "1.0.5"\n+      },\n+      "dependencies": {\n+        "querystringify": {\n+          "version": "0.0.4",\n+          "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-0.0.4.tgz",\n+          "integrity": "sha1-DPf4T5Rj/wrlHExLFC2VvjdyTZw=",\n+          "optional": true\n+        },\n+        "url-parse": {\n+          "version": "1.0.5",\n+          "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.0.5.tgz",\n+          "integrity": "sha1-CFSGBCKv3P7+tsllxmLUgAFpkns=",\n+          "optional": true,\n+          "requires": {\n+            "querystringify": "0.0.4",\n+            "requires-port": "1.0.0"\n+          }\n+        }\n+      }\n+    },\n+    "os-browserify": {\n+      "version": "0.3.0",\n+      "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",\n+      "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc="\n+    },\n+    "os-homedir": {\n       "version": "1.0.2",\n       "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",\n       "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="\n     },\n     "os-locale": {\n-      "version": "2.1.0",\n-      "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz",\n-      "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==",\n+      "version": "1.4.0",\n+      "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",\n+      "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",\n+      "optional": true,\n       "requires": {\n-        "execa": "0.7.0",\n-        "lcid": "1.0.0",\n-        "mem": "1.1.0"\n+        "lcid": "1.0.0"\n       }\n     },\n     "os-tmpdir": {\n@@ -4283,18 +5356,32 @@\n       "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="\n     },\n     "p-limit": {\n-      "version": "1.1.0",\n-      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.1.0.tgz",\n-      "integrity": "sha1-sH/y2aXYi+yAYDWJWiurZqJ5iLw="\n+      "version": "1.2.0",\n+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz",\n+      "integrity": "sha512-Y/OtIaXtUPr4/YpMv1pCL5L5ed0rumAaAeBSj12F+bSlMdys7i8oQF/GUJmfpTS/QoaRrS/k6pma29haJpsMng==",\n+      "requires": {\n+        "p-try": "1.0.0"\n+      }\n     },\n     "p-locate": {\n       "version": "2.0.0",\n       "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",\n       "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",\n       "requires": {\n-        "p-limit": "1.1.0"\n+        "p-limit": "1.2.0"\n       }\n     },\n+    "p-map": {\n+      "version": "1.2.0",\n+      "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz",\n+      "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==",\n+      "optional": true\n+    },\n+    "p-try": {\n+      "version": "1.0.0",\n+      "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",\n+      "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M="\n+    },\n     "pako": {\n       "version": "1.0.6",\n       "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz",\n@@ -4305,7 +5392,7 @@\n       "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.0.tgz",\n       "integrity": "sha1-N8T5t+06tlx0gXtfJICTf7+XxxI=",\n       "requires": {\n-        "asn1.js": "4.9.2",\n+        "asn1.js": "4.10.1",\n         "browserify-aes": "1.1.1",\n         "create-hash": "1.1.3",\n         "evp_bytestokey": "1.0.3",\n@@ -4374,21 +5461,35 @@\n       "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",\n       "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M="\n     },\n+    "pascalcase": {\n+      "version": "0.1.1",\n+      "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",\n+      "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ="\n+    },\n     "path-browserify": {\n       "version": "0.0.0",\n       "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz",\n       "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo="\n     },\n     "path-exists": {\n-      "version": "3.0.0",\n-      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",\n-      "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="\n+      "version": "2.1.0",\n+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",\n+      "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",\n+      "requires": {\n+        "pinkie-promise": "2.0.1"\n+      }\n     },\n     "path-is-absolute": {\n       "version": "1.0.1",\n       "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",\n       "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="\n     },\n+    "path-is-inside": {\n+      "version": "1.0.2",\n+      "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",\n+      "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=",\n+      "optional": true\n+    },\n     "path-key": {\n       "version": "2.0.1",\n       "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",\n@@ -4400,11 +5501,20 @@\n       "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="\n     },\n     "path-type": {\n-      "version": "2.0.0",\n-      "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz",\n-      "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=",\n+      "version": "1.1.0",\n+      "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",\n+      "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",\n       "requires": {\n-        "pify": "2.3.0"\n+        "graceful-fs": "4.1.11",\n+        "pify": "2.3.0",\n+        "pinkie-promise": "2.0.1"\n+      },\n+      "dependencies": {\n+        "pify": {\n+          "version": "2.3.0",\n+          "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",\n+          "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="\n+        }\n       }\n     },\n     "pause-stream": {\n@@ -4424,7 +5534,7 @@\n         "create-hmac": "1.1.6",\n         "ripemd160": "2.0.1",\n         "safe-buffer": "5.1.1",\n-        "sha.js": "2.4.9"\n+        "sha.js": "2.4.10"\n       }\n     },\n     "performance-now": {\n@@ -4433,9 +5543,22 @@\n       "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="\n     },\n     "pify": {\n-      "version": "2.3.0",\n-      "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",\n-      "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="\n+      "version": "3.0.0",\n+      "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",\n+      "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY="\n+    },\n+    "pinkie": {\n+      "version": "2.0.4",\n+      "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",\n+      "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA="\n+    },\n+    "pinkie-promise": {\n+      "version": "2.0.1",\n+      "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",\n+      "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",\n+      "requires": {\n+        "pinkie": "2.0.4"\n+      }\n     },\n     "pkginfo": {\n       "version": "0.3.1",\n@@ -4448,6 +5571,25 @@\n       "integrity": "sha1-HPWjCw2AbNGPiPxBprXUrWFbO6k=",\n       "dev": true\n     },\n+    "portfinder": {\n+      "version": "1.0.13",\n+      "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.13.tgz",\n+      "integrity": "sha1-uzLs2HwnEErm7kS1o8y/Drsa7ek=",\n+      "optional": true,\n+      "requires": {\n+        "async": "1.5.2",\n+        "debug": "2.6.7",\n+        "mkdirp": "0.5.1"\n+      },\n+      "dependencies": {\n+        "async": {\n+          "version": "1.5.2",\n+          "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",\n+          "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=",\n+          "optional": true\n+        }\n+      }\n+    },\n     "postcss": {\n       "version": "5.2.18",\n       "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",\n@@ -5034,6 +6176,23 @@\n       "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",\n       "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M="\n     },\n+    "promise": {\n+      "version": "7.3.1",\n+      "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",\n+      "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",\n+      "requires": {\n+        "asap": "2.0.6"\n+      }\n+    },\n+    "promise-worker": {\n+      "version": "1.1.1",\n+      "resolved": "https://registry.npmjs.org/promise-worker/-/promise-worker-1.1.1.tgz",\n+      "integrity": "sha1-wrddBF0kliXAImTi3/mtIuAxxps=",\n+      "requires": {\n+        "is-promise": "2.1.0",\n+        "lie": "3.2.0"\n+      }\n+    },\n     "prompt": {\n       "version": "0.2.14",\n       "resolved": "https://registry.npmjs.org/prompt/-/prompt-0.2.14.tgz",\n@@ -5046,6 +6205,16 @@\n         "winston": "0.8.3"\n       }\n     },\n+    "prop-types": {\n+      "version": "15.6.0",\n+      "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.0.tgz",\n+      "integrity": "sha1-zq8IMCL8RrSjX2nhPvda7Q1jmFY=",\n+      "requires": {\n+        "fbjs": "0.8.16",\n+        "loose-envify": "1.3.1",\n+        "object-assign": "4.1.1"\n+      }\n+    },\n     "protobufjs": {\n       "version": "3.2.4",\n       "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-3.2.4.tgz",\n@@ -5065,9 +6234,9 @@\n       }\n     },\n     "prr": {\n-      "version": "0.0.0",\n-      "resolved": "https://registry.npmjs.org/prr/-/prr-0.0.0.tgz",\n-      "integrity": "sha1-GoS4WQgyVQFBGFPQCB7j+obikmo="\n+      "version": "1.0.1",\n+      "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",\n+      "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY="\n     },\n     "ps-tree": {\n       "version": "0.0.3",\n@@ -5109,7 +6278,7 @@\n         "browserify-rsa": "4.0.1",\n         "create-hash": "1.1.3",\n         "parse-asn1": "5.1.0",\n-        "randombytes": "2.0.5"\n+        "randombytes": "2.0.6"\n       }\n     },\n     "punycode": {\n@@ -5151,6 +6320,19 @@\n       "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",\n       "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM="\n     },\n+    "querystringify": {\n+      "version": "1.0.0",\n+      "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-1.0.0.tgz",\n+      "integrity": "sha1-YoYkIRLFtxL6ZU5SZlK/ahP/Bcs="\n+    },\n+    "raf": {\n+      "version": "3.4.0",\n+      "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.0.tgz",\n+      "integrity": "sha512-pDP/NMRAXoTfrhCfyfSEwJAKLaxBU9eApMeBPB1TkDouZmvPerIClV8lTAd+uF8ZiTaVl69e1FCxQrAd/VTjGw==",\n+      "requires": {\n+        "performance-now": "2.1.0"\n+      }\n+    },\n     "random-token": {\n       "version": "0.0.8",\n       "resolved": "https://registry.npmjs.org/random-token/-/random-token-0.0.8.tgz",\n@@ -5194,19 +6376,19 @@\n       }\n     },\n     "randombytes": {\n-      "version": "2.0.5",\n-      "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.5.tgz",\n-      "integrity": "sha512-8T7Zn1AhMsQ/HI1SjcCfT/t4ii3eAqco3yOcSzS4mozsOz69lHLsoMXmF9nZgnFanYscnSlUSgs8uZyKzpE6kg==",\n+      "version": "2.0.6",\n+      "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz",\n+      "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==",\n       "requires": {\n         "safe-buffer": "5.1.1"\n       }\n     },\n     "randomfill": {\n-      "version": "1.0.3",\n-      "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.3.tgz",\n-      "integrity": "sha512-YL6GrhrWoic0Eq8rXVbMptH7dAxCs0J+mh5Y0euNekPPYaxEmdVGim6GdoxoRzKW2yJoU8tueifS7mYxvcFDEQ==",\n+      "version": "1.0.4",\n+      "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz",\n+      "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==",\n       "requires": {\n-        "randombytes": "2.0.5",\n+        "randombytes": "2.0.6",\n         "safe-buffer": "5.1.1"\n       }\n     },\n@@ -5246,6 +6428,195 @@\n         }\n       }\n     },\n+    "react": {\n+      "version": "15.6.2",\n+      "resolved": "https://registry.npmjs.org/react/-/react-15.6.2.tgz",\n+      "integrity": "sha1-26BDSrQ5z+gvEI8PURZjkIF5qnI=",\n+      "requires": {\n+        "create-react-class": "15.6.3",\n+        "fbjs": "0.8.16",\n+        "loose-envify": "1.3.1",\n+        "object-assign": "4.1.1",\n+        "prop-types": "15.6.0"\n+      }\n+    },\n+    "react-addons-perf": {\n+      "version": "15.4.2",\n+      "resolved": "https://registry.npmjs.org/react-addons-perf/-/react-addons-perf-15.4.2.tgz",\n+      "integrity": "sha1-EQvc9cRZxPd8uF7WNLzTOXU2ODs=",\n+      "requires": {\n+        "fbjs": "0.8.16",\n+        "object-assign": "4.1.1"\n+      }\n+    },\n+    "react-addons-shallow-compare": {\n+      "version": "0.14.8",\n+      "resolved": "https://registry.npmjs.org/react-addons-shallow-compare/-/react-addons-shallow-compare-0.14.8.tgz",\n+      "integrity": "sha1-HyZTPXjK2r9GOXVuwNrlq0VCenQ="\n+    },\n+    "react-addons-test-utils": {\n+      "version": "15.6.2",\n+      "resolved": "https://registry.npmjs.org/react-addons-test-utils/-/react-addons-test-utils-15.6.2.tgz",\n+      "integrity": "sha1-wStu/cIkfBDae4dw0YUICnsEcVY="\n+    },\n+    "react-collapse": {\n+      "version": "4.0.3",\n+      "resolved": "https://registry.npmjs.org/react-collapse/-/react-collapse-4.0.3.tgz",\n+      "integrity": "sha512-OO4NhtEqFtz+1ma31J1B7+ezdRnzHCZiTGSSd/Pxoks9hxrZYhzFEddeYt05A/1477xTtdrwo7xEa2FLJyWGCQ==",\n+      "requires": {\n+        "prop-types": "15.6.0"\n+      }\n+    },\n+    "react-dom": {\n+      "version": "15.6.2",\n+      "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-15.6.2.tgz",\n+      "integrity": "sha1-Qc+t9pO3V/rycIRDodH9WgK+9zA=",\n+      "requires": {\n+        "fbjs": "0.8.16",\n+        "loose-envify": "1.3.1",\n+        "object-assign": "4.1.1",\n+        "prop-types": "15.6.0"\n+      }\n+    },\n+    "react-height": {\n+      "version": "2.2.1",\n+      "resolved": "https://registry.npmjs.org/react-height/-/react-height-2.2.1.tgz",\n+      "integrity": "sha1-CQINnSKkgSGno4E14jRStH96mH8=",\n+      "requires": {\n+        "create-react-class": "15.5.2",\n+        "prop-types": "15.5.8"\n+      },\n+      "dependencies": {\n+        "create-react-class": {\n+          "version": "15.5.2",\n+          "resolved": "https://registry.npmjs.org/create-react-class/-/create-react-class-15.5.2.tgz",\n+          "integrity": "sha1-aodYNI32YLiDJqDnZNVp8nSq1oE=",\n+          "requires": {\n+            "fbjs": "0.8.16",\n+            "object-assign": "4.1.1"\n+          }\n+        },\n+        "prop-types": {\n+          "version": "15.5.8",\n+          "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.5.8.tgz",\n+          "integrity": "sha1-a3suFBCDvjjIWVqlH8VXdccZk5Q=",\n+          "requires": {\n+            "fbjs": "0.8.16"\n+          }\n+        }\n+      }\n+    },\n+    "react-hot-api": {\n+      "version": "0.4.7",\n+      "resolved": "https://registry.npmjs.org/react-hot-api/-/react-hot-api-0.4.7.tgz",\n+      "integrity": "sha1-p+IqVtJS4Rq9k2a2EmTPRJLFgXE="\n+    },\n+    "react-hot-loader": {\n+      "version": "1.3.1",\n+      "resolved": "https://registry.npmjs.org/react-hot-loader/-/react-hot-loader-1.3.1.tgz",\n+      "integrity": "sha1-yVZHrni3Pfzv9uxx/8sEGC/22vk=",\n+      "requires": {\n+        "react-hot-api": "0.4.7",\n+        "source-map": "0.4.4"\n+      },\n+      "dependencies": {\n+        "source-map": {\n+          "version": "0.4.4",\n+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",\n+          "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",\n+          "requires": {\n+            "amdefine": "1.0.1"\n+          }\n+        }\n+      }\n+    },\n+    "react-immutable-proptypes": {\n+      "version": "2.1.0",\n+      "resolved": "https://registry.npmjs.org/react-immutable-proptypes/-/react-immutable-proptypes-2.1.0.tgz",\n+      "integrity": "sha1-Aj1vObsVyXwHHp5g0A0TbqxfoLQ="\n+    },\n+    "react-immutable-pure-component": {\n+      "version": "1.1.1",\n+      "resolved": "https://registry.npmjs.org/react-immutable-pure-component/-/react-immutable-pure-component-1.1.1.tgz",\n+      "integrity": "sha512-/SEHxOlbPpfsqRmTXiLetOSUexnKeY7CfrKfdyPudCpFyGNcPXtbtq0cgeVPmo4NyxeluYrq0FZSMhXj6ICtOA=="\n+    },\n+    "react-markdown": {\n+      "version": "2.5.1",\n+      "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-2.5.1.tgz",\n+      "integrity": "sha512-N5xMde42RrclLIdF16bckTApFM56vkn4q3GoZlLkuE8IK23GOIqJsuE62RTrkgq//pAt4dovVgZcgawh7YtN4w==",\n+      "requires": {\n+        "commonmark": "0.24.0",\n+        "commonmark-react-renderer": "4.3.4",\n+        "prop-types": "15.6.0"\n+      },\n+      "dependencies": {\n+        "commonmark": {\n+          "version": "0.24.0",\n+          "resolved": "https://registry.npmjs.org/commonmark/-/commonmark-0.24.0.tgz",\n+          "integrity": "sha1-uA3gGCxUY1VkOqFdsSv7KCNoJ48=",\n+          "requires": {\n+            "entities": "1.1.1",\n+            "mdurl": "1.0.1",\n+            "string.prototype.repeat": "0.2.0"\n+          }\n+        }\n+      }\n+    },\n+    "react-motion": {\n+      "version": "0.5.2",\n+      "resolved": "https://registry.npmjs.org/react-motion/-/react-motion-0.5.2.tgz",\n+      "integrity": "sha512-9q3YAvHoUiWlP3cK0v+w1N5Z23HXMj4IF4YuvjvWegWqNPfLXsOBE/V7UvQGpXxHFKRQQcNcVQE31g9SB/6qgQ==",\n+      "requires": {\n+        "performance-now": "0.2.0",\n+        "prop-types": "15.6.0",\n+        "raf": "3.4.0"\n+      },\n+      "dependencies": {\n+        "performance-now": {\n+          "version": "0.2.0",\n+          "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz",\n+          "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU="\n+        }\n+      }\n+    },\n+    "react-object-inspector": {\n+      "version": "0.2.1",\n+      "resolved": "https://registry.npmjs.org/react-object-inspector/-/react-object-inspector-0.2.1.tgz",\n+      "integrity": "sha1-jsMpUb3ox2sHLvCEp056nS0K63I="\n+    },\n+    "react-redux": {\n+      "version": "4.4.8",\n+      "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-4.4.8.tgz",\n+      "integrity": "sha1-57wd0QDotk6WrIIS2xEyObni4I8=",\n+      "requires": {\n+        "create-react-class": "15.6.3",\n+        "hoist-non-react-statics": "1.2.0",\n+        "invariant": "2.2.2",\n+        "lodash": "4.17.5",\n+        "loose-envify": "1.3.1",\n+        "prop-types": "15.6.0"\n+      }\n+    },\n+    "react-split-pane": {\n+      "version": "0.1.70",\n+      "resolved": "https://registry.npmjs.org/react-split-pane/-/react-split-pane-0.1.70.tgz",\n+      "integrity": "sha512-vXLE4gTI9gTFXEaX2pKKyZilwDsxGVmAQi7yombplzzj2oBY/fmd3o4DlNSMN43m9XchtStcWri9mOrBx3yMiQ==",\n+      "requires": {\n+        "@types/inline-style-prefixer": "3.0.1",\n+        "@types/react": "16.0.38",\n+        "inline-style-prefixer": "3.0.8",\n+        "prop-types": "15.6.0",\n+        "react-style-proptype": "3.2.0"\n+      }\n+    },\n+    "react-style-proptype": {\n+      "version": "3.2.0",\n+      "resolved": "https://registry.npmjs.org/react-style-proptype/-/react-style-proptype-3.2.0.tgz",\n+      "integrity": "sha512-Mafmkzj3oNmLSJNOlH+WWWyGIdzVLhPj+d12fDxQMQdwDQ5sMX7vQKOLpry4U+zRWieTCx448AyRKK0NLWuXmg==",\n+      "requires": {\n+        "prop-types": "15.6.0"\n+      }\n+    },\n     "read": {\n       "version": "1.0.7",\n       "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz",\n@@ -5255,22 +6626,22 @@\n       }\n     },\n     "read-pkg": {\n-      "version": "2.0.0",\n-      "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz",\n-      "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=",\n+      "version": "1.1.0",\n+      "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",\n+      "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",\n       "requires": {\n-        "load-json-file": "2.0.0",\n+        "load-json-file": "1.1.0",\n         "normalize-package-data": "2.4.0",\n-        "path-type": "2.0.0"\n+        "path-type": "1.1.0"\n       }\n     },\n     "read-pkg-up": {\n-      "version": "2.0.0",\n-      "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz",\n-      "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=",\n+      "version": "1.0.1",\n+      "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",\n+      "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",\n       "requires": {\n-        "find-up": "2.1.0",\n-        "read-pkg": "2.0.0"\n+        "find-up": "1.1.2",\n+        "read-pkg": "1.1.0"\n       }\n     },\n     "readable-stream": {\n@@ -5298,6 +6669,16 @@\n         "set-immediate-shim": "1.0.1"\n       }\n     },\n+    "redent": {\n+      "version": "1.0.0",\n+      "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",\n+      "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=",\n+      "optional": true,\n+      "requires": {\n+        "indent-string": "2.1.0",\n+        "strip-indent": "1.0.1"\n+      }\n+    },\n     "reduce-css-calc": {\n       "version": "1.3.0",\n       "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz",\n@@ -5330,11 +6711,43 @@\n         }\n       }\n     },\n+    "redux": {\n+      "version": "3.7.2",\n+      "resolved": "https://registry.npmjs.org/redux/-/redux-3.7.2.tgz",\n+      "integrity": "sha512-pNqnf9q1hI5HHZRBkj3bAngGZW/JMCmexDlOxw4XagXY2o1327nHH54LoTjiPJ0gizoqPDRqWyX/00g0hD6w+A==",\n+      "requires": {\n+        "lodash": "4.17.5",\n+        "lodash-es": "4.17.5",\n+        "loose-envify": "1.3.1",\n+        "symbol-observable": "1.2.0"\n+      }\n+    },\n+    "redux-immutable": {\n+      "version": "3.0.8",\n+      "resolved": "https://registry.npmjs.org/redux-immutable/-/redux-immutable-3.0.8.tgz",\n+      "integrity": "sha1-31pdYByIInujj0dM+C99AOVvjBQ=",\n+      "requires": {\n+        "immutable": "3.8.2"\n+      }\n+    },\n+    "redux-logger": {\n+      "version": "3.0.6",\n+      "resolved": "https://registry.npmjs.org/redux-logger/-/redux-logger-3.0.6.tgz",\n+      "integrity": "sha1-91VZZvMJjzyIYExEnPC69XeCdL8=",\n+      "requires": {\n+        "deep-diff": "0.3.8"\n+      }\n+    },\n     "regenerate": {\n       "version": "1.3.3",\n       "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.3.tgz",\n       "integrity": "sha512-jVpo1GadrDAK59t/0jRx5VxYWQEDkkEKi6+HjE3joFVLfDOh9Xrdh0dF1eSq+BI/SwvTQ44gSscJ8N5zYL61sg=="\n     },\n+    "regenerator-runtime": {\n+      "version": "0.11.1",\n+      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",\n+      "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="\n+    },\n     "regex-cache": {\n       "version": "0.4.3",\n       "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz",\n@@ -5367,6 +6780,26 @@\n         "jsesc": "0.5.0"\n       }\n     },\n+    "remarkable": {\n+      "version": "1.7.1",\n+      "resolved": "https://registry.npmjs.org/remarkable/-/remarkable-1.7.1.tgz",\n+      "integrity": "sha1-qspJchALZqZCpjoQIcpLrBvjv/Y=",\n+      "requires": {\n+        "argparse": "0.1.16",\n+        "autolinker": "0.15.3"\n+      },\n+      "dependencies": {\n+        "argparse": {\n+          "version": "0.1.16",\n+          "resolved": "https://registry.npmjs.org/argparse/-/argparse-0.1.16.tgz",\n+          "integrity": "sha1-z9AeD7uj1srtBJ+9dY1A9lGW9Xw=",\n+          "requires": {\n+            "underscore": "1.7.0",\n+            "underscore.string": "2.4.0"\n+          }\n+        }\n+      }\n+    },\n     "remove-trailing-separator": {\n       "version": "1.0.2",\n       "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.0.2.tgz",\n@@ -5382,6 +6815,15 @@\n       "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-0.2.2.tgz",\n       "integrity": "sha1-x6jTI2BoNiBZp+RlH8aITosftK4="\n     },\n+    "repeating": {\n+      "version": "2.0.1",\n+      "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",\n+      "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=",\n+      "optional": true,\n+      "requires": {\n+        "is-finite": "1.0.2"\n+      }\n+    },\n     "request": {\n       "version": "2.83.0",\n       "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz",\n@@ -5467,8 +6909,21 @@\n           "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz",\n           "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=",\n           "requires": {\n-            "ajv": "5.5.1",\n+            "ajv": "5.5.2",\n             "har-schema": "2.0.0"\n+          },\n+          "dependencies": {\n+            "ajv": {\n+              "version": "5.5.2",\n+              "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",\n+              "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",\n+              "requires": {\n+                "co": "4.6.0",\n+                "fast-deep-equal": "1.0.0",\n+                "fast-json-stable-stringify": "2.0.0",\n+                "json-schema-traverse": "0.3.1"\n+              }\n+            }\n           }\n         },\n         "hawk": {\n@@ -5547,7 +7002,7 @@\n       "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=",\n       "dev": true,\n       "requires": {\n-        "lodash": "4.17.4"\n+        "lodash": "4.17.5"\n       }\n     },\n     "request-promise-native": {\n@@ -5580,6 +7035,16 @@\n         "semver": "5.4.1"\n       }\n     },\n+    "requires-port": {\n+      "version": "1.0.0",\n+      "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",\n+      "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="\n+    },\n+    "reselect": {\n+      "version": "2.5.3",\n+      "resolved": "https://registry.npmjs.org/reselect/-/reselect-2.5.3.tgz",\n+      "integrity": "sha1-I2WRE2rV/2PuUM3YT+/39q/YDuo="\n+    },\n     "resolve": {\n       "version": "1.1.7",\n       "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz",\n@@ -5640,6 +7105,69 @@\n       "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",\n       "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="\n     },\n+    "sanitize-html": {\n+      "version": "1.17.0",\n+      "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-1.17.0.tgz",\n+      "integrity": "sha512-5r265ukJgS+MXVMK0OxXLn7iBqRTIxYK0m6Bc+/gFhCY20Vr/KFp/ZTKu9hyB3tKkiGPiQ08aGDPUbjbBhRpXw==",\n+      "requires": {\n+        "chalk": "2.3.1",\n+        "htmlparser2": "3.9.2",\n+        "lodash.clonedeep": "4.5.0",\n+        "lodash.escaperegexp": "4.1.2",\n+        "lodash.mergewith": "4.6.1",\n+        "postcss": "6.0.18",\n+        "srcset": "1.0.0",\n+        "xtend": "4.0.1"\n+      },\n+      "dependencies": {\n+        "ansi-styles": {\n+          "version": "3.2.0",\n+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz",\n+          "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==",\n+          "requires": {\n+            "color-convert": "1.9.1"\n+          }\n+        },\n+        "chalk": {\n+          "version": "2.3.1",\n+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.1.tgz",\n+          "integrity": "sha512-QUU4ofkDoMIVO7hcx1iPTISs88wsO8jA92RQIm4JAwZvFGGAV2hSAA1NX7oVj2Ej2Q6NDTcRDjPTFrMCRZoJ6g==",\n+          "requires": {\n+            "ansi-styles": "3.2.0",\n+            "escape-string-regexp": "1.0.5",\n+            "supports-color": "5.2.0"\n+          }\n+        },\n+        "has-flag": {\n+          "version": "3.0.0",\n+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",\n+          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="\n+        },\n+        "postcss": {\n+          "version": "6.0.18",\n+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.18.tgz",\n+          "integrity": "sha512-X8MyLi3OYI1o71u0SsefWLpGBo5xnGiK1Pn+nrZFplc671Ts7L8aPwEbPIO8AWpulK5wuaVzyM9Rw6R8o7hYBw==",\n+          "requires": {\n+            "chalk": "2.3.1",\n+            "source-map": "0.6.1",\n+            "supports-color": "5.2.0"\n+          }\n+        },\n+        "source-map": {\n+          "version": "0.6.1",\n+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",\n+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="\n+        },\n+        "supports-color": {\n+          "version": "5.2.0",\n+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.2.0.tgz",\n+          "integrity": "sha512-F39vS48la4YvTZUPVeTqsjsFNrvcMwrV3RLZINsmHo+7djCvuUzSIeXOnZ5hmjef4bajL1dNccN+tg5XAliO5Q==",\n+          "requires": {\n+            "has-flag": "3.0.0"\n+          }\n+        }\n+      }\n+    },\n     "sax": {\n       "version": "1.2.4",\n       "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",\n@@ -5650,11 +7178,56 @@\n       "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.3.tgz",\n       "integrity": "sha512-sgv/iF/T4/SewJkaVpldKC4WjSkz0JsOh2eKtxCPpCO1oR05+7MOF+H476HVRbLArkgA7j5TRJJ4p2jdFkUGQQ==",\n       "requires": {\n-        "ajv": "5.5.1",\n+        "ajv": "5.5.2",\n         "ajv-keywords": "2.1.1"\n-      }\n-    },\n-    "semver": {\n+      },\n+      "dependencies": {\n+        "ajv": {\n+          "version": "5.5.2",\n+          "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",\n+          "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",\n+          "requires": {\n+            "co": "4.6.0",\n+            "fast-deep-equal": "1.0.0",\n+            "fast-json-stable-stringify": "2.0.0",\n+            "json-schema-traverse": "0.3.1"\n+          }\n+        }\n+      }\n+    },\n+    "scroll-to": {\n+      "version": "0.0.2",\n+      "resolved": "https://registry.npmjs.org/scroll-to/-/scroll-to-0.0.2.tgz",\n+      "integrity": "sha1-k205ipEzZgokkhRcLACB38sHKPM=",\n+      "requires": {\n+        "component-raf": "1.2.0",\n+        "component-tween": "1.2.0"\n+      }\n+    },\n+    "scroll-to-element": {\n+      "version": "2.0.0",\n+      "resolved": "https://registry.npmjs.org/scroll-to-element/-/scroll-to-element-2.0.0.tgz",\n+      "integrity": "sha1-NGczDjOEdDtylaxkswJ5mQxawWQ=",\n+      "requires": {\n+        "scroll-to": "0.0.2"\n+      }\n+    },\n+    "select-hose": {\n+      "version": "2.0.0",\n+      "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",\n+      "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=",\n+      "optional": true\n+    },\n+    "selfsigned": {\n+      "version": "1.10.2",\n+      "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.2.tgz",\n+      "integrity": "sha1-tESVgNmZKbZbEKSDiTAaZZIIh1g=",\n+      "optional": true,\n+      "requires": {\n+        "node-forge": "0.7.1"\n+      }\n+    },\n+    "semver": {\n       "version": "5.4.1",\n       "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",\n       "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg=="\n@@ -5699,6 +7272,60 @@\n         }\n       }\n     },\n+    "serialize-error": {\n+      "version": "2.0.0",\n+      "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-2.0.0.tgz",\n+      "integrity": "sha1-bBFT9+4/5/c/8bG30rSUtntnXro="\n+    },\n+    "serve-index": {\n+      "version": "1.9.1",\n+      "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz",\n+      "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=",\n+      "optional": true,\n+      "requires": {\n+        "accepts": "1.3.4",\n+        "batch": "0.6.1",\n+        "debug": "2.6.9",\n+        "escape-html": "1.0.3",\n+        "http-errors": "1.6.2",\n+        "mime-types": "2.1.18",\n+        "parseurl": "1.3.2"\n+      },\n+      "dependencies": {\n+        "accepts": {\n+          "version": "1.3.4",\n+          "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz",\n+          "integrity": "sha1-hiRnWMfdbSGmR0/whKR0DsBesh8=",\n+          "optional": true,\n+          "requires": {\n+            "mime-types": "2.1.18",\n+            "negotiator": "0.6.1"\n+          }\n+        },\n+        "debug": {\n+          "version": "2.6.9",\n+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",\n+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",\n+          "optional": true,\n+          "requires": {\n+            "ms": "2.0.0"\n+          }\n+        },\n+        "mime-db": {\n+          "version": "1.33.0",\n+          "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz",\n+          "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ=="\n+        },\n+        "mime-types": {\n+          "version": "2.1.18",\n+          "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz",\n+          "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==",\n+          "requires": {\n+            "mime-db": "1.33.0"\n+          }\n+        }\n+      }\n+    },\n     "serve-static": {\n       "version": "1.13.1",\n       "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.1.tgz",\n@@ -5762,14 +7389,22 @@\n       }\n     },\n     "sha.js": {\n-      "version": "2.4.9",\n-      "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.9.tgz",\n-      "integrity": "sha512-G8zektVqbiPHrylgew9Zg1VRB1L/DtXNUVAM6q4QLy8NE3qtHlFXTf8VLL4k1Yl6c7NMjtZUTdXV+X44nFaT6A==",\n+      "version": "2.4.10",\n+      "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.10.tgz",\n+      "integrity": "sha512-vnwmrFDlOExK4Nm16J2KMWHLrp14lBrjxMxBJpu++EnsuBmpiYaM/MEs46Vxxm/4FvdP5yTwuCTO9it5FSjrqA==",\n       "requires": {\n         "inherits": "2.0.3",\n         "safe-buffer": "5.1.1"\n       }\n     },\n+    "shallowequal": {\n+      "version": "0.2.2",\n+      "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-0.2.2.tgz",\n+      "integrity": "sha1-HjL9W8q2rWiKSBLLDMBO/HXHAU4=",\n+      "requires": {\n+        "lodash.keys": "3.1.2"\n+      }\n+    },\n     "share2nightscout-bridge": {\n       "version": "git://github.com/bewest/share2nightscout-bridge.git#34e3c59567b6d74c0d543b234f354bea1cf807e1",\n       "requires": {\n@@ -5922,9 +7557,9 @@\n       "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="\n     },\n     "shiro-trie": {\n-      "version": "0.3.13",\n-      "resolved": "https://registry.npmjs.org/shiro-trie/-/shiro-trie-0.3.13.tgz",\n-      "integrity": "sha1-pKZrVJjWm5RgLnqYsAVzFbO1x0Q="\n+      "version": "0.4.5",\n+      "resolved": "https://registry.npmjs.org/shiro-trie/-/shiro-trie-0.4.5.tgz",\n+      "integrity": "sha512-l9XaQKFi6hX0ZGSlrhLHiI9UGYxJtZTWbg/otqX/5Kx5Xdhbtd/TPnjP9PF9cOHzhw8nV3EDIEry/rt5mSEkJg=="\n     },\n     "should": {\n       "version": "11.1.2",\n@@ -6141,6 +7776,49 @@\n         }\n       }\n     },\n+    "sockjs": {\n+      "version": "0.3.18",\n+      "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.18.tgz",\n+      "integrity": "sha1-2bKJMWyn33dZXvKZ4HXw+TfrQgc=",\n+      "optional": true,\n+      "requires": {\n+        "faye-websocket": "0.10.0",\n+        "uuid": "2.0.3"\n+      },\n+      "dependencies": {\n+        "uuid": {\n+          "version": "2.0.3",\n+          "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz",\n+          "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=",\n+          "optional": true\n+        }\n+      }\n+    },\n+    "sockjs-client": {\n+      "version": "1.1.2",\n+      "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.1.2.tgz",\n+      "integrity": "sha1-8CEqhVDkyUaMjM6u79LjSTwDOtU=",\n+      "optional": true,\n+      "requires": {\n+        "debug": "2.6.7",\n+        "eventsource": "0.1.6",\n+        "faye-websocket": "0.11.1",\n+        "inherits": "2.0.3",\n+        "json3": "3.3.2",\n+        "url-parse": "1.2.0"\n+      },\n+      "dependencies": {\n+        "faye-websocket": {\n+          "version": "0.11.1",\n+          "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.1.tgz",\n+          "integrity": "sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg=",\n+          "optional": true,\n+          "requires": {\n+            "websocket-driver": "0.7.0"\n+          }\n+        }\n+      }\n+    },\n     "sort-keys": {\n       "version": "1.1.2",\n       "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz",\n@@ -6177,6 +7855,57 @@\n       "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz",\n       "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc="\n     },\n+    "spdy": {\n+      "version": "3.4.7",\n+      "resolved": "https://registry.npmjs.org/spdy/-/spdy-3.4.7.tgz",\n+      "integrity": "sha1-Qv9B7OXMD5mjpsKKq7c/XDsDrLw=",\n+      "optional": true,\n+      "requires": {\n+        "debug": "2.6.9",\n+        "handle-thing": "1.2.5",\n+        "http-deceiver": "1.2.7",\n+        "safe-buffer": "5.1.1",\n+        "select-hose": "2.0.0",\n+        "spdy-transport": "2.0.20"\n+      },\n+      "dependencies": {\n+        "debug": {\n+          "version": "2.6.9",\n+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",\n+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",\n+          "optional": true,\n+          "requires": {\n+            "ms": "2.0.0"\n+          }\n+        }\n+      }\n+    },\n+    "spdy-transport": {\n+      "version": "2.0.20",\n+      "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-2.0.20.tgz",\n+      "integrity": "sha1-c15yBUxIayNU/onnAiVgBKOazk0=",\n+      "optional": true,\n+      "requires": {\n+        "debug": "2.6.9",\n+        "detect-node": "2.0.3",\n+        "hpack.js": "2.1.6",\n+        "obuf": "1.1.1",\n+        "readable-stream": "2.3.3",\n+        "safe-buffer": "5.1.1",\n+        "wbuf": "1.7.2"\n+      },\n+      "dependencies": {\n+        "debug": {\n+          "version": "2.6.9",\n+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",\n+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",\n+          "optional": true,\n+          "requires": {\n+            "ms": "2.0.0"\n+          }\n+        }\n+      }\n+    },\n     "split": {\n       "version": "0.3.3",\n       "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz",\n@@ -6190,6 +7919,15 @@\n       "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",\n       "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="\n     },\n+    "srcset": {\n+      "version": "1.0.0",\n+      "resolved": "https://registry.npmjs.org/srcset/-/srcset-1.0.0.tgz",\n+      "integrity": "sha1-pWad4StC87HV6D7QPHEEb8SPQe8=",\n+      "requires": {\n+        "array-uniq": "1.0.3",\n+        "number-is-nan": "1.0.1"\n+      }\n+    },\n     "sshpk": {\n       "version": "1.13.1",\n       "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz",\n@@ -6251,9 +7989,9 @@\n       }\n     },\n     "stream-http": {\n-      "version": "2.7.2",\n-      "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.7.2.tgz",\n-      "integrity": "sha512-c0yTD2rbQzXtSsFSVhtpvY/vS6u066PcXOX9kBB3mSO76RiUQzL340uJkGBWnlBg4/HZzqiUXtaVA7wcRcJgEw==",\n+      "version": "2.8.0",\n+      "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.0.tgz",\n+      "integrity": "sha512-sZOFxI/5xw058XIRHl4dU3dZ+TTOIGJR78Dvo0oEAejIt4ou27k+3ne1zYmCV+v7UucbxIFQuOgnkTVHh8YPnw==",\n       "requires": {\n         "builtin-status-codes": "3.0.0",\n         "inherits": "2.0.3",\n@@ -6268,34 +8006,20 @@\n       "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM="\n     },\n     "string-width": {\n-      "version": "2.1.1",\n-      "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",\n-      "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",\n+      "version": "1.0.2",\n+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",\n+      "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",\n       "requires": {\n-        "is-fullwidth-code-point": "2.0.0",\n-        "strip-ansi": "4.0.0"\n-      },\n-      "dependencies": {\n-        "ansi-regex": {\n-          "version": "3.0.0",\n-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",\n-          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="\n-        },\n-        "is-fullwidth-code-point": {\n-          "version": "2.0.0",\n-          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",\n-          "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="\n-        },\n-        "strip-ansi": {\n-          "version": "4.0.0",\n-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",\n-          "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",\n-          "requires": {\n-            "ansi-regex": "3.0.0"\n-          }\n-        }\n+        "code-point-at": "1.1.0",\n+        "is-fullwidth-code-point": "1.0.0",\n+        "strip-ansi": "3.0.1"\n       }\n     },\n+    "string.prototype.repeat": {\n+      "version": "0.2.0",\n+      "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-0.2.0.tgz",\n+      "integrity": "sha1-q6Nt4I3O5qWjN9SbLqHaGyj8Ds8="\n+    },\n     "string_decoder": {\n       "version": "1.0.3",\n       "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",\n@@ -6318,15 +8042,27 @@\n       }\n     },\n     "strip-bom": {\n-      "version": "3.0.0",\n-      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",\n-      "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM="\n+      "version": "2.0.0",\n+      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",\n+      "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",\n+      "requires": {\n+        "is-utf8": "0.2.1"\n+      }\n     },\n     "strip-eof": {\n       "version": "1.0.0",\n       "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",\n       "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8="\n     },\n+    "strip-indent": {\n+      "version": "1.0.1",\n+      "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz",\n+      "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=",\n+      "optional": true,\n+      "requires": {\n+        "get-stdin": "4.0.1"\n+      }\n+    },\n     "strip-json-comments": {\n       "version": "2.0.1",\n       "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",\n@@ -6425,6 +8161,107 @@\n         }\n       }\n     },\n+    "swagger-client": {\n+      "version": "3.4.11",\n+      "resolved": "https://registry.npmjs.org/swagger-client/-/swagger-client-3.4.11.tgz",\n+      "integrity": "sha1-JAgauyn7gGTJtY6TDP+lzfQXyNY=",\n+      "requires": {\n+        "babel-runtime": "6.26.0",\n+        "btoa": "1.1.2",\n+        "cookie": "0.3.1",\n+        "cross-fetch": "0.0.8",\n+        "deep-extend": "0.4.2",\n+        "encode-3986": "1.0.0",\n+        "fast-json-patch": "1.2.2",\n+        "isomorphic-form-data": "0.0.1",\n+        "js-yaml": "3.9.0",\n+        "lodash": "4.17.5",\n+        "qs": "6.4.0",\n+        "url": "0.11.0",\n+        "utf8-bytes": "0.0.1",\n+        "utfstring": "2.0.0"\n+      }\n+    },\n+    "swagger-ui": {\n+      "version": "3.10.0",\n+      "resolved": "https://registry.npmjs.org/swagger-ui/-/swagger-ui-3.10.0.tgz",\n+      "integrity": "sha1-DvKnBFlu6kIChtQuEtdNFdrumWQ=",\n+      "requires": {\n+        "@braintree/sanitize-url": "2.1.0",\n+        "base64-js": "1.2.3",\n+        "brace": "0.7.0",\n+        "classnames": "2.2.5",\n+        "commonmark": "0.28.1",\n+        "core-js": "2.5.3",\n+        "css.escape": "1.5.1",\n+        "deep-extend": "0.4.1",\n+        "expect": "1.20.2",\n+        "getbase": "2.8.2",\n+        "ieee754": "1.1.8",\n+        "immutable": "3.8.2",\n+        "js-yaml": "3.9.0",\n+        "lodash": "4.17.2",\n+        "matcher": "0.1.2",\n+        "memoizee": "0.4.1",\n+        "promise-worker": "1.1.1",\n+        "prop-types": "15.6.0",\n+        "react": "15.6.2",\n+        "react-addons-perf": "15.4.2",\n+        "react-addons-shallow-compare": "0.14.8",\n+        "react-addons-test-utils": "15.6.2",\n+        "react-collapse": "4.0.3",\n+        "react-dom": "15.6.2",\n+        "react-height": "2.2.1",\n+        "react-hot-loader": "1.3.1",\n+        "react-immutable-proptypes": "2.1.0",\n+        "react-immutable-pure-component": "1.1.1",\n+        "react-markdown": "2.5.1",\n+        "react-motion": "0.5.2",\n+        "react-object-inspector": "0.2.1",\n+        "react-redux": "4.4.8",\n+        "react-split-pane": "0.1.70",\n+        "redux": "3.7.2",\n+        "redux-immutable": "3.0.8",\n+        "redux-logger": "3.0.6",\n+        "remarkable": "1.7.1",\n+        "reselect": "2.5.3",\n+        "sanitize-html": "1.17.0",\n+        "scroll-to-element": "2.0.0",\n+        "serialize-error": "2.0.0",\n+        "shallowequal": "0.2.2",\n+        "swagger-client": "3.4.11",\n+        "url-parse": "1.2.0",\n+        "webpack-dev-server": "2.5.0",\n+        "whatwg-fetch": "0.11.1",\n+        "worker-loader": "0.7.1",\n+        "xml": "1.0.1",\n+        "xml-but-prettier": "1.0.1",\n+        "yaml-js": "0.2.0",\n+        "zenscroll": "4.0.0"\n+      },\n+      "dependencies": {\n+        "deep-extend": {\n+          "version": "0.4.1",\n+          "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.1.tgz",\n+          "integrity": "sha1-7+QRPQgIX05vlod1mBD4B0aeIlM="\n+        },\n+        "lodash": {\n+          "version": "4.17.2",\n+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.2.tgz",\n+          "integrity": "sha1-NKMFW6vgTOQkZ7YH1wAHLH/2v0I="\n+        }\n+      }\n+    },\n+    "swagger-ui-dist": {\n+      "version": "3.10.0",\n+      "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-3.10.0.tgz",\n+      "integrity": "sha1-ilrzP/ImPHFaFD9z8qjUfVOZQ+8="\n+    },\n+    "symbol-observable": {\n+      "version": "1.2.0",\n+      "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",\n+      "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ=="\n+    },\n     "symbol-tree": {\n       "version": "3.2.2",\n       "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz",\n@@ -6492,19 +8329,45 @@\n       "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",\n       "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="\n     },\n+    "thunky": {\n+      "version": "1.0.2",\n+      "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.0.2.tgz",\n+      "integrity": "sha1-qGLgGOP7HqLsP85dVWBc9X8kc3E=",\n+      "optional": true\n+    },\n+    "time-stamp": {\n+      "version": "2.0.0",\n+      "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-2.0.0.tgz",\n+      "integrity": "sha1-lcakRTDhW6jW9KPsuMOj+sRto1c=",\n+      "optional": true\n+    },\n     "timers-browserify": {\n-      "version": "2.0.4",\n-      "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.4.tgz",\n-      "integrity": "sha512-uZYhyU3EX8O7HQP+J9fTVYwsq90Vr68xPEFo7yrVImIxYvHgukBEgOB/SgGoorWVTzGM/3Z+wUNnboA4M8jWrg==",\n+      "version": "2.0.6",\n+      "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.6.tgz",\n+      "integrity": "sha512-HQ3nbYRAowdVd0ckGFvmJPPCOH/CHleFN/Y0YQCX1DVaB7t+KFvisuyN09fuP8Jtp1CpfSh8O8bMkHbdbPe6Pw==",\n       "requires": {\n         "setimmediate": "1.0.5"\n       }\n     },\n+    "timers-ext": {\n+      "version": "0.1.2",\n+      "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.2.tgz",\n+      "integrity": "sha1-YcxHp2wavTGV8UUn+XjViulMUgQ=",\n+      "requires": {\n+        "es5-ext": "0.10.39",\n+        "next-tick": "1.0.0"\n+      }\n+    },\n     "timespan": {\n       "version": "2.3.0",\n       "resolved": "https://registry.npmjs.org/timespan/-/timespan-2.3.0.tgz",\n       "integrity": "sha1-SQLOBAvRPYRcj1myfp1ZutbzmSk="\n     },\n+    "tmatch": {\n+      "version": "2.0.1",\n+      "resolved": "https://registry.npmjs.org/tmatch/-/tmatch-2.0.1.tgz",\n+      "integrity": "sha1-DFYkbzPzDaG409colauvFmYPOM8="\n+    },\n     "to-array": {\n       "version": "0.1.4",\n       "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz",\n@@ -6515,14 +8378,6 @@\n       "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",\n       "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M="\n     },\n-    "topo": {\n-      "version": "1.1.0",\n-      "resolved": "https://registry.npmjs.org/topo/-/topo-1.1.0.tgz",\n-      "integrity": "sha1-6ddRYV0buH3IZdsYL6HKCl71NtU=",\n-      "requires": {\n-        "hoek": "2.16.3"\n-      }\n-    },\n     "tough-cookie": {\n       "version": "2.3.2",\n       "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz",\n@@ -6542,6 +8397,18 @@\n       "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz",\n       "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc="\n     },\n+    "trim-newlines": {\n+      "version": "1.0.0",\n+      "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",\n+      "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=",\n+      "optional": true\n+    },\n+    "tryer": {\n+      "version": "1.0.0",\n+      "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.0.tgz",\n+      "integrity": "sha1-Antp+oIyJeVRys4+8DsR9qs3wdc=",\n+      "dev": true\n+    },\n     "tty-browserify": {\n       "version": "0.0.0",\n       "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",\n@@ -6576,6 +8443,11 @@\n         "mime-types": "2.1.15"\n       }\n     },\n+    "ua-parser-js": {\n+      "version": "0.7.17",\n+      "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.17.tgz",\n+      "integrity": "sha512-uRdSdu1oA1rncCQL7sCj8vSyZkgtL7faaw9Tc9rZ3mGgraQ7+Pdx7w5mnOSF3gw9ZNG6oc+KXfkon3bKuROm0g=="\n+    },\n     "uglify-js": {\n       "version": "3.2.1",\n       "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.2.1.tgz",\n@@ -6631,6 +8503,16 @@\n       "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz",\n       "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po="\n     },\n+    "underscore": {\n+      "version": "1.7.0",\n+      "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz",\n+      "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk="\n+    },\n+    "underscore.string": {\n+      "version": "2.4.0",\n+      "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.4.0.tgz",\n+      "integrity": "sha1-jN2PusTi0uoefi6Al8QvRCKA+Fs="\n+    },\n     "uniq": {\n       "version": "1.0.1",\n       "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz",\n@@ -6670,6 +8552,25 @@\n         }\n       }\n     },\n+    "url-parse": {\n+      "version": "1.2.0",\n+      "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.2.0.tgz",\n+      "integrity": "sha512-DT1XbYAfmQP65M/mE6OALxmXzZ/z1+e5zk2TcSKe/KiYbNGZxgtttzC0mR/sjopbpOXcbniq7eIKmocJnUWlEw==",\n+      "requires": {\n+        "querystringify": "1.0.0",\n+        "requires-port": "1.0.0"\n+      }\n+    },\n+    "utf8-bytes": {\n+      "version": "0.0.1",\n+      "resolved": "https://registry.npmjs.org/utf8-bytes/-/utf8-bytes-0.0.1.tgz",\n+      "integrity": "sha1-EWsCVEjJtQAIHN+/H01sbDfYg30="\n+    },\n+    "utfstring": {\n+      "version": "2.0.0",\n+      "resolved": "https://registry.npmjs.org/utfstring/-/utfstring-2.0.0.tgz",\n+      "integrity": "sha512-/ugBfyvIoLe9xqkFHio3CxXnpUKQ1p2LfTxPr6QTRj6GiwpHo73YGdh03UmAzDQNOWpNIE0J5nLss00L4xlWgg=="\n+    },\n     "util": {\n       "version": "0.10.3",\n       "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",\n@@ -6755,6 +8656,11 @@\n         "indexof": "0.0.1"\n       }\n     },\n+    "w3c-blob": {\n+      "version": "0.0.1",\n+      "resolved": "https://registry.npmjs.org/w3c-blob/-/w3c-blob-0.0.1.tgz",\n+      "integrity": "sha1-sM01KhpQ9RVWNCD/1YYflQ8dhbg="\n+    },\n     "watchpack": {\n       "version": "1.4.0",\n       "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.4.0.tgz",\n@@ -6770,11 +8676,19 @@\n           "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz",\n           "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==",\n           "requires": {\n-            "lodash": "4.17.4"\n+            "lodash": "4.17.5"\n           }\n         }\n       }\n     },\n+    "wbuf": {\n+      "version": "1.7.2",\n+      "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.2.tgz",\n+      "integrity": "sha1-1pe5nx9ZUS3ydRvkJ2nBWAtYAf4=",\n+      "requires": {\n+        "minimalistic-assert": "1.0.0"\n+      }\n+    },\n     "webidl-conversions": {\n       "version": "4.0.1",\n       "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.1.tgz",\n@@ -6782,14 +8696,14 @@\n       "dev": true\n     },\n     "webpack": {\n-      "version": "3.10.0",\n-      "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.10.0.tgz",\n-      "integrity": "sha512-fxxKXoicjdXNUMY7LIdY89tkJJJ0m1Oo8PQutZ5rLgWbV5QVKI15Cn7+/IHnRTd3vfKfiwBx6SBqlorAuNA8LA==",\n+      "version": "3.11.0",\n+      "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.11.0.tgz",\n+      "integrity": "sha512-3kOFejWqj5ISpJk4Qj/V7w98h9Vl52wak3CLiw/cDOfbVTq7FeoZ0SdoHHY9PYlHr50ZS42OfvzE2vB4nncKQg==",\n       "requires": {\n-        "acorn": "5.2.1",\n+        "acorn": "5.4.1",\n         "acorn-dynamic-import": "2.0.2",\n-        "ajv": "5.5.1",\n-        "ajv-keywords": "2.1.1",\n+        "ajv": "6.1.1",\n+        "ajv-keywords": "3.1.0",\n         "async": "2.6.0",\n         "enhanced-resolve": "3.4.1",\n         "escope": "3.6.0",\n@@ -6811,16 +8725,36 @@\n       },\n       "dependencies": {\n         "acorn": {\n-          "version": "5.2.1",\n-          "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.2.1.tgz",\n-          "integrity": "sha512-jG0u7c4Ly+3QkkW18V+NRDN+4bWHdln30NL1ZL2AvFZZmQe/BfopYCtghCKKVBUSetZ4QKcyA0pY6/4Gw8Pv8w=="\n+          "version": "5.4.1",\n+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.4.1.tgz",\n+          "integrity": "sha512-XLmq3H/BVvW6/GbxKryGxWORz1ebilSsUDlyC27bXhWGWAZWkGwS6FLHjOlwFXNFoWFQEO/Df4u0YYd0K3BQgQ=="\n+        },\n+        "ajv": {\n+          "version": "6.1.1",\n+          "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.1.1.tgz",\n+          "integrity": "sha1-l41Zf7wrfQ5aXD3esUmmgvKr+g4=",\n+          "requires": {\n+            "fast-deep-equal": "1.0.0",\n+            "fast-json-stable-stringify": "2.0.0",\n+            "json-schema-traverse": "0.3.1"\n+          }\n+        },\n+        "ajv-keywords": {\n+          "version": "3.1.0",\n+          "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.1.0.tgz",\n+          "integrity": "sha1-rCsnk5xUPpXSwG5/f1wnvkqlQ74="\n+        },\n+        "ansi-regex": {\n+          "version": "3.0.0",\n+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",\n+          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="\n         },\n         "async": {\n           "version": "2.6.0",\n           "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz",\n           "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==",\n           "requires": {\n-            "lodash": "4.17.4"\n+            "lodash": "4.17.5"\n           }\n         },\n         "camelcase": {\n@@ -6850,11 +8784,101 @@\n             }\n           }\n         },\n+        "find-up": {\n+          "version": "2.1.0",\n+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",\n+          "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",\n+          "requires": {\n+            "locate-path": "2.0.0"\n+          }\n+        },\n         "has-flag": {\n           "version": "2.0.0",\n           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",\n           "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE="\n         },\n+        "load-json-file": {\n+          "version": "2.0.0",\n+          "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",\n+          "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=",\n+          "requires": {\n+            "graceful-fs": "4.1.11",\n+            "parse-json": "2.2.0",\n+            "pify": "2.3.0",\n+            "strip-bom": "3.0.0"\n+          }\n+        },\n+        "os-locale": {\n+          "version": "2.1.0",\n+          "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz",\n+          "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==",\n+          "requires": {\n+            "execa": "0.7.0",\n+            "lcid": "1.0.0",\n+            "mem": "1.1.0"\n+          }\n+        },\n+        "path-type": {\n+          "version": "2.0.0",\n+          "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz",\n+          "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=",\n+          "requires": {\n+            "pify": "2.3.0"\n+          }\n+        },\n+        "pify": {\n+          "version": "2.3.0",\n+          "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",\n+          "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="\n+        },\n+        "read-pkg": {\n+          "version": "2.0.0",\n+          "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz",\n+          "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=",\n+          "requires": {\n+            "load-json-file": "2.0.0",\n+            "normalize-package-data": "2.4.0",\n+            "path-type": "2.0.0"\n+          }\n+        },\n+        "read-pkg-up": {\n+          "version": "2.0.0",\n+          "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz",\n+          "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=",\n+          "requires": {\n+            "find-up": "2.1.0",\n+            "read-pkg": "2.0.0"\n+          }\n+        },\n+        "string-width": {\n+          "version": "2.1.1",\n+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",\n+          "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",\n+          "requires": {\n+            "is-fullwidth-code-point": "2.0.0",\n+            "strip-ansi": "4.0.0"\n+          },\n+          "dependencies": {\n+            "is-fullwidth-code-point": {\n+              "version": "2.0.0",\n+              "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",\n+              "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="\n+            },\n+            "strip-ansi": {\n+              "version": "4.0.0",\n+              "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",\n+              "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",\n+              "requires": {\n+                "ansi-regex": "3.0.0"\n+              }\n+            }\n+          }\n+        },\n+        "strip-bom": {\n+          "version": "3.0.0",\n+          "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",\n+          "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM="\n+        },\n         "supports-color": {\n           "version": "4.5.0",\n           "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz",\n@@ -6863,6 +8887,11 @@\n             "has-flag": "2.0.0"\n           }\n         },\n+        "which-module": {\n+          "version": "2.0.0",\n+          "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",\n+          "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="\n+        },\n         "yargs": {\n           "version": "8.0.2",\n           "resolved": "https://registry.npmjs.org/yargs/-/yargs-8.0.2.tgz",\n@@ -6882,49 +8911,198 @@\n             "y18n": "3.2.1",\n             "yargs-parser": "7.0.0"\n           }\n+        },\n+        "yargs-parser": {\n+          "version": "7.0.0",\n+          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz",\n+          "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=",\n+          "requires": {\n+            "camelcase": "4.1.0"\n+          }\n         }\n       }\n     },\n     "webpack-bundle-analyzer": {\n-      "version": "2.9.1",\n-      "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-2.9.1.tgz",\n-      "integrity": "sha512-a+UcvlsXvCmclNgfThT8PVyuJKd029By7CxkYEbNNCfs0Lqj9gagjkdv3S3MBvCIKBaUGYs8l4UpiVI0bFoh2Q==",\n+      "version": "2.10.0",\n+      "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-2.10.0.tgz",\n+      "integrity": "sha512-eA/9F/ZLFlVXfCLYqefHFbelJ3JcvyeFdmpAG6Vu3iJNcisj3KWNPqu00lCqK9caeaesipVrGb9alUSi2lEvAg==",\n       "dev": true,\n       "requires": {\n-        "acorn": "5.2.1",\n-        "chalk": "1.1.3",\n-        "commander": "2.12.2",\n+        "acorn": "5.4.1",\n+        "bfj-node4": "5.2.1",\n+        "chalk": "2.3.1",\n+        "commander": "2.14.1",\n         "ejs": "2.5.7",\n         "express": "4.16.2",\n-        "filesize": "3.5.11",\n-        "gzip-size": "3.0.0",\n-        "lodash": "4.17.4",\n+        "filesize": "3.6.0",\n+        "gzip-size": "4.1.0",\n+        "lodash": "4.17.5",\n         "mkdirp": "0.5.1",\n         "opener": "1.4.3",\n-        "ws": "3.3.1"\n+        "ws": "4.0.0"\n       },\n       "dependencies": {\n         "acorn": {\n-          "version": "5.2.1",\n-          "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.2.1.tgz",\n-          "integrity": "sha512-jG0u7c4Ly+3QkkW18V+NRDN+4bWHdln30NL1ZL2AvFZZmQe/BfopYCtghCKKVBUSetZ4QKcyA0pY6/4Gw8Pv8w==",\n+          "version": "5.4.1",\n+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.4.1.tgz",\n+          "integrity": "sha512-XLmq3H/BVvW6/GbxKryGxWORz1ebilSsUDlyC27bXhWGWAZWkGwS6FLHjOlwFXNFoWFQEO/Df4u0YYd0K3BQgQ==",\n+          "dev": true\n+        },\n+        "ansi-styles": {\n+          "version": "3.2.0",\n+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz",\n+          "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==",\n+          "dev": true,\n+          "requires": {\n+            "color-convert": "1.9.1"\n+          }\n+        },\n+        "chalk": {\n+          "version": "2.3.1",\n+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.1.tgz",\n+          "integrity": "sha512-QUU4ofkDoMIVO7hcx1iPTISs88wsO8jA92RQIm4JAwZvFGGAV2hSAA1NX7oVj2Ej2Q6NDTcRDjPTFrMCRZoJ6g==",\n+          "dev": true,\n+          "requires": {\n+            "ansi-styles": "3.2.0",\n+            "escape-string-regexp": "1.0.5",\n+            "supports-color": "5.2.0"\n+          }\n+        },\n+        "commander": {\n+          "version": "2.14.1",\n+          "resolved": "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz",\n+          "integrity": "sha512-+YR16o3rK53SmWHU3rEM3tPAh2rwb1yPcQX5irVn7mb0gXbwuCCrnkbV5+PBfETdfg1vui07nM6PCG1zndcjQw==",\n+          "dev": true\n+        },\n+        "has-flag": {\n+          "version": "3.0.0",\n+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",\n+          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",\n           "dev": true\n         },\n+        "supports-color": {\n+          "version": "5.2.0",\n+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.2.0.tgz",\n+          "integrity": "sha512-F39vS48la4YvTZUPVeTqsjsFNrvcMwrV3RLZINsmHo+7djCvuUzSIeXOnZ5hmjef4bajL1dNccN+tg5XAliO5Q==",\n+          "dev": true,\n+          "requires": {\n+            "has-flag": "3.0.0"\n+          }\n+        },\n         "ultron": {\n-          "version": "1.1.0",\n-          "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.0.tgz",\n-          "integrity": "sha1-sHoualQagV/Go0zNRTO67DB8qGQ=",\n+          "version": "1.1.1",\n+          "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz",\n+          "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==",\n           "dev": true\n         },\n         "ws": {\n-          "version": "3.3.1",\n-          "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.1.tgz",\n-          "integrity": "sha512-8A/uRMnQy8KCQsmep1m7Bk+z/+LIkeF7w+TDMLtX1iZm5Hq9HsUDmgFGaW1ACW5Cj0b2Qo7wCvRhYN2ErUVp/A==",\n+          "version": "4.0.0",\n+          "resolved": "https://registry.npmjs.org/ws/-/ws-4.0.0.tgz",\n+          "integrity": "sha512-QYslsH44bH8O7/W2815u5DpnCpXWpEK44FmaHffNwgJI4JMaSZONgPBTOfrxJ29mXKbXak+LsJ2uAkDTYq2ptQ==",\n           "dev": true,\n           "requires": {\n             "async-limiter": "1.0.0",\n             "safe-buffer": "5.1.1",\n-            "ultron": "1.1.0"\n+            "ultron": "1.1.1"\n+          }\n+        }\n+      }\n+    },\n+    "webpack-dev-middleware": {\n+      "version": "1.12.2",\n+      "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-1.12.2.tgz",\n+      "integrity": "sha512-FCrqPy1yy/sN6U/SaEZcHKRXGlqU0DUaEBL45jkUYoB8foVb6wCnbIJ1HKIx+qUFTW+3JpVcCJCxZ8VATL4e+A==",\n+      "optional": true,\n+      "requires": {\n+        "memory-fs": "0.4.1",\n+        "mime": "1.6.0",\n+        "path-is-absolute": "1.0.1",\n+        "range-parser": "1.2.0",\n+        "time-stamp": "2.0.0"\n+      },\n+      "dependencies": {\n+        "mime": {\n+          "version": "1.6.0",\n+          "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",\n+          "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",\n+          "optional": true\n+        }\n+      }\n+    },\n+    "webpack-dev-server": {\n+      "version": "2.5.0",\n+      "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-2.5.0.tgz",\n+      "integrity": "sha1-TTanKLA7iyr6SO0wJCiEfOooQK0=",\n+      "optional": true,\n+      "requires": {\n+        "ansi-html": "0.0.7",\n+        "bonjour": "3.5.0",\n+        "chokidar": "1.7.0",\n+        "compression": "1.7.1",\n+        "connect-history-api-fallback": "1.5.0",\n+        "del": "3.0.0",\n+        "express": "4.16.2",\n+        "html-entities": "1.2.1",\n+        "http-proxy-middleware": "0.17.4",\n+        "internal-ip": "1.2.0",\n+        "opn": "4.0.2",\n+        "portfinder": "1.0.13",\n+        "selfsigned": "1.10.2",\n+        "serve-index": "1.9.1",\n+        "sockjs": "0.3.18",\n+        "sockjs-client": "1.1.2",\n+        "spdy": "3.4.7",\n+        "strip-ansi": "3.0.1",\n+        "supports-color": "3.2.3",\n+        "webpack-dev-middleware": "1.12.2",\n+        "yargs": "6.6.0"\n+      },\n+      "dependencies": {\n+        "camelcase": {\n+          "version": "3.0.0",\n+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",\n+          "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",\n+          "optional": true\n+        },\n+        "cliui": {\n+          "version": "3.2.0",\n+          "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",\n+          "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",\n+          "optional": true,\n+          "requires": {\n+            "string-width": "1.0.2",\n+            "strip-ansi": "3.0.1",\n+            "wrap-ansi": "2.1.0"\n+          }\n+        },\n+        "supports-color": {\n+          "version": "3.2.3",\n+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",\n+          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",\n+          "optional": true,\n+          "requires": {\n+            "has-flag": "1.0.0"\n+          }\n+        },\n+        "yargs": {\n+          "version": "6.6.0",\n+          "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz",\n+          "integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=",\n+          "optional": true,\n+          "requires": {\n+            "camelcase": "3.0.0",\n+            "cliui": "3.2.0",\n+            "decamelize": "1.2.0",\n+            "get-caller-file": "1.0.2",\n+            "os-locale": "1.4.0",\n+            "read-pkg-up": "1.0.1",\n+            "require-directory": "2.1.1",\n+            "require-main-filename": "1.0.1",\n+            "set-blocking": "2.0.0",\n+            "string-width": "1.0.2",\n+            "which-module": "1.0.0",\n+            "y18n": "3.2.1",\n+            "yargs-parser": "4.2.1"\n           }\n         }\n       }\n@@ -6945,6 +9123,20 @@\n         }\n       }\n     },\n+    "websocket-driver": {\n+      "version": "0.7.0",\n+      "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz",\n+      "integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=",\n+      "requires": {\n+        "http-parser-js": "0.4.10",\n+        "websocket-extensions": "0.1.3"\n+      }\n+    },\n+    "websocket-extensions": {\n+      "version": "0.1.3",\n+      "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz",\n+      "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg=="\n+    },\n     "whatwg-encoding": {\n       "version": "1.0.1",\n       "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.1.tgz",\n@@ -6962,6 +9154,11 @@\n         }\n       }\n     },\n+    "whatwg-fetch": {\n+      "version": "0.11.1",\n+      "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-0.11.1.tgz",\n+      "integrity": "sha1-bT3tJF/dl81yjg4lh7VLczlJ5mM="\n+    },\n     "whatwg-url": {\n       "version": "6.1.0",\n       "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.1.0.tgz",\n@@ -6987,9 +9184,10 @@\n       }\n     },\n     "which-module": {\n-      "version": "2.0.0",\n-      "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",\n-      "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="\n+      "version": "1.0.0",\n+      "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz",\n+      "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=",\n+      "optional": true\n     },\n     "wide-align": {\n       "version": "1.1.2",\n@@ -7049,6 +9247,27 @@\n       "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",\n       "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc="\n     },\n+    "worker-loader": {\n+      "version": "0.7.1",\n+      "resolved": "https://registry.npmjs.org/worker-loader/-/worker-loader-0.7.1.tgz",\n+      "integrity": "sha1-kf/S4vv3aSGkPoyjdm0S6VN/XXA=",\n+      "requires": {\n+        "loader-utils": "0.2.17"\n+      },\n+      "dependencies": {\n+        "loader-utils": {\n+          "version": "0.2.17",\n+          "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz",\n+          "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=",\n+          "requires": {\n+            "big.js": "3.1.3",\n+            "emojis-list": "2.1.0",\n+            "json5": "0.5.1",\n+            "object-assign": "4.1.1"\n+          }\n+        }\n+      }\n+    },\n     "wrap-ansi": {\n       "version": "2.1.0",\n       "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",\n@@ -7056,18 +9275,6 @@\n       "requires": {\n         "string-width": "1.0.2",\n         "strip-ansi": "3.0.1"\n-      },\n-      "dependencies": {\n-        "string-width": {\n-          "version": "1.0.2",\n-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",\n-          "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",\n-          "requires": {\n-            "code-point-at": "1.1.0",\n-            "is-fullwidth-code-point": "1.0.0",\n-            "strip-ansi": "3.0.1"\n-          }\n-        }\n       }\n     },\n     "wrappy": {\n@@ -7089,6 +9296,26 @@\n       "resolved": "https://registry.npmjs.org/wtf-8/-/wtf-8-1.0.0.tgz",\n       "integrity": "sha1-OS2LotDxw00e4tYw8V0O+2jhBIo="\n     },\n+    "xml": {\n+      "version": "1.0.1",\n+      "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz",\n+      "integrity": "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU="\n+    },\n+    "xml-but-prettier": {\n+      "version": "1.0.1",\n+      "resolved": "https://registry.npmjs.org/xml-but-prettier/-/xml-but-prettier-1.0.1.tgz",\n+      "integrity": "sha1-9aMyZ+1CzNTjVcYlV6XjmwH7QPM=",\n+      "requires": {\n+        "repeat-string": "1.6.1"\n+      },\n+      "dependencies": {\n+        "repeat-string": {\n+          "version": "1.6.1",\n+          "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",\n+          "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc="\n+        }\n+      }\n+    },\n     "xml-name-validator": {\n       "version": "2.0.1",\n       "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz",\n@@ -7100,6 +9327,11 @@\n       "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz",\n       "integrity": "sha1-GFqIjATspGw+QHDZn3tJ3jUomS0="\n     },\n+    "xss-filters": {\n+      "version": "1.2.7",\n+      "resolved": "https://registry.npmjs.org/xss-filters/-/xss-filters-1.2.7.tgz",\n+      "integrity": "sha1-Wfod4gHzby80cNysX1jMwoMLCpo="\n+    },\n     "xtend": {\n       "version": "4.0.1",\n       "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",\n@@ -7115,6 +9347,11 @@\n       "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",\n       "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="\n     },\n+    "yaml-js": {\n+      "version": "0.2.0",\n+      "resolved": "https://registry.npmjs.org/yaml-js/-/yaml-js-0.2.0.tgz",\n+      "integrity": "sha512-3s7pA2Imzux1zIPyrSEj01B1fvAcb2TwNRhXjqhWosJn2CaWlQSshE1tJOFAjtPYHEcCVmOEtko1Km+qGH/06A=="\n+    },\n     "yargs": {\n       "version": "3.10.0",\n       "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",\n@@ -7127,17 +9364,19 @@\n       }\n     },\n     "yargs-parser": {\n-      "version": "7.0.0",\n-      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz",\n-      "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=",\n+      "version": "4.2.1",\n+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz",\n+      "integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=",\n+      "optional": true,\n       "requires": {\n-        "camelcase": "4.1.0"\n+        "camelcase": "3.0.0"\n       },\n       "dependencies": {\n         "camelcase": {\n-          "version": "4.1.0",\n-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",\n-          "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0="\n+          "version": "3.0.0",\n+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",\n+          "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",\n+          "optional": true\n         }\n       }\n     },\n@@ -7145,6 +9384,11 @@\n       "version": "0.1.2",\n       "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz",\n       "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk="\n+    },\n+    "zenscroll": {\n+      "version": "4.0.0",\n+      "resolved": "https://registry.npmjs.org/zenscroll/-/zenscroll-4.0.0.tgz",\n+      "integrity": "sha1-S676Shufs7zG02XiAGSP8znkR6g="\n     }\n   }\n }\ndiff --git a/package.json b/package.json\nindex 0be3f5d8..bcb99686 100644\n--- a/package.json\n+++ b/package.json\n@@ -1,6 +1,6 @@\n {\n   "name": "Nightscout",\n-  "version": "0.10.3-dev-20171205",\n+  "version": "0.10.3-dev-20180304",\n   "description": "Nightscout acts as a web-based CGM (Continuous Glucose Montinor) to allow multiple caregivers to remotely view a patients glucose data in realtime.",\n   "license": "AGPL-3.0",\n   "author": "Nightscout Team",\n@@ -27,8 +27,9 @@\n     "start": "node server.js",\n     "test": "make test",\n     "env": "env",\n-    "postinstall": "webpack --config webpack.config.js && npm run-script update-buster",\n-    "bundle": "webpack --config webpack.config.js && npm run-script update-buster",\n+    "postinstall": "webpack --mode production --config webpack.config.js && npm run-script update-buster",\n+    "bundle": "webpack --mode production --config webpack.config.js && npm run-script update-buster",\n+    "bundle-dev": "webpack --mode development --config webpack.config.js && npm run-script update-buster",\n     "update-buster": "node bin/generateCacheBuster.js >tmp/cacheBusterToken"\n   },\n   "config": {\n@@ -46,39 +47,40 @@\n     }\n   },\n   "engines": {\n-    "node": "8.9.x",\n-    "npm": "5.6.x || 5.2.0 || 5.3.0 ||\xa05.0.3"\n+    "node": "8.x||9.x",\n+    "npm": "5.8.x || 5.7.x || 5.6.x"\n   },\n   "dependencies": {\n+    "ajv": "^6.4.0",\n     "async": "^0.9.2",\n     "body-parser": "^1.18.2",\n     "bootevent": "0.0.1",\n-    "compression": "^1.7.1",\n-    "css-loader": "^0.28.9",\n+    "compression": "^1.7.2",\n+    "css-loader": "^0.28.10",\n     "cssmin": "^0.4.3",\n     "d3": "^3.5.17",\n-    "ejs": "^2.5.7",\n+    "ejs": "^2.5.8",\n     "errorhandler": "^1.5.0",\n     "event-stream": "^3.3.4",\n     "expand-braces": "^0.1.2",\n     "expose-loader": "^0.7.4",\n     "express": "^4.16.2",\n     "express-extension-to-accept": "0.0.2",\n-    "express-minify": "^0.2.0",\n-    "file-loader": "^1.1.6",\n+    "express-minify": "^1.0.0",\n+    "file-loader": "^1.1.11",\n     "flot": "^0.8.0-alpha",\n     "forever": "^0.15.3",\n-    "jquery": "^2.2.4",\n-    "jquery-ui-bundle": "^1.12.1",\n-    "jquery.tipsy": "^1.0.3",\n+    "jquery": "^3.3.1",\n+    "jquery-ui-bundle": "^1.12.1-migrate",\n+    "jquery.tooltips": "^1.0.0",\n     "js-storage": "^1.0.4",\n-    "jsonwebtoken": "^7.4.3",\n-    "lodash": "^4.17.4",\n+    "jsonwebtoken": "^8.2.0",\n+    "lodash": "^4.17.5",\n     "long": "^3.2.0",\n     "minimed-connect-to-nightscout": "git://github.com/mddub/minimed-connect-to-nightscout.git#v1.1.0",\n-    "moment": "^2.19.3",\n+    "moment": "^2.21.0",\n     "moment-timezone": "^0.5.14",\n-    "mongodb": "^3.0.2",\n+    "mongodb": "^3.0.5",\n     "mongomock": "^0.1.2",\n     "mqtt": "^0.3.13",\n     "node-cache": "^4.1.1",\n@@ -91,11 +93,12 @@\n     "share2nightscout-bridge": "git://github.com/bewest/share2nightscout-bridge.git#wip/generalize",\n     "shiro-trie": "^0.3.13",\n     "simple-statistics": "^0.7.0",\n-    "socket.io": "^1.7.4",\n-    "style-loader": "^0.20.1",\n+    "socket.io": "^2.0.4",\n+    "style-loader": "^0.20.2",\n     "traverse": "^0.6.6",\n-    "uglify-js": "^3.2.1",\n-    "webpack": "^3.10.0"\n+    "uglify-js": "^3.3.13",\n+    "uuid": "^3.2.1",\n+    "webpack": "^4.3.0"\n   },\n   "devDependencies": {\n     "benv": "3.3.0",\n@@ -104,6 +107,7 @@\n     "mocha": "~3.1.2",\n     "should": "~11.1.1",\n     "supertest": "~2.0.0",\n-    "webpack-bundle-analyzer": "^2.9.1"\n+    "webpack-bundle-analyzer": "^2.11.1",\n+    "webpack-cli": "^2.0.13"\n   }\n }\ndiff --git a/static/api-docs.html b/static/api-docs.html\nindex f58fd52b..dfec386b 100644\n--- a/static/api-docs.html\n+++ b/static/api-docs.html\n@@ -1,9 +1,11 @@\n+<!-- HTML for static distribution bundle build -->\n <!DOCTYPE html>\n-<html>\n+<html lang="en">\n <head>\n   <meta charset="UTF-8">\n-  <title>Nightscout API</title>\n-\n+  <title>Swagger UI: Nightscout API</title>\n+  <link href="https://fonts.googleapis.com/css?family=Open+Sans:400,700|Source+Code+Pro:300,600|Titillium+Web:400,600,700" rel="stylesheet">\n+  <link rel="stylesheet" type="text/css" href="swagger-ui-dist/swagger-ui.css" >\n   <link rel="apple-touch-icon" sizes="57x57" href="/images/apple-touch-icon-57x57.png">\n   <link rel="apple-touch-icon" sizes="60x60" href="/images/apple-touch-icon-60x60.png">\n   <link rel="apple-touch-icon" sizes="72x72" href="/images/apple-touch-icon-72x72.png">\n@@ -22,89 +24,88 @@\n   <meta name="msapplication-TileColor" content="#00a300">\n   <meta name="msapplication-TileImage" content="/images/mstile-144x144.png">\n   <meta name="msapplication-config" content="/browserconfig.xml">\n-  <meta name="theme-color" content="#333333">\n+  <style>\n+    html\n+    {\n+      box-sizing: border-box;\n+      overflow: -moz-scrollbars-vertical;\n+      overflow-y: scroll;\n+    }\n+    *,\n+    *:before,\n+    *:after\n+    {\n+      box-sizing: inherit;\n+    }\n+\n+    body {\n+      margin:0;\n+      background: #fafafa;\n+    }\n+  </style>\n+</head>\n \n-  <link href=\'/bower_components/swagger-ui/dist/css/typography.css\' media=\'screen\' rel=\'stylesheet\' type=\'text/css\'/>\n-  <link href=\'/bower_components/swagger-ui/dist/css/reset.css\' media=\'screen\' rel=\'stylesheet\' type=\'text/css\'/>\n-  <link href=\'/bower_components/swagger-ui/dist/css/screen.css\' media=\'screen\' rel=\'stylesheet\' type=\'text/css\'/>\n-  <link href=\'/bower_components/swagger-ui/dist/css/reset.css\' media=\'print\' rel=\'stylesheet\' type=\'text/css\'/>\n-  <link href=\'/bower_components/swagger-ui/dist/css/print.css\' media=\'print\' rel=\'stylesheet\' type=\'text/css\'/>\n-  <script src=\'/bower_components/swagger-ui/dist/lib/jquery-1.8.0.min.js\' type=\'text/javascript\'></script>\n-  <script src=\'/bower_components/swagger-ui/dist/lib/jquery.slideto.min.js\' type=\'text/javascript\'></script>\n-  <script src=\'/bower_components/swagger-ui/dist/lib/jquery.wiggle.min.js\' type=\'text/javascript\'></script>\n-  <script src=\'/bower_components/swagger-ui/dist/lib/jquery.ba-bbq.min.js\' type=\'text/javascript\'></script>\n-  <script src=\'/bower_components/swagger-ui/dist/lib/handlebars-2.0.0.js\' type=\'text/javascript\'></script>\n-  <script src=\'/bower_components/swagger-ui/dist/lib/underscore-min.js\' type=\'text/javascript\'></script>\n-  <script src=\'/bower_components/swagger-ui/dist/lib/backbone-min.js\' type=\'text/javascript\'></script>\n-  <script src=\'/bower_components/swagger-ui/dist/swagger-ui.js\' type=\'text/javascript\'></script>\n-  <script src=\'/bower_components/swagger-ui/dist/lib/highlight.7.3.pack.js\' type=\'text/javascript\'></script>\n-  <script src=\'/bower_components/swagger-ui/dist/lib/jsoneditor.min.js\' type=\'text/javascript\'></script>\n-  <script src=\'/bower_components/swagger-ui/dist/lib/marked.js\' type=\'text/javascript\'></script>\n-  <script src=\'/bower_components/swagger-ui/dist/lib/swagger-oauth.js\' type=\'text/javascript\'></script>\n+<body>\n \n-  <!-- Some basic translations -->\n-  <!-- <script src=\'lang/translator.js\' type=\'text/javascript\'></script> -->\n-  <!-- <script src=\'lang/ru.js\' type=\'text/javascript\'></script> -->\n-  <!-- <script src=\'lang/en.js\' type=\'text/javascript\'></script> -->\n+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position:absolute;width:0;height:0">\n+  <defs>\n+    <symbol viewBox="0 0 20 20" id="unlocked">\n+          <path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V6h2v-.801C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8z"></path>\n+    </symbol>\n \n-  <script type="text/javascript">\n-    $(function () {\n-      // Pre load translate...\n-      if(window.SwaggerTranslator) {\n-        window.SwaggerTranslator.translate();\n-      }\n-      window.swaggerUi = new SwaggerUi({\n-        url: \'/swagger.yaml\',\n-        dom_id: \'swagger-ui-container\',\n-        supportedSubmitMethods: [\'get\', \'post\', \'put\', \'delete\', \'patch\'],\n-        onComplete: function(/*swaggerApi, swaggerUi*/){\n-          if(window.SwaggerTranslator) {\n-            window.SwaggerTranslator.translate();\n-          }\n+    <symbol viewBox="0 0 20 20" id="locked">\n+      <path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8zM12 8H8V5.199C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8z"/>\n+    </symbol>\n \n-          $(\'pre code\').each(function(i, e) {\n-            hljs.highlightBlock(e)\n-          });\n+    <symbol viewBox="0 0 20 20" id="close">\n+      <path d="M14.348 14.849c-.469.469-1.229.469-1.697 0L10 11.819l-2.651 3.029c-.469.469-1.229.469-1.697 0-.469-.469-.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-.469-.469-.469-1.228 0-1.697.469-.469 1.228-.469 1.697 0L10 8.183l2.651-3.031c.469-.469 1.228-.469 1.697 0 .469.469.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c.469.469.469 1.229 0 1.698z"/>\n+    </symbol>\n \n-          addApiKeyAuthorization();\n-        },\n-        onFailure: function(data) {\n-          log(\'Unable to Load SwaggerUI\', data);\n-        },\n-        docExpansion: \'none\',\n-        apisSorter: \'alpha\',\n-        showRequestHeaders: false\n-      });\n+    <symbol viewBox="0 0 20 20" id="large-arrow">\n+      <path d="M13.25 10L6.109 2.58c-.268-.27-.268-.707 0-.979.268-.27.701-.27.969 0l7.83 7.908c.268.271.268.709 0 .979l-7.83 7.908c-.268.271-.701.27-.969 0-.268-.269-.268-.707 0-.979L13.25 10z"/>\n+    </symbol>\n \n-      function addApiKeyAuthorization(){\n-        var key = encodeURIComponent($(\'#input_apiKey\')[0].value);\n-        if(key && key.trim() !== \'\') {\n-          var apiKeyAuth = new SwaggerClient.ApiKeyAuthorization(\'api_secret\', key, \'query\');\n-          window.swaggerUi.api.clientAuthorizations.add(\'api_secret\', apiKeyAuth);\n-          log(\'added key \' + key);\n-        }\n-      }\n+    <symbol viewBox="0 0 20 20" id="large-arrow-down">\n+      <path d="M17.418 6.109c.272-.268.709-.268.979 0s.271.701 0 .969l-7.908 7.83c-.27.268-.707.268-.979 0l-7.908-7.83c-.27-.268-.27-.701 0-.969.271-.268.709-.268.979 0L10 13.25l7.418-7.141z"/>\n+    </symbol>\n \n-      $(\'#input_apiKey\').change(addApiKeyAuthorization);\n \n-      window.swaggerUi.load();\n-    });\n-  </script>\n-</head>\n+    <symbol viewBox="0 0 24 24" id="jump-to">\n+      <path d="M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.41L5.83 13H21V7z"/>\n+    </symbol>\n+    \n+    <symbol viewBox="0 0 24 24" id="expand">\n+      <path d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"/>\n+    </symbol>\n \n-<body class="swagger-section">\n-<div id=\'header\'>\n-  <div class="swagger-ui-wrap">\n-    <a id="logo" href="http://swagger.io">swagger</a>\n-    <form id=\'api_selector\'>\n-      <div class=\'input\'><input placeholder="http://example.com/api" id="input_baseUrl" name="baseUrl" type="text"/></div>\n-      <div class=\'input\'><input placeholder="api_secret" id="input_apiKey" name="apiKey" type="text"/></div>\n-      <div class=\'input\'><a id="explore" href="#" data-sw-translate>Explore</a></div>\n-    </form>\n-  </div>\n-</div>\n+  </defs>\n+</svg>\n \n-<div id="message-bar" class="swagger-ui-wrap" data-sw-translate>&nbsp;</div>\n-<div id="swagger-ui-container" class="swagger-ui-wrap"></div>\n+<div id="swagger-ui"></div>\n+\n+<script src="swagger-ui-dist/swagger-ui-bundle.js"> </script>\n+<script src="swagger-ui-dist/swagger-ui-standalone-preset.js"> </script>\n+<script>\n+window.onload = function() {\n+  \n+  // Build a system\n+  const ui = SwaggerUIBundle({\n+    url: "/swagger.json",\n+    dom_id: \'#swagger-ui\',\n+    deepLinking: true,\n+    presets: [\n+      SwaggerUIBundle.presets.apis,\n+      SwaggerUIStandalonePreset\n+    ],\n+    plugins: [\n+      SwaggerUIBundle.plugins.DownloadUrl\n+    ],\n+    layout: "StandaloneLayout"\n+  })\n+\n+  window.ui = ui\n+}\n+</script>\n </body>\n+\n </html>\ndiff --git a/swagger.json b/swagger.json\nnew file mode 100644\nindex 00000000..6aada878\n--- /dev/null\n+++ b/swagger.json\n@@ -0,0 +1,952 @@\n+{\n+  "openapi": "3.0.0",\n+  "servers": [\n+    {\n+      "url": "/api/v1"\n+    }\n+  ],\n+  "info": {\n+    "title": "Nightscout API",\n+    "description": "Own your DData with the Nightscout API",\n+    "version": "0.10.3-dev-20171205",\n+    "license": {\n+      "name": "AGPL 3",\n+      "url": "https://www.gnu.org/licenses/agpl.txt"\n+    }\n+  },\n+  "security": [\n+    {\n+      "api_secret": [],\n+      "token_in_url": [],\n+      "jwtoken": []\n+    }\n+  ],\n+  "paths": {\n+    "/entries/{spec}": {\n+      "get": {\n+        "summary": "All Entries matching query",\n+        "description": "The Entries endpoint returns information about the\\nNightscout entries.\\n",\n+        "parameters": [\n+          {\n+            "name": "spec",\n+            "in": "path",\n+            "description": "entry id, such as `55cf81bc436037528ec75fa5` or a type filter such\\nas `sgv`, `mbg`, etc.\\n",\n+            "required": true,\n+            "schema": {\n+              "type": "string",\n+              "default": "sgv"\n+            }\n+          },\n+          {\n+            "name": "find",\n+            "in": "query",\n+            "description": "The query used to find entries, support nested query syntax, for\\nexample `find[dateString][$gte]=2015-08-27`.  All find parameters\\nare interpreted as strings.\\n",\n+            "required": false,\n+            "schema": {\n+              "type": "string"\n+            }\n+          },\n+          {\n+            "name": "count",\n+            "in": "query",\n+            "description": "Number of entries to return.",\n+            "required": false,\n+            "schema": {\n+              "type": "number"\n+            }\n+          }\n+        ],\n+        "tags": [\n+          "Entries"\n+        ],\n+        "responses": {\n+          "200": {\n+            "description": "An array of entries",\n+            "content": {\n+              "application/json": {\n+                "schema": {\n+                  "$ref": "#/components/schemas/Entries"\n+                }\n+              }\n+            }\n+          },\n+          "default": {\n+            "description": "Entries",\n+            "content": {\n+              "application/json": {\n+                "schema": {\n+                  "$ref": "#/components/schemas/Entries"\n+                }\n+              }\n+            }\n+          }\n+        }\n+      }\n+    },\n+    "/slice/{storage}/{field}/{type}/{prefix}/{regex}": {\n+      "get": {\n+        "summary": "All Entries matching query",\n+        "description": "The Entries endpoint returns information about the Nightscout entries.",\n+        "parameters": [\n+          {\n+            "name": "storage",\n+            "in": "path",\n+            "description": "Prefix to use in constructing a prefix-based regex, default is `entries`.",\n+            "required": true,\n+            "schema": {\n+              "type": "string",\n+              "default": "entries"\n+            }\n+          },\n+          {\n+            "name": "field",\n+            "in": "path",\n+            "description": "Name of the field to use Regex against in query object, default is `dateString`.",\n+            "required": true,\n+            "schema": {\n+              "type": "string",\n+              "default": "dateString"\n+            }\n+          },\n+          {\n+            "name": "type",\n+            "in": "path",\n+            "description": "The type field to search against, default is sgv.",\n+            "required": true,\n+            "schema": {\n+              "type": "string",\n+              "default": "sgv"\n+            }\n+          },\n+          {\n+            "name": "prefix",\n+            "in": "path",\n+            "description": "Prefix to use in constructing a prefix-based regex.",\n+            "required": true,\n+            "schema": {\n+              "type": "string",\n+              "default": "2015"\n+            }\n+          },\n+          {\n+            "name": "regex",\n+            "in": "path",\n+            "description": "Tail part of regexp to use in expanding/construccting a query object.\\nRegexp also has bash-style brace and glob expansion applied to it,\\ncreating ways to search for modal times of day, perhaps using\\nsomething like this syntax: `T{15..17}:.*`, this would search for\\nall records from 3pm to 5pm.\\n",\n+            "required": true,\n+            "schema": {\n+              "type": "string",\n+              "default": ".*"\n+            }\n+          },\n+          {\n+            "name": "find",\n+            "in": "query",\n+            "description": "The query used to find entries, support nested query syntax, for\\nexample `find[dateString][$gte]=2015-08-27`.  All find parameters\\nare interpreted as strings.\\n",\n+            "required": false,\n+            "schema": {\n+              "type": "string"\n+            }\n+          },\n+          {\n+            "name": "count",\n+            "in": "query",\n+            "description": "Number of entries to return.",\n+            "required": false,\n+            "schema": {\n+              "type": "number"\n+            }\n+          }\n+        ],\n+        "tags": [\n+          "Entries"\n+        ],\n+        "responses": {\n+          "200": {\n+            "description": "An array of entries",\n+            "content": {\n+              "application/json": {\n+                "schema": {\n+                  "$ref": "#/components/schemas/Entries"\n+                }\n+              }\n+            }\n+          },\n+          "default": {\n+            "description": "Unexpected error",\n+            "content": {\n+              "application/json": {\n+                "schema": {\n+                  "$ref": "#/components/schemas/Error"\n+                }\n+              }\n+            }\n+          }\n+        }\n+      }\n+    },\n+    "/echo/{storage}/{spec}": {\n+      "get": {\n+        "summary": "View generated Mongo Query object",\n+        "description": "Information about the mongo query object created by the query.\\n",\n+        "parameters": [\n+          {\n+            "name": "storage",\n+            "in": "path",\n+            "description": "`entries`, or `treatments` to select the storage layer.\\n",\n+            "required": true,\n+            "schema": {\n+              "type": "string",\n+              "default": "sgv"\n+            }\n+          },\n+          {\n+            "name": "spec",\n+            "in": "path",\n+            "description": "entry id, such as `55cf81bc436037528ec75fa5` or a type filter such\\nas `sgv`, `mbg`, etc.\\nThis parameter is optional.\\n",\n+            "required": true,\n+            "schema": {\n+              "type": "string",\n+              "default": "sgv"\n+            }\n+          },\n+          {\n+            "name": "find",\n+            "in": "query",\n+            "description": "The query used to find entries, support nested query syntax, for\\nexample `find[dateString][$gte]=2015-08-27`.  All find parameters\\nare interpreted as strings.\\n",\n+            "required": false,\n+            "schema": {\n+              "type": "string"\n+            }\n+          },\n+          {\n+            "name": "count",\n+            "in": "query",\n+            "description": "Number of entries to return.",\n+            "required": false,\n+            "schema": {\n+              "type": "number"\n+            }\n+          }\n+        ],\n+        "tags": [\n+          "Entries",\n+          "Debug"\n+        ],\n+        "responses": {\n+          "200": {\n+            "description": "An array of entries",\n+            "content": {\n+              "application/json": {\n+                "schema": {\n+                  "$ref": "#/components/schemas/MongoQuery"\n+                }\n+              }\n+            }\n+          }\n+        }\n+      }\n+    },\n+    "/times/echo/{prefix}/{regex}": {\n+      "get": {\n+        "summary": "Echo the query object to be used.",\n+        "description": "Echo debug information about the query object constructed.",\n+        "parameters": [\n+          {\n+            "name": "prefix",\n+            "in": "path",\n+            "description": "Prefix to use in constructing a prefix-based regex.",\n+            "required": true,\n+            "schema": {\n+              "type": "string"\n+            }\n+          },\n+          {\n+            "name": "regex",\n+            "in": "path",\n+            "description": "Tail part of regexp to use in expanding/construccting a query object.\\nRegexp also has bash-style brace and glob expansion applied to it,\\ncreating ways to search for modal times of day, perhaps using\\nsomething like this syntax: `T{15..17}:.*`, this would search for\\nall records from 3pm to 5pm.\\n",\n+            "required": true,\n+            "schema": {\n+              "type": "string"\n+            }\n+          },\n+          {\n+            "name": "find",\n+            "in": "query",\n+            "description": "The query used to find entries, support nested query syntax, for example `find[dateString][$gte]=2015-08-27`.  All find parameters are interpreted as strings.",\n+            "required": false,\n+            "schema": {\n+              "type": "string"\n+            }\n+          },\n+          {\n+            "name": "count",\n+            "in": "query",\n+            "description": "Number of entries to return.",\n+            "required": false,\n+            "schema": {\n+              "type": "number"\n+            }\n+          }\n+        ],\n+        "tags": [\n+          "Entries",\n+          "Debug"\n+        ],\n+        "responses": {\n+          "200": {\n+            "description": "An array of entries",\n+            "content": {\n+              "application/json": {\n+                "schema": {\n+                  "$ref": "#/components/schemas/MongoQuery"\n+                }\n+              }\n+            }\n+          },\n+          "default": {\n+            "description": "Unexpected error",\n+            "content": {\n+              "application/json": {\n+                "schema": {\n+                  "$ref": "#/components/schemas/Error"\n+                }\n+              }\n+            }\n+          }\n+        }\n+      }\n+    },\n+    "/times/{prefix}/{regex}": {\n+      "get": {\n+        "summary": "All Entries matching query",\n+        "description": "The Entries endpoint returns information about the Nightscout entries.",\n+        "parameters": [\n+          {\n+            "name": "prefix",\n+            "in": "path",\n+            "description": "Prefix to use in constructing a prefix-based regex.",\n+            "required": true,\n+            "schema": {\n+              "type": "string"\n+            }\n+          },\n+          {\n+            "name": "regex",\n+            "in": "path",\n+            "description": "Tail part of regexp to use in expanding/construccting a query object.\\nRegexp also has bash-style brace and glob expansion applied to it,\\ncreating ways to search for modal times of day, perhaps using\\nsomething like this syntax: `T{15..17}:.*`, this would search for\\nall records from 3pm to 5pm.\\n",\n+            "required": true,\n+            "schema": {\n+              "type": "string"\n+            }\n+          },\n+          {\n+            "name": "find",\n+            "in": "query",\n+            "description": "The query used to find entries, support nested query syntax, for example `find[dateString][$gte]=2015-08-27`.  All find parameters are interpreted as strings.",\n+            "required": false,\n+            "schema": {\n+              "type": "string"\n+            }\n+          },\n+          {\n+            "name": "count",\n+            "in": "query",\n+            "description": "Number of entries to return.",\n+            "required": false,\n+            "schema": {\n+              "type": "number"\n+            }\n+          }\n+        ],\n+        "tags": [\n+          "Entries"\n+        ],\n+        "responses": {\n+          "200": {\n+            "description": "An array of entries",\n+            "content": {\n+              "application/json": {\n+                "schema": {\n+                  "$ref": "#/components/schemas/Entries"\n+                }\n+              }\n+            }\n+          },\n+          "default": {\n+            "description": "Unexpected error",\n+            "content": {\n+              "application/json": {\n+                "schema": {\n+                  "$ref": "#/components/schemas/Error"\n+                }\n+              }\n+            }\n+          }\n+        }\n+      }\n+    },\n+    "/entries": {\n+      "get": {\n+        "summary": "All Entries matching query",\n+        "description": "The Entries endpoint returns information about the Nightscout entries.",\n+        "parameters": [\n+          {\n+            "name": "find",\n+            "in": "query",\n+            "description": "The query used to find entries, support nested query syntax, for example `find[dateString][$gte]=2015-08-27`.  All find parameters are interpreted as strings.",\n+            "required": false,\n+            "schema": {\n+              "type": "string"\n+            }\n+          },\n+          {\n+            "name": "count",\n+            "in": "query",\n+            "description": "Number of entries to return.",\n+            "required": false,\n+            "schema": {\n+              "type": "number"\n+            }\n+          }\n+        ],\n+        "tags": [\n+          "Entries"\n+        ],\n+        "responses": {\n+          "200": {\n+            "description": "An array of entries",\n+            "content": {\n+              "application/json": {\n+                "schema": {\n+                  "$ref": "#/components/schemas/Entries"\n+                }\n+              }\n+            }\n+          },\n+          "default": {\n+            "description": "Unexpected error",\n+            "content": {\n+              "application/json": {\n+                "schema": {\n+                  "$ref": "#/components/schemas/Error"\n+                }\n+              }\n+            }\n+          }\n+        }\n+      },\n+      "post": {\n+        "tags": [\n+          "Entries"\n+        ],\n+        "summary": "Add new entries.",\n+        "description": "",\n+        "operationId": "addEntries",\n+        "responses": {\n+          "200": {\n+            "description": "Rejected list of entries.  Empty list is success."\n+          },\n+          "405": {\n+            "description": "Invalid input"\n+          }\n+        },\n+        "requestBody": {\n+          "content": {\n+            "application/json": {\n+              "schema": {\n+                "$ref": "#/components/schemas/Entries"\n+              }\n+            },\n+            "text/plain": {\n+              "schema": {\n+                "$ref": "#/components/schemas/Entries"\n+              }\n+            }\n+          },\n+          "description": "Entries to be uploaded.",\n+          "required": true\n+        }\n+      },\n+      "delete": {\n+        "tags": [\n+          "Entries"\n+        ],\n+        "summary": "Delete entries matching query.",\n+        "description": "Remove entries, same search syntax as GET.",\n+        "operationId": "remove",\n+        "parameters": [\n+          {\n+            "name": "find",\n+            "in": "query",\n+            "description": "The query used to find entries, support nested query syntax, for example `find[dateString][$gte]=2015-08-27`.  All find parameters are interpreted as strings.",\n+            "required": false,\n+            "schema": {\n+              "type": "string"\n+            }\n+          },\n+          {\n+            "name": "count",\n+            "in": "query",\n+            "description": "Number of entries to return.",\n+            "required": false,\n+            "schema": {\n+              "type": "number"\n+            }\n+          }\n+        ],\n+        "responses": {\n+          "200": {\n+            "description": "Empty list is success."\n+          }\n+        }\n+      }\n+    },\n+    "/treatments": {\n+      "get": {\n+        "summary": "Treatments",\n+        "description": "The Treatments endpoint returns information about the Nightscout treatments.",\n+        "tags": [\n+          "Treatments"\n+        ],\n+        "parameters": [\n+          {\n+            "name": "find",\n+            "in": "query",\n+            "description": "The query used to find entries, supports nested query syntax.  Examples `find[insulin][$gte]=3` `find[carb][$gte]=100` `find[eventType]=Correction+Bolus` All find parameters are interpreted as strings.",\n+            "required": false,\n+            "schema": {\n+              "type": "string"\n+            }\n+          },\n+          {\n+            "name": "count",\n+            "in": "query",\n+            "description": "Number of entries to return.",\n+            "required": false,\n+            "schema": {\n+              "type": "number"\n+            }\n+          }\n+        ],\n+        "responses": {\n+          "200": {\n+            "description": "An array of treatments",\n+            "content": {\n+              "application/json": {\n+                "schema": {\n+                  "$ref": "#/components/schemas/Treatments"\n+                }\n+              }\n+            }\n+          },\n+          "default": {\n+            "description": "Unexpected error",\n+            "content": {\n+              "application/json": {\n+                "schema": {\n+                  "$ref": "#/components/schemas/Error"\n+                }\n+              }\n+            }\n+          }\n+        }\n+      },\n+      "post": {\n+        "tags": [\n+          "Treatments"\n+        ],\n+        "summary": "Add new treatments.",\n+        "description": "",\n+        "operationId": "addTreatments",\n+        "responses": {\n+          "200": {\n+            "description": "Rejected list of treatments.  Empty list is success."\n+          },\n+          "405": {\n+            "description": "Invalid input"\n+          }\n+        },\n+        "requestBody": {\n+          "content": {\n+            "application/json": {\n+              "schema": {\n+                "$ref": "#/components/schemas/Treatments"\n+              }\n+            }\n+          },\n+          "description": "Treatments to be uploaded.",\n+          "required": true\n+        }\n+      }\n+    },\n+    "/profile": {\n+      "get": {\n+        "summary": "Profile",\n+        "description": "The Profile endpoint returns information about the Nightscout Treatment Profiles.",\n+        "tags": [\n+          "Profile"\n+        ],\n+        "responses": {\n+          "200": {\n+            "description": "An array of treatments",\n+            "content": {\n+              "application/json": {\n+                "schema": {\n+                  "$ref": "#/components/schemas/Profile"\n+                }\n+              }\n+            }\n+          },\n+          "default": {\n+            "description": "Unexpected error",\n+            "content": {\n+              "application/json": {\n+                "schema": {\n+                  "$ref": "#/components/schemas/Error"\n+                }\n+              }\n+            }\n+          }\n+        }\n+      }\n+    },\n+    "/status": {\n+      "get": {\n+        "summary": "Status",\n+        "description": "Server side status, default settings and capabilities.",\n+        "tags": [\n+          "Status"\n+        ],\n+        "responses": {\n+          "200": {\n+            "description": "Server capabilities and status.",\n+            "content": {\n+              "application/json": {\n+                "schema": {\n+                  "$ref": "#/components/schemas/Status"\n+                }\n+              }\n+            }\n+          },\n+          "default": {\n+            "description": "Unexpected error",\n+            "content": {\n+              "application/json": {\n+                "schema": {\n+                  "$ref": "#/components/schemas/Error"\n+                }\n+              }\n+            }\n+          }\n+        }\n+      }\n+    }\n+  },\n+  "components": {\n+    "securitySchemes": {\n+      "api_secret": {\n+        "type": "apiKey",\n+        "name": "api_secret",\n+        "in": "header",\n+        "description": "The hash of the API_SECRET env var"\n+      },\n+      "token_in_url": {\n+        "type": "apiKey",\n+        "name": "token",\n+        "in": "query",\n+        "description": "Add token as query item in the URL. You can manage access Token in `/admin`. This uses json webtokens."\n+      },\n+      "jwtoken": {\n+        "type": "http",\n+        "scheme": "bearer",\n+        "description": "Use this if you know the temporary json webtoken.",\n+        "bearerFormat": "JWT"\n+      }\n+    },\n+    "schemas": {\n+      "Entry": {\n+        "properties": {\n+          "type": {\n+            "type": "string",\n+            "description": "sgv, mbg, cal, etc"\n+          },\n+          "dateString": {\n+            "type": "string",\n+            "description": "dateString, prefer ISO `8601`"\n+          },\n+          "date": {\n+            "type": "number",\n+            "description": "Epoch"\n+          },\n+          "sgv": {\n+            "type": "number",\n+            "description": "The glucose reading. (only available for sgv types)"\n+          },\n+          "direction": {\n+            "type": "string",\n+            "description": "Direction of glucose trend reported by CGM. (only available for sgv types)"\n+          },\n+          "noise": {\n+            "type": "number",\n+            "description": "Noise level at time of reading. (only available for sgv types)"\n+          },\n+          "filtered": {\n+            "type": "number",\n+            "description": "The raw filtered value directly from CGM transmitter. (only available for sgv types)"\n+          },\n+          "unfiltered": {\n+            "type": "number",\n+            "description": "The raw unfiltered value directly from CGM transmitter. (only available for sgv types)"\n+          },\n+          "rssi": {\n+            "type": "number",\n+            "description": "The signal strength from CGM transmitter. (only available for sgv types)"\n+          }\n+        }\n+      },\n+      "Entries": {\n+        "type": "array",\n+        "items": {\n+          "$ref": "#/components/schemas/Entry"\n+        }\n+      },\n+      "Treatment": {\n+        "properties": {\n+          "_id": {\n+            "type": "string",\n+            "description": "Internally assigned id."\n+          },\n+          "eventType": {\n+            "type": "string",\n+            "description": "The type of treatment event."\n+          },\n+          "created_at": {\n+            "type": "string",\n+            "description": "The date of the event, might be set retroactively ."\n+          },\n+          "glucose": {\n+            "type": "string",\n+            "description": "Current glucose."\n+          },\n+          "glucoseType": {\n+            "type": "string",\n+            "description": "Method used to obtain glucose, Finger or Sensor."\n+          },\n+          "carbs": {\n+            "type": "number",\n+            "description": "Number of carbs."\n+          },\n+          "insulin": {\n+            "type": "number",\n+            "description": "Amount of insulin, if any."\n+          },\n+          "units": {\n+            "type": "string",\n+            "description": "The units for the glucose value, mg/dl or mmol."\n+          },\n+          "notes": {\n+            "type": "string",\n+            "description": "Description/notes of treatment."\n+          },\n+          "enteredBy": {\n+            "type": "string",\n+            "description": "Who entered the treatment."\n+          }\n+        }\n+      },\n+      "Treatments": {\n+        "type": "array",\n+        "items": {\n+          "$ref": "#/components/schemas/Treatment"\n+        }\n+      },\n+      "Profile": {\n+        "properties": {\n+          "sens": {\n+            "type": "integer",\n+            "description": "Internally assigned id"\n+          },\n+          "dia": {\n+            "type": "integer",\n+            "description": "Internally assigned id"\n+          },\n+          "carbratio": {\n+            "type": "integer",\n+            "description": "Internally assigned id"\n+          },\n+          "carbs_hr": {\n+            "type": "integer",\n+            "description": "Internally assigned id"\n+          },\n+          "_id": {\n+            "type": "string",\n+            "description": "Internally assigned id"\n+          }\n+        }\n+      },\n+      "Status": {\n+        "properties": {\n+          "apiEnabled": {\n+            "type": "boolean",\n+            "description": "Whether or not the REST API is enabled."\n+          },\n+          "careportalEnabled": {\n+            "type": "boolean",\n+            "description": "Whether or not the careportal is enabled in the API."\n+          },\n+          "head": {\n+            "type": "string",\n+            "description": "The git identifier for the running instance of the app."\n+          },\n+          "name": {\n+            "type": "string",\n+            "description": "Nightscout (static)"\n+          },\n+          "version": {\n+            "type": "string",\n+            "description": "The version label of the app."\n+          },\n+          "settings": {\n+            "$ref": "#/components/schemas/Settings"\n+          },\n+          "extendedSettings": {\n+            "$ref": "#/components/schemas/ExtendedSettings"\n+          }\n+        }\n+      },\n+      "Settings": {\n+        "properties": {\n+          "units": {\n+            "type": "string",\n+            "description": "Default units for glucose measurements across the server."\n+          },\n+          "timeFormat": {\n+            "type": "string",\n+            "description": "Default time format",\n+            "enum": [\n+              12,\n+              24\n+            ]\n+          },\n+          "customTitle": {\n+            "type": "string",\n+            "description": "Default custom title to be displayed system wide."\n+          },\n+          "nightMode": {\n+            "type": "boolean",\n+            "description": "Should Night mode be enabled by default?"\n+          },\n+          "theme": {\n+            "type": "string",\n+            "description": "Default theme to be displayed system wide, `default`, `colors`, `colorblindfriendly`."\n+          },\n+          "language": {\n+            "type": "string",\n+            "description": "Default language code to be used system wide"\n+          },\n+          "showPlugins": {\n+            "type": "string",\n+            "description": "Plugins that should be shown by default"\n+          },\n+          "showRawbg": {\n+            "type": "string",\n+            "description": "If Raw BG is enabled when should it be shown? `never`, `always`, `noise`"\n+          },\n+          "alarmTypes": {\n+            "type": "array",\n+            "items": {\n+              "type": "string"\n+            },\n+            "enum": [\n+              "simple",\n+              "predict"\n+            ],\n+            "description": "Enabled alarm types, can be multiple"\n+          },\n+          "alarmUrgentHigh": {\n+            "type": "boolean",\n+            "description": "Enable/Disable client-side Urgent High alarms by default, for use with `simple` alarms."\n+          },\n+          "alarmHigh": {\n+            "type": "boolean",\n+            "description": "Enable/Disable client-side High alarms by default, for use with `simple` alarms."\n+          },\n+          "alarmLow": {\n+            "type": "boolean",\n+            "description": "Enable/Disable client-side Low alarms by default, for use with `simple` alarms."\n+          },\n+          "alarmUrgentLow": {\n+            "type": "boolean",\n+            "description": "Enable/Disable client-side Urgent Low alarms by default, for use with `simple` alarms."\n+          },\n+          "alarmTimeagoWarn": {\n+            "type": "boolean",\n+            "description": "Enable/Disable client-side stale data alarms by default."\n+          },\n+          "alarmTimeagoWarnMins": {\n+            "type": "number",\n+            "description": "Number of minutes before a stale data warning is generated."\n+          },\n+          "alarmTimeagoUrgent": {\n+            "type": "boolean",\n+            "description": "Enable/Disable client-side urgent stale data alarms by default."\n+          },\n+          "alarmTimeagoUrgentMins": {\n+            "type": "number",\n+            "description": "Number of minutes before a stale data warning is generated."\n+          },\n+          "enable": {\n+            "type": "array",\n+            "items": {\n+              "type": "string"\n+            },\n+            "description": "Enabled features"\n+          },\n+          "thresholds": {\n+            "$ref": "#/components/schemas/Threshold"\n+          }\n+        }\n+      },\n+      "Threshold": {\n+        "properties": {\n+          "bg_high": {\n+            "type": "integer",\n+            "description": "High BG range."\n+          },\n+          "bg_target_top": {\n+            "type": "integer",\n+            "description": "Top of target range."\n+          },\n+          "bg_target_bottom": {\n+            "type": "integer",\n+            "description": "Bottom of target range."\n+          },\n+          "bg_low": {\n+            "type": "integer",\n+            "description": "Low BG range."\n+          }\n+        }\n+      },\n+      "ExtendedSettings": {\n+        "description": "Extended settings of client side plugins"\n+      },\n+      "MongoQuery": {\n+        "description": "Mongo Query object."\n+      },\n+      "Error": {\n+        "properties": {\n+          "code": {\n+            "type": "integer",\n+            "format": "int32"\n+          },\n+          "message": {\n+            "type": "string"\n+          },\n+          "fields": {\n+            "type": "object"\n+          }\n+        }\n+      }\n+    }\n+  }\n+}\n\\ No newline at end of file\ndiff --git a/swagger.yaml b/swagger.yaml\nindex ce9204ce..a9fe3f82 100644\n--- a/swagger.yaml\n+++ b/swagger.yaml\n@@ -1,36 +1,34 @@\n-swagger: \'2.0\'\n+openapi: 3.0.0\n+servers:\n+  - url: /api/v1\n info:\n   title: Nightscout API\n   description: Own your DData with the Nightscout API\n-  version: "0.8.0"\n+  version: 0.10.3-dev-20171205\n   license:\n     name: AGPL 3\n-    url: https://www.gnu.org/licenses/agpl.txt\n-basePath: /api/v1\n-produces:\n-  - application/json\n+    url: \'https://www.gnu.org/licenses/agpl.txt\'\n security:\n   - api_secret: []\n-\n+    token_in_url: []\n+    jwtoken: []\n paths:\n-\n-  /entries/{spec}:\n+  \'/entries/{spec}\':\n     get:\n       summary: All Entries matching query\n       description: |\n         The Entries endpoint returns information about the\n         Nightscout entries.\n-\n       parameters:\n         - name: spec\n           in: path\n-          type: string\n           description: |\n-              entry id, such as `55cf81bc436037528ec75fa5` or a type filter such\n-              as `sgv`, `mbg`, etc.\n-\n-          default: sgv\n+            entry id, such as `55cf81bc436037528ec75fa5` or a type filter such\n+            as `sgv`, `mbg`, etc.\n           required: true\n+          schema:\n+            type: string\n+            default: sgv\n         - name: find\n           in: query\n           description: |\n@@ -38,64 +36,83 @@ paths:\n             example `find[dateString][$gte]=2015-08-27`.  All find parameters\n             are interpreted as strings.\n           required: false\n-          type: string\n+          schema:\n+            type: string\n         - name: count\n           in: query\n           description: Number of entries to return.\n           required: false\n-          type: number\n+          schema:\n+            type: number\n       tags:\n         - Entries\n       responses:\n-        "200":\n+        \'200\':\n           description: An array of entries\n-          schema:\n-            $ref: \'#/definitions/Entries\'\n+          content:\n+            application/json:\n+              schema:\n+                $ref: \'#/components/schemas/Entries\'\n         default:\n           description: Entries\n-          schema:\n-            $ref: \'#/definitions/Entries\'\n-\n-  /slice/{storage}/{field}/{type}/{prefix}/{regex}:\n+          content:\n+            application/json:\n+              schema:\n+                $ref: \'#/components/schemas/Entries\'\n+  \'/slice/{storage}/{field}/{type}/{prefix}/{regex}\':\n     get:\n       summary: All Entries matching query\n       description: The Entries endpoint returns information about the Nightscout entries.\n       parameters:\n         - name: storage\n           in: path\n-          type: string\n-          description: Prefix to use in constructing a prefix-based regex, default is `entries`.\n+          description: >-\n+            Prefix to use in constructing a prefix-based regex, default is\n+            `entries`.\n           required: true\n-          default: entries\n+          schema:\n+            type: string\n+            default: entries\n         - name: field\n           in: path\n-          type: string\n-          description: Name of the field to use Regex against in query object, default is `dateString`.\n-          default: dateString\n+          description: >-\n+            Name of the field to use Regex against in query object, default is\n+            `dateString`.\n           required: true\n+          schema:\n+            type: string\n+            default: dateString\n         - name: type\n           in: path\n-          type: string\n-          description: The type field to search against, default is sgv.\n+          description: \'The type field to search against, default is sgv.\'\n           required: true\n-          default: sgv\n+          schema:\n+            type: string\n+            default: sgv\n         - name: prefix\n           in: path\n-          type: string\n           description: Prefix to use in constructing a prefix-based regex.\n           required: true\n-          default: \'2015\'\n+          schema:\n+            type: string\n+            default: \'2015\'\n         - name: regex\n           in: path\n-          type: string\n-          description: |\n-            Tail part of regexp to use in expanding/construccting a query object.\n+          description: >\n+            Tail part of regexp to use in expanding/construccting a query\n+            object.\n+\n             Regexp also has bash-style brace and glob expansion applied to it,\n+\n             creating ways to search for modal times of day, perhaps using\n+\n             something like this syntax: `T{15..17}:.*`, this would search for\n+\n             all records from 3pm to 5pm.\n           required: true\n-          default: .*\n+          schema:\n+            type: string\n+            default: .*\n         - name: find\n           in: query\n           description: |\n@@ -103,49 +120,53 @@ paths:\n             example `find[dateString][$gte]=2015-08-27`.  All find parameters\n             are interpreted as strings.\n           required: false\n-          type: string\n+          schema:\n+            type: string\n         - name: count\n           in: query\n           description: Number of entries to return.\n           required: false\n-          type: number\n+          schema:\n+            type: number\n       tags:\n         - Entries\n       responses:\n-        "200":\n+        \'200\':\n           description: An array of entries\n-          schema:\n-            $ref: \'#/definitions/Entries\'\n+          content:\n+            application/json:\n+              schema:\n+                $ref: \'#/components/schemas/Entries\'\n         default:\n           description: Unexpected error\n-          schema:\n-            $ref: \'#/definitions/Error\'\n-\n-  /echo/{storage}/{spec}:\n+          content:\n+            application/json:\n+              schema:\n+                $ref: \'#/components/schemas/Error\'\n+  \'/echo/{storage}/{spec}\':\n     get:\n       summary: View generated Mongo Query object\n       description: |\n         Information about the mongo query object created by the query.\n-\n       parameters:\n         - name: storage\n           in: path\n-          type: string\n           description: |\n-              `entries`, or `treatments` to select the storage layer.\n-\n-          default: sgv\n+            `entries`, or `treatments` to select the storage layer.\n           required: true\n+          schema:\n+            type: string\n+            default: sgv\n         - name: spec\n           in: path\n-          type: string\n           description: |\n-              entry id, such as `55cf81bc436037528ec75fa5` or a type filter such\n-              as `sgv`, `mbg`, etc.\n-              This parameter is optional.\n-\n-          default: sgv\n+            entry id, such as `55cf81bc436037528ec75fa5` or a type filter such\n+            as `sgv`, `mbg`, etc.\n+            This parameter is optional.\n           required: true\n+          schema:\n+            type: string\n+            default: sgv\n         - name: find\n           in: query\n           description: |\n@@ -153,108 +174,139 @@ paths:\n             example `find[dateString][$gte]=2015-08-27`.  All find parameters\n             are interpreted as strings.\n           required: false\n-          type: string\n+          schema:\n+            type: string\n         - name: count\n           in: query\n           description: Number of entries to return.\n           required: false\n-          type: number\n+          schema:\n+            type: number\n       tags:\n         - Entries\n         - Debug\n       responses:\n-        "200":\n+        \'200\':\n           description: An array of entries\n-          schema:\n-            $ref: \'#/definitions/MongoQuery\'\n-\n-  /times/echo/{prefix}/{regex}:\n+          content:\n+            application/json:\n+              schema:\n+                $ref: \'#/components/schemas/MongoQuery\'\n+  \'/times/echo/{prefix}/{regex}\':\n     get:\n       summary: Echo the query object to be used.\n       description: Echo debug information about the query object constructed.\n       parameters:\n         - name: prefix\n           in: path\n-          type: string\n           description: Prefix to use in constructing a prefix-based regex.\n           required: true\n+          schema:\n+            type: string\n         - name: regex\n           in: path\n-          type: string\n-          description: |\n-            Tail part of regexp to use in expanding/construccting a query object.\n+          description: >\n+            Tail part of regexp to use in expanding/construccting a query\n+            object.\n+\n             Regexp also has bash-style brace and glob expansion applied to it,\n+\n             creating ways to search for modal times of day, perhaps using\n+\n             something like this syntax: `T{15..17}:.*`, this would search for\n+\n             all records from 3pm to 5pm.\n           required: true\n+          schema:\n+            type: string\n         - name: find\n           in: query\n-          description: The query used to find entries, support nested query syntax, for example `find[dateString][$gte]=2015-08-27`.  All find parameters are interpreted as strings.\n+          description: >-\n+            The query used to find entries, support nested query syntax, for\n+            example `find[dateString][$gte]=2015-08-27`.  All find parameters\n+            are interpreted as strings.\n           required: false\n-          type: string\n+          schema:\n+            type: string\n         - name: count\n           in: query\n           description: Number of entries to return.\n           required: false\n-          type: number\n+          schema:\n+            type: number\n       tags:\n         - Entries\n         - Debug\n       responses:\n-        "200":\n+        \'200\':\n           description: An array of entries\n-          schema:\n-            $ref: \'#/definitions/MongoQuery\'\n+          content:\n+            application/json:\n+              schema:\n+                $ref: \'#/components/schemas/MongoQuery\'\n         default:\n           description: Unexpected error\n-          schema:\n-            $ref: \'#/definitions/Error\'\n-\n-\n-  /times/{prefix}/{regex}:\n+          content:\n+            application/json:\n+              schema:\n+                $ref: \'#/components/schemas/Error\'\n+  \'/times/{prefix}/{regex}\':\n     get:\n       summary: All Entries matching query\n       description: The Entries endpoint returns information about the Nightscout entries.\n       parameters:\n         - name: prefix\n           in: path\n-          type: string\n           description: Prefix to use in constructing a prefix-based regex.\n           required: true\n+          schema:\n+            type: string\n         - name: regex\n           in: path\n-          type: string\n-          description: |\n-            Tail part of regexp to use in expanding/construccting a query object.\n+          description: >\n+            Tail part of regexp to use in expanding/construccting a query\n+            object.\n+\n             Regexp also has bash-style brace and glob expansion applied to it,\n+\n             creating ways to search for modal times of day, perhaps using\n+\n             something like this syntax: `T{15..17}:.*`, this would search for\n+\n             all records from 3pm to 5pm.\n           required: true\n+          schema:\n+            type: string\n         - name: find\n           in: query\n-          description: The query used to find entries, support nested query syntax, for example `find[dateString][$gte]=2015-08-27`.  All find parameters are interpreted as strings.\n+          description: >-\n+            The query used to find entries, support nested query syntax, for\n+            example `find[dateString][$gte]=2015-08-27`.  All find parameters\n+            are interpreted as strings.\n           required: false\n-          type: string\n+          schema:\n+            type: string\n         - name: count\n           in: query\n           description: Number of entries to return.\n           required: false\n-          type: number\n+          schema:\n+            type: number\n       tags:\n         - Entries\n       responses:\n-        "200":\n+        \'200\':\n           description: An array of entries\n-          schema:\n-            $ref: \'#/definitions/Entries\'\n+          content:\n+            application/json:\n+              schema:\n+                $ref: \'#/components/schemas/Entries\'\n         default:\n           description: Unexpected error\n-          schema:\n-            $ref: \'#/definitions/Error\'\n-\n-\n+          content:\n+            application/json:\n+              schema:\n+                $ref: \'#/components/schemas/Error\'\n   /entries:\n     get:\n       summary: All Entries matching query\n@@ -262,376 +314,413 @@ paths:\n       parameters:\n         - name: find\n           in: query\n-          description: The query used to find entries, support nested query syntax, for example `find[dateString][$gte]=2015-08-27`.  All find parameters are interpreted as strings.\n+          description: >-\n+            The query used to find entries, support nested query syntax, for\n+            example `find[dateString][$gte]=2015-08-27`.  All find parameters\n+            are interpreted as strings.\n           required: false\n-          type: string\n+          schema:\n+            type: string\n         - name: count\n           in: query\n           description: Number of entries to return.\n           required: false\n-          type: number\n+          schema:\n+            type: number\n       tags:\n         - Entries\n       responses:\n-        "200":\n+        \'200\':\n           description: An array of entries\n-          schema:\n-            $ref: \'#/definitions/Entries\'\n+          content:\n+            application/json:\n+              schema:\n+                $ref: \'#/components/schemas/Entries\'\n         default:\n           description: Unexpected error\n-          schema:\n-            $ref: \'#/definitions/Error\'\n-\n+          content:\n+            application/json:\n+              schema:\n+                $ref: \'#/components/schemas/Error\'\n     post:\n       tags:\n         - Entries\n       summary: Add new entries.\n-      description: ""\n+      description: \'\'\n       operationId: addEntries\n-      consumes:\n-        - application/json\n-        - text/plain\n-      produces:\n-        - application/json\n-        - text/plain\n-      parameters:\n-        - in: body\n-          name: body\n-          description: Entries to be uploaded.\n-          required: true\n-          schema:\n-            $ref: "#/definitions/Entries"\n       responses:\n-        "405":\n-          description: Invalid input\n-        "200":\n+        \'200\':\n           description: Rejected list of entries.  Empty list is success.\n+        \'405\':\n+          description: Invalid input\n+      requestBody:\n+        content:\n+          application/json:\n+            schema:\n+              $ref: \'#/components/schemas/Entries\'\n+          text/plain:\n+            schema:\n+              $ref: \'#/components/schemas/Entries\'\n+        description: Entries to be uploaded.\n+        required: true\n     delete:\n       tags:\n         - Entries\n       summary: Delete entries matching query.\n-      description: "Remove entries, same search syntax as GET."\n+      description: \'Remove entries, same search syntax as GET.\'\n       operationId: remove\n       parameters:\n         - name: find\n           in: query\n-          description: The query used to find entries, support nested query syntax, for example `find[dateString][$gte]=2015-08-27`.  All find parameters are interpreted as strings.\n+          description: >-\n+            The query used to find entries, support nested query syntax, for\n+            example `find[dateString][$gte]=2015-08-27`.  All find parameters\n+            are interpreted as strings.\n           required: false\n-          type: string\n+          schema:\n+            type: string\n         - name: count\n           in: query\n           description: Number of entries to return.\n           required: false\n-          type: number\n+          schema:\n+            type: number\n       responses:\n-        "200":\n+        \'200\':\n           description: Empty list is success.\n-\n   /treatments:\n     get:\n       summary: Treatments\n-      description: The Treatments endpoint returns information about the Nightscout treatments.\n+      description: >-\n+        The Treatments endpoint returns information about the Nightscout\n+        treatments.\n       tags:\n         - Treatments\n       parameters:\n         - name: find\n           in: query\n-          description:\n-            The query used to find entries, supports nested query syntax.  Examples\n-            `find[insulin][$gte]=3`\n-            `find[carb][$gte]=100`\n-            `find[eventType]=Correction+Bolus`\n-            All find parameters are interpreted as strings.\n+          description: >-\n+            The query used to find entries, supports nested query syntax. \n+            Examples `find[insulin][$gte]=3` `find[carb][$gte]=100`\n+            `find[eventType]=Correction+Bolus` All find parameters are\n+            interpreted as strings.\n           required: false\n-          type: string\n+          schema:\n+            type: string\n         - name: count\n           in: query\n           description: Number of entries to return.\n           required: false\n-          type: number\n+          schema:\n+            type: number\n       responses:\n-        "200":\n+        \'200\':\n           description: An array of treatments\n-          schema:\n-            $ref: \'#/definitions/Treatments\'\n+          content:\n+            application/json:\n+              schema:\n+                $ref: \'#/components/schemas/Treatments\'\n         default:\n           description: Unexpected error\n-          schema:\n-            $ref: \'#/definitions/Error\'\n-    post:\n-          tags:\n-            - Treatments\n-          summary: Add new treatments.\n-          description: ""\n-          operationId: addTreatments\n-          consumes:\n-            - application/json\n-          produces:\n-            - application/json\n-          parameters:\n-            - in: body\n-              name: body\n-              description: Treatments to be uploaded.\n-              required: true\n+          content:\n+            application/json:\n               schema:\n-                $ref: "#/definitions/Treatments"\n-          responses:\n-            "405":\n-              description: Invalid input\n-            "200":\n-              description: Rejected list of treatments.  Empty list is success.\n-\n+                $ref: \'#/components/schemas/Error\'\n+    post:\n+      tags:\n+        - Treatments\n+      summary: Add new treatments.\n+      description: \'\'\n+      operationId: addTreatments\n+      responses:\n+        \'200\':\n+          description: Rejected list of treatments.  Empty list is success.\n+        \'405\':\n+          description: Invalid input\n+      requestBody:\n+        content:\n+          application/json:\n+            schema:\n+              $ref: \'#/components/schemas/Treatments\'\n+        description: Treatments to be uploaded.\n+        required: true\n   /profile:\n     get:\n       summary: Profile\n-      description: The Profile endpoint returns information about the Nightscout Treatment Profiles.\n+      description: >-\n+        The Profile endpoint returns information about the Nightscout Treatment\n+        Profiles.\n       tags:\n         - Profile\n       responses:\n-        "200":\n+        \'200\':\n           description: An array of treatments\n-          schema:\n-            $ref: \'#/definitions/Profile\'\n+          content:\n+            application/json:\n+              schema:\n+                $ref: \'#/components/schemas/Profile\'\n         default:\n           description: Unexpected error\n-          schema:\n-            $ref: \'#/definitions/Error\'\n-\n+          content:\n+            application/json:\n+              schema:\n+                $ref: \'#/components/schemas/Error\'\n   /status:\n     get:\n       summary: Status\n-      description: Server side status, default settings and capabilities.\n+      description: \'Server side status, default settings and capabilities.\'\n       tags:\n         - Status\n       responses:\n-        "200":\n+        \'200\':\n           description: Server capabilities and status.\n-          schema:\n-            $ref: \'#/definitions/Status\'\n+          content:\n+            application/json:\n+              schema:\n+                $ref: \'#/components/schemas/Status\'\n         default:\n           description: Unexpected error\n-          schema:\n-            $ref: \'#/definitions/Error\'\n-\n-securityDefinitions:\n-  api_secret:\n-    type: apiKey\n-    name: api_secret\n-    in: header\n-    description: The hash of the API_SECRET env var\n-\n-definitions:\n-  Entry:\n-    properties:\n-      type:\n-        type: string\n-        description: "sgv, mbg, cal, etc"\n-      dateString:\n-        type: string\n-        description: dateString, prefer ISO `8601`\n-      date:\n-        type: number\n-        description: Epoch\n-      sgv:\n-        type: number\n-        description: The glucose reading. (only available for sgv types)\n-      direction:\n-        type: string\n-        description: Direction of glucose trend reported by CGM. (only available for sgv types)\n-      noise:\n-        type: number\n-        description: Noise level at time of reading. (only available for sgv types)\n-      filtered:\n-        type: number\n-        description: The raw filtered value directly from CGM transmitter. (only available for sgv types)\n-      unfiltered:\n-        type: number\n-        description: The raw unfiltered value directly from CGM transmitter. (only available for sgv types)\n-      rssi:\n-        type: number\n-        description: The signal strength from CGM transmitter. (only available for sgv types)\n-\n-  Entries:\n-    type: array\n-    items:\n-      $ref: \'#/definitions/Entry\'\n-\n-  Treatment:\n-    properties:\n-      _id:\n-        type: string\n-        description: Internally assigned id.\n-      eventType:\n-        type: string\n-        description: The type of treatment event.\n-      created_at:\n-        type: string\n-        description: The date of the event, might be set retroactively .\n-      glucose:\n-        type: string\n-        description: Current glucose.\n-      glucoseType:\n-        type: string\n-        description: Method used to obtain glucose, Finger or Sensor.\n-      carbs:\n-        type: number\n-        description: Number of carbs.\n-      insulin:\n-        type: number\n-        description: Amount of insulin, if any.\n-      units:\n-        type: string\n-        description: The units for the glucose value, mg/dl or mmol.\n-      notes:\n-        type: string\n-        description: Description/notes of treatment.\n-      enteredBy:\n-        type: string\n-        description: Who entered the treatment.\n-\n-  Treatments:\n-    type: array\n-    items:\n-      $ref: \'#/definitions/Treatment\'\n-\n-  Profile:\n-    properties:\n-      sens:\n-        type: integer\n-        description: \'Internally assigned id\'\n-      dia:\n-        type: integer\n-        description: \'Internally assigned id\'\n-      carbratio:\n-        type: integer\n-        description: \'Internally assigned id\'\n-      carbs_hr:\n-        type: integer\n-        description: \'Internally assigned id\'\n-      _id:\n-        type: string\n-        description: \'Internally assigned id\'\n-\n-  Status:\n-    properties:\n-      apiEnabled:\n-        type: boolean\n-        description: \'Whether or not the REST API is enabled.\'\n-      careportalEnabled:\n-        type: boolean\n-        description: \'Whether or not the careportal is enabled in the API.\'\n-      head:\n-        type: string\n-        description: \'The git identifier for the running instance of the app.\'\n-      name:\n-        type: string\n-        description: Nightscout (static)\n-      version:\n-        type: string\n-        description: \'The version label of the app.\'\n-      settings:\n-        $ref: \'#/definitions/Settings\'\n-      extendedSettings:\n-        $ref: \'#/definitions/ExtendedSettings\'\n-\n-  Settings:\n-    properties:\n-      units:\n-        type: string\n-        description: Default units for glucose measurements across the server.\n-      timeFormat:\n-        type: string\n-        description: Default time format\n-        enum:\n-          - 12\n-          - 24\n-      customTitle:\n-        type: string\n-        description: Default custom title to be displayed system wide.\n-      nightMode:\n-        type: boolean\n-        description: Should Night mode be enabled by default?\n-      theme:\n-        type: string\n-        description: Default theme to be displayed system wide, `default`, `colors`, `colorblindfriendly`.\n-      language:\n-        type: string\n-        description: Default language code to be used system wide\n-      showPlugins:\n-        type: string\n-        description: Plugins that should be shown by default\n-      showRawbg:\n-        type: string\n-        description: If Raw BG is enabled when should it be shown? `never`, `always`, `noise`\n-      alarmTypes:\n-        type: array\n-        items:\n+          content:\n+            application/json:\n+              schema:\n+                $ref: \'#/components/schemas/Error\'\n+components:\n+  securitySchemes:\n+    api_secret:\n+      type: apiKey\n+      name: api_secret\n+      in: header\n+      description: The hash of the API_SECRET env var\n+    token_in_url:\n+      type: apiKey\n+      name: token\n+      in: query\n+      description: Add token as query item in the URL. You can manage access Token in `/admin`. This uses json webtokens.\n+    jwtoken:\n+      type: http\n+      scheme: bearer\n+      description: Use this if you know the temporary json webtoken.\n+      bearerFormat: JWT\n+  schemas:\n+    Entry:\n+      properties:\n+        type:\n           type: string\n-        enum:\n-          - simple\n-          - predict\n-        description: Enabled alarm types, can be multiple\n-      alarmUrgentHigh:\n-        type: boolean\n-        description: Enable/Disable client-side Urgent High alarms by default, for use with `simple` alarms.\n-      alarmHigh:\n-        type: boolean\n-        description: Enable/Disable client-side High alarms by default, for use with `simple` alarms.\n-      alarmLow:\n-        type: boolean\n-        description: Enable/Disable client-side Low alarms by default, for use with `simple` alarms.\n-      alarmUrgentLow:\n-        type: boolean\n-        description: Enable/Disable client-side Urgent Low alarms by default, for use with `simple` alarms.\n-      alarmTimeagoWarn:\n-        type: boolean\n-        description: Enable/Disable client-side stale data alarms by default.\n-      alarmTimeagoWarnMins:\n-        type: number\n-        description: Number of minutes before a stale data warning is generated.\n-      alarmTimeagoUrgent:\n-        type: boolean\n-        description: Enable/Disable client-side urgent stale data alarms by default.\n-      alarmTimeagoUrgentMins:\n-        type: number\n-        description: Number of minutes before a stale data warning is generated.\n-      enable:\n-        type: array\n-        items:\n+          description: \'sgv, mbg, cal, etc\'\n+        dateString:\n           type: string\n-        description: Enabled features\n-      thresholds:\n-        $ref: \'#/definitions/Threshold\'\n-\n-  Threshold:\n-    properties:\n-      bg_high:\n-        type: integer\n-        description: \'High BG range.\'\n-      bg_target_top:\n-        type: integer\n-        description: \'Top of target range.\'\n-      bg_target_bottom:\n-        type: integer\n-        description: \'Bottom of target range.\'\n-      bg_low:\n-        type: integer\n-        description: \'Low BG range.\'\n-\n-  ExtendedSettings:\n-    description: Extended settings of client side plugins\n-\n-  MongoQuery:\n-    description: Mongo Query object.\n-\n-\n-  Error:\n-    properties:\n-      code:\n-        type: integer\n-        format: int32\n-      message:\n-        type: string\n-      fields:\n-        type: object\n-\n+          description: \'dateString, prefer ISO `8601`\'\n+        date:\n+          type: number\n+          description: Epoch\n+        sgv:\n+          type: number\n+          description: The glucose reading. (only available for sgv types)\n+        direction:\n+          type: string\n+          description: >-\n+            Direction of glucose trend reported by CGM. (only available for sgv\n+            types)\n+        noise:\n+          type: number\n+          description: Noise level at time of reading. (only available for sgv types)\n+        filtered:\n+          type: number\n+          description: >-\n+            The raw filtered value directly from CGM transmitter. (only\n+            available for sgv types)\n+        unfiltered:\n+          type: number\n+          description: >-\n+            The raw unfiltered value directly from CGM transmitter. (only\n+            available for sgv types)\n+        rssi:\n+          type: number\n+          description: >-\n+            The signal strength from CGM transmitter. (only available for sgv\n+            types)\n+    Entries:\n+      type: array\n+      items:\n+        $ref: \'#/components/schemas/Entry\'\n+    Treatment:\n+      properties:\n+        _id:\n+          type: string\n+          description: Internally assigned id.\n+        eventType:\n+          type: string\n+          description: The type of treatment event.\n+        created_at:\n+          type: string\n+          description: \'The date of the event, might be set retroactively .\'\n+        glucose:\n+          type: string\n+          description: Current glucose.\n+        glucoseType:\n+          type: string\n+          description: \'Method used to obtain glucose, Finger or Sensor.\'\n+        carbs:\n+          type: number\n+          description: Number of carbs.\n+        insulin:\n+          type: number\n+          description: \'Amount of insulin, if any.\'\n+        units:\n+          type: string\n+          description: \'The units for the glucose value, mg/dl or mmol.\'\n+        notes:\n+          type: string\n+          description: Description/notes of treatment.\n+        enteredBy:\n+          type: string\n+          description: Who entered the treatment.\n+    Treatments:\n+      type: array\n+      items:\n+        $ref: \'#/components/schemas/Treatment\'\n+    Profile:\n+      properties:\n+        sens:\n+          type: integer\n+          description: Internally assigned id\n+        dia:\n+          type: integer\n+          description: Internally assigned id\n+        carbratio:\n+          type: integer\n+          description: Internally assigned id\n+        carbs_hr:\n+          type: integer\n+          description: Internally assigned id\n+        _id:\n+          type: string\n+          description: Internally assigned id\n+    Status:\n+      properties:\n+        apiEnabled:\n+          type: boolean\n+          description: Whether or not the REST API is enabled.\n+        careportalEnabled:\n+          type: boolean\n+          description: Whether or not the careportal is enabled in the API.\n+        head:\n+          type: string\n+          description: The git identifier for the running instance of the app.\n+        name:\n+          type: string\n+          description: Nightscout (static)\n+        version:\n+          type: string\n+          description: The version label of the app.\n+        settings:\n+          $ref: \'#/components/schemas/Settings\'\n+        extendedSettings:\n+          $ref: \'#/components/schemas/ExtendedSettings\'\n+    Settings:\n+      properties:\n+        units:\n+          type: string\n+          description: Default units for glucose measurements across the server.\n+        timeFormat:\n+          type: string\n+          description: Default time format\n+          enum:\n+            - 12\n+            - 24\n+        customTitle:\n+          type: string\n+          description: Default custom title to be displayed system wide.\n+        nightMode:\n+          type: boolean\n+          description: Should Night mode be enabled by default?\n+        theme:\n+          type: string\n+          description: >-\n+            Default theme to be displayed system wide, `default`, `colors`,\n+            `colorblindfriendly`.\n+        language:\n+          type: string\n+          description: Default language code to be used system wide\n+        showPlugins:\n+          type: string\n+          description: Plugins that should be shown by default\n+        showRawbg:\n+          type: string\n+          description: >-\n+            If Raw BG is enabled when should it be shown? `never`, `always`,\n+            `noise`\n+        alarmTypes:\n+          type: array\n+          items:\n+            type: string\n+          enum:\n+            - simple\n+            - predict\n+          description: \'Enabled alarm types, can be multiple\'\n+        alarmUrgentHigh:\n+          type: boolean\n+          description: >-\n+            Enable/Disable client-side Urgent High alarms by default, for use\n+            with `simple` alarms.\n+        alarmHigh:\n+          type: boolean\n+          description: >-\n+            Enable/Disable client-side High alarms by default, for use with\n+            `simple` alarms.\n+        alarmLow:\n+          type: boolean\n+          description: >-\n+            Enable/Disable client-side Low alarms by default, for use with\n+            `simple` alarms.\n+        alarmUrgentLow:\n+          type: boolean\n+          description: >-\n+            Enable/Disable client-side Urgent Low alarms by default, for use\n+            with `simple` alarms.\n+        alarmTimeagoWarn:\n+          type: boolean\n+          description: Enable/Disable client-side stale data alarms by default.\n+        alarmTimeagoWarnMins:\n+          type: number\n+          description: Number of minutes before a stale data warning is generated.\n+        alarmTimeagoUrgent:\n+          type: boolean\n+          description: Enable/Disable client-side urgent stale data alarms by default.\n+        alarmTimeagoUrgentMins:\n+          type: number\n+          description: Number of minutes before a stale data warning is generated.\n+        enable:\n+          type: array\n+          items:\n+            type: string\n+          description: Enabled features\n+        thresholds:\n+          $ref: \'#/components/schemas/Threshold\'\n+    Threshold:\n+      properties:\n+        bg_high:\n+          type: integer\n+          description: High BG range.\n+        bg_target_top:\n+          type: integer\n+          description: Top of target range.\n+        bg_target_bottom:\n+          type: integer\n+          description: Bottom of target range.\n+        bg_low:\n+          type: integer\n+          description: Low BG range.\n+    ExtendedSettings:\n+      description: Extended settings of client side plugins\n+    MongoQuery:\n+      description: Mongo Query object.\n+    Error:\n+      properties:\n+        code:\n+          type: integer\n+          format: int32\n+        message:\n+          type: string\n+        fields:\n+          type: object\n\\ No newline at end of file\ndiff --git a/tests/admintools.test.js b/tests/admintools.test.js\nindex f1851010..b5be4858 100644\n--- a/tests/admintools.test.js\n+++ b/tests/admintools.test.js\n@@ -67,7 +67,7 @@ describe(\'admintools\', function ( ) {\n       \n       self.localCookieStorage = self.localStorage = self.$.localStorage = require(\'./fixtures/localstorage\');\n \n-      self.$.fn.tipsy = function mockTipsy ( ) { };\n+      self.$.fn.tooltip = function mockTooltip ( ) { };\n \n       self.$.fn.dialog = function mockDialog (opts) {\n         function maybeCall (name, obj) {\ndiff --git a/tests/cob.test.js b/tests/cob.test.js\nindex 9f917cb4..dbbecda0 100644\n--- a/tests/cob.test.js\n+++ b/tests/cob.test.js\n@@ -8,6 +8,7 @@ describe(\'COB\', function ( ) {\n   var ctx = {};\n   ctx.settings = {};\n   ctx.language = require(\'../lib/language\')();\n+  ctx.language.set(\'en\');\n \n   var cob = require(\'../lib/plugins/cob\')(ctx);\n   \ndiff --git a/tests/fixtures/headless.js b/tests/fixtures/headless.js\nindex 567262ad..8b59b7b5 100644\n--- a/tests/fixtures/headless.js\n+++ b/tests/fixtures/headless.js\n@@ -24,7 +24,7 @@ function headless (benv, binding) {\n       //self.$ = require(\'jquery\');\n       //self.$.localStorage = require(localStorage);\n \n-      self.$.fn.tipsy = function mockTipsy ( ) { };\n+      self.$.fn.tooltip = function mockTooltip ( ) { };\n \n       var indexHtml = read(htmlFile, \'utf8\');\n       self.$(\'body\').html(indexHtml);\n@@ -37,7 +37,7 @@ function headless (benv, binding) {\n         self.$.plot = function mockPlot () {\n         };\n \n-        self.$.fn.tipsy = function mockTipsy ( ) { };\n+        self.$.fn.tooltip = function mockTooltip ( ) { };\n \n         self.$.fn.dialog = function mockDialog (opts) {\n           function maybeCall (name, obj) {\ndiff --git a/tests/hashauth.test.js b/tests/hashauth.test.js\nindex 19fb50cc..c8b1bf50 100644\n--- a/tests/hashauth.test.js\n+++ b/tests/hashauth.test.js\n@@ -33,7 +33,7 @@ describe(\'hashauth\', function ( ) {\n       self.$ = require(\'jquery\');\n       self.$.localStorage = require(\'./fixtures/localstorage\');\n \n-      self.$.fn.tipsy = function mockTipsy ( ) { };\n+      self.$.fn.tooltip = function mockTooltip ( ) { };\n \n       var indexHtml = read(__dirname + \'/../static/index.html\', \'utf8\');\n       self.$(\'body\').html(indexHtml);\ndiff --git a/tests/loop.test.js b/tests/loop.test.js\nindex 78580470..ca2d33a8 100644\n--- a/tests/loop.test.js\n+++ b/tests/loop.test.js\n@@ -7,6 +7,7 @@ var moment = require(\'moment\');\n var ctx = {\n   language: require(\'../lib/language\')()\n };\n+ctx.language.set(\'en\');\n var env = require(\'../env\')();\n var loop = require(\'../lib/plugins/loop\')(ctx);\n var sandbox = require(\'../lib/sandbox\')();\ndiff --git a/tests/openaps.test.js b/tests/openaps.test.js\nindex 798e3519..296caf29 100644\n--- a/tests/openaps.test.js\n+++ b/tests/openaps.test.js\n@@ -7,6 +7,7 @@ var moment = require(\'moment\');\n var ctx = {\n   language: require(\'../lib/language\')()\n };\n+ctx.language.set(\'en\');\n var env = require(\'../env\')();\n var openaps = require(\'../lib/plugins/openaps\')(ctx);\n var sandbox = require(\'../lib/sandbox\')();\ndiff --git a/tests/pump.test.js b/tests/pump.test.js\nindex deb2b359..3907acbc 100644\n--- a/tests/pump.test.js\n+++ b/tests/pump.test.js\n@@ -7,6 +7,7 @@ var moment = require(\'moment\');\n var ctx = {\n   language: require(\'../lib/language\')()\n };\n+ctx.language.set(\'en\');\n var env = require(\'../env\')();\n var pump = require(\'../lib/plugins/pump\')(ctx);\n var sandbox = require(\'../lib/sandbox\')();\n@@ -253,7 +254,7 @@ describe(\'pump\', function ( ) {\n       , notifications: require(\'../lib/notifications\')(env, ctx)\n       , language: require(\'../lib/language\')()\n     };\n-\n+    ctx.language.set(\'en\');\n     var sbx = sandbox.clientInit(ctx, now.valueOf(), {devicestatus: statuses});\n     pump.setProperties(sbx);\n \n@@ -265,7 +266,7 @@ describe(\'pump\', function ( ) {\n \n       pump.alexa.intentHandlers[1].intentHandler(function next(title, response) {\n         title.should.equal(\'Pump battery\');\n-        response.should.equal(\'Your battery is at 1.52 volts\');\n+        response.should.equal(\'Your pump battery is at 1.52 volts\');\n         done();\n       }, [], sbx);\n \ndiff --git a/tests/rawbg.test.js b/tests/rawbg.test.js\nindex 4697bea9..017fcf9d 100644\n--- a/tests/rawbg.test.js\n+++ b/tests/rawbg.test.js\n@@ -3,10 +3,13 @@\n require(\'should\');\n \n describe(\'Raw BG\', function ( ) {\n-  var rawbg = require(\'../lib/plugins/rawbg\')({\n-    settings: {}\n-    , language: require(\'../lib/language\')()\n-  });\n+  var ctx =  {\n+      settings: {}\n+      , language: require(\'../lib/language\')()\n+  };\n+  ctx.language.set(\'en\');\n+\n+  var rawbg = require(\'../lib/plugins/rawbg\')(ctx);\n \n   var now = Date.now();\n   var data = {\ndiff --git a/tests/upbat.test.js b/tests/upbat.test.js\nindex 0d70e581..8585d0d8 100644\n--- a/tests/upbat.test.js\n+++ b/tests/upbat.test.js\n@@ -9,7 +9,9 @@ describe(\'Uploader Battery\', function ( ) {\n     var sandbox = require(\'../lib/sandbox\')();\n     var ctx = {\n       settings: {}\n+      , language: require(\'../lib/language\')()\n     };\n+    ctx.language.set(\'en\');\n     var sbx = sandbox.clientInit(ctx, Date.now(), data);\n \n     sbx.offerProperty = function mockedOfferProperty (name, setter) {\n@@ -22,7 +24,7 @@ describe(\'Uploader Battery\', function ( ) {\n       done();\n     };\n \n-    var upbat = require(\'../lib/plugins/upbat\')();\n+    var upbat = require(\'../lib/plugins/upbat\')(ctx);\n     upbat.setProperties(sbx);\n \n   });\n@@ -38,11 +40,13 @@ describe(\'Uploader Battery\', function ( ) {\n           done();\n         }\n       }\n+      , language: require(\'../lib/language\')()\n     };\n+    ctx.language.set(\'en\');\n \n     var sandbox = require(\'../lib/sandbox\')();\n     var sbx = sandbox.clientInit(ctx, Date.now(), data);\n-    var upbat = require(\'../lib/plugins/upbat\')();\n+    var upbat = require(\'../lib/plugins/upbat\')(ctx);\n     upbat.setProperties(sbx);\n     upbat.updateVisualisation(sbx);\n \n@@ -57,11 +61,13 @@ describe(\'Uploader Battery\', function ( ) {\n           done();\n         }\n       }\n+      , language: require(\'../lib/language\')()\n     };\n+    ctx.language.set(\'en\');\n \n     var sandbox = require(\'../lib/sandbox\')();\n     var sbx = sandbox.clientInit(ctx, Date.now(), {});\n-    var upbat = require(\'../lib/plugins/upbat\')();\n+    var upbat = require(\'../lib/plugins/upbat\')(ctx);\n     upbat.setProperties(sbx);\n     upbat.updateVisualisation(sbx);\n   });\n@@ -74,12 +80,13 @@ describe(\'Uploader Battery\', function ( ) {\n           options.hide.should.equal(true);\n           done();\n         }\n-      }\n+      }, language: require(\'../lib/language\')()\n     };\n+    ctx.language.set(\'en\');\n \n     var sandbox = require(\'../lib/sandbox\')();\n     var sbx = sandbox.clientInit(ctx, Date.now(), {devicestatus: [{uploader: {battery: -1}}]});\n-    var upbat = require(\'../lib/plugins/upbat\')();\n+    var upbat = require(\'../lib/plugins/upbat\')(ctx);\n     upbat.setProperties(sbx);\n     upbat.updateVisualisation(sbx);\n   });\n@@ -88,11 +95,13 @@ describe(\'Uploader Battery\', function ( ) {\n \n     var ctx = {\n       settings: {}\n+      , language: require(\'../lib/language\')()\n     };\n+    ctx.language.set(\'en\');\n \n     var sandbox = require(\'../lib/sandbox\')();\n     var sbx = sandbox.clientInit(ctx, Date.now(), data);\n-    var upbat = require(\'../lib/plugins/upbat\')();\n+    var upbat = require(\'../lib/plugins/upbat\')(ctx);\n     upbat.setProperties(sbx);\n \n     upbat.alexa.intentHandlers.length.should.equal(1);\ndiff --git a/views/bgclock.html b/views/bgclock.html\nindex 183a5bb8..903a395d 100644\n--- a/views/bgclock.html\n+++ b/views/bgclock.html\n@@ -1,83 +1,142 @@\n <!DOCTYPE html>\n <html>\n <head>\n-  <meta name="viewport" content="width=device-width, initial-scale=1.0">\n-  <title>Nightscout BG NOW</title>\n-  <link href="/images/round1.png" rel="icon" id="favicon" type="image/png" />\n-  <link rel=\'stylesheet\' type=\'text/css\' href=\'/css/main.css\' />\n-  <style type="text/css">\n-    img#arrow { height: 15vmin; }\n-    .center {\n-      text-align: center;\n-      padding: 0;\n-      margin: 0;\n-    }\n-    h1 {\n-      padding: 0;\n-      margin: 0;\n-      font-size: 1500%;\n-    }\n-    html, body {\n-      padding: 0;\n-      margin: 0;\n-      height: 100%;\n-    }\n-    html {\n-    }\n-    body {\n-      font-size: 100%;\n-      min-height: 100%;\n-\n-    }\n-\n-    .stale {\n-      text-decoration: line-through;\n-\n-    }\n+\t<meta name="viewport" content="width=device-width, initial-scale=1.0">\n+\t<meta name="apple-mobile-web-app-capable" content="yes">\n+  \n+\t<title>Nightscout</title>\n+  \n+\t<link href="/images/round1.png" rel="icon" id="favicon" type="image/png" />\n+\t<link rel="apple-touch-icon" sizes="57x57" href="/images/apple-touch-icon-57x57.png">\n+\t<link rel="apple-touch-icon" sizes="60x60" href="/images/apple-touch-icon-60x60.png">\n+\t<link rel="apple-touch-icon" sizes="72x72" href="/images/apple-touch-icon-72x72.png">\n+\t<link rel="apple-touch-icon" sizes="76x76" href="/images/apple-touch-icon-76x76.png">\n+\t<link rel="apple-touch-icon" sizes="114x114" href="/images/apple-touch-icon-114x114.png">\n+\t<link rel="apple-touch-icon" sizes="120x120" href="/images/apple-touch-icon-120x120.png">\n+\t<link rel="apple-touch-icon" sizes="144x144" href="/images/apple-touch-icon-144x144.png">\n+\t<link rel="apple-touch-icon" sizes="152x152" href="/images/apple-touch-icon-152x152.png">\n+\t<link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-180x180.png">\n+  \n+\t<style type="text/css">\n+\t\t@import url("//fonts.googleapis.com/css?family=Open+Sans:700");\n+    \tbody {\n+\t\t\ttext-align: center;\n+\t\t\tmargin: 0 0;\n+\t\t\tpadding: 0;\n+\t\t\toverflow: hidden;\n+\t\t\tfont-family: \'Open Sans\';\n+\t\t\tcolor: grey;\n+\t\t\tbackground-color: black;\n+\t\t}\n+\t\tmain {\n+\t\t\tdisplay: -webkit-box;\n+\t\t\tdisplay: -ms-flexbox;\n+\t\t\tdisplay: -webkit-flex;\n+\t\t\tdisplay: flex;\n+\t\t\t-webkit-box-align: center;\n+\t\t\t-ms-flex-align: center;\n+\t\t\t-webkit-align-items: center;\n+\t\t\talign-items: center;\n+\t\t\theight: 100vh;\n+\t\t}\n+\t\t.inner {\n+\t\t\twidth: 100%;\n+\t\t\t-webkit-transform: translateY(-2%);\n+\t\t}\n+\t\t#trend {\n+\t\t\tdisplay: -ms-flexbox;\n+\t\t\tdisplay: -webkit-flex;\n+\t\t\tdisplay: flex;\n+\t\t\t-ms-flex-align: center;\n+\t\t\t-webkit-align-items: center;\n+\t\t\talign-items: center;\n+\t\t\tjustify-content: center;\n+\t\t\t-webkit-flex-direction: row;\n+\t\t\tflex-direction: row;\n+\t\t}\n+\t\t#bgnow, #arrowDiv {\n+\t\t\tdisplay: flex;\n+\t\t\tflex-grow: 0;\n+\t\t\tfont-weight: 700;\n+\t\t\tfont-size: 30vmin;\n+\t\t\tpadding: 0 20px;\n+\t\t\tmargin: 0;\n+\t\t}\n+\t\timg#arrow {\n+\t\t\theight: 15vmin;\n+\t\t}\n+\t\t#clock {\n+\t\t\tfont-weight: 700;\n+\t\t\tfont-size: 25vmin;\n+\t\t}\n+\t\t.stale {\n+\t\t\ttext-decoration: line-through;\n+\t\t}\n   </style>\n </head>\n+\n <body>\n-  <div class="center">\n-    <h1 class="bgnow"></h1>\n-    <h1 class="clock"></h1>\n-  </div>\n-  <script src="/api/v1/status.js"></script>\n-  <script src="/js/bundle.js?v=<%= locals.cachebuster %>"></script>\n-  <script type="text/javascript">\n-    function query ( ) {\n-      console.log(\'query\');\n-      $.ajax(\'/api/v1/entries/current.json\', { success: render });\n-    }\n \n-    function render (xhr) {\n-      console.log(\'xhr\', xhr);\n-      var rec = xhr[0];\n-      var last = new Date(rec.date);\n-      var now = new Date( );\n-      if (window.serverSettings.settings.units == \'mmol\') {\n-        rec.sgv = Nightscout.units.mgdlToMMOL(rec.sgv);\n-      }\n-      $(\'.bgnow\').html(rec.sgv + \'<img id="arrow" src="">\');\n-      $(\'#arrow\').attr(\'src\', \'images/\'+rec.direction+\'.svg\');\n-      var threshold = 1000 * 60 * 13;\n-      $(\'.bgnow\').toggleClass(\'stale\', (now - last > threshold));\n-      \n-      var timeDivisor = (window.serverSettings.settings.timeFormat) ? window.serverSettings.settings.timeFormat : 12;\n-      \n-      var today = new Date(),\n-            h = today.getHours() % timeDivisor || timeDivisor,\n-            m = today.getMinutes();\n-      if (m < 10) m = "0" + m;\n-      $(\'.clock\').text(h + ":" + m);\n-    }\n+\t<main>\n+\t\t<div class="inner">\n+\t\t\t<div id="trend">\n+\t\t\t\t<div id="bgnow"></div>\n+\t\t\t\t<div id="arrowDiv"><img id="arrow" src=""/></div>\n+\t\t\t</div>\n+\t\t\t<div id="clock"></div>\n+\t\t</div>\n+\t</main>\n+\t\n+\t<script src="/api/v1/status.js"></script>\n+\t<script src="/js/bundle.js?v=<%= locals.cachebuster %>"></script>\n+\n+\t<script type="text/javascript">\n+\t\tfunction query ( ) {\n+\t\t\tconsole.log(\'query\');\n+\t\t\t$.ajax(\'/api/v1/entries/current.json\', { success: render });\n+\t\t}\n+\n+\t\tfunction render (xhr) {\n+\t\t\tconsole.log(\'xhr\', xhr);\n+\t\t\t\n+\t\t\tvar rec = xhr[0];\n+\t\t\tvar last = new Date(rec.date);\n+\t\t\tvar now = new Date( );\n+\t\t\t\n+\t\t\t// Convert BG to mmol/L if necessary.\n+\t\t\tif (window.serverSettings.settings.units == \'mmol\') {\n+\t\t\t\trec.sgv = Nightscout.units.mgdlToMMOL(rec.sgv);\n+\t\t\t}\n+\t\t\t\n+\t\t\t// Insert the BG value text.\n+\t\t\t$(\'#bgnow\').html(rec.sgv);\n+\t\t\t\n+\t\t\t// Insert the trend arrow.\n+\t\t\t$(\'#arrow\').attr(\'src\', \'images/\'+rec.direction+\'.svg\');\n+\t\t\t\n+\t\t\t// Time before data considered stale.\n+\t\t\tvar staleMinutes = 13;\t\t\t\t\t\t\t\t\t\t\n+\t\t\tvar threshold = 1000 * 60 * staleMinutes;\n+\t\t\t\n+\t\t\t// Toggle stale if necessary.\n+\t\t\t$(\'#bgnow\').toggleClass(\'stale\', (now - last > threshold));\n+\n+\t\t\t// Generate and insert the clock.\n+\t\t\tvar timeDivisor = (window.serverSettings.settings.timeFormat) ? window.serverSettings.settings.timeFormat : 12;\n+\t\t\tvar today = new Date(),\n+\t\t\th = today.getHours() % timeDivisor || timeDivisor,\n+\t\t\tm = today.getMinutes();\n+\t\t\tif (m < 10) m = "0" + m;\n+\t\t\t$(\'#clock\').text(h + ":" + m);\n+\t\t}\n \n-    function init ( ) {\n-      console.log(\'init\');\n-      query( );\n-      setInterval(query, 1 * 60 * 1000);\n-    }\n+\t\tfunction init ( ) {\n+\t\t\tconsole.log(\'init\');\n+\t\t\tquery( );\n+\t\t\tsetInterval(query, 1 * 60 * 1000);\n+\t\t}\n \n-    init( );\n-  </script>\n+\t\tinit( );\n+\t</script>\n </body>\n </html>\ndiff --git a/views/clock.html b/views/clock.html\nindex 95f56a1e..c0ac35d6 100644\n--- a/views/clock.html\n+++ b/views/clock.html\n@@ -1,78 +1,132 @@\n <!DOCTYPE html>\n <html>\n <head>\n-  <meta name="viewport" content="width=device-width, initial-scale=1.0">\n-  <title>Nightscout BG NOW</title>\n-  <link href="/images/round1.png" rel="icon" id="favicon" type="image/png" />\n-  <link rel=\'stylesheet\' type=\'text/css\' href=\'/css/main.css\' />\n-  <style type="text/css">\n-  \t@import url("//fonts.googleapis.com/css?family=Open+Sans:700");\n-    body {\n-\t\ttext-align: center;\n-\t\tmargin: 0 0;\n-\t\tpadding: 0;\n-\t\toverflow: hidden;\n-\t\tfont-family: \'Open Sans\';\n-\t}\n-\tmain {\n-\t\tdisplay: -webkit-box;\n-\t\tdisplay: -ms-flexbox;\n-\t\tdisplay: -webkit-flex;\n-\t\tdisplay: flex;\n-\t\t-webkit-box-align: center;\n-\t\t-ms-flex-align: center;\n-\t\t-webkit-align-items: center;\n-\t\talign-items: center;\n-\t\theight: 100vh;\n-\t}\n-    .center {\n-\t\twidth: 100%;\n-\t\t-webkit-transform: translateY(-3%);\n-    }\n-    h1 {\n-\t\tfont-weight: 700;\n-\t\tfont-size: 50vmin;\n-    }\n-    .stale {\n-      text-decoration: line-through;\n-    }\n-  </style>\n+\t<meta name="viewport" content="width=device-width, initial-scale=1.0">\n+\t<meta name="apple-mobile-web-app-capable" content="yes">\n+  \n+\t<title>Nightscout</title>\n+  \n+\t<link href="/images/round1.png" rel="icon" id="favicon" type="image/png" />\n+\t<link rel="apple-touch-icon" sizes="57x57" href="/images/apple-touch-icon-57x57.png">\n+\t<link rel="apple-touch-icon" sizes="60x60" href="/images/apple-touch-icon-60x60.png">\n+\t<link rel="apple-touch-icon" sizes="72x72" href="/images/apple-touch-icon-72x72.png">\n+\t<link rel="apple-touch-icon" sizes="76x76" href="/images/apple-touch-icon-76x76.png">\n+\t<link rel="apple-touch-icon" sizes="114x114" href="/images/apple-touch-icon-114x114.png">\n+\t<link rel="apple-touch-icon" sizes="120x120" href="/images/apple-touch-icon-120x120.png">\n+\t<link rel="apple-touch-icon" sizes="144x144" href="/images/apple-touch-icon-144x144.png">\n+\t<link rel="apple-touch-icon" sizes="152x152" href="/images/apple-touch-icon-152x152.png">\n+\t<link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-180x180.png">\n+  \n+\t<style type="text/css">\n+\t\t@import url("//fonts.googleapis.com/css?family=Open+Sans:700");\n+  \n+\t\tbody {\n+\t\t\ttext-align: center;\n+\t\t\tmargin: 0 0;\n+\t\t\tpadding: 0;\n+\t\t\toverflow: hidden;\n+\t\t\tfont-family: \'Open Sans\';\n+\t\t\tcolor: grey;\n+\t\t\tbackground-color: black;\n+\t\t}\n+\t\tmain {\n+\t\t\tdisplay: -webkit-box;\n+\t\t\tdisplay: -ms-flexbox;\n+\t\t\tdisplay: -webkit-flex;\n+\t\t\tdisplay: flex;\n+\t\t\t-webkit-box-align: center;\n+\t\t\t-ms-flex-align: center;\n+\t\t\t-webkit-align-items: center;\n+\t\t\talign-items: center;\n+\t\t\theight: 100vh;\n+\t\t}\n+\t\t.inner {\n+\t\t\twidth: 100%;\n+\t\t\t-webkit-transform: translateY(-5%);\n+\t\t}\n+\t\t#bgnow {\n+\t\t\tfont-weight: 700;\n+\t\t\tfont-size: 40vmin;\n+\t\t}\n+\t\t#trend {\n+\t\t\tdisplay: -ms-flexbox;\n+\t\t\tdisplay: -webkit-flex;\n+\t\t\tdisplay: flex;\n+\t\t\t-ms-flex-align: center;\n+\t\t\t-webkit-align-items: center;\n+\t\t\t-webkit-transform: translateX(1%);\n+\t\t\talign-items: center;\n+\t\t\tjustify-content: center;\n+\t\t\t-webkit-flex-direction: column;\n+\t\t\tflex-direction: column;\n+\t\t}\n+\t\t#staleTime {\n+\t\t\tflex-grow: 1;\n+\t\t\tfont-size: 6vmin;\n+\t\t\tdisplay: none;\n+\t\t}\n+\t</style>\n </head>\n+\n <body>\n+\n \t<main>\n-\t\t<div class="center">\n-\t\t\t<h1 class="bgnow"></h1>\n+\t\t<div class="inner">\n+\t\t\t<div id="bgnow"></div>\n+\t\t\t<div id="trend">\n+\t\t\t\t<div id="staleTime"></div>\n+\t\t\t</div>\n \t\t</div>\n \t</main>\n+\t\n   <script src="/api/v1/status.js"></script>\n   <script src="/js/bundle.js?v=<%= locals.cachebuster %>"></script>\n-  <script type="text/javascript">\n-    function query ( ) {\n-      console.log(\'query\');\n-      $.ajax(\'/api/v1/entries/current.json\', { success: render });\n-    }\n+  \n+\t<script type="text/javascript">\n+\t\tfunction query ( ) {\n+\t\t\tconsole.log(\'query\');\n+\t\t\t$.ajax(\'/api/v1/entries/current.json\', { success: render });\n+\t\t}\n+\n+\t\tfunction render (xhr) {\n+\t\t\tconsole.log(\'xhr\', xhr);\n+\n+\t\t\tvar rec = xhr[0];\n+\t\t\tvar last = new Date(rec.date);\n+\t\t\tvar now = new Date( );\n+\t\t\tvar elapsedMins = Math.round(((now - last) / 1000) / 60);\n+\n+\t\t\t// Convert BG to mmol/L if necessary.\n+\t\t\tif (window.serverSettings.settings.units == \'mmol\') {\n+\t\t\t\trec.sgv = Nightscout.units.mgdlToMMOL(rec.sgv);\n+\t\t\t}\n \n-    function render (xhr) {\n-      console.log(\'xhr\', xhr);\n-      var rec = xhr[0];\n-      var last = new Date(rec.date);\n-      var now = new Date( );\n-      if (window.serverSettings.settings.units == \'mmol\') {\n-        rec.sgv = Nightscout.units.mgdlToMMOL(rec.sgv);\n-      }\n-      $(\'.bgnow\').text(rec.sgv);\n-      var threshold = 1000 * 60 * 13;\n-      $(\'.bgnow\').toggleClass(\'stale\', (now - last > threshold));\n-    }\n+\t\t\t// Insert the BG value text.\n+\t\t\t$(\'#bgnow\').text(rec.sgv);\n+\t\t\n+\t\t\t// Insert the BG stale time text.\n+\t\t\t$(\'#staleTime\').text(elapsedMins+\' minutes ago\');\n+\t\t\n+\t\t\t// Time before data considered stale.\n+\t\t\tvar staleMinutes = 13;\n+\t\t\tvar threshold = 1000 * 60 * staleMinutes;\n+\t\t\n+\t\t\t// Make the "x minutes ago" visible.\n+\t\t\tif (now - last > threshold) {\n+\t\t\t\t$(\'#staleTime\').css(\'display\', \'block\');\n+\t\t\t} else {\n+\t\t\t\t$(\'#staleTime\').css(\'display\', \'none\');\n+\t\t\t}\n+\t\t}\n \n-    function init ( ) {\n-      console.log(\'init\');\n-      query( );\n-      setInterval(query, 1 * 60 * 1000);\n-    }\n+\t\tfunction init ( ) {\n+\t\t\tconsole.log(\'init\');\n+\t\t\tquery( );\n+\t\t\tsetInterval(query, 1 * 60 * 1000);\n+\t\t}\n \n-    init( );\n-  </script>\n+\t\tinit( );\n+\t</script>\n </body>\n </html>\n \ndiff --git a/webpack.config.js b/webpack.config.js\nindex fd5b9bea..fd3bd125 100644\n--- a/webpack.config.js\n+++ b/webpack.config.js\n@@ -7,19 +7,7 @@ var sourceMapType = \'source-map\';\n \n if (process.env.NODE_ENV !== \'development\') {\n \n-    console.log(\'Production environment detected, enabling UglifyJsPlugin\');\n-\n-    var uglify = new webpack.optimize.UglifyJsPlugin({\n-        compress: {\n-            warnings: false\n-        },\n-        output: {\n-            comments: false\n-        }\n-        , sourceMap: true\n-    });\n-\n-    pluginArray.push(uglify);\n+    console.log(\'Production environment detected. Enabling --optimize-minimize\');\n \n /*\n     console.log(\'Development environment detected, enabling Bundle Analyzer\');\n', 'commit_subject': 'Merge pull request #8 from nightscout/dev', 'repo_name': 'nightscout/cgm-remote-monitor', 'committer': {'name': 'GitHub', 'email': '1505422b2465e9a84f6fdfaa161078890c593f06@github.com', 'time_sec': '1527538470', 'tz_offset': '120', 'date': {'seconds': '1527538470'}}, 'commit_tree': '8b01ec5063cea88d68348be4ca3f54f48df9f1f0', 'commit_message': 'Merge pull request #8 from nightscout/dev\n\nRefresh dev from nightscout', 'language_name': 'HTML', 'license': 'agpl-3.0', 'hunks': "@@ -9,7 +9,9 @@ describe('Uploader Battery', function ( ) {\n     var sandbox = require('../lib/sandbox')();\n     var ctx = {\n       settings: {}\n+      , language: require('../lib/language')()\n     };\n+    ctx.language.set('en');\n     var sbx = sandbox.clientInit(ctx, Date.now(), data);\n \n     sbx.offerProperty = function mockedOfferProperty (name, setter) {\n@@ -22,7 +24,7 @@ describe('Uploader Battery', function ( ) {\n       done();\n     };\n \n-    var upbat = require('../lib/plugins/upbat')();\n+    var upbat = require('../lib/plugins/upbat')(ctx);\n     upbat.setProperties(sbx);\n \n   });\n@@ -38,11 +40,13 @@ describe('Uploader Battery', function ( ) {\n           done();\n         }\n       }\n+      , language: require('../lib/language')()\n     };\n+    ctx.language.set('en');\n \n     var sandbox = require('../lib/sandbox')();\n     var sbx = sandbox.clientInit(ctx, Date.now(), data);\n-    var upbat = require('../lib/plugins/upbat')();\n+    var upbat = require('../lib/plugins/upbat')(ctx);\n     upbat.setProperties(sbx);\n     upbat.updateVisualisation(sbx);\n \n@@ -57,11 +61,13 @@ describe('Uploader Battery', function ( ) {\n           done();\n         }\n       }\n+      , language: require('../lib/language')()\n     };\n+    ctx.language.set('en');\n \n     var sandbox = require('../lib/sandbox')();\n     var sbx = sandbox.clientInit(ctx, Date.now(), {});\n-    var upbat = require('../lib/plugins/upbat')();\n+    var upbat = require('../lib/plugins/upbat')(ctx);\n     upbat.setProperties(sbx);\n     upbat.updateVisualisation(sbx);\n   });\n@@ -74,12 +80,13 @@ describe('Uploader Battery', function ( ) {\n           options.hide.should.equal(true);\n           done();\n         }\n-      }\n+      }, language: require('../lib/language')()\n     };\n+    ctx.language.set('en');\n \n     var sandbox = require('../lib/sandbox')();\n     var sbx = sandbox.clientInit(ctx, Date.now(), {devicestatus: [{uploader: {battery: -1}}]});\n-    var upbat = require('../lib/plugins/upbat')();\n+    var upbat = require('../lib/plugins/upbat')(ctx);\n     upbat.setProperties(sbx);\n     upbat.updateVisualisation(sbx);\n   });\n@@ -88,11 +95,13 @@ describe('Uploader Battery', function ( ) {\n \n     var ctx = {\n       settings: {}\n+      , language: require('../lib/language')()\n     };\n+    ctx.language.set('en');\n \n     var sandbox = require('../lib/sandbox')();\n     var sbx = sandbox.clientInit(ctx, Date.now(), data);\n-    var upbat = require('../lib/plugins/upbat')();\n+    var upbat = require('../lib/plugins/upbat')(ctx);\n     upbat.setProperties(sbx);\n \n     upbat.alexa.intentHandlers.length.should.equal(1);\n", 'addition_count': 15, 'deletion_count': 6, 'src_file': 'a/tests/upbat.test.js', 'tgt_file': 'b/tests/upbat.test.js', 'file_extension': '.js', 'before_file': "'use strict';\n\nrequire('should');\nconst fs = require('fs');\n\nvar levels = require('../lib/levels');\n\ndescribe('Uploader Battery', function ( ) {\n    var sandbox = require('../lib/sandbox')();\n    var ctx = {\n      settings: {}\n    };\n    var sbx = sandbox.clientInit(ctx, Date.now(), data);\n\n    sbx.offerProperty = function mockedOfferProperty (name, setter) {\n    var sandbox = require('../lib/sandbox')(ctx);\n    \n    var sbx = sandbox.clientInit(ctx, Date.now(), data);\n\n    sbx.offerProperty = function mockedOfferProperty (name, setter) {\n      name.should.equal('upbat');\n      done();\n    };\n\n    var upbat = require('../lib/plugins/upbat')();\n    upbat.setProperties(sbx);\n\n  });\n\n    var upbat = require('../lib/plugins/upbat')(ctx);\n    upbat.setProperties(sbx);\n\n  });\n\n  it('set a pill to the uploader battery status', function (done) {\n    var ctx = {\n      settings: {}\n          done();\n        }\n      }\n    };\n\n    var sandbox = require('../lib/sandbox')();\n    var sbx = sandbox.clientInit(ctx, Date.now(), data);\n    var upbat = require('../lib/plugins/upbat')();\n    upbat.setProperties(sbx);\n    upbat.updateVisualisation(sbx);\n\n    var sandbox = require('../lib/sandbox')();\n    var sbx = sandbox.clientInit(ctx, Date.now(), data);\n    var upbat = require('../lib/plugins/upbat')(ctx);\n    upbat.setProperties(sbx);\n    upbat.updateVisualisation(sbx);\n\n  });\n\n          done();\n        }\n      }\n    };\n\n    var sandbox = require('../lib/sandbox')();\n    var sbx = sandbox.clientInit(ctx, Date.now(), {});\n    var upbat = require('../lib/plugins/upbat')();\n    upbat.setProperties(sbx);\n    upbat.updateVisualisation(sbx);\n  });\n\n    var sandbox = require('../lib/sandbox')();\n    var sbx = sandbox.clientInit(ctx, Date.now(), {});\n    var upbat = require('../lib/plugins/upbat')(ctx);\n    upbat.setProperties(sbx);\n    upbat.updateVisualisation(sbx);\n          options.hide.should.equal(true);\n          done();\n        }\n      }\n    };\n\n    var sandbox = require('../lib/sandbox')();\n    var sbx = sandbox.clientInit(ctx, Date.now(), {devicestatus: [{uploader: {battery: -1}}]});\n    var upbat = require('../lib/plugins/upbat')();\n    upbat.setProperties(sbx);\n    upbat.updateVisualisation(sbx);\n  });\n    ctx.language.set('en');\n\n\n    var ctx = {\n      settings: {}\n    };\n\n    var sandbox = require('../lib/sandbox')();\n    var sbx = sandbox.clientInit(ctx, Date.now(), data);\n    var upbat = require('../lib/plugins/upbat')();\n    upbat.setProperties(sbx);\n\n    upbat.alexa.intentHandlers.length.should.equal(1);\n    };\n    ctx.language.set('en');\n\n    var sandbox = require('../lib/sandbox')();\n    var sbx = sandbox.clientInit(ctx, Date.now(), data);\n    var upbat = require('../lib/plugins/upbat')(ctx);\n    upbat.setProperties(sbx);\n\n    upbat.virtAsst.intentHandlers.length.should.equal(2);\n\n    upbat.virtAsst.intentHandlers[0].intentHandler(function next(title, response) {\n      title.should.equal('Uploader Battery');\n      response.should.equal('Your uploader battery is at 20%');\n      \n      upbat.virtAsst.intentHandlers[1].intentHandler(function next(title, response) {\n        title.should.equal('Uploader Battery');\n        response.should.equal('Your uploader battery is at 20%');\n\n        done();\n      }, [], sbx);\n      \n    }, [], sbx);\n\n  });\n\n});\n", 'message': 'Merge pull request #8 from nightscout/dev\n\nRefresh dev from nightscout', 'author_name': 'GitHub', 'lang': 'test'}