From ddce2b91cd59873200c1238fcf732498e952b08f Mon Sep 17 00:00:00 2001 From: PieterGit Date: Thu, 14 Sep 2017 19:16:32 +0200 Subject: [PATCH 01/51] decrease timeouts to detect regressions faster in future --- Makefile | 2 +- tests/admintools.test.js | 2 +- tests/hashauth.test.js | 5 ----- tests/profileeditor.test.js | 2 +- 4 files changed, 3 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 34f9030cb34..4c4a6b043ac 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ all: test coverage: NODE_ENV=test ${MONGO_SETTINGS} \ - ${ISTANBUL} cover ${MOCHA} -- --timeout 30000 -R tap ${TESTS} + ${ISTANBUL} cover ${MOCHA} -- --timeout 15000 -R tap ${TESTS} report: test -f ${ANALYZED} && \ diff --git a/tests/admintools.test.js b/tests/admintools.test.js index a2374ff1ff2..28462b0f9d6 100644 --- a/tests/admintools.test.js +++ b/tests/admintools.test.js @@ -57,7 +57,7 @@ var someData = { describe('admintools', function ( ) { var self = this; - this.timeout(30000); + this.timeout(20000); // TODO: see why this test takes longer on Travis to complete before(function (done) { benv.setup(function() { diff --git a/tests/hashauth.test.js b/tests/hashauth.test.js index 21f249a57a7..3f92f51d369 100644 --- a/tests/hashauth.test.js +++ b/tests/hashauth.test.js @@ -63,7 +63,6 @@ describe('hashauth', function ( ) { */ it ('should make module unauthorized', function () { - this.timeout(50000); var client = require('../lib/client'); var hashauth = require('../lib/hashauth'); @@ -82,7 +81,6 @@ describe('hashauth', function ( ) { }); it ('should make module authorized', function () { - this.timeout(50000); var client = require('../lib/client'); var hashauth = require('../lib/hashauth'); @@ -99,9 +97,6 @@ describe('hashauth', function ( ) { }); it ('should store hash and the remove authentication', function () { - - this.timeout(50000); - var client = require('../lib/client'); var hashauth = require('../lib/hashauth'); var localStorage = require('./fixtures/localstorage'); diff --git a/tests/profileeditor.test.js b/tests/profileeditor.test.js index 4791b139544..e34e080e9b4 100644 --- a/tests/profileeditor.test.js +++ b/tests/profileeditor.test.js @@ -71,7 +71,7 @@ var someData = { describe('Profile editor', function ( ) { - this.timeout(30000); + this.timeout(20000); //TODO: see why this test takes longer on Travis to complete var headless = require('./fixtures/headless')(benv, this); before(function (done) { From 2676cee355c2c4a2a5abd813c62276ac7bf45853 Mon Sep 17 00:00:00 2001 From: PieterGit Date: Thu, 14 Sep 2017 19:26:50 +0200 Subject: [PATCH 02/51] Admintools and profileeditor test fails with 20 sec timeout. Increasing to 25 sec. ``` not ok 1 admintools "before all" hook Error: timeout of 20000ms exceeded. Ensure the done() callback is being called in this test. at tests/admintools.test.js:177:7 at Object.done (node_modules/benv/index.js:32:21) at process.nextTick (node_modules/jsdom/lib/old-api.js:347:18) at _combinedTickCallback (internal/process/next_tick.js:131:7) at process._tickCallback (internal/process/next_tick.js:180:9) not ok 203 Profile editor "before each" hook for "should produce some html" Error: timeout of 20000ms exceeded. Ensure the done() callback is being called in this test. at tests/fixtures/headless.js:160:7 at Object.module.exports.setup (node_modules/benv/index.js:24:56) at Function.init [as setup] (tests/fixtures/headless.js:16:10) at Context. (tests/profileeditor.test.js:94:14) ``` --- tests/admintools.test.js | 2 +- tests/profileeditor.test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/admintools.test.js b/tests/admintools.test.js index 28462b0f9d6..3419c4531ed 100644 --- a/tests/admintools.test.js +++ b/tests/admintools.test.js @@ -57,7 +57,7 @@ var someData = { describe('admintools', function ( ) { var self = this; - this.timeout(20000); // TODO: see why this test takes longer on Travis to complete + this.timeout(25000); // TODO: see why this test takes longer on Travis to complete before(function (done) { benv.setup(function() { diff --git a/tests/profileeditor.test.js b/tests/profileeditor.test.js index e34e080e9b4..3d601fed5f0 100644 --- a/tests/profileeditor.test.js +++ b/tests/profileeditor.test.js @@ -71,7 +71,7 @@ var someData = { describe('Profile editor', function ( ) { - this.timeout(20000); //TODO: see why this test takes longer on Travis to complete + this.timeout(25000); //TODO: see why this test takes longer on Travis to complete var headless = require('./fixtures/headless')(benv, this); before(function (done) { From 2caa67d5528a43f0c76884e41257e8765123a5a8 Mon Sep 17 00:00:00 2001 From: PieterGit Date: Thu, 14 Sep 2017 19:37:28 +0200 Subject: [PATCH 03/51] optimize travis tests. see if 5 sec per test is enough (in stead of 50 sec per test) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 4c4a6b043ac..b3748228830 100644 --- a/Makefile +++ b/Makefile @@ -45,7 +45,7 @@ test: travis: NODE_ENV=test ${MONGO_SETTINGS} \ - ${ISTANBUL} cover ${MOCHA} --report lcovonly -- --timeout 50000 -R tap ${TESTS} + ${ISTANBUL} cover ${MOCHA} --report lcovonly -- --timeout 5000 -R tap ${TESTS} docker_release: # Get the version from the package.json file From ec06d5da3bff6971dbc9fe2508260ea9a21c8bf1 Mon Sep 17 00:00:00 2001 From: PieterGit Date: Thu, 14 Sep 2017 19:54:46 +0200 Subject: [PATCH 04/51] the following tests don't complete in 5 sec. increase timeout to 25 sec. --- tests/careportal.test.js | 2 ++ tests/hashauth.test.js | 2 ++ tests/pluginbase.test.js | 2 ++ 3 files changed, 6 insertions(+) diff --git a/tests/careportal.test.js b/tests/careportal.test.js index 1241ebe703a..80d99041c6d 100644 --- a/tests/careportal.test.js +++ b/tests/careportal.test.js @@ -13,6 +13,8 @@ var nowData = { }; describe('client', function ( ) { + this.timeout(25000); // TODO: see why this test takes longer on Travis to complete + var self = this; var headless = require('./fixtures/headless')(benv, this); diff --git a/tests/hashauth.test.js b/tests/hashauth.test.js index 3f92f51d369..8c115bdcacd 100644 --- a/tests/hashauth.test.js +++ b/tests/hashauth.test.js @@ -6,6 +6,8 @@ var read = require('fs').readFileSync; var serverSettings = require('./fixtures/default-server-settings'); describe('hashauth', function ( ) { + this.timeout(25000); // TODO: see why this test takes longer on Travis to complete + var self = this; var headless = require('./fixtures/headless')(benv, this); diff --git a/tests/pluginbase.test.js b/tests/pluginbase.test.js index c04f0c802ce..d9f44e36dd5 100644 --- a/tests/pluginbase.test.js +++ b/tests/pluginbase.test.js @@ -4,6 +4,8 @@ require('should'); var benv = require('benv'); describe('pluginbase', function ( ) { + this.timeout(25000); // TODO: see why this test takes longer on Travis to complete + var headless = require('./fixtures/headless')(benv, this); before(function (done) { From 2cadcb0f767827167bd6f2245f24f4ac857760f4 Mon Sep 17 00:00:00 2001 From: PieterGit Date: Thu, 14 Sep 2017 20:03:42 +0200 Subject: [PATCH 05/51] increase profileeditor tests to 40 sec --- tests/profileeditor.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/profileeditor.test.js b/tests/profileeditor.test.js index 3d601fed5f0..9c915027c84 100644 --- a/tests/profileeditor.test.js +++ b/tests/profileeditor.test.js @@ -71,7 +71,7 @@ var someData = { describe('Profile editor', function ( ) { - this.timeout(25000); //TODO: see why this test takes longer on Travis to complete + this.timeout(40000); //TODO: see why this test takes longer on Travis to complete var headless = require('./fixtures/headless')(benv, this); before(function (done) { From 2f46e051289a396f74084be43bcf0f79c616834a Mon Sep 17 00:00:00 2001 From: PieterGit Date: Thu, 14 Sep 2017 20:11:41 +0200 Subject: [PATCH 06/51] hasauth.test.js fails with 25 sec. increasing to 40 sec --- tests/hashauth.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/hashauth.test.js b/tests/hashauth.test.js index 8c115bdcacd..19fb50cc69e 100644 --- a/tests/hashauth.test.js +++ b/tests/hashauth.test.js @@ -6,7 +6,7 @@ var read = require('fs').readFileSync; var serverSettings = require('./fixtures/default-server-settings'); describe('hashauth', function ( ) { - this.timeout(25000); // TODO: see why this test takes longer on Travis to complete + this.timeout(40000); // TODO: see why this test takes longer on Travis to complete var self = this; var headless = require('./fixtures/headless')(benv, this); From bf82c4314bc750f2ac47c71eee3006deeeff1100 Mon Sep 17 00:00:00 2001 From: Sulka Haro Date: Tue, 26 Sep 2017 16:57:03 +0300 Subject: [PATCH 07/51] Create issue_template.md Adding an issue template to help solve bugs --- docs/issue_template.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 docs/issue_template.md diff --git a/docs/issue_template.md b/docs/issue_template.md new file mode 100644 index 00000000000..e3ae7d24d3e --- /dev/null +++ b/docs/issue_template.md @@ -0,0 +1,11 @@ +Please include the following information with your bug report: + +Is this a new bug with the latest release, have you seen this earlier? + +Which device / browser version was used to reproduce the bug? + +Does this happen every time you launch Nightscout, or sometimes? + +Steps how to reproduce (if you can’t reproduce the issue, please don’t report the issue / if we can't reproduce the bug, we can't fix) + +Please include 1 or more screenshots of the issue appearing, ideally with an annotation on what's wrong From 68af094c7733d8c57b3799b4c0f82ff92e7da48a Mon Sep 17 00:00:00 2001 From: Christopher Fredregill Date: Sun, 15 Oct 2017 15:39:38 -0700 Subject: [PATCH 08/51] Adding some test coverage for /lib/client/renderer.js --- .gitignore | 3 ++- tests/client.renderer.test.js | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 tests/client.renderer.test.js diff --git a/.gitignore b/.gitignore index e088fce0240..2cb28800650 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ node_modules/ bundle/bundle.out.js +.vscode/ .idea/ *.iml my.env @@ -22,4 +23,4 @@ coverage/ npm-debug.log *.heapsnapshot -/tmp \ No newline at end of file +/tmp diff --git a/tests/client.renderer.test.js b/tests/client.renderer.test.js new file mode 100644 index 00000000000..ec70a627d4f --- /dev/null +++ b/tests/client.renderer.test.js @@ -0,0 +1,29 @@ +'use strict'; + +require('should'); +let _ = require('lodash'); + +let renderer = require('../lib/client/renderer'); +const MAX_DELTA = 0.0001; +const PREV_CHART_WIDTHS = [ + { width: 400, expectedScale: 3.5 } + , { width: 500, expectedScale: 2.625 } + , { width: 900, expectedScale: 1.75 } +]; + +describe('renderer', () => { + describe('bubbleScale', () => { + _.forEach(PREV_CHART_WIDTHS, (prev) => { + describe(`prevChartWidth < ${prev.width}`, () => { + let mockClient = { + utils: true + , chart: { prevChartWidth: prev.width } + , foucusRangeMS: true + }; + it('scales correctly', () => { + renderer(mockClient, {}).bubbleScale().should.be.approximately(prev.expectedScale, MAX_DELTA); + }); + }); + }); + }); +}); From f13b6af0c8b6d20a3b04af379cf091cd5b92a4cc Mon Sep 17 00:00:00 2001 From: MilosKozak Date: Mon, 16 Oct 2017 19:51:40 +0200 Subject: [PATCH 09/51] send foods via websockets --- lib/data/dataloader.js | 12 +++++++++++- lib/data/ddata.js | 2 ++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/data/dataloader.js b/lib/data/dataloader.js index 78b979e29a4..541e32a9c38 100644 --- a/lib/data/dataloader.js +++ b/lib/data/dataloader.js @@ -66,6 +66,7 @@ function init(env, ctx) { , loadProfileSwitchTreatments.bind(null, ddata, ctx) , loadSensorAndInsulinTreatments.bind(null, ddata, ctx) , loadProfile.bind(null, ddata, ctx) + , loadFood.bind(null, ddata, ctx) , loadDeviceStatus.bind(null, ddata, env, ctx) ], loadComplete); @@ -249,7 +250,16 @@ function loadProfile (ddata, ctx, callback) { }); } -function loadDeviceStatus (ddata, env, ctx, callback) { + function loadFood (ddata, ctx, callback) { + ctx.food.list(function (err, results) { + if (!err && results) { + ddata.food = results; + } + callback(); + }); + } + + function loadDeviceStatus (ddata, env, ctx, callback) { var dateRange = { $gte: new Date(ddata.lastUpdated - ONE_DAY).toISOString() }; diff --git a/lib/data/ddata.js b/lib/data/ddata.js index c975bd41f02..98d85b31c4f 100644 --- a/lib/data/ddata.js +++ b/lib/data/ddata.js @@ -14,6 +14,7 @@ function init( ) { , cals: [] , profiles: [] , devicestatus: [] + , food: [] , lastUpdated: 0 }; @@ -66,6 +67,7 @@ function init( ) { result.first.profiles = ddata.profiles; result.rest.mbgs = ddata.mbgs.filter(filterMax); + result.rest.food = ddata.food; console.log('results.first size', JSON.stringify(result.first).length,'bytes'); console.log('results.rest size', JSON.stringify(result.rest).length,'bytes'); From 3457de5b7ebc52126e4d6acf06e6aca95b63db68 Mon Sep 17 00:00:00 2001 From: MilosKozak Date: Mon, 16 Oct 2017 20:43:49 +0200 Subject: [PATCH 10/51] use websockeets instead of rest api for food --- lib/client/boluscalc.js | 52 ++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/lib/client/boluscalc.js b/lib/client/boluscalc.js index d9999599094..e97e7a73fcc 100644 --- a/lib/client/boluscalc.js +++ b/lib/client/boluscalc.js @@ -621,41 +621,39 @@ function init(client, $) { boluscalc.loadFoodDatabase = function loadFoodDatabase(event, callback) { categories = []; foodlist = []; - $.ajax('/api/v1/food/regular.json', { - headers: client.headers() - , success: function (records) { - records.forEach(function (r) { - foodlist.push(r); - if (r.category && !categories[r.category]) { - categories[r.category] = {}; - } - if (r.category && r.subcategory) { - categories[r.category][r.subcategory] = true; - } - }); - databaseloaded = true; - console.log('Food database loaded'); - fillForm(); + client.sbx.data.food.forEach(function (r) { + if (r.type == 'food') { + foodlist.push(r); + if (r.category && !categories[r.category]) { + categories[r.category] = {}; + } + if (r.category && r.subcategory) { + categories[r.category][r.subcategory] = true; + } } - }).done(function() { if (callback) { callback(); } }); + }); + databaseloaded = true; + console.log('Food database loaded'); + fillForm(); maybePrevent(event); + if (callback) { callback(); } }; boluscalc.loadFoodQuickpicks = function loadFoodQuickpicks( ) { // Load quickpicks - $.ajax('/api/v1/food/quickpicks.json', { - headers: client.headers() - , success: function (records) { - quickpicks = records; - $('#bc_quickpick').empty().append(''); - for (var i=0; i' + r.name + ' (' + r.carbs + ' g)'); - }; - $('#bc_quickpick').val(-1); - $('#bc_quickpick').change(quickpickChange); + quickpicks = []; + client.sbx.data.food.forEach(function (r) { + if (r.type == 'quickpick') { + quickpicks.push(r); } }); + $('#bc_quickpick').empty().append(''); + for (var i=0; i' + r.name + ' (' + r.carbs + ' g)'); + }; + $('#bc_quickpick').val(-1); + $('#bc_quickpick').change(quickpickChange); }; function fillForm(event) { From 257371f43f548686288f32a8d22c8e458a8ddcaa Mon Sep 17 00:00:00 2001 From: MilosKozak Date: Mon, 16 Oct 2017 21:25:08 +0200 Subject: [PATCH 11/51] add fat,protein,energy to food editor --- lib/client/boluscalc.js | 6 ++++-- lib/language.js | 9 +++++++++ static/food/js/food.js | 26 ++++++++++++++++++++++---- views/foodindex.html | 9 +++++++++ 4 files changed, 44 insertions(+), 6 deletions(-) diff --git a/lib/client/boluscalc.js b/lib/client/boluscalc.js index e97e7a73fcc..5c83f478f57 100644 --- a/lib/client/boluscalc.js +++ b/lib/client/boluscalc.js @@ -621,7 +621,8 @@ function init(client, $) { boluscalc.loadFoodDatabase = function loadFoodDatabase(event, callback) { categories = []; foodlist = []; - client.sbx.data.food.forEach(function (r) { + var records = client.sbx.data.food || []; + records.forEach(function (r) { if (r.type == 'food') { foodlist.push(r); if (r.category && !categories[r.category]) { @@ -642,7 +643,8 @@ function init(client, $) { boluscalc.loadFoodQuickpicks = function loadFoodQuickpicks( ) { // Load quickpicks quickpicks = []; - client.sbx.data.food.forEach(function (r) { + var records = client.sbx.data.food || []; + records.forEach(function (r) { if (r.type == 'quickpick') { quickpicks.push(r); } diff --git a/lib/language.js b/lib/language.js index 01fc8da6fe6..6b2482d4cfa 100644 --- a/lib/language.js +++ b/lib/language.js @@ -10566,6 +10566,15 @@ function init() { , sv: 'no' , zh_cn: 'no' , zh_tw: 'no' + }, + 'Fat [g]': { + cs: 'Tuk [g]' + }, + 'Protein [g]': { + cs: 'Proteiny [g]' + }, + 'Energy [kJ]': { + cs: 'Energie [kJ]' } }; diff --git a/static/food/js/food.js b/static/food/js/food.js index d743994d598..2ffc78d2623 100644 --- a/static/food/js/food.js +++ b/static/food/js/food.js @@ -19,6 +19,9 @@ client.init(function loaded () { , name: '' , portion: 0 , carbs: 0 + , fat: 0 // in grams + , protein: 0 // in grams + , energy: 0 // in kJ , gi: 2 , unit: 'g' }; @@ -222,7 +225,10 @@ client.init(function loaded () { .append($('').attr('class','width100px').css('text-align','center').append(translate('Carbs'))) .append($('').attr('class','width100px').css('text-align','center').append(translate('GI')+' [1-3]')) .append($('').attr('class','width150px').append(translate('Category'))) - .append($('').attr('class','width150px').append(translate('Subcategory'))); + .append($('').attr('class','width150px').append(translate('Subcategory'))) + .append($('').attr('class','width100px').append(translate('Fat [g]'))) + .append($('').attr('class','width100px').append(translate('Protein [g]'))) + .append($('').attr('class','width100px').append(translate('Energy [kJ]'))); $('#fe_data').empty(); @@ -244,6 +250,9 @@ client.init(function loaded () { .append($('').addClass('width100px').css('text-align','center').append(foodlist[i].gi)) .append($('').addClass('width150px').append(foodlist[i].category)) .append($('').addClass('width150px').append(foodlist[i].subcategory)) + .append($('').addClass('width100px').append(foodlist[i].fat)) + .append($('').addClass('width100px').append(foodlist[i].protein)) + .append($('').addClass('width100px').append(foodlist[i].energy)) ); } @@ -465,9 +474,12 @@ client.init(function loaded () { $('#fe_name').val(foodrec.name); $('#fe_portion').val(foodrec.portion ? foodrec.portion : ''); $('#fe_unit').val(foodrec.unit); - $('#fe_carbs').val(foodrec.carbs ? foodrec.carbs : ''); - $('#fe_gi').val(foodrec.gi); - + $('#fe_carbs').val(foodrec.carbs ? foodrec.carbs : '') + $('#fe_gi').val(foodrec.gi) + $('#fe_fat').val(foodrec.fat ? foodrec.fat : '') + $('#fe_protein').val(foodrec.protein ? foodrec.protein : '') + $('#fe_energy').val(foodrec.energy ? foodrec.energy : ''); + $('#fe_quickpick_showhidden').prop('checked',showhidden); console.info(JSON.stringify(foodrec)); @@ -488,6 +500,12 @@ client.init(function loaded () { foodrec.unit = $('#fe_unit').val(); foodrec.carbs = parseInt($('#fe_carbs').val()); foodrec.carbs = foodrec.carbs || 0; + foodrec.fat = parseInt($('#fe_fat').val()); + foodrec.fat = foodrec.fat || 0; + foodrec.protein = parseInt($('#fe_protein').val()); + foodrec.protein = foodrec.protein || 0; + foodrec.energy = parseInt($('#fe_energy').val()); + foodrec.energy = foodrec.energy || 0; foodrec.gi = parseInt($('#fe_gi').val()); showhidden = $('#fe_quickpick_showhidden').is(':checked'); diff --git a/views/foodindex.html b/views/foodindex.html index cc506a46bb8..ea0d153958f 100644 --- a/views/foodindex.html +++ b/views/foodindex.html @@ -88,6 +88,15 @@

Food Editor


+ + Fat [g]:
+ + + Protein [g]:
+ + + Energy [kJ]:
+ From 94d21d2ae43b284fca8131353b8cf7287506159a Mon Sep 17 00:00:00 2001 From: Sulka Haro Date: Mon, 16 Oct 2017 22:55:02 +0300 Subject: [PATCH 12/51] Re-enable source maps --- webpack.config.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/webpack.config.js b/webpack.config.js index a8e969c1e33..b08f3aa6deb 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -3,6 +3,8 @@ const webpack = require('webpack'); var pluginArray = []; +var sourceMapType = 'source-map'; + if (process.env.NODE_ENV !== 'development') { console.log('Production environment detected, enabling UglifyJsPlugin'); @@ -14,6 +16,7 @@ if (process.env.NODE_ENV !== 'development') { output: { comments: false } + , sourceMap: true }); pluginArray.push(uglify); @@ -24,7 +27,7 @@ if (process.env.NODE_ENV === 'development') { console.log('Development environment detected, enabling Bundle Analyzer'); - + var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; pluginArray.push(new BundleAnalyzerPlugin({ @@ -78,9 +81,10 @@ module.exports = { output: { path: path.resolve(__dirname, './tmp'), publicPath: '/', - filename: 'js/bundle.js' + filename: 'js/bundle.js', + sourceMapFilename: "js/bundle.js.map", }, - devtool: "#inline-source-map", + devtool: sourceMapType, plugins: pluginArray, module: { rules: [{ From 6c86a6d404292ddf66a390be58d6a86446abe3a4 Mon Sep 17 00:00:00 2001 From: Scott Date: Mon, 16 Oct 2017 18:01:11 -0700 Subject: [PATCH 13/51] replace 3HR with 2HR and (default) 4HR views --- lib/settings.js | 2 +- views/index.html | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/settings.js b/lib/settings.js index f7d6367d69c..74c084593e6 100644 --- a/lib/settings.js +++ b/lib/settings.js @@ -31,7 +31,7 @@ function init ( ) { , scaleY: 'log' , showPlugins: '' , showForecast: 'ar2' - , focusHours: 3 + , focusHours: 4 , heartbeat: 60 , baseURL: '' , authDefaultRoles: 'readable' diff --git a/views/index.html b/views/index.html index 237c0297a5c..58e2e1b5562 100644 --- a/views/index.html +++ b/views/index.html @@ -148,7 +148,8 @@
    -
  • 3HR
  • +
  • 2HR
  • +
  • 4HR
  • 6HR
  • 12HR
  • 24HR
  • From e433cc813f490dee37275694f49901074a4ed559 Mon Sep 17 00:00:00 2001 From: Scott Date: Mon, 16 Oct 2017 18:02:46 -0700 Subject: [PATCH 14/51] only show focusHours' worth of predictions; strip leading zero from bolus amounts --- lib/client/renderer.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/client/renderer.js b/lib/client/renderer.js index 6e085f31460..b52d96c510d 100644 --- a/lib/client/renderer.js +++ b/lib/client/renderer.js @@ -3,7 +3,7 @@ var _ = require('lodash'); var times = require('../times'); -var DEFAULT_FOCUS = times.hours(3).msecs +var DEFAULT_FOCUS = times.hours(4).msecs , WIDTH_SMALL_DOTS = 420 , WIDTH_BIG_DOTS = 800 , TOOLTIP_TRANS_MS = 100 // milliseconds @@ -23,7 +23,7 @@ function init (client, d3) { } function focusRangeAdjustment ( ) { - return client.foucusRangeMS === DEFAULT_FOCUS ? 1 : 1 + ((client.foucusRangeMS - DEFAULT_FOCUS) / DEFAULT_FOCUS / 8); + return client.focusRangeMS === DEFAULT_FOCUS ? 1 : 1 + ((client.focusRangeMS - DEFAULT_FOCUS) / DEFAULT_FOCUS / 8); } var dotRadius = function(type) { @@ -74,6 +74,9 @@ function init (client, d3) { return client.settings.showForecast.indexOf(point.info.type) > -1; }); var maxForecastMills = _.max(_.map(shownForecastPoints, function (point) {return point.mills})); + // limit lookahead to the same as lookback + var focusHoursAheadMills = chart().brush.extent()[1].getTime() + client.focusRangeMS; + maxForecastMills = Math.min(focusHoursAheadMills, maxForecastMills); client.forecastTime = maxForecastMills > 0 ? maxForecastMills - client.sbx.lastSGVMills() : 0; focusData = focusData.concat(shownForecastPoints); } @@ -431,8 +434,10 @@ function init (client, d3) { arc_data[1].element = arc_data[1].element + " " + treatment.foodType; } - if (treatment.insulin > 0) { - arc_data[3].element = Math.round(treatment.insulin * 100) / 100 + ' U'; + if ( treatment.insulin > 0) { + // remove leading zeros to avoid overlap with adjacent boluses + var units = Math.round(treatment.insulin * 100)/100; + arc_data[3].element = (units+"").replace(/^0/,""); } if (treatment.status) { From 38d35398d13812cf41d43daeacd2a20c82d5b71d Mon Sep 17 00:00:00 2001 From: Scott Date: Mon, 16 Oct 2017 18:03:08 -0700 Subject: [PATCH 15/51] fix spelling of focusRangeMS --- lib/client/chart.js | 2 +- lib/client/index.js | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/client/chart.js b/lib/client/chart.js index 7361c1a7098..32a15ba0155 100644 --- a/lib/client/chart.js +++ b/lib/client/chart.js @@ -511,7 +511,7 @@ function init (client, d3, $) { var updateBrush = d3.select('.brush').transition(); updateBrush - .call(chart.brush.extent([new Date(dataRange[1].getTime() - client.foucusRangeMS), dataRange[1]])); + .call(chart.brush.extent([new Date(dataRange[1].getTime() - client.focusRangeMS), dataRange[1]])); client.brushed(true); renderer.addContextCircles(); diff --git a/lib/client/index.js b/lib/client/index.js index ac801e2561e..f8ca8e56fbe 100644 --- a/lib/client/index.js +++ b/lib/client/index.js @@ -221,7 +221,7 @@ client.load = function load(serverSettings, callback) { client.hashauth.initAuthentication(client.afterAuth); - client.foucusRangeMS = times.hours(client.settings.focusHours).msecs; + client.focusRangeMS = times.hours(client.settings.focusHours).msecs; $('.focus-range li[data-hours=' + client.settings.focusHours + ']').addClass('selected'); client.brushed = brushed; client.formatTime = formatTime; @@ -365,7 +365,7 @@ client.load = function load(serverSettings, callback) { d3.select('.brush') .transition() .duration(UPDATE_TRANS_MS) - .call(chart.brush.extent([new Date(dataRange[1].getTime() - client.foucusRangeMS), dataRange[1]])); + .call(chart.brush.extent([new Date(dataRange[1].getTime() - client.focusRangeMS), dataRange[1]])); if (!skipBrushing) { brushed(); @@ -385,14 +385,14 @@ client.load = function load(serverSettings, callback) { var brushExtent = chart.brush.extent(); // ensure that brush extent is fixed at 3.5 hours - if (brushExtent[1].getTime() - brushExtent[0].getTime() !== client.foucusRangeMS) { + if (brushExtent[1].getTime() - brushExtent[0].getTime() !== client.focusRangeMS) { // ensure that brush updating is with the time range - if (brushExtent[0].getTime() + client.foucusRangeMS > client.dataExtent()[1].getTime()) { - brushExtent[0] = new Date(brushExtent[1].getTime() - client.foucusRangeMS); + if (brushExtent[0].getTime() + client.focusRangeMS > client.dataExtent()[1].getTime()) { + brushExtent[0] = new Date(brushExtent[1].getTime() - client.focusRangeMS); d3.select('.brush') .call(chart.brush.extent([brushExtent[0], brushExtent[1]])); } else { - brushExtent[1] = new Date(brushExtent[0].getTime() + client.foucusRangeMS); + brushExtent[1] = new Date(brushExtent[0].getTime() + client.focusRangeMS); d3.select('.brush') .call(chart.brush.extent([brushExtent[0], brushExtent[1]])); } @@ -868,7 +868,7 @@ client.load = function load(serverSettings, callback) { $('.focus-range li').removeClass('selected'); li.addClass('selected'); var hours = Number(li.data('hours')); - client.foucusRangeMS = times.hours(hours).msecs; + client.focusRangeMS = times.hours(hours).msecs; Storages.localStorage.set('focusHours', hours); refreshChart(); } else { From e60ff3aa9d6c6cb18fe8b414d95cef09e76350b6 Mon Sep 17 00:00:00 2001 From: Scott Date: Mon, 16 Oct 2017 18:06:54 -0700 Subject: [PATCH 16/51] change default back to 3HR --- lib/client/renderer.js | 2 +- lib/settings.js | 2 +- views/index.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/client/renderer.js b/lib/client/renderer.js index b52d96c510d..cbb075a15aa 100644 --- a/lib/client/renderer.js +++ b/lib/client/renderer.js @@ -3,7 +3,7 @@ var _ = require('lodash'); var times = require('../times'); -var DEFAULT_FOCUS = times.hours(4).msecs +var DEFAULT_FOCUS = times.hours(3).msecs , WIDTH_SMALL_DOTS = 420 , WIDTH_BIG_DOTS = 800 , TOOLTIP_TRANS_MS = 100 // milliseconds diff --git a/lib/settings.js b/lib/settings.js index 74c084593e6..f7d6367d69c 100644 --- a/lib/settings.js +++ b/lib/settings.js @@ -31,7 +31,7 @@ function init ( ) { , scaleY: 'log' , showPlugins: '' , showForecast: 'ar2' - , focusHours: 4 + , focusHours: 3 , heartbeat: 60 , baseURL: '' , authDefaultRoles: 'readable' diff --git a/views/index.html b/views/index.html index 58e2e1b5562..0cc6c903834 100644 --- a/views/index.html +++ b/views/index.html @@ -149,7 +149,7 @@
    • 2HR
    • -
    • 4HR
    • +
    • 3HR
    • 6HR
    • 12HR
    • 24HR
    • From fb4e74e9160b42992e81e261d60ebf6bac06d85b Mon Sep 17 00:00:00 2001 From: Scott Date: Tue, 17 Oct 2017 14:16:30 -0700 Subject: [PATCH 17/51] try larger label font: 35 instead of 25 (vs. 40) --- lib/client/renderer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/client/renderer.js b/lib/client/renderer.js index cbb075a15aa..ab25f80819b 100644 --- a/lib/client/renderer.js +++ b/lib/client/renderer.js @@ -845,7 +845,7 @@ function init (client, d3) { label.append('text') // reduce the treatment label font size to make it readable with SMB - .style('font-size', 25 / opts.scale) + .style('font-size', 35 / opts.scale) .style('text-shadow', '0px 0px 10px rgba(0, 0, 0, 1)') .attr('text-anchor', 'middle') .attr('dy', '.35em') From 33f16f4439262da2ec74c196bfa7f244910bb6fe Mon Sep 17 00:00:00 2001 From: Scott Date: Tue, 17 Oct 2017 17:15:13 -0700 Subject: [PATCH 18/51] allow treatment bubbles to scale up past 1U/20g size --- lib/client/renderer.js | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/lib/client/renderer.js b/lib/client/renderer.js index ab25f80819b..d92559926e8 100644 --- a/lib/client/renderer.js +++ b/lib/client/renderer.js @@ -391,16 +391,23 @@ function init (client, d3) { contextCircles.exit().remove(); }; - function calcTreatmentRadius(treatment, opts) { - var CR = treatment.CR || 20; + function calcTreatmentRadius(treatment, opts, carbratio) { + var CR = treatment.CR || carbratio || 20; var carbs = treatment.carbs || CR; var insulin = treatment.insulin || 1; + var carbsOrInsulin = CR; + if ( treatment.carbs ) { + carbsOrInsulin = treatment.carbs; + } else if ( treatment.insulin ) { + carbsOrInsulin = treatment.insulin * CR; + } - var R1 = Math.sqrt(Math.min(carbs, insulin * CR)) / opts.scale - , R2 = Math.sqrt(Math.max(carbs, insulin * CR)) / opts.scale - , R3 = R2 + 8 / opts.scale - // R4 determines how far from the treatment dot the labels are placed - , R4 = R2 + 25 / opts.scale + // R1 determines the size of the treatment dot + var R1 = Math.sqrt(2*carbsOrInsulin) / opts.scale + , R2 = R1 + // R3/R4 determine how far from the treatment dot the labels are placed + , R3 = R1 + 8 / opts.scale + , R4 = R1 + 25 / opts.scale ; return { @@ -414,8 +421,10 @@ function init (client, d3) { function prepareArc(treatment, radius) { var arc_data = [ + // white carb half-circle on top { 'element': '', 'color': 'white', 'start': -1.5708, 'end': 1.5708, 'inner': 0, 'outer': radius.R1 }, { 'element': '', 'color': 'transparent', 'start': -1.5708, 'end': 1.5708, 'inner': radius.R2, 'outer': radius.R3 }, + // blue insulin half-circle on bottom { 'element': '', 'color': '#0099ff', 'start': 1.5708, 'end': 4.7124, 'inner': 0, 'outer': radius.R1 }, // these form a very short transparent arc along the bottom of an insulin treatment to position the label // these used to be semicircles from 1.5708 to 4.7124, but that made the tooltip target too big @@ -845,7 +854,7 @@ function init (client, d3) { label.append('text') // reduce the treatment label font size to make it readable with SMB - .style('font-size', 35 / opts.scale) + .style('font-size', 30 / opts.scale) .style('text-shadow', '0px 0px 10px rgba(0, 0, 0, 1)') .attr('text-anchor', 'middle') .attr('dy', '.35em') @@ -866,11 +875,11 @@ function init (client, d3) { renderer.drawTreatment(d, { scale: renderer.bubbleScale() , showLabels: true - }); + }, client.sbx.data.profile.getCarbRatio(new Date())); }); }; - renderer.drawTreatment = function drawTreatment(treatment, opts) { + renderer.drawTreatment = function drawTreatment(treatment, opts, carbratio) { if (!treatment.carbs && !treatment.insulin) { return; } @@ -882,7 +891,7 @@ function init (client, d3) { return; } - var radius = calcTreatmentRadius(treatment, opts); + var radius = calcTreatmentRadius(treatment, opts, carbratio); if (radius.isNaN) { console.warn('Bad Data: Found isNaN value in treatment', treatment); return; From 8f66f09f3a724cf62843dc0271108e6d208007cb Mon Sep 17 00:00:00 2001 From: Scott Date: Thu, 19 Oct 2017 20:12:53 -0700 Subject: [PATCH 19/51] back to smaller treatment dots --- lib/client/renderer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/client/renderer.js b/lib/client/renderer.js index d92559926e8..1194638f19b 100644 --- a/lib/client/renderer.js +++ b/lib/client/renderer.js @@ -403,7 +403,7 @@ function init (client, d3) { } // R1 determines the size of the treatment dot - var R1 = Math.sqrt(2*carbsOrInsulin) / opts.scale + var R1 = Math.sqrt(carbsOrInsulin) / opts.scale , R2 = R1 // R3/R4 determine how far from the treatment dot the labels are placed , R3 = R1 + 8 / opts.scale From 532d7660027c58be00da18a2874439cd176d082e Mon Sep 17 00:00:00 2001 From: MilosKozak Date: Fri, 20 Oct 2017 17:11:08 +0200 Subject: [PATCH 20/51] handle AAPS profile switches well --- lib/client/renderer.js | 4 ++-- lib/profilefunctions.js | 20 ++++++++++++++++++++ lib/report_plugins/daytoday.js | 4 ++-- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/lib/client/renderer.js b/lib/client/renderer.js index ca263bac6f1..122a50abfb8 100644 --- a/lib/client/renderer.js +++ b/lib/client/renderer.js @@ -1075,9 +1075,9 @@ function init (client, d3) { var sign = t.first ? '▲▲▲' : '▬▬▬'; var ret; if (t.cutting) { - ret = sign + ' ' + t.cutting + ' ' + '►►►' + ' ' + t.profile + ' ' + sign; + ret = sign + ' ' + client.profilefunctions.profileSwitchName(t.cutting) + ' ' + '►►►' + ' ' + client.profilefunctions.profileSwitchName(t.profile) + ' ' + sign; } else { - ret = sign + ' ' + t.profile + ' ' + sign; + ret = sign + ' ' + client.profilefunctions.profileSwitchName(t.profile) + ' ' + sign; } return ret; }; diff --git a/lib/profilefunctions.js b/lib/profilefunctions.js index 582dca2a375..b7f85537ac0 100644 --- a/lib/profilefunctions.js +++ b/lib/profilefunctions.js @@ -235,9 +235,23 @@ function init (profileData) { var duration = times.mins(t.duration || 0).msecs; if (duration != 0 && time < t.mills + duration) { treatment = t; + // if profile switch contains json of profile inject it in to store to be findable by profile name + if (treatment.profileJson && !profile.data[0].store[treatment.profile]) { + if (treatment.profile.indexOf("@@@@@") < 0) + treatment.profile += "@@@@@" + treatment.mills; + var json = JSON.parse(treatment.profileJson); + profile.data[0].store[treatment.profile] = json; + } } if (duration == 0) { treatment = t; + // if profile switch contains json of profile inject it in to store to be findable by profile name + if (treatment.profileJson && !profile.data[0].store[treatment.profile]) { + if (treatment.profile.indexOf("@@@@@") < 0) + treatment.profile += "@@@@@" + treatment.mills; + var json = JSON.parse(treatment.profileJson); + profile.data[0].store[treatment.profile] = json; + } } } }); @@ -248,6 +262,12 @@ function init (profileData) { return returnValue; }; + profile.profileSwitchName = function profileSwitchName(name) { + var index = name.indexOf("@@@@@"); + if (index < 0) return name; + else return name.substring(0, index); + } + profile.tempBasalTreatment = function tempBasalTreatment (time) { // Most queries for the data in reporting will match the latest found value, caching that hugely improves performance diff --git a/lib/report_plugins/daytoday.js b/lib/report_plugins/daytoday.js index 69392d56e13..3f66a29de44 100644 --- a/lib/report_plugins/daytoday.js +++ b/lib/report_plugins/daytoday.js @@ -832,9 +832,9 @@ daytoday.report = function report_daytoday(datastorage,sorteddaystoshow,options) var sign = treatment.first ? '▲▲▲' : '▬▬▬'; var text; if (treatment.cutting) { - text = sign + ' ' + treatment.cutting + ' ' + '►►►' + ' ' + treatment.profile + ' ' + sign; + text = sign + ' ' + client.profilefunctions.profileSwitchName(treatment.cutting) + ' ' + '►►►' + ' ' + client.profilefunctions.profileSwitchName(treatment.profile) + ' ' + sign; } else { - text = sign + ' ' + treatment.profile + ' ' + sign; + text = sign + ' ' + client.profilefunctions.profileSwitchName(treatment.profile) + ' ' + sign; } context.append('text') .style('font-size', 12) From 3a7dc5854339a619d2fdbc47d9dadba72d6f4977 Mon Sep 17 00:00:00 2001 From: Nico Schmitz Date: Fri, 20 Oct 2017 17:40:46 +0200 Subject: [PATCH 21/51] Fix URLs of [mongostring] and [autoconfigure] --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cdb941efbf9..8d1d59e9543 100644 --- a/README.md +++ b/README.md @@ -121,8 +121,8 @@ The data being uploaded from the server to the client is from a MongoDB server such as [mongolab][mongodb]. [mongodb]: https://mongolab.com -[autoconfigure]: http://nightscout.github.io/pages/configure/ -[mongostring]: http://nightscout.github.io/pages/mongostring/ +[autoconfigure]: https://nightscout.github.io/pages/configure/ +[mongostring]: https://nightscout.github.io/pages/mongostring/ [update-fork]: http://nightscout.github.io/pages/update-fork/ ## Updating my version? From 62f352cdb9f27943c5da4d5dfb311bbb13cca7c8 Mon Sep 17 00:00:00 2001 From: PieterGit Date: Sat, 21 Oct 2017 14:30:00 +0200 Subject: [PATCH 22/51] update nodejs to 8.7.0 and npm update --- package-lock.json | 1706 +++++++++++++-------------------------------- package.json | 20 +- 2 files changed, 498 insertions(+), 1228 deletions(-) diff --git a/package-lock.json b/package-lock.json index 819ed2151e4..7f5027f68ea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -59,9 +59,9 @@ "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" }, "ajv": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.2.2.tgz", - "integrity": "sha1-R8aNaehvXZUxA7AHSpQw3GPaXjk=", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.2.3.tgz", + "integrity": "sha1-wG9Zh3jETGsWGrr+NGa4GtGBTtI=", "requires": { "co": "4.6.0", "fast-deep-equal": "1.0.0", @@ -369,34 +369,55 @@ "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" }, "body-parser": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.0.tgz", - "integrity": "sha1-07Ik1Gf6LOjUNYnAJFBDJnwJNjQ=", + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", + "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", "requires": { "bytes": "3.0.0", - "content-type": "1.0.2", - "debug": "2.6.8", + "content-type": "1.0.4", + "debug": "2.6.9", "depd": "1.1.1", "http-errors": "1.6.2", - "iconv-lite": "0.4.18", + "iconv-lite": "0.4.19", "on-finished": "2.3.0", - "qs": "6.5.0", - "raw-body": "2.3.1", + "qs": "6.5.1", + "raw-body": "2.3.2", "type-is": "1.6.15" }, "dependencies": { + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, "debug": { - "version": "2.6.8", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", - "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "requires": { "ms": "2.0.0" } }, + "iconv-lite": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" + }, "qs": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.0.tgz", - "integrity": "sha512-fjVFjW9yhqMhVGwRExCXLhJKrLlkYSaxNWdyc9rmHlrVZbk35YHH312dFd7191uQeXkI3mKLZTIbSvIeFwFemg==" + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" + }, + "raw-body": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", + "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.2", + "iconv-lite": "0.4.19", + "unpipe": "1.0.0" + } } } }, @@ -751,7 +772,6 @@ "requires": { "anymatch": "1.3.0", "async-each": "1.0.1", - "fsevents": "1.1.2", "glob-parent": "2.0.0", "inherits": "2.0.3", "is-binary-path": "1.0.1", @@ -944,31 +964,53 @@ } }, "compression": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.0.tgz", - "integrity": "sha1-AwyfGY8WQ6BX13anOOki2kNzAS0=", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.1.tgz", + "integrity": "sha1-7/JgPvwuIs+G810uuTWJ+YdTc9s=", "requires": { - "accepts": "1.3.3", - "bytes": "2.5.0", + "accepts": "1.3.4", + "bytes": "3.0.0", "compressible": "2.0.11", - "debug": "2.6.8", + "debug": "2.6.9", "on-headers": "1.0.1", "safe-buffer": "5.1.1", - "vary": "1.1.1" + "vary": "1.1.2" }, "dependencies": { - "bytes": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.5.0.tgz", - "integrity": "sha1-TJQj6i0lLCcMQbK97+/5u2tiwGo=" + "accepts": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz", + "integrity": "sha1-hiRnWMfdbSGmR0/whKR0DsBesh8=", + "requires": { + "mime-types": "2.1.17", + "negotiator": "0.6.1" + } }, "debug": { - "version": "2.6.8", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", - "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "requires": { "ms": "2.0.0" } + }, + "mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=" + }, + "mime-types": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", + "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "requires": { + "mime-db": "1.30.0" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" } } }, @@ -995,11 +1037,6 @@ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" }, - "content-type": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz", - "integrity": "sha1-t9ETrueo3Se9IRM8TcJSnfFyHu0=" - }, "content-type-parser": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/content-type-parser/-/content-type-parser-1.0.1.tgz", @@ -1673,11 +1710,6 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" }, - "etag": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.0.tgz", - "integrity": "sha1-b2Ma7zNtbEY2K1F2QETOIWvjwFE=" - }, "event-emitter": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", @@ -1699,13 +1731,6 @@ "split": "0.3.3", "stream-combiner": "0.0.4", "through": "2.3.8" - }, - "dependencies": { - "duplexer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", - "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=" - } } }, "eventemitter2": { @@ -1774,57 +1799,180 @@ "integrity": "sha1-NfvTZZeJ5PqoH1nei36fw55GbVE=" }, "express": { - "version": "4.15.4", - "resolved": "https://registry.npmjs.org/express/-/express-4.15.4.tgz", - "integrity": "sha1-Ay4iU0ic+PzgJma+yj0R7XotrtE=", + "version": "4.16.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.2.tgz", + "integrity": "sha1-41xt/i1kt9ygpc1PIXgb4ymeB2w=", "requires": { - "accepts": "1.3.3", + "accepts": "1.3.4", "array-flatten": "1.1.1", + "body-parser": "1.18.2", "content-disposition": "0.5.2", - "content-type": "1.0.2", + "content-type": "1.0.4", "cookie": "0.3.1", "cookie-signature": "1.0.6", - "debug": "2.6.8", + "debug": "2.6.9", "depd": "1.1.1", "encodeurl": "1.0.1", "escape-html": "1.0.3", - "etag": "1.8.0", - "finalhandler": "1.0.4", - "fresh": "0.5.0", + "etag": "1.8.1", + "finalhandler": "1.1.0", + "fresh": "0.5.2", "merge-descriptors": "1.0.1", "methods": "1.1.2", "on-finished": "2.3.0", - "parseurl": "1.3.1", + "parseurl": "1.3.2", "path-to-regexp": "0.1.7", - "proxy-addr": "1.1.5", - "qs": "6.5.0", + "proxy-addr": "2.0.2", + "qs": "6.5.1", "range-parser": "1.2.0", - "send": "0.15.4", - "serve-static": "1.12.4", - "setprototypeof": "1.0.3", + "safe-buffer": "5.1.1", + "send": "0.16.1", + "serve-static": "1.13.1", + "setprototypeof": "1.1.0", "statuses": "1.3.1", "type-is": "1.6.15", - "utils-merge": "1.0.0", - "vary": "1.1.1" + "utils-merge": "1.0.1", + "vary": "1.1.2" }, "dependencies": { + "accepts": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz", + "integrity": "sha1-hiRnWMfdbSGmR0/whKR0DsBesh8=", + "requires": { + "mime-types": "2.1.17", + "negotiator": "0.6.1" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, "debug": { - "version": "2.6.8", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", - "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "requires": { "ms": "2.0.0" } }, - "depd": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", - "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "finalhandler": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", + "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", + "requires": { + "debug": "2.6.9", + "encodeurl": "1.0.1", + "escape-html": "1.0.3", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "statuses": "1.3.1", + "unpipe": "1.0.0" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "ipaddr.js": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.5.2.tgz", + "integrity": "sha1-1LUFvemUaYfM8PxY2QEP+WB+P6A=" + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" + }, + "mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=" + }, + "mime-types": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", + "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "requires": { + "mime-db": "1.30.0" + } + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" + }, + "proxy-addr": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.2.tgz", + "integrity": "sha1-ZXFQT0e7mI7IGAJT+F3X4UlSvew=", + "requires": { + "forwarded": "0.1.2", + "ipaddr.js": "1.5.2" + } }, "qs": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.0.tgz", - "integrity": "sha512-fjVFjW9yhqMhVGwRExCXLhJKrLlkYSaxNWdyc9rmHlrVZbk35YHH312dFd7191uQeXkI3mKLZTIbSvIeFwFemg==" + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" + }, + "send": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.1.tgz", + "integrity": "sha512-ElCLJdJIKPk6ux/Hocwhk7NFHpI3pVm/IZOYWqUmoxcgeyM+MpxHHKhb8QmlJDX1pU6WrgaHBkVNm73Sv7uc2A==", + "requires": { + "debug": "2.6.9", + "depd": "1.1.1", + "destroy": "1.0.4", + "encodeurl": "1.0.1", + "escape-html": "1.0.3", + "etag": "1.8.1", + "fresh": "0.5.2", + "http-errors": "1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "2.3.0", + "range-parser": "1.2.0", + "statuses": "1.3.1" + } + }, + "serve-static": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.1.tgz", + "integrity": "sha512-hSMUZrsPa/I09VYFJwa627JJkNs0NrfL1Uzuup+GqHfToR2KcsXFymXSV90hoyw3M+msjFuQly+YzIH/q0MGlQ==", + "requires": { + "encodeurl": "1.0.1", + "escape-html": "1.0.3", + "parseurl": "1.3.2", + "send": "0.16.1" + } + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" } } }, @@ -1854,16 +2002,16 @@ }, "dependencies": { "source-map": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", - "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=" + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" }, "uglify-js": { "version": "2.8.29", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", "requires": { - "source-map": "0.5.6", + "source-map": "0.5.7", "uglify-to-browserify": "1.0.2", "yargs": "3.10.0" } @@ -1960,30 +2108,6 @@ } } }, - "finalhandler": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.4.tgz", - "integrity": "sha512-16l/r8RgzlXKmFOhZpHBztvye+lAhC5SU7hXavnerC9UfZqZxxXl3BzL8MhffPT3kF61lj9Oav2LKEzh0ei7tg==", - "requires": { - "debug": "2.6.8", - "encodeurl": "1.0.1", - "escape-html": "1.0.3", - "on-finished": "2.3.0", - "parseurl": "1.3.1", - "statuses": "1.3.1", - "unpipe": "1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.8", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", - "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", - "requires": { - "ms": "2.0.0" - } - } - } - }, "find-up": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", @@ -2013,911 +2137,116 @@ } } } - }, - "flatten": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz", - "integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=" - }, - "flot": { - "version": "0.8.0-alpha", - "resolved": "https://registry.npmjs.org/flot/-/flot-0.8.0-alpha.tgz", - "integrity": "sha1-nLvHFHwQpH0lSduQvSmH7BunhLo=" - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" - }, - "for-own": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", - "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", - "requires": { - "for-in": "1.0.2" - } - }, - "forever": { - "version": "0.15.3", - "resolved": "https://registry.npmjs.org/forever/-/forever-0.15.3.tgz", - "integrity": "sha1-d9nX4V/S9RGtnYShEMfdj8js68I=", - "requires": { - "cliff": "0.1.10", - "clone": "1.0.2", - "colors": "0.6.2", - "flatiron": "0.4.3", - "forever-monitor": "1.7.1", - "nconf": "0.6.9", - "nssocket": "0.5.3", - "object-assign": "3.0.0", - "optimist": "0.6.1", - "path-is-absolute": "1.0.1", - "prettyjson": "1.2.1", - "shush": "1.0.0", - "timespan": "2.3.0", - "utile": "0.2.1", - "winston": "0.8.3" - }, - "dependencies": { - "optimist": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", - "requires": { - "minimist": "0.0.10", - "wordwrap": "0.0.3" - } - } - } - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" - }, - "forever-monitor": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/forever-monitor/-/forever-monitor-1.7.1.tgz", - "integrity": "sha1-XYIPSjp42y2BriZx8Vi56GoJG7g=", - "requires": { - "broadway": "0.3.6", - "chokidar": "1.7.0", - "minimatch": "3.0.4", - "ps-tree": "0.0.3", - "utile": "0.2.1" - } - }, - "form-data": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.1.tgz", - "integrity": "sha1-rjFduaSQf6BlUCMEpm13M0de43w=", - "requires": { - "async": "2.5.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.15" - }, - "dependencies": { - "async": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/async/-/async-2.5.0.tgz", - "integrity": "sha512-e+lJAJeNWuPCNyxZKOBdaJGyLGHugXVQtrAwtuAe2vhxTYxFTKE73p8JuTmdH0qdQZtDvI4dhJwjZc5zsfIsYw==", - "requires": { - "lodash": "4.17.4" - } - } - } - }, - "formidable": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.1.1.tgz", - "integrity": "sha1-lriIb3w8NQi5Mta9cMTTqI818ak=", - "dev": true - }, - "forwarded": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.0.tgz", - "integrity": "sha1-Ge+YdMSuHCl7zweP3mOgm2aoQ2M=" - }, - "fresh": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.0.tgz", - "integrity": "sha1-9HTKXmqSRtb9jglTz6m5yAWvp44=" - }, - "from": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", - "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=" - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "fsevents": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.2.tgz", - "integrity": "sha512-Sn44E5wQW4bTHXvQmvSHwqbuiXtduD6Rrjm2ZtUEGbyrig+nUH3t/QD4M4/ZXViY556TBpRgZkHLDx3JxPwxiw==", - "optional": true, - "requires": { - "nan": "2.7.0", - "node-pre-gyp": "0.6.36" - }, - "dependencies": { - "abbrev": { - "version": "1.1.0", - "bundled": true, - "optional": true - }, - "ajv": { - "version": "4.11.8", - "bundled": true, - "optional": true, - "requires": { - "co": "4.6.0", - "json-stable-stringify": "1.0.1" - } - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true - }, - "aproba": { - "version": "1.1.1", - "bundled": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.4", - "bundled": true, - "optional": true, - "requires": { - "delegates": "1.0.0", - "readable-stream": "2.2.9" - } - }, - "asn1": { - "version": "0.2.3", - "bundled": true, - "optional": true - }, - "assert-plus": { - "version": "0.2.0", - "bundled": true, - "optional": true - }, - "asynckit": { - "version": "0.4.0", - "bundled": true, - "optional": true - }, - "aws-sign2": { - "version": "0.6.0", - "bundled": true, - "optional": true - }, - "aws4": { - "version": "1.6.0", - "bundled": true, - "optional": true - }, - "balanced-match": { - "version": "0.4.2", - "bundled": true - }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "bundled": true, - "optional": true, - "requires": { - "tweetnacl": "0.14.5" - } - }, - "block-stream": { - "version": "0.0.9", - "bundled": true, - "requires": { - "inherits": "2.0.3" - } - }, - "boom": { - "version": "2.10.1", - "bundled": true, - "requires": { - "hoek": "2.16.3" - } - }, - "brace-expansion": { - "version": "1.1.7", - "bundled": true, - "requires": { - "balanced-match": "0.4.2", - "concat-map": "0.0.1" - } - }, - "buffer-shims": { - "version": "1.0.0", - "bundled": true - }, - "caseless": { - "version": "0.12.0", - "bundled": true, - "optional": true - }, - "co": { - "version": "4.6.0", - "bundled": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true - }, - "combined-stream": { - "version": "1.0.5", - "bundled": true, - "requires": { - "delayed-stream": "1.0.0" - } - }, - "concat-map": { - "version": "0.0.1", - "bundled": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true - }, - "cryptiles": { - "version": "2.0.5", - "bundled": true, - "optional": true, - "requires": { - "boom": "2.10.1" - } - }, - "dashdash": { - "version": "1.14.1", - "bundled": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "optional": true - } - } - }, - "debug": { - "version": "2.6.8", - "bundled": true, - "optional": true, - "requires": { - "ms": "2.0.0" - } - }, - "deep-extend": { - "version": "0.4.2", - "bundled": true, - "optional": true - }, - "delayed-stream": { - "version": "1.0.0", - "bundled": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "ecc-jsbn": { - "version": "0.1.1", - "bundled": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "extend": { - "version": "3.0.1", - "bundled": true, - "optional": true - }, - "extsprintf": { - "version": "1.0.2", - "bundled": true - }, - "forever-agent": { - "version": "0.6.1", - "bundled": true, - "optional": true - }, - "form-data": { - "version": "2.1.4", - "bundled": true, - "optional": true, - "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.15" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true - }, - "fstream": { - "version": "1.0.11", - "bundled": true, - "requires": { - "graceful-fs": "4.1.11", - "inherits": "2.0.3", - "mkdirp": "0.5.1", - "rimraf": "2.6.1" - } - }, - "fstream-ignore": { - "version": "1.0.5", - "bundled": true, - "optional": true, - "requires": { - "fstream": "1.0.11", - "inherits": "2.0.3", - "minimatch": "3.0.4" - } - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "optional": true, - "requires": { - "aproba": "1.1.1", - "console-control-strings": "1.1.0", - "has-unicode": "2.0.1", - "object-assign": "4.1.1", - "signal-exit": "3.0.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wide-align": "1.1.2" - } - }, - "getpass": { - "version": "0.1.7", - "bundled": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "optional": true - } - } - }, - "glob": { - "version": "7.1.2", - "bundled": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "graceful-fs": { - "version": "4.1.11", - "bundled": true - }, - "har-schema": { - "version": "1.0.5", - "bundled": true, - "optional": true - }, - "har-validator": { - "version": "4.2.1", - "bundled": true, - "optional": true, - "requires": { - "ajv": "4.11.8", - "har-schema": "1.0.5" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "optional": true - }, - "hawk": { - "version": "3.1.3", - "bundled": true, - "optional": true, - "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" - } - }, - "hoek": { - "version": "2.16.3", - "bundled": true - }, - "http-signature": { - "version": "1.1.1", - "bundled": true, - "optional": true, - "requires": { - "assert-plus": "0.2.0", - "jsprim": "1.4.0", - "sshpk": "1.13.0" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true - }, - "ini": { - "version": "1.3.4", - "bundled": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "requires": { - "number-is-nan": "1.0.1" - } - }, - "is-typedarray": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true - }, - "isstream": { - "version": "0.1.2", - "bundled": true, - "optional": true - }, - "jodid25519": { - "version": "1.0.2", - "bundled": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "jsbn": { - "version": "0.1.1", - "bundled": true, - "optional": true - }, - "json-schema": { - "version": "0.2.3", - "bundled": true, - "optional": true - }, - "json-stable-stringify": { - "version": "1.0.1", - "bundled": true, - "optional": true, - "requires": { - "jsonify": "0.0.0" - } - }, - "json-stringify-safe": { - "version": "5.0.1", - "bundled": true, - "optional": true - }, - "jsonify": { - "version": "0.0.0", - "bundled": true, - "optional": true - }, - "jsprim": { - "version": "1.4.0", - "bundled": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.0.2", - "json-schema": "0.2.3", - "verror": "1.3.6" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "optional": true - } - } - }, - "mime-db": { - "version": "1.27.0", - "bundled": true - }, - "mime-types": { - "version": "2.1.15", - "bundled": true, - "requires": { - "mime-db": "1.27.0" - } - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "requires": { - "brace-expansion": "1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "bundled": true, - "optional": true - }, - "node-pre-gyp": { - "version": "0.6.36", - "bundled": true, - "optional": true, - "requires": { - "mkdirp": "0.5.1", - "nopt": "4.0.1", - "npmlog": "4.1.0", - "rc": "1.2.1", - "request": "2.81.0", - "rimraf": "2.6.1", - "semver": "5.3.0", - "tar": "2.2.1", - "tar-pack": "3.4.0" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "optional": true, - "requires": { - "abbrev": "1.1.0", - "osenv": "0.1.4" - } - }, - "npmlog": { - "version": "4.1.0", - "bundled": true, - "optional": true, - "requires": { - "are-we-there-yet": "1.1.4", - "console-control-strings": "1.1.0", - "gauge": "2.7.4", - "set-blocking": "2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true - }, - "oauth-sign": { - "version": "0.8.2", - "bundled": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "osenv": { - "version": "0.1.4", - "bundled": true, - "optional": true, - "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true - }, - "performance-now": { - "version": "0.2.0", - "bundled": true, - "optional": true - }, - "process-nextick-args": { - "version": "1.0.7", - "bundled": true - }, - "punycode": { - "version": "1.4.1", - "bundled": true, - "optional": true - }, - "qs": { - "version": "6.4.0", - "bundled": true, - "optional": true - }, - "rc": { - "version": "1.2.1", - "bundled": true, - "optional": true, - "requires": { - "deep-extend": "0.4.2", - "ini": "1.3.4", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.2.9", - "bundled": true, - "requires": { - "buffer-shims": "1.0.0", - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "string_decoder": "1.0.1", - "util-deprecate": "1.0.2" - } - }, - "request": { - "version": "2.81.0", - "bundled": true, - "optional": true, - "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.6.0", - "caseless": "0.12.0", - "combined-stream": "1.0.5", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.1.4", - "har-validator": "4.2.1", - "hawk": "3.1.3", - "http-signature": "1.1.1", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.15", - "oauth-sign": "0.8.2", - "performance-now": "0.2.0", - "qs": "6.4.0", - "safe-buffer": "5.0.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.2", - "tunnel-agent": "0.6.0", - "uuid": "3.0.1" - } - }, - "rimraf": { - "version": "2.6.1", - "bundled": true, - "requires": { - "glob": "7.1.2" - } - }, - "safe-buffer": { - "version": "5.0.1", - "bundled": true - }, - "semver": { - "version": "5.3.0", - "bundled": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "optional": true - }, - "sntp": { - "version": "1.0.9", - "bundled": true, - "optional": true, - "requires": { - "hoek": "2.16.3" - } - }, - "sshpk": { - "version": "1.13.0", - "bundled": true, - "optional": true, - "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.1", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.7", - "jodid25519": "1.0.2", - "jsbn": "0.1.1", - "tweetnacl": "0.14.5" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "optional": true - } - } - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - } - }, - "string_decoder": { - "version": "1.0.1", - "bundled": true, - "requires": { - "safe-buffer": "5.0.1" - } - }, - "stringstream": { - "version": "0.0.5", - "bundled": true, - "optional": true - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "optional": true - }, - "tar": { - "version": "2.2.1", - "bundled": true, - "requires": { - "block-stream": "0.0.9", - "fstream": "1.0.11", - "inherits": "2.0.3" - } - }, - "tar-pack": { - "version": "3.4.0", - "bundled": true, - "optional": true, - "requires": { - "debug": "2.6.8", - "fstream": "1.0.11", - "fstream-ignore": "1.0.5", - "once": "1.4.0", - "readable-stream": "2.2.9", - "rimraf": "2.6.1", - "tar": "2.2.1", - "uid-number": "0.0.6" - } - }, - "tough-cookie": { - "version": "2.3.2", - "bundled": true, - "optional": true, - "requires": { - "punycode": "1.4.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "bundled": true, - "optional": true, - "requires": { - "safe-buffer": "5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "bundled": true, - "optional": true - }, - "uid-number": { - "version": "0.0.6", - "bundled": true, - "optional": true - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true - }, - "uuid": { - "version": "3.0.1", - "bundled": true, - "optional": true - }, - "verror": { - "version": "1.3.6", - "bundled": true, - "optional": true, + }, + "flatten": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz", + "integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=" + }, + "flot": { + "version": "0.8.0-alpha", + "resolved": "https://registry.npmjs.org/flot/-/flot-0.8.0-alpha.tgz", + "integrity": "sha1-nLvHFHwQpH0lSduQvSmH7BunhLo=" + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "requires": { + "for-in": "1.0.2" + } + }, + "forever": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/forever/-/forever-0.15.3.tgz", + "integrity": "sha1-d9nX4V/S9RGtnYShEMfdj8js68I=", + "requires": { + "cliff": "0.1.10", + "clone": "1.0.2", + "colors": "0.6.2", + "flatiron": "0.4.3", + "forever-monitor": "1.7.1", + "nconf": "0.6.9", + "nssocket": "0.5.3", + "object-assign": "3.0.0", + "optimist": "0.6.1", + "path-is-absolute": "1.0.1", + "prettyjson": "1.2.1", + "shush": "1.0.0", + "timespan": "2.3.0", + "utile": "0.2.1", + "winston": "0.8.3" + }, + "dependencies": { + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", "requires": { - "extsprintf": "1.0.2" + "minimist": "0.0.10", + "wordwrap": "0.0.3" } - }, - "wide-align": { - "version": "1.1.2", - "bundled": true, - "optional": true, + } + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "forever-monitor": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/forever-monitor/-/forever-monitor-1.7.1.tgz", + "integrity": "sha1-XYIPSjp42y2BriZx8Vi56GoJG7g=", + "requires": { + "broadway": "0.3.6", + "chokidar": "1.7.0", + "minimatch": "3.0.4", + "ps-tree": "0.0.3", + "utile": "0.2.1" + } + }, + "form-data": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.1.tgz", + "integrity": "sha1-rjFduaSQf6BlUCMEpm13M0de43w=", + "requires": { + "async": "2.5.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.15" + }, + "dependencies": { + "async": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/async/-/async-2.5.0.tgz", + "integrity": "sha512-e+lJAJeNWuPCNyxZKOBdaJGyLGHugXVQtrAwtuAe2vhxTYxFTKE73p8JuTmdH0qdQZtDvI4dhJwjZc5zsfIsYw==", "requires": { - "string-width": "1.0.2" + "lodash": "4.17.4" } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true } } }, + "formidable": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.1.1.tgz", + "integrity": "sha1-lriIb3w8NQi5Mta9cMTTqI818ak=", + "dev": true + }, + "from": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", + "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -3028,7 +2357,6 @@ "integrity": "sha1-PTDHGLCaPZbyPqTMH0A8TTup/08=", "dev": true, "requires": { - "async": "0.9.2", "optimist": "0.5.2", "source-map": "0.1.43", "uglify-js": "2.8.29" @@ -3070,11 +2398,6 @@ } } }, - "har-schema": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", - "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=" - }, "har-validator": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-1.8.0.tgz", @@ -3220,11 +2543,6 @@ "resolved": "https://registry.npmjs.org/i/-/i-0.3.5.tgz", "integrity": "sha1-HSuFQVjsgWkRPGy39raAHpniEdU=" }, - "iconv-lite": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.18.tgz", - "integrity": "sha512-sr1ZQph3UwHTR0XftSbK85OvBbxe/abLGzEnPENCQwmHf7sck8Oyu4ob3LgBxWWxRoM+QszeUyl7jbqapu2TqA==" - }, "icss-replace-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", @@ -3330,11 +2648,6 @@ "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" }, - "ipaddr.js": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.4.0.tgz", - "integrity": "sha1-KWrKh4qCGBbluF0KKFqZvP9FgvA=" - }, "is-absolute-url": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", @@ -3494,7 +2807,6 @@ "dev": true, "requires": { "abbrev": "1.0.9", - "async": "0.9.2", "escodegen": "0.0.15", "esprima": "1.0.2", "glob": "7.1.2", @@ -3516,7 +2828,7 @@ "requires": { "hoek": "2.16.3", "isemail": "1.2.0", - "moment": "2.18.1", + "moment": "2.19.1", "topo": "1.1.0" } }, @@ -3587,7 +2899,7 @@ "nwmatcher": "1.4.1", "parse5": "3.0.2", "pn": "1.0.0", - "request": "2.81.0", + "request": "2.83.0", "request-promise-native": "1.0.4", "sax": "1.2.4", "symbol-tree": "3.2.2", @@ -4005,7 +3317,8 @@ "mime": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz", - "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM=" + "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM=", + "dev": true }, "mime-db": { "version": "1.27.0", @@ -4129,28 +3442,37 @@ } }, "moment": { - "version": "2.18.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.18.1.tgz", - "integrity": "sha1-w2GT3Tzhwu7SrbfIAtu8d6gbHA8=" + "version": "2.19.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.19.1.tgz", + "integrity": "sha1-VtoaLRy/AdOLfhr8McELz6GSkWc=" }, "moment-timezone": { "version": "0.5.13", "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.13.tgz", "integrity": "sha1-mc5cfYJyYusPH3AgRBd/YHRde5A=", "requires": { - "moment": "2.18.1" + "moment": "2.19.1" } }, "mongodb": { - "version": "2.2.31", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-2.2.31.tgz", - "integrity": "sha1-GUBEXGYeGSF7s7+CRdmFSq71SNs=", + "version": "2.2.33", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-2.2.33.tgz", + "integrity": "sha1-tTfEcdNKZlG0jzb9vyl1A0Dgi1A=", "requires": { "es6-promise": "3.2.1", - "mongodb-core": "2.1.15", + "mongodb-core": "2.1.17", "readable-stream": "2.2.7" }, "dependencies": { + "mongodb-core": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-2.1.17.tgz", + "integrity": "sha1-pBizN6FKFJkPtRC5I97mqBMXPfg=", + "requires": { + "bson": "1.0.4", + "require_optional": "1.0.1" + } + }, "readable-stream": { "version": "2.2.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.7.tgz", @@ -4167,15 +3489,6 @@ } } }, - "mongodb-core": { - "version": "2.1.15", - "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-2.1.15.tgz", - "integrity": "sha1-hB9TuH//9MdFgYnDXIroJ+EWl2Q=", - "requires": { - "bson": "1.0.4", - "require_optional": "1.0.1" - } - }, "mongomock": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/mongomock/-/mongomock-0.1.2.tgz", @@ -4225,12 +3538,6 @@ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" }, - "nan": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.7.0.tgz", - "integrity": "sha1-2Vv3IeyHfgjbJ27T/G63j5CDrUY=", - "optional": true - }, "nconf": { "version": "0.6.9", "resolved": "https://registry.npmjs.org/nconf/-/nconf-0.6.9.tgz", @@ -4586,11 +3893,6 @@ "better-assert": "1.0.2" } }, - "parseurl": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.1.tgz", - "integrity": "sha1-yKuMkiO6NIiKpkopeyiFO+wY2lY=" - }, "path": { "version": "0.12.7", "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", @@ -4653,11 +3955,6 @@ "sha.js": "2.4.8" } }, - "performance-now": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", - "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=" - }, "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", @@ -5252,15 +4549,6 @@ "bytebuffer": "3.1.1" } }, - "proxy-addr": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.5.tgz", - "integrity": "sha1-ccDuOxAt4/IC87ZPYI0XP8uhqRg=", - "requires": { - "forwarded": "0.1.0", - "ipaddr.js": "1.4.0" - } - }, "prr": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/prr/-/prr-0.0.0.tgz", @@ -5327,7 +4615,8 @@ "qs": { "version": "6.4.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", - "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=" + "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=", + "dev": true }, "query-string": { "version": "4.3.4", @@ -5410,17 +4699,6 @@ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" }, - "raw-body": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.1.tgz", - "integrity": "sha512-sxkd1uqaSj41SG5Vet9sNAxBMCMsmZ3LVhRkDlK8SbCpelTUB7JiMGHG70AZS6cFiCRgfNQhU2eLnTHYRFf7LA==", - "requires": { - "bytes": "3.0.0", - "http-errors": "1.6.2", - "iconv-lite": "0.4.18", - "unpipe": "1.0.0" - } - }, "read": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", @@ -5558,89 +4836,164 @@ "integrity": "sha1-x6jTI2BoNiBZp+RlH8aITosftK4=" }, "request": { - "version": "2.81.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", - "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", + "version": "2.83.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", + "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==", "requires": { - "aws-sign2": "0.6.0", + "aws-sign2": "0.7.0", "aws4": "1.6.0", "caseless": "0.12.0", "combined-stream": "1.0.5", "extend": "3.0.1", "forever-agent": "0.6.1", - "form-data": "2.1.4", - "har-validator": "4.2.1", - "hawk": "3.1.3", - "http-signature": "1.1.1", + "form-data": "2.3.1", + "har-validator": "5.0.3", + "hawk": "6.0.2", + "http-signature": "1.2.0", "is-typedarray": "1.0.0", "isstream": "0.1.2", "json-stringify-safe": "5.0.1", - "mime-types": "2.1.15", + "mime-types": "2.1.17", "oauth-sign": "0.8.2", - "performance-now": "0.2.0", - "qs": "6.4.0", + "performance-now": "2.1.0", + "qs": "6.5.1", "safe-buffer": "5.1.1", "stringstream": "0.0.5", - "tough-cookie": "2.3.2", + "tough-cookie": "2.3.3", "tunnel-agent": "0.6.0", "uuid": "3.1.0" }, "dependencies": { "assert-plus": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", - "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, "aws-sign2": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", - "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=" + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "boom": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", + "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", + "requires": { + "hoek": "4.2.0" + } }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, + "cryptiles": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", + "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", + "requires": { + "boom": "5.2.0" + }, + "dependencies": { + "boom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", + "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", + "requires": { + "hoek": "4.2.0" + } + } + } + }, "form-data": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", - "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", + "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", "requires": { "asynckit": "0.4.0", "combined-stream": "1.0.5", - "mime-types": "2.1.15" + "mime-types": "2.1.17" } }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, "har-validator": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", - "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", "requires": { - "ajv": "4.11.8", - "har-schema": "1.0.5" - }, - "dependencies": { - "ajv": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", - "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", - "requires": { - "co": "4.6.0", - "json-stable-stringify": "1.0.1" - } - } + "ajv": "5.2.3", + "har-schema": "2.0.0" + } + }, + "hawk": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", + "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", + "requires": { + "boom": "4.3.1", + "cryptiles": "3.1.2", + "hoek": "4.2.0", + "sntp": "2.0.2" } }, + "hoek": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz", + "integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ==" + }, "http-signature": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", - "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "requires": { - "assert-plus": "0.2.0", + "assert-plus": "1.0.0", "jsprim": "1.4.0", "sshpk": "1.13.1" } }, + "mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=" + }, + "mime-types": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", + "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "requires": { + "mime-db": "1.30.0" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" + }, + "sntp": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.0.2.tgz", + "integrity": "sha1-UGQRDwr4X3z9t9a2ekACjOUrSys=", + "requires": { + "hoek": "4.2.0" + } + }, + "tough-cookie": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", + "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", + "requires": { + "punycode": "1.4.1" + } + }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -5648,11 +5001,6 @@ "requires": { "safe-buffer": "5.1.1" } - }, - "uuid": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", - "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==" } } }, @@ -5786,63 +5134,6 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==" }, - "send": { - "version": "0.15.4", - "resolved": "https://registry.npmjs.org/send/-/send-0.15.4.tgz", - "integrity": "sha1-mF+qPihLAnPHkzZKNcZze9k5Bbk=", - "requires": { - "debug": "2.6.8", - "depd": "1.1.1", - "destroy": "1.0.4", - "encodeurl": "1.0.1", - "escape-html": "1.0.3", - "etag": "1.8.0", - "fresh": "0.5.0", - "http-errors": "1.6.2", - "mime": "1.3.4", - "ms": "2.0.0", - "on-finished": "2.3.0", - "range-parser": "1.2.0", - "statuses": "1.3.1" - }, - "dependencies": { - "debug": { - "version": "2.6.8", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", - "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", - "requires": { - "ms": "2.0.0" - } - }, - "depd": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", - "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" - }, - "http-errors": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", - "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", - "requires": { - "depd": "1.1.1", - "inherits": "2.0.3", - "setprototypeof": "1.0.3", - "statuses": "1.3.1" - } - } - } - }, - "serve-static": { - "version": "1.12.4", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.12.4.tgz", - "integrity": "sha1-m2qpjutyU8Tu3Ewfb9vKYJkBqWE=", - "requires": { - "encodeurl": "1.0.1", - "escape-html": "1.0.3", - "parseurl": "1.3.1", - "send": "0.15.4" - } - }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -6673,18 +5964,18 @@ } }, "uglify-js": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.1.0.tgz", - "integrity": "sha512-PGUXuTJ5AkrfPsyg0L9/LD+BWYm9feVngbWpW5bg7Q3B7hqDM3xz00tNby4yY0CqjrLTF6CP9wpb/aNITRuSXg==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.1.4.tgz", + "integrity": "sha512-DcbkPg11Lw2lAWpwCmQDX+qoR4JiII6ypsQmF6tscZtlxGPFAmSRUGuMoVT3/0EHqypVik/TpkH4ITiMJeQqQA==", "requires": { "commander": "2.11.0", - "source-map": "0.5.7" + "source-map": "0.6.1" }, "dependencies": { "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" } } }, @@ -6816,11 +6107,6 @@ } } }, - "utils-merge": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz", - "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg=" - }, "uuid": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", @@ -6835,11 +6121,6 @@ "spdx-expression-parse": "1.0.4" } }, - "vary": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.1.tgz", - "integrity": "sha1-Z1Neu2lMHVIldFeYRmUyP1h+jTc=" - }, "vendors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.1.tgz", @@ -6888,13 +6169,13 @@ "dev": true }, "webpack": { - "version": "3.5.6", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.5.6.tgz", - "integrity": "sha512-sXnxfx6KoZVrFAGLjdhCCwDtDwkYMfwm8mJjkQv3thr5pjTlbxopVlr/kJwc9Bz317gL+gNjvz++ir9TgG1MDg==", + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.8.1.tgz", + "integrity": "sha512-5ZXLWWsMqHKFr5y0N3Eo5IIisxeEeRAajNq4mELb/WELOR7srdbQk2N5XiyNy2A/AgvlR3AmeBCZJW8lHrolbw==", "requires": { "acorn": "5.1.2", "acorn-dynamic-import": "2.0.2", - "ajv": "5.2.2", + "ajv": "5.2.3", "ajv-keywords": "2.1.0", "async": "2.5.0", "enhanced-resolve": "3.4.1", @@ -6908,7 +6189,7 @@ "mkdirp": "0.5.1", "node-libs-browser": "2.0.0", "source-map": "0.5.7", - "supports-color": "4.4.0", + "supports-color": "4.5.0", "tapable": "0.2.8", "uglifyjs-webpack-plugin": "0.4.6", "watchpack": "1.4.0", @@ -6921,21 +6202,10 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.1.2.tgz", "integrity": "sha512-o96FZLJBPY1lvTuJylGA9Bk3t/GKPPJG8H0ydQQl01crzwJgspa4AEIq/pVTXigmK0PHVQhiAtn8WMBLL9D2WA==" }, - "ajv": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.2.2.tgz", - "integrity": "sha1-R8aNaehvXZUxA7AHSpQw3GPaXjk=", - "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.0.0", - "json-schema-traverse": "0.3.1", - "json-stable-stringify": "1.0.1" - } - }, "async": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/async/-/async-2.5.0.tgz", - "integrity": "sha1-hDGQ/WtzV6C54clW7d3V7IRitU0=", + "integrity": "sha512-e+lJAJeNWuPCNyxZKOBdaJGyLGHugXVQtrAwtuAe2vhxTYxFTKE73p8JuTmdH0qdQZtDvI4dhJwjZc5zsfIsYw==", "requires": { "lodash": "4.17.4" } @@ -6951,9 +6221,9 @@ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" }, "supports-color": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", - "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", "requires": { "has-flag": "2.0.0" } @@ -6970,7 +6240,7 @@ "chalk": "1.1.3", "commander": "2.11.0", "ejs": "2.5.7", - "express": "4.15.4", + "express": "4.16.2", "filesize": "3.5.10", "gzip-size": "3.0.0", "lodash": "4.17.4", diff --git a/package.json b/package.json index 8e693af40a6..dcd0059e271 100644 --- a/package.json +++ b/package.json @@ -47,14 +47,14 @@ } }, "engines": { - "node": "8.5.0" + "node": "8.7.0" }, "dependencies": { - "ajv": "^5.2.2", + "ajv": "^5.2.3", "async": "^0.9.2", - "body-parser": "^1.18.0", + "body-parser": "^1.18.2", "bootevent": "0.0.1", - "compression": "^1.7.0", + "compression": "^1.7.1", "css-loader": "^0.28.7", "cssmin": "^0.4.3", "d3": "^3.5.17", @@ -63,7 +63,7 @@ "event-stream": "^3.3.4", "expand-braces": "^0.1.2", "expose-loader": "^0.7.3", - "express": "^4.15.4", + "express": "^4.16.2", "express-extension-to-accept": "0.0.2", "express-minify": "^0.2.0", "file-loader": "^0.11.2", @@ -79,9 +79,9 @@ "long": "^3.2.0", "mfb": "^0.12.0", "minimed-connect-to-nightscout": "git://github.com/mddub/minimed-connect-to-nightscout.git#v1.1.0", - "moment": "^2.18.1", + "moment": "^2.19.1", "moment-timezone": "^0.5.13", - "mongodb": "^2.2.31", + "mongodb": "^2.2.33", "mongomock": "^0.1.2", "mqtt": "^0.3.13", "node-cache": "^4.1.1", @@ -90,7 +90,7 @@ "prettyjson": "^1.2.1", "pushover-notifications": "^0.2.4", "random-token": "0.0.8", - "request": "^2.81.0", + "request": "^2.83.0", "sgvdata": "git://github.com/ktind/sgvdata.git#wip/protobuf", "share2nightscout-bridge": "git://github.com/bewest/share2nightscout-bridge.git#wip/generalize", "shiro-trie": "^0.3.13", @@ -100,9 +100,9 @@ "sugar": "^1.5.0", "sync-exec": "^0.6.2", "traverse": "^0.6.6", - "uglify-js": "^3.1.0", + "uglify-js": "^3.1.4", "uuid": "^3.1.0", - "webpack": "^3.5.6" + "webpack": "^3.8.1" }, "devDependencies": { "benv": "3.3.0", From 3995a2630eba0c3d4afc8181efebf7501e84b11e Mon Sep 17 00:00:00 2001 From: MilosKozak Date: Sat, 21 Oct 2017 16:17:10 +0200 Subject: [PATCH 23/51] do not upload temporary profiles from store --- lib/data/ddata.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/data/ddata.js b/lib/data/ddata.js index 98d85b31c4f..49f874cb2d1 100644 --- a/lib/data/ddata.js +++ b/lib/data/ddata.js @@ -64,7 +64,17 @@ function init( ) { result.first.sgvs = ddata.sgvs.filter(filterMax); result.first.cals = ddata.cals; - result.first.profiles = ddata.profiles; + + var profiles = _.cloneDeep(ddata.profiles); + if (profiles && profiles[0]) + for (var k in profiles[0].store) { + if (profiles[0].store.hasOwnProperty(k)) { + if (k.indexOf('@@@@@') > 0) { + delete profiles[0].store[k]; + } + } + } + result.first.profiles = profiles; result.rest.mbgs = ddata.mbgs.filter(filterMax); result.rest.food = ddata.food; From 64913d3e9207450dae2a7191f94acd92bcca2c21 Mon Sep 17 00:00:00 2001 From: PieterGit Date: Sun, 22 Oct 2017 01:08:58 +0200 Subject: [PATCH 24/51] also update nodjes used by travis from 8.5.0 to 8.7.0 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c4e348952a8..816b17d26c9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: node_js sudo: required node_js: - - "8.5.0" + - "8.7.0" matrix: fast_finish: true services: From 2b5c66045f94e615ddee477803bad9fee555d5b5 Mon Sep 17 00:00:00 2001 From: PieterGit Date: Sun, 22 Oct 2017 01:38:04 +0200 Subject: [PATCH 25/51] Increase timeout for careportal.test.js and pluginbase.test from 25 to 30 sec., just to be sure. I seem to work once with Node 8.7.0, but the test did a timeout once on Node 8.5.0 on Travis. --- tests/careportal.test.js | 2 +- tests/pluginbase.test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/careportal.test.js b/tests/careportal.test.js index 80d99041c6d..782bc4fa566 100644 --- a/tests/careportal.test.js +++ b/tests/careportal.test.js @@ -13,7 +13,7 @@ var nowData = { }; describe('client', function ( ) { - this.timeout(25000); // TODO: see why this test takes longer on Travis to complete + this.timeout(30000); // TODO: see why this test takes longer on Travis to complete var self = this; diff --git a/tests/pluginbase.test.js b/tests/pluginbase.test.js index d9f44e36dd5..0b0b1ba76d4 100644 --- a/tests/pluginbase.test.js +++ b/tests/pluginbase.test.js @@ -4,7 +4,7 @@ require('should'); var benv = require('benv'); describe('pluginbase', function ( ) { - this.timeout(25000); // TODO: see why this test takes longer on Travis to complete + this.timeout(30000); // TODO: see why this test takes longer on Travis to complete var headless = require('./fixtures/headless')(benv, this); From c0388ab9dab6652b0b3044c21a26d0fc11b526b7 Mon Sep 17 00:00:00 2001 From: PieterGit Date: Sun, 22 Oct 2017 01:51:07 +0200 Subject: [PATCH 26/51] increase timeout of admintools.test.js from 25 to 30 seconds --- tests/admintools.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/admintools.test.js b/tests/admintools.test.js index 3419c4531ed..f1851010bb1 100644 --- a/tests/admintools.test.js +++ b/tests/admintools.test.js @@ -57,7 +57,7 @@ var someData = { describe('admintools', function ( ) { var self = this; - this.timeout(25000); // TODO: see why this test takes longer on Travis to complete + this.timeout(30000); // TODO: see why this test takes longer on Travis to complete before(function (done) { benv.setup(function() { From cbee7f2a4845935b5a361c8698f9896fb79dfde8 Mon Sep 17 00:00:00 2001 From: PieterGit Date: Sun, 22 Oct 2017 02:01:10 +0200 Subject: [PATCH 27/51] pluginbase.test.js fails with 30 sec. upping to 40 sec timeout ``` not ok 188 pluginbase "before each" hook for "does stuff" Error: timeout of 30000ms exceeded. Ensure the done() callback is being called in this test. ``` --- tests/pluginbase.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/pluginbase.test.js b/tests/pluginbase.test.js index 0b0b1ba76d4..d80a328648e 100644 --- a/tests/pluginbase.test.js +++ b/tests/pluginbase.test.js @@ -4,7 +4,7 @@ require('should'); var benv = require('benv'); describe('pluginbase', function ( ) { - this.timeout(30000); // TODO: see why this test takes longer on Travis to complete + this.timeout(40000); // TODO: see why this test takes longer on Travis to complete var headless = require('./fixtures/headless')(benv, this); From f51a24f0d0b52280aa058544657d41b259f28662 Mon Sep 17 00:00:00 2001 From: PieterGit Date: Wed, 25 Oct 2017 08:00:22 +0200 Subject: [PATCH 28/51] update to nodejs 8.8.0 and npm update --- .travis.yml | 2 +- package-lock.json | 323 ++++++++++++++++++++++++---------------------- package.json | 6 +- 3 files changed, 173 insertions(+), 158 deletions(-) diff --git a/.travis.yml b/.travis.yml index 816b17d26c9..741a44fe006 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: node_js sudo: required node_js: - - "8.7.0" + - "8.8.0" matrix: fast_finish: true services: diff --git a/package-lock.json b/package-lock.json index 7f5027f68ea..8d5d2826986 100644 --- a/package-lock.json +++ b/package-lock.json @@ -59,14 +59,14 @@ "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" }, "ajv": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.2.3.tgz", - "integrity": "sha1-wG9Zh3jETGsWGrr+NGa4GtGBTtI=", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.3.0.tgz", + "integrity": "sha1-RBT/dKUIecII7l/cgm4ywwNUnto=", "requires": { "co": "4.6.0", "fast-deep-equal": "1.0.0", - "json-schema-traverse": "0.3.1", - "json-stable-stringify": "1.0.1" + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" } }, "ajv-keywords": { @@ -385,11 +385,6 @@ "type-is": "1.6.15" }, "dependencies": { - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" - }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -398,26 +393,10 @@ "ms": "2.0.0" } }, - "iconv-lite": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", - "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" - }, "qs": { "version": "6.5.1", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" - }, - "raw-body": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", - "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", - "requires": { - "bytes": "3.0.0", - "http-errors": "1.6.2", - "iconv-lite": "0.4.19", - "unpipe": "1.0.0" - } } } }, @@ -1006,11 +985,6 @@ "requires": { "mime-db": "1.30.0" } - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" } } }, @@ -1037,6 +1011,11 @@ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, "content-type-parser": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/content-type-parser/-/content-type-parser-1.0.1.tgz", @@ -1710,6 +1689,11 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, "event-emitter": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", @@ -1844,11 +1828,6 @@ "negotiator": "0.6.1" } }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" - }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -1857,45 +1836,6 @@ "ms": "2.0.0" } }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" - }, - "finalhandler": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", - "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", - "requires": { - "debug": "2.6.9", - "encodeurl": "1.0.1", - "escape-html": "1.0.3", - "on-finished": "2.3.0", - "parseurl": "1.3.2", - "statuses": "1.3.1", - "unpipe": "1.0.0" - } - }, - "forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" - }, - "ipaddr.js": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.5.2.tgz", - "integrity": "sha1-1LUFvemUaYfM8PxY2QEP+WB+P6A=" - }, - "mime": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", - "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" - }, "mime-db": { "version": "1.30.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", @@ -1909,70 +1849,15 @@ "mime-db": "1.30.0" } }, - "parseurl": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", - "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" - }, - "proxy-addr": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.2.tgz", - "integrity": "sha1-ZXFQT0e7mI7IGAJT+F3X4UlSvew=", - "requires": { - "forwarded": "0.1.2", - "ipaddr.js": "1.5.2" - } - }, "qs": { "version": "6.5.1", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" }, - "send": { - "version": "0.16.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.16.1.tgz", - "integrity": "sha512-ElCLJdJIKPk6ux/Hocwhk7NFHpI3pVm/IZOYWqUmoxcgeyM+MpxHHKhb8QmlJDX1pU6WrgaHBkVNm73Sv7uc2A==", - "requires": { - "debug": "2.6.9", - "depd": "1.1.1", - "destroy": "1.0.4", - "encodeurl": "1.0.1", - "escape-html": "1.0.3", - "etag": "1.8.1", - "fresh": "0.5.2", - "http-errors": "1.6.2", - "mime": "1.4.1", - "ms": "2.0.0", - "on-finished": "2.3.0", - "range-parser": "1.2.0", - "statuses": "1.3.1" - } - }, - "serve-static": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.1.tgz", - "integrity": "sha512-hSMUZrsPa/I09VYFJwa627JJkNs0NrfL1Uzuup+GqHfToR2KcsXFymXSV90hoyw3M+msjFuQly+YzIH/q0MGlQ==", - "requires": { - "encodeurl": "1.0.1", - "escape-html": "1.0.3", - "parseurl": "1.3.2", - "send": "0.16.1" - } - }, "setprototypeof": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" } } }, @@ -2057,6 +1942,11 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=" }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + }, "fastparse": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.1.tgz", @@ -2108,6 +1998,30 @@ } } }, + "finalhandler": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", + "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", + "requires": { + "debug": "2.6.9", + "encodeurl": "1.0.1", + "escape-html": "1.0.3", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "statuses": "1.3.1", + "unpipe": "1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + } + } + }, "find-up": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", @@ -2237,6 +2151,16 @@ "integrity": "sha1-lriIb3w8NQi5Mta9cMTTqI818ak=", "dev": true }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, "from": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", @@ -2398,6 +2322,11 @@ } } }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, "har-validator": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-1.8.0.tgz", @@ -2543,6 +2472,11 @@ "resolved": "https://registry.npmjs.org/i/-/i-0.3.5.tgz", "integrity": "sha1-HSuFQVjsgWkRPGy39raAHpniEdU=" }, + "iconv-lite": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" + }, "icss-replace-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", @@ -2648,6 +2582,11 @@ "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" }, + "ipaddr.js": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.5.2.tgz", + "integrity": "sha1-1LUFvemUaYfM8PxY2QEP+WB+P6A=" + }, "is-absolute-url": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", @@ -3464,15 +3403,6 @@ "readable-stream": "2.2.7" }, "dependencies": { - "mongodb-core": { - "version": "2.1.17", - "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-2.1.17.tgz", - "integrity": "sha1-pBizN6FKFJkPtRC5I97mqBMXPfg=", - "requires": { - "bson": "1.0.4", - "require_optional": "1.0.1" - } - }, "readable-stream": { "version": "2.2.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.7.tgz", @@ -3489,6 +3419,15 @@ } } }, + "mongodb-core": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-2.1.17.tgz", + "integrity": "sha1-pBizN6FKFJkPtRC5I97mqBMXPfg=", + "requires": { + "bson": "1.0.4", + "require_optional": "1.0.1" + } + }, "mongomock": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/mongomock/-/mongomock-0.1.2.tgz", @@ -3893,6 +3832,11 @@ "better-assert": "1.0.2" } }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" + }, "path": { "version": "0.12.7", "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", @@ -3955,6 +3899,11 @@ "sha.js": "2.4.8" } }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", @@ -4549,6 +4498,15 @@ "bytebuffer": "3.1.1" } }, + "proxy-addr": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.2.tgz", + "integrity": "sha1-ZXFQT0e7mI7IGAJT+F3X4UlSvew=", + "requires": { + "forwarded": "0.1.2", + "ipaddr.js": "1.5.2" + } + }, "prr": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/prr/-/prr-0.0.0.tgz", @@ -4699,6 +4657,17 @@ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" }, + "raw-body": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", + "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.2", + "iconv-lite": "0.4.19", + "unpipe": "1.0.0" + } + }, "read": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", @@ -4915,17 +4884,12 @@ "mime-types": "2.1.17" } }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" - }, "har-validator": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", "requires": { - "ajv": "5.2.3", + "ajv": "5.3.0", "har-schema": "2.0.0" } }, @@ -4968,11 +4932,6 @@ "mime-db": "1.30.0" } }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" - }, "qs": { "version": "6.5.1", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", @@ -5134,6 +5093,52 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==" }, + "send": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.1.tgz", + "integrity": "sha512-ElCLJdJIKPk6ux/Hocwhk7NFHpI3pVm/IZOYWqUmoxcgeyM+MpxHHKhb8QmlJDX1pU6WrgaHBkVNm73Sv7uc2A==", + "requires": { + "debug": "2.6.9", + "depd": "1.1.1", + "destroy": "1.0.4", + "encodeurl": "1.0.1", + "escape-html": "1.0.3", + "etag": "1.8.1", + "fresh": "0.5.2", + "http-errors": "1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "2.3.0", + "range-parser": "1.2.0", + "statuses": "1.3.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" + } + } + }, + "serve-static": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.1.tgz", + "integrity": "sha512-hSMUZrsPa/I09VYFJwa627JJkNs0NrfL1Uzuup+GqHfToR2KcsXFymXSV90hoyw3M+msjFuQly+YzIH/q0MGlQ==", + "requires": { + "encodeurl": "1.0.1", + "escape-html": "1.0.3", + "parseurl": "1.3.2", + "send": "0.16.1" + } + }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -5964,9 +5969,9 @@ } }, "uglify-js": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.1.4.tgz", - "integrity": "sha512-DcbkPg11Lw2lAWpwCmQDX+qoR4JiII6ypsQmF6tscZtlxGPFAmSRUGuMoVT3/0EHqypVik/TpkH4ITiMJeQqQA==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.1.5.tgz", + "integrity": "sha512-tSqlO7/GZHAVSw6mbtJt2kz0ZcUrKUH7Xg92o52aE+gL0r6cXiASZY4dpHqQ7RVGXmoQuPA2qAkG4TkP59f8XA==", "requires": { "commander": "2.11.0", "source-map": "0.6.1" @@ -6107,6 +6112,11 @@ } } }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, "uuid": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", @@ -6121,6 +6131,11 @@ "spdx-expression-parse": "1.0.4" } }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, "vendors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.1.tgz", @@ -6175,7 +6190,7 @@ "requires": { "acorn": "5.1.2", "acorn-dynamic-import": "2.0.2", - "ajv": "5.2.3", + "ajv": "5.3.0", "ajv-keywords": "2.1.0", "async": "2.5.0", "enhanced-resolve": "3.4.1", diff --git a/package.json b/package.json index dcd0059e271..d963fef5111 100644 --- a/package.json +++ b/package.json @@ -47,10 +47,10 @@ } }, "engines": { - "node": "8.7.0" + "node": "8.8.0" }, "dependencies": { - "ajv": "^5.2.3", + "ajv": "^5.3.0", "async": "^0.9.2", "body-parser": "^1.18.2", "bootevent": "0.0.1", @@ -100,7 +100,7 @@ "sugar": "^1.5.0", "sync-exec": "^0.6.2", "traverse": "^0.6.6", - "uglify-js": "^3.1.4", + "uglify-js": "^3.1.5", "uuid": "^3.1.0", "webpack": "^3.8.1" }, From 68536d9dc35bdb9315a48359efb8c5868cf5afb6 Mon Sep 17 00:00:00 2001 From: PieterGit Date: Wed, 25 Oct 2017 08:05:25 +0200 Subject: [PATCH 29/51] npm update with nodejs 8.8.0 --- package-lock.json | 51 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8d5d2826986..e79a9001456 100644 --- a/package-lock.json +++ b/package-lock.json @@ -173,15 +173,6 @@ "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" }, - "ascli": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ascli/-/ascli-1.0.1.tgz", - "integrity": "sha1-vPpZdKYvGOgcq660lzKrSoj5Brw=", - "requires": { - "colour": "0.7.1", - "optjs": "3.2.2" - } - }, "asn1": { "version": "0.1.11", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz", @@ -2281,11 +2272,18 @@ "integrity": "sha1-PTDHGLCaPZbyPqTMH0A8TTup/08=", "dev": true, "requires": { + "async": "1.5.2", "optimist": "0.5.2", "source-map": "0.1.43", "uglify-js": "2.8.29" }, "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, "uglify-js": { "version": "2.8.29", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", @@ -2746,6 +2744,7 @@ "dev": true, "requires": { "abbrev": "1.0.9", + "async": "1.5.2", "escodegen": "0.0.15", "esprima": "1.0.2", "glob": "7.1.2", @@ -2758,6 +2757,14 @@ "supports-color": "2.0.0", "which": "1.2.14", "wordwrap": "0.0.3" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + } } }, "joi": { @@ -3308,6 +3315,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=" }, + "node-uuid": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", + "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=" + }, "qs": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/qs/-/qs-5.1.0.tgz", @@ -3566,11 +3578,6 @@ } } }, - "node-uuid": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", - "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=" - }, "nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", @@ -4496,6 +4503,17 @@ "requires": { "ascli": "1.0.1", "bytebuffer": "3.1.1" + }, + "dependencies": { + "ascli": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ascli/-/ascli-1.0.1.tgz", + "integrity": "sha1-vPpZdKYvGOgcq660lzKrSoj5Brw=", + "requires": { + "colour": "0.7.1", + "optjs": "3.2.2" + } + } } }, "proxy-addr": { @@ -5284,6 +5302,11 @@ "mime-db": "1.12.0" } }, + "node-uuid": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", + "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=" + }, "oauth-sign": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.6.0.tgz", From a869e3cbec6027fd84d96be5410bd24ed0c8953b Mon Sep 17 00:00:00 2001 From: Sulka Haro Date: Wed, 25 Oct 2017 20:08:53 +0300 Subject: [PATCH 30/51] Update version, remove package-lock.json --- bower.json | 2 +- package-lock.json => npm-shrinkwrap.json | 794 ++++++++++++++++++++++- package.json | 2 +- 3 files changed, 795 insertions(+), 3 deletions(-) rename package-lock.json => npm-shrinkwrap.json (91%) diff --git a/bower.json b/bower.json index 22b34c36623..4f37100f92f 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "nightscout", - "version": "0.10.2-dev-20171016", + "version": "0.10.2-release-20171025", "dependencies": { "colorbrewer": "~1.0.0", "jQuery-Storage-API": "~1.7.2", diff --git a/package-lock.json b/npm-shrinkwrap.json similarity index 91% rename from package-lock.json rename to npm-shrinkwrap.json index e79a9001456..4b4e6c88db9 100644 --- a/package-lock.json +++ b/npm-shrinkwrap.json @@ -1,6 +1,6 @@ { "name": "Nightscout", - "version": "0.10.2-dev-20171016", + "version": "0.10.2-release-20171025", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -742,6 +742,7 @@ "requires": { "anymatch": "1.3.0", "async-each": "1.0.1", + "fsevents": "1.1.2", "glob-parent": "2.0.0", "inherits": "2.0.3", "is-binary-path": "1.0.1", @@ -2162,6 +2163,791 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, + "fsevents": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.2.tgz", + "integrity": "sha512-Sn44E5wQW4bTHXvQmvSHwqbuiXtduD6Rrjm2ZtUEGbyrig+nUH3t/QD4M4/ZXViY556TBpRgZkHLDx3JxPwxiw==", + "optional": true, + "requires": { + "nan": "2.7.0", + "node-pre-gyp": "0.6.36" + }, + "dependencies": { + "abbrev": { + "version": "1.1.0", + "bundled": true, + "optional": true + }, + "ajv": { + "version": "4.11.8", + "bundled": true, + "optional": true, + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + } + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true + }, + "aproba": { + "version": "1.1.1", + "bundled": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.4", + "bundled": true, + "optional": true, + "requires": { + "delegates": "1.0.0", + "readable-stream": "2.2.9" + } + }, + "asn1": { + "version": "0.2.3", + "bundled": true, + "optional": true + }, + "assert-plus": { + "version": "0.2.0", + "bundled": true, + "optional": true + }, + "asynckit": { + "version": "0.4.0", + "bundled": true, + "optional": true + }, + "aws-sign2": { + "version": "0.6.0", + "bundled": true, + "optional": true + }, + "aws4": { + "version": "1.6.0", + "bundled": true, + "optional": true + }, + "balanced-match": { + "version": "0.4.2", + "bundled": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "bundled": true, + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "block-stream": { + "version": "0.0.9", + "bundled": true, + "requires": { + "inherits": "2.0.3" + } + }, + "boom": { + "version": "2.10.1", + "bundled": true, + "requires": { + "hoek": "2.16.3" + } + }, + "brace-expansion": { + "version": "1.1.7", + "bundled": true, + "requires": { + "balanced-match": "0.4.2", + "concat-map": "0.0.1" + } + }, + "buffer-shims": { + "version": "1.0.0", + "bundled": true + }, + "caseless": { + "version": "0.12.0", + "bundled": true, + "optional": true + }, + "co": { + "version": "4.6.0", + "bundled": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true + }, + "combined-stream": { + "version": "1.0.5", + "bundled": true, + "requires": { + "delayed-stream": "1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true + }, + "cryptiles": { + "version": "2.0.5", + "bundled": true, + "optional": true, + "requires": { + "boom": "2.10.1" + } + }, + "dashdash": { + "version": "1.14.1", + "bundled": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "optional": true + } + } + }, + "debug": { + "version": "2.6.8", + "bundled": true, + "optional": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-extend": { + "version": "0.4.2", + "bundled": true, + "optional": true + }, + "delayed-stream": { + "version": "1.0.0", + "bundled": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "ecc-jsbn": { + "version": "0.1.1", + "bundled": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "extend": { + "version": "3.0.1", + "bundled": true, + "optional": true + }, + "extsprintf": { + "version": "1.0.2", + "bundled": true + }, + "forever-agent": { + "version": "0.6.1", + "bundled": true, + "optional": true + }, + "form-data": { + "version": "2.1.4", + "bundled": true, + "optional": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.15" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true + }, + "fstream": { + "version": "1.0.11", + "bundled": true, + "requires": { + "graceful-fs": "4.1.11", + "inherits": "2.0.3", + "mkdirp": "0.5.1", + "rimraf": "2.6.1" + } + }, + "fstream-ignore": { + "version": "1.0.5", + "bundled": true, + "optional": true, + "requires": { + "fstream": "1.0.11", + "inherits": "2.0.3", + "minimatch": "3.0.4" + } + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "optional": true, + "requires": { + "aproba": "1.1.1", + "console-control-strings": "1.1.0", + "has-unicode": "2.0.1", + "object-assign": "4.1.1", + "signal-exit": "3.0.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wide-align": "1.1.2" + } + }, + "getpass": { + "version": "0.1.7", + "bundled": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "optional": true + } + } + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "bundled": true + }, + "har-schema": { + "version": "1.0.5", + "bundled": true, + "optional": true + }, + "har-validator": { + "version": "4.2.1", + "bundled": true, + "optional": true, + "requires": { + "ajv": "4.11.8", + "har-schema": "1.0.5" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "optional": true + }, + "hawk": { + "version": "3.1.3", + "bundled": true, + "optional": true, + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + } + }, + "hoek": { + "version": "2.16.3", + "bundled": true + }, + "http-signature": { + "version": "1.1.1", + "bundled": true, + "optional": true, + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.4.0", + "sshpk": "1.13.0" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true + }, + "ini": { + "version": "1.3.4", + "bundled": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true + }, + "isstream": { + "version": "0.1.2", + "bundled": true, + "optional": true + }, + "jodid25519": { + "version": "1.0.2", + "bundled": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "jsbn": { + "version": "0.1.1", + "bundled": true, + "optional": true + }, + "json-schema": { + "version": "0.2.3", + "bundled": true, + "optional": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "bundled": true, + "optional": true, + "requires": { + "jsonify": "0.0.0" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "bundled": true, + "optional": true + }, + "jsonify": { + "version": "0.0.0", + "bundled": true, + "optional": true + }, + "jsprim": { + "version": "1.4.0", + "bundled": true, + "optional": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.0.2", + "json-schema": "0.2.3", + "verror": "1.3.6" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "optional": true + } + } + }, + "mime-db": { + "version": "1.27.0", + "bundled": true + }, + "mime-types": { + "version": "2.1.15", + "bundled": true, + "requires": { + "mime-db": "1.27.0" + } + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "requires": { + "brace-expansion": "1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "bundled": true, + "optional": true + }, + "node-pre-gyp": { + "version": "0.6.36", + "bundled": true, + "optional": true, + "requires": { + "mkdirp": "0.5.1", + "nopt": "4.0.1", + "npmlog": "4.1.0", + "rc": "1.2.1", + "request": "2.81.0", + "rimraf": "2.6.1", + "semver": "5.3.0", + "tar": "2.2.1", + "tar-pack": "3.4.0" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "optional": true, + "requires": { + "abbrev": "1.1.0", + "osenv": "0.1.4" + } + }, + "npmlog": { + "version": "4.1.0", + "bundled": true, + "optional": true, + "requires": { + "are-we-there-yet": "1.1.4", + "console-control-strings": "1.1.0", + "gauge": "2.7.4", + "set-blocking": "2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true + }, + "oauth-sign": { + "version": "0.8.2", + "bundled": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "osenv": { + "version": "0.1.4", + "bundled": true, + "optional": true, + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true + }, + "performance-now": { + "version": "0.2.0", + "bundled": true, + "optional": true + }, + "process-nextick-args": { + "version": "1.0.7", + "bundled": true + }, + "punycode": { + "version": "1.4.1", + "bundled": true, + "optional": true + }, + "qs": { + "version": "6.4.0", + "bundled": true, + "optional": true + }, + "rc": { + "version": "1.2.1", + "bundled": true, + "optional": true, + "requires": { + "deep-extend": "0.4.2", + "ini": "1.3.4", + "minimist": "1.2.0", + "strip-json-comments": "2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.2.9", + "bundled": true, + "requires": { + "buffer-shims": "1.0.0", + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "1.0.1", + "util-deprecate": "1.0.2" + } + }, + "request": { + "version": "2.81.0", + "bundled": true, + "optional": true, + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "4.2.1", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.15", + "oauth-sign": "0.8.2", + "performance-now": "0.2.0", + "qs": "6.4.0", + "safe-buffer": "5.0.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.2", + "tunnel-agent": "0.6.0", + "uuid": "3.0.1" + } + }, + "rimraf": { + "version": "2.6.1", + "bundled": true, + "requires": { + "glob": "7.1.2" + } + }, + "safe-buffer": { + "version": "5.0.1", + "bundled": true + }, + "semver": { + "version": "5.3.0", + "bundled": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "optional": true + }, + "sntp": { + "version": "1.0.9", + "bundled": true, + "optional": true, + "requires": { + "hoek": "2.16.3" + } + }, + "sshpk": { + "version": "1.13.0", + "bundled": true, + "optional": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jodid25519": "1.0.2", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "optional": true + } + } + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "string_decoder": { + "version": "1.0.1", + "bundled": true, + "requires": { + "safe-buffer": "5.0.1" + } + }, + "stringstream": { + "version": "0.0.5", + "bundled": true, + "optional": true + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "optional": true + }, + "tar": { + "version": "2.2.1", + "bundled": true, + "requires": { + "block-stream": "0.0.9", + "fstream": "1.0.11", + "inherits": "2.0.3" + } + }, + "tar-pack": { + "version": "3.4.0", + "bundled": true, + "optional": true, + "requires": { + "debug": "2.6.8", + "fstream": "1.0.11", + "fstream-ignore": "1.0.5", + "once": "1.4.0", + "readable-stream": "2.2.9", + "rimraf": "2.6.1", + "tar": "2.2.1", + "uid-number": "0.0.6" + } + }, + "tough-cookie": { + "version": "2.3.2", + "bundled": true, + "optional": true, + "requires": { + "punycode": "1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "bundled": true, + "optional": true, + "requires": { + "safe-buffer": "5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "bundled": true, + "optional": true + }, + "uid-number": { + "version": "0.0.6", + "bundled": true, + "optional": true + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true + }, + "uuid": { + "version": "3.0.1", + "bundled": true, + "optional": true + }, + "verror": { + "version": "1.3.6", + "bundled": true, + "optional": true, + "requires": { + "extsprintf": "1.0.2" + } + }, + "wide-align": { + "version": "1.1.2", + "bundled": true, + "optional": true, + "requires": { + "string-width": "1.0.2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true + } + } + }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -3489,6 +4275,12 @@ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" }, + "nan": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.7.0.tgz", + "integrity": "sha1-2Vv3IeyHfgjbJ27T/G63j5CDrUY=", + "optional": true + }, "nconf": { "version": "0.6.9", "resolved": "https://registry.npmjs.org/nconf/-/nconf-0.6.9.tgz", diff --git a/package.json b/package.json index d963fef5111..9f271c04f00 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "Nightscout", - "version": "0.10.2-dev-20171016", + "version": "0.10.2-release-20171025", "description": "Nightscout acts as a web-based CGM (Continuous Glucose Montinor) to allow multiple caregivers to remotely view a patients glucose data in realtime.", "license": "AGPL-3.0", "author": "Nightscout Team", From dd1cc9cb83133e1f3f2eef5179933e7f2160aebd Mon Sep 17 00:00:00 2001 From: PieterGit Date: Wed, 25 Oct 2017 21:00:09 +0200 Subject: [PATCH 31/51] upgrade node in .nvmrc from 8.1.4 to 8.8.0 set travis container to dist: trusty and give sudo: false a try --- .nvmrc | 2 +- .travis.yml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.nvmrc b/.nvmrc index ac2895c5967..3b6825376ad 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -8.1.4 +8.8.0 diff --git a/.travis.yml b/.travis.yml index 741a44fe006..ae7f1fca067 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,6 @@ language: node_js -sudo: required +sudo: false +dist: trusty node_js: - "8.8.0" matrix: From 9c403e5819dcdf93c53ba8a37007a5a684380431 Mon Sep 17 00:00:00 2001 From: PieterGit Date: Wed, 25 Oct 2017 21:14:46 +0200 Subject: [PATCH 32/51] set sudo back to required (used for docker and mongodb commands) --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ae7f1fca067..09467e2a3c3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: node_js -sudo: false +sudo: required dist: trusty node_js: - "8.8.0" From 9c971f0422bca099c9496cd0a3644ad5eeab56b4 Mon Sep 17 00:00:00 2001 From: PieterGit Date: Wed, 25 Oct 2017 21:40:43 +0200 Subject: [PATCH 33/51] more node upgrade stuff --- Dockerfile.example | 2 +- README.md | 4 ++-- setup.sh | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Dockerfile.example b/Dockerfile.example index d6f6f0f8821..2c44bc654dc 100644 --- a/Dockerfile.example +++ b/Dockerfile.example @@ -1,4 +1,4 @@ -FROM node:8.5.0 +FROM node:8.8.0 MAINTAINER Nightscout Contributors diff --git a/README.md b/README.md index cdb941efbf9..a14822230d6 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,7 @@ Community maintained fork of the Requirements: -- [Node.js](http://nodejs.org/) +- [Node.js](http://nodejs.org/) 8.8.0 (use [Install instructions for Node](https://nodejs.org/en/download/package-manager/) or `setup.sh`) Clone this repo then install dependencies into the root of the project: @@ -113,7 +113,7 @@ Clone this repo then install dependencies into the root of the project: $ npm install ``` -If deploying the software to Microsoft Azure, you must set *WEBSITE_NODE_DEFAULT_VERSION* in the app settings to *8.5.0* or the site deployment will fail. Other hosting environments do not require this setting. +If deploying the software to Microsoft Azure, you must set *WEBSITE_NODE_DEFAULT_VERSION* in the app settings to *8.8.0* or the site deployment will fail. Other hosting environments do not require this setting. # Usage diff --git a/setup.sh b/setup.sh index e520a97a025..605696532ff 100755 --- a/setup.sh +++ b/setup.sh @@ -1,9 +1,9 @@ #!/bin/sh +curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash - sudo apt-get update -sudo apt-get install -y python-software-properties python g++ make git -sudo add-apt-repository ppa:chris-lea/node.js -sudo apt-get update -sudo apt-get install nodejs +sudo apt-get install -y nodejs +sudo apt-get install -y python-software-properties python git +sudo apt-get install -y build-essential npm install \ No newline at end of file From 56092f37bd830b3b22169472bf7e674d0f94cb52 Mon Sep 17 00:00:00 2001 From: Sulka Haro Date: Wed, 25 Oct 2017 22:49:49 +0300 Subject: [PATCH 34/51] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a14822230d6..02665369d6d 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,7 @@ Clone this repo then install dependencies into the root of the project: $ npm install ``` -If deploying the software to Microsoft Azure, you must set *WEBSITE_NODE_DEFAULT_VERSION* in the app settings to *8.8.0* or the site deployment will fail. Other hosting environments do not require this setting. +If deploying the software to Microsoft Azure, you must set *WEBSITE_NODE_DEFAULT_VERSION* in the app settings to *8.8.0* **before** you deploy the latest Nightscout or the site deployment will likely fail. Other hosting environments do not require this setting. # Usage From f6f55496d3ad736460bea9c1ccee612380ba7aaf Mon Sep 17 00:00:00 2001 From: Sulka Haro Date: Wed, 25 Oct 2017 23:16:49 +0300 Subject: [PATCH 35/51] Fix a bug with time comparison on if-modified-since support for treatments --- lib/api/entries/index.js | 2 +- lib/api/treatments/index.js | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/api/entries/index.js b/lib/api/entries/index.js index ffecef92f78..425fee4f7a1 100644 --- a/lib/api/entries/index.js +++ b/lib/api/entries/index.js @@ -86,7 +86,7 @@ function configure (app, wares, ctx) { var ifModifiedSince = req.get('If-Modified-Since'); if (!ifModifiedSince) { return next(); } - if (lastEntryDate <= new Date(ifModifiedSince)) { + if (lastEntryDate.getTime() <= new Date(ifModifiedSince).getTime()) { res.status(304).send({status:304, message: 'Not modified', type:'internal'}); return; } diff --git a/lib/api/treatments/index.js b/lib/api/treatments/index.js index 5b0c0500b77..d4dd0a67530 100644 --- a/lib/api/treatments/index.js +++ b/lib/api/treatments/index.js @@ -2,6 +2,7 @@ var _ = require('lodash'); var consts = require('../../constants'); +var moment = require('moment'); function configure(app, wares, ctx) { var express = require('express') @@ -41,14 +42,14 @@ function configure(app, wares, ctx) { var d2 = new Date(t.timestamp); - if (d1 == null || d2 > d1) { + if (d1 == null || d2.getTime() > d1.getTime()) { d1 = d2; } }); if (!_.isNil(d1)) res.setHeader('Last-Modified', d1.toUTCString()); - if (ifModifiedSince && d1 <= new Date(ifModifiedSince)) { + if (ifModifiedSince && d1.getTime() <= moment(ifModifiedSince).valueOf()) { res.status(304).send({ status: 304 , message: 'Not modified' From c16ad7b989112e16679e06c6cde93cc425076aef Mon Sep 17 00:00:00 2001 From: Sulka Haro Date: Wed, 25 Oct 2017 23:48:49 +0300 Subject: [PATCH 36/51] Check both created_at and timestamp fields for treatments in if-modified-since logic --- lib/api/treatments/index.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/api/treatments/index.js b/lib/api/treatments/index.js index d4dd0a67530..842c26df800 100644 --- a/lib/api/treatments/index.js +++ b/lib/api/treatments/index.js @@ -40,8 +40,18 @@ function configure(app, wares, ctx) { t.carbs = Number(t.carbs); t.insulin = Number(t.insulin); - var d2 = new Date(t.timestamp); + var d2 = null; + if (t.hasOwnProperty('created_at')) { + d2 = new Date(t.created_at); + } else { + if (t.hasOwnProperty('timestamp')) { + d2 = new Date(t.timestamp); + } + } + + if (d2 == null) { return; } + if (d1 == null || d2.getTime() > d1.getTime()) { d1 = d2; } From 3867becfcbd7d501d53d0cc72b987eb6d2dffec7 Mon Sep 17 00:00:00 2001 From: Alim Hassam Date: Sun, 15 Oct 2017 19:42:23 -0400 Subject: [PATCH 37/51] Add Total daily pasal to profile editor. Small improvoment to profile editor while geting familiar about the code. Added a simple estimated total daily basal field. --- lib/language.js | 23 +++++++++++++++++++ static/profile/js/profileeditor.js | 37 ++++++++++++++++++++++++++---- views/profileindex.html | 1 + 3 files changed, 56 insertions(+), 5 deletions(-) diff --git a/lib/language.js b/lib/language.js index 6b2482d4cfa..840f493c31d 100644 --- a/lib/language.js +++ b/lib/language.js @@ -1736,6 +1736,29 @@ function init() { ,ko: '날짜 전체' ,zh_cn: '天总计' } + ,'Total per day' : { + cs: 'dní celkem' + ,de: 'Gesamttage' + ,es: 'Total de días' + ,fr: 'Total journalier' + ,el: 'ημέρες συνολικά' + ,pt: 'dias no total' + ,sv: 'antal dagar' + ,ro: 'total zile' + ,bg: 'общо за деня' + ,hr: 'ukupno dana' + ,it: 'Giorni totali' + ,dk: 'antal dage' + ,fi: 'päivän arvio' + ,nb: 'antall dager' + ,he: 'מספר ימים' + ,pl: 'dni łącznie' + ,ru: 'всего дней' + ,sk: 'dní celkom' + ,nl: 'Totaal dagen' + ,ko: '날짜 전체' + ,zh_cn: '天总计' + } ,'Overall' : { cs: 'Celkem' ,de: 'Insgesamt' diff --git a/static/profile/js/profileeditor.js b/static/profile/js/profileeditor.js index b5db65be0bd..3ff7435e0e8 100644 --- a/static/profile/js/profileeditor.js +++ b/static/profile/js/profileeditor.js @@ -199,6 +199,28 @@ initProfile(); } + function timeDiffMinutes(time1, time2) + { + var minutes1 = toMinutesFromMidnight(time1); + var minutes2 = toMinutesFromMidnight(time2); + if (minutes2 <= minutes1) { + minutes2 += 24*60; + } + return minutes2-minutes1; + } + function refreshTotalBasal() + { + GUIToObject(); + var total = 0; + for (var i=0, len=c_profile['basal'].length; i').append(translate('From') + ': ').append(select)); - tr.append($('').append(e.label).append($('').attr('id',e.prefix+'_val_'+i).attr('value',c_profile[e.array][i].value))); + tr.append($('').append(e.label).append($('').attr('id',e.prefix+'_val_'+i).attr('value',c_profile[e.array][i].value).attr('class', e.prefix + '_value'))); var icons_td = $('').append($('').attr('class','addsingle').attr('style','cursor:pointer').attr('title',translate('Add new interval before')).attr('src',icon_add).attr('array',e.array).attr('pos',i)); if (c_profile[e.array].length>1) { icons_td.append($('').attr('class','delsingle').attr('style','cursor:pointer').attr('title',translate('Delete interval')).attr('src',icon_remove).attr('array',e.array).attr('pos',i)); @@ -436,13 +459,15 @@ html += ''; $('#'+e.prefix+'_placeholder').html(html); }); - + $('.pe_basal_value').on('change keyup paste', refreshTotalBasal); $('.addsingle').click(function addsingle_click() { var array = $(this).attr('array'); var pos = $(this).attr('pos'); GUIToObject(); c_profile[array].splice(pos,0,{time:'00:00',value:0}); - return fillTimeRanges(); + var retVal = fillTimeRanges(); + refreshTotalBasal(); + return retVal; }); $('.delsingle').click(function delsingle_click() { @@ -451,7 +476,9 @@ GUIToObject(); c_profile[array].splice(pos,1); c_profile[array][0].time = '00:00'; - return fillTimeRanges(); + var retVal = fillTimeRanges(); + refreshTotalBasal(); + return retVal; }); function addBGLine(i) { @@ -512,7 +539,7 @@ return fillTimeRanges(); }); - $('.pe_selectabletime').unbind().on('change', fillTimeRanges); + $('.pe_selectabletime').unbind().on('change', fillTimeRanges).on('change', refreshTotalBasal); objectToGUI(); maybePreventDefault(event); diff --git a/views/profileindex.html b/views/profileindex.html index 7b1ff2d5b4c..a0e99fc7e0f 100644 --- a/views/profileindex.html +++ b/views/profileindex.html @@ -150,6 +150,7 @@

      Profile Editor

      Basal rates [unit/hour]
      +
      Total per day:
      From dd5c125fc539931f11ad5ff671cd85c71923e25d Mon Sep 17 00:00:00 2001 From: Sulka Haro Date: Thu, 26 Oct 2017 20:28:08 +0300 Subject: [PATCH 38/51] Bump 8.8.0 to 8.8.1 --- .nvmrc | 2 +- .travis.yml | 2 +- Dockerfile.example | 2 +- README.md | 4 ++-- bower.json | 2 +- npm-shrinkwrap.json | 2 +- package.json | 4 ++-- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.nvmrc b/.nvmrc index 3b6825376ad..eec6dacbd48 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -8.8.0 +8.8.1 diff --git a/.travis.yml b/.travis.yml index 09467e2a3c3..b795df9bc3e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: node_js sudo: required dist: trusty node_js: - - "8.8.0" + - "8.8.1" matrix: fast_finish: true services: diff --git a/Dockerfile.example b/Dockerfile.example index 2c44bc654dc..24caa59b55c 100644 --- a/Dockerfile.example +++ b/Dockerfile.example @@ -1,4 +1,4 @@ -FROM node:8.8.0 +FROM node:8.8.1 MAINTAINER Nightscout Contributors diff --git a/README.md b/README.md index 02665369d6d..ffb9b6d7f7b 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,7 @@ Community maintained fork of the Requirements: -- [Node.js](http://nodejs.org/) 8.8.0 (use [Install instructions for Node](https://nodejs.org/en/download/package-manager/) or `setup.sh`) +- [Node.js](http://nodejs.org/) 8.8.1 (use [Install instructions for Node](https://nodejs.org/en/download/package-manager/) or `setup.sh`) Clone this repo then install dependencies into the root of the project: @@ -113,7 +113,7 @@ Clone this repo then install dependencies into the root of the project: $ npm install ``` -If deploying the software to Microsoft Azure, you must set *WEBSITE_NODE_DEFAULT_VERSION* in the app settings to *8.8.0* **before** you deploy the latest Nightscout or the site deployment will likely fail. Other hosting environments do not require this setting. +If deploying the software to Microsoft Azure, you must set *WEBSITE_NODE_DEFAULT_VERSION* in the app settings to *8.8.1* **before** you deploy the latest Nightscout or the site deployment will likely fail. Other hosting environments do not require this setting. # Usage diff --git a/bower.json b/bower.json index 4f37100f92f..7dcdfdf6717 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "nightscout", - "version": "0.10.2-release-20171025", + "version": "0.10.2-release-20171026", "dependencies": { "colorbrewer": "~1.0.0", "jQuery-Storage-API": "~1.7.2", diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 4b4e6c88db9..3bf32f1760e 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,6 +1,6 @@ { "name": "Nightscout", - "version": "0.10.2-release-20171025", + "version": "0.10.2-release-20171026", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 9f271c04f00..5fd8189df38 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "Nightscout", - "version": "0.10.2-release-20171025", + "version": "0.10.2-release-20171026", "description": "Nightscout acts as a web-based CGM (Continuous Glucose Montinor) to allow multiple caregivers to remotely view a patients glucose data in realtime.", "license": "AGPL-3.0", "author": "Nightscout Team", @@ -47,7 +47,7 @@ } }, "engines": { - "node": "8.8.0" + "node": "8.8.1" }, "dependencies": { "ajv": "^5.3.0", From 3f01d323d8142327bb8e618c78caba2e0a47f636 Mon Sep 17 00:00:00 2001 From: Scott Date: Tue, 17 Oct 2017 17:15:13 -0700 Subject: [PATCH 39/51] cherry pick 33f16f4439262da2ec74c196bfa7f244910bb6fe --- lib/client/renderer.js | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/lib/client/renderer.js b/lib/client/renderer.js index 4786da57a45..72d857a1df0 100644 --- a/lib/client/renderer.js +++ b/lib/client/renderer.js @@ -388,16 +388,23 @@ function init (client, d3) { contextCircles.exit().remove(); }; - function calcTreatmentRadius(treatment, opts) { - var CR = treatment.CR || 20; + function calcTreatmentRadius(treatment, opts, carbratio) { + var CR = treatment.CR || carbratio || 20; var carbs = treatment.carbs || CR; var insulin = treatment.insulin || 1; + var carbsOrInsulin = CR; + if ( treatment.carbs ) { + carbsOrInsulin = treatment.carbs; + } else if ( treatment.insulin ) { + carbsOrInsulin = treatment.insulin * CR; + } - var R1 = Math.sqrt(Math.min(carbs, insulin * CR)) / opts.scale - , R2 = Math.sqrt(Math.max(carbs, insulin * CR)) / opts.scale - , R3 = R2 + 8 / opts.scale - // R4 determines how far from the treatment dot the labels are placed - , R4 = R2 + 25 / opts.scale + // R1 determines the size of the treatment dot + var R1 = Math.sqrt(2*carbsOrInsulin) / opts.scale + , R2 = R1 + // R3/R4 determine how far from the treatment dot the labels are placed + , R3 = R1 + 8 / opts.scale + , R4 = R1 + 25 / opts.scale ; return { @@ -411,8 +418,10 @@ function init (client, d3) { function prepareArc(treatment, radius) { var arc_data = [ + // white carb half-circle on top { 'element': '', 'color': 'white', 'start': -1.5708, 'end': 1.5708, 'inner': 0, 'outer': radius.R1 }, { 'element': '', 'color': 'transparent', 'start': -1.5708, 'end': 1.5708, 'inner': radius.R2, 'outer': radius.R3 }, + // blue insulin half-circle on bottom { 'element': '', 'color': '#0099ff', 'start': 1.5708, 'end': 4.7124, 'inner': 0, 'outer': radius.R1 }, // these form a very short transparent arc along the bottom of an insulin treatment to position the label // these used to be semicircles from 1.5708 to 4.7124, but that made the tooltip target too big @@ -840,7 +849,7 @@ function init (client, d3) { label.append('text') // reduce the treatment label font size to make it readable with SMB - .style('font-size', 40 / opts.scale) + .style('font-size', 30 / opts.scale) .style('text-shadow', '0px 0px 10px rgba(0, 0, 0, 1)') .attr('text-anchor', 'middle') .attr('dy', '.35em') @@ -861,11 +870,11 @@ function init (client, d3) { renderer.drawTreatment(d, { scale: renderer.bubbleScale() , showLabels: true - }); + }, client.sbx.data.profile.getCarbRatio(new Date())); }); }; - renderer.drawTreatment = function drawTreatment(treatment, opts) { + renderer.drawTreatment = function drawTreatment(treatment, opts, carbratio) { if (!treatment.carbs && !treatment.insulin) { return; } @@ -877,7 +886,7 @@ function init (client, d3) { return; } - var radius = calcTreatmentRadius(treatment, opts); + var radius = calcTreatmentRadius(treatment, opts, carbratio); if (radius.isNaN) { console.warn('Bad Data: Found isNaN value in treatment', treatment); return; From d2a8d50a0a7503ad58a7f88f81b78ffab06ccb10 Mon Sep 17 00:00:00 2001 From: Scott Date: Tue, 17 Oct 2017 14:16:30 -0700 Subject: [PATCH 40/51] merge rendering --- lib/client/renderer.js | 2105 ++++++++++++++++++++-------------------- 1 file changed, 1055 insertions(+), 1050 deletions(-) diff --git a/lib/client/renderer.js b/lib/client/renderer.js index 72d857a1df0..1a1ee5f1316 100644 --- a/lib/client/renderer.js +++ b/lib/client/renderer.js @@ -4,1130 +4,1135 @@ var _ = require('lodash'); var times = require('../times'); var DEFAULT_FOCUS = times.hours(3).msecs - , WIDTH_SMALL_DOTS = 420 - , WIDTH_BIG_DOTS = 800 - , TOOLTIP_TRANS_MS = 100 // milliseconds - , TOOLTIP_WIDTH = 150 //min-width + padding - ; + , WIDTH_SMALL_DOTS = 420 + , WIDTH_BIG_DOTS = 800 + , TOOLTIP_TRANS_MS = 100 // milliseconds + , TOOLTIP_WIDTH = 150 //min-width + padding +; function init (client, d3) { - var renderer = { }; + var renderer = { }; - var utils = client.utils; - var translate = client.translate; + var utils = client.utils; + var translate = client.translate; - //chart isn't created till the client gets data, so can grab the var at init - function chart() { - return client.chart; - } - - function focusRangeAdjustment ( ) { - return client.foucusRangeMS === DEFAULT_FOCUS ? 1 : 1 + ((client.foucusRangeMS - DEFAULT_FOCUS) / DEFAULT_FOCUS / 8); - } + //chart isn't created till the client gets data, so can grab the var at init + function chart() { + return client.chart; + } - var dotRadius = function(type) { - var radius = chart().prevChartWidth > WIDTH_BIG_DOTS ? 4 : (chart().prevChartWidth < WIDTH_SMALL_DOTS ? 2 : 3); - if (type === 'mbg') { - radius *= 2; - } else if (type === 'forecast') { - radius = Math.min(3, radius - 1); - } else if (type === 'rawbg') { - radius = Math.min(2, radius - 1); + function focusRangeAdjustment ( ) { + return client.focusRangeMS === DEFAULT_FOCUS ? 1 : 1 + ((client.focusRangeMS - DEFAULT_FOCUS) / DEFAULT_FOCUS / 8); } - return radius / focusRangeAdjustment(); - }; - - function tooltipLeft ( ) { - var windowWidth = $(client.tooltip).parent().parent().width(); - var left = d3.event.pageX + TOOLTIP_WIDTH < windowWidth ? d3.event.pageX : windowWidth - TOOLTIP_WIDTH - 10; - return left + 'px'; - } - - function hideTooltip ( ) { - client.tooltip.transition() - .duration(TOOLTIP_TRANS_MS) - .style('opacity', 0); - } - - // get the desired opacity for context chart based on the brush extent - renderer.highlightBrushPoints = function highlightBrushPoints(data) { - if (data.mills >= chart().brush.extent()[0].getTime() && data.mills <= chart().brush.extent()[1].getTime()) { - return chart().futureOpacity(data.mills - client.latestSGV.mills); - } else { - return 0.5; + var dotRadius = function(type) { + var radius = chart().prevChartWidth > WIDTH_BIG_DOTS ? 4 : (chart().prevChartWidth < WIDTH_SMALL_DOTS ? 2 : 3); + if (type === 'mbg') { + radius *= 2; + } else if (type === 'forecast') { + radius = Math.min(3, radius - 1); + } else if (type === 'rawbg') { + radius = Math.min(2, radius - 1); + } + + return radius / focusRangeAdjustment(); + }; + + function tooltipLeft ( ) { + var windowWidth = $(client.tooltip).parent().parent().width(); + var left = d3.event.pageX + TOOLTIP_WIDTH < windowWidth ? d3.event.pageX : windowWidth - TOOLTIP_WIDTH - 10; + return left + 'px'; } - }; - - renderer.bubbleScale = function bubbleScale ( ) { - // a higher bubbleScale will produce smaller bubbles (it's not a radius like focusDotRadius) - return (chart().prevChartWidth < WIDTH_SMALL_DOTS ? 4 : (chart().prevChartWidth < WIDTH_BIG_DOTS ? 3 : 2)) * focusRangeAdjustment(); - }; - - renderer.addFocusCircles = function addFocusCircles ( ) { - // get slice of data so that concatenation of predictions do not interfere with subsequent updates - var focusData = client.entries.slice(); - - if (client.sbx.pluginBase.forecastPoints) { - var shownForecastPoints = _.filter(client.sbx.pluginBase.forecastPoints, function isShown(point) { - return client.settings.showForecast.indexOf(point.info.type) > -1; - }); - var maxForecastMills = _.max(_.map(shownForecastPoints, function (point) {return point.mills})); - client.forecastTime = maxForecastMills > 0 ? maxForecastMills - client.sbx.lastSGVMills() : 0; - focusData = focusData.concat(shownForecastPoints); + + function hideTooltip ( ) { + client.tooltip.transition() + .duration(TOOLTIP_TRANS_MS) + .style('opacity', 0); } - // bind up the focus chart data to an array of circles - // selects all our data into data and uses date function to get current max date - var focusCircles = chart().focus.selectAll('circle').data(focusData, client.entryToDate); - - function prepareFocusCircles(sel) { - var badData = []; - sel.attr('cx', function (d) { - if (!d) { - console.error('Bad data', d); - return chart().xScale(new Date(0)); - } else if (!d.mills) { - console.error('Bad data, no mills', d); - return chart().xScale(new Date(0)); + // get the desired opacity for context chart based on the brush extent + renderer.highlightBrushPoints = function highlightBrushPoints(data) { + if (data.mills >= chart().brush.extent()[0].getTime() && data.mills <= chart().brush.extent()[1].getTime()) { + return chart().futureOpacity(data.mills - client.latestSGV.mills); } else { - return chart().xScale(new Date(d.mills)); + return 0.5; } - }) - .attr('cy', function (d) { - var scaled = client.sbx.scaleEntry(d); - if (isNaN(scaled)) { - badData.push(d); - return chart().yScale(utils.scaleMgdl(450)); - } else { - return chart().yScale(scaled); - } - }) - .attr('fill', function (d) { - return d.type === 'forecast' ? 'none' : d.color; - }) - .attr('opacity', function (d) { - return d.noFade ? 100 : chart().futureOpacity(d.mills - client.latestSGV.mills); - }) - .attr('stroke-width', function (d) { - return d.type === 'mbg' ? 2 : d.type === 'forecast' ? 2 : 0; - }) - .attr('stroke', function (d) { - return (d.type === 'mbg' ? 'white' : d.color); - }) - .attr('r', function (d) { - return dotRadius(d.type); - }); + }; - if (badData.length > 0) { - console.warn('Bad Data: isNaN(sgv)', badData); - } + renderer.bubbleScale = function bubbleScale ( ) { + // a higher bubbleScale will produce smaller bubbles (it's not a radius like focusDotRadius) + return (chart().prevChartWidth < WIDTH_SMALL_DOTS ? 4 : (chart().prevChartWidth < WIDTH_BIG_DOTS ? 3 : 2)) * focusRangeAdjustment(); + }; - return sel; - } + renderer.addFocusCircles = function addFocusCircles ( ) { + // get slice of data so that concatenation of predictions do not interfere with subsequent updates + var focusData = client.entries.slice(); - function focusCircleTooltip (d) { - if (d.type !== 'sgv' && d.type !== 'mbg' && d.type !== 'forecast') { - return; - } - - function getRawbgInfo ( ) { - var info = { }; - if (d.type === 'sgv') { - info.noise = client.rawbg.noiseCodeToDisplay(d.mgdl, d.noise); - if (client.rawbg.showRawBGs(d.mgdl, d.noise, client.ddata.cal, client.sbx)) { - info.value = utils.scaleMgdl(client.rawbg.calc(d, client.ddata.cal, client.sbx)); - } + if (client.sbx.pluginBase.forecastPoints) { + var shownForecastPoints = _.filter(client.sbx.pluginBase.forecastPoints, function isShown(point) { + return client.settings.showForecast.indexOf(point.info.type) > -1; + }); + var maxForecastMills = _.max(_.map(shownForecastPoints, function (point) {return point.mills})); + // limit lookahead to the same as lookback + var focusHoursAheadMills = chart().brush.extent()[1].getTime() + client.focusRangeMS; + maxForecastMills = Math.min(focusHoursAheadMills, maxForecastMills); + client.forecastTime = maxForecastMills > 0 ? maxForecastMills - client.sbx.lastSGVMills() : 0; + focusData = focusData.concat(shownForecastPoints); } - return info; - } - - var rawbgInfo = getRawbgInfo(); - - client.tooltip.transition().duration(TOOLTIP_TRANS_MS).style('opacity', .9); - client.tooltip.html('' + translate('BG')+ ': ' + client.sbx.scaleEntry( d ) + - (d.type === 'mbg' ? '
      ' + translate('Device') + ': ' + d.device : '') + - (d.type === 'forecast' ? '
      ' + translate('Forecast Type') + ': ' + d.forecastType : '') + - (rawbgInfo.value ? '
      ' + translate('Raw BG') + ': ' + rawbgInfo.value : '') + - (rawbgInfo.noise ? '
      ' + translate('Noise') + ': ' + rawbgInfo.noise : '') + - '
      ' + translate('Time') + ': ' + client.formatTime(new Date(d.mills))) - .style('left', tooltipLeft()) - .style('top', (d3.event.pageY + 15) + 'px'); - } - // if already existing then transition each circle to its new position - prepareFocusCircles(focusCircles.transition()); - - // if new circle then just display - prepareFocusCircles(focusCircles.enter().append('circle')) - .on('mouseover', focusCircleTooltip) - .on('mouseout', hideTooltip); - - focusCircles.exit().remove(); - }; - - renderer.addTreatmentCircles = function addTreatmentCircles ( ) { - function treatmentTooltip (d) { - return ''+translate('Time')+': ' + client.formatTime(new Date(d.mills)) + '
      ' + - (d.eventType ? ''+translate('Treatment type')+': ' + translate(client.careportal.resolveEventName(d.eventType)) + '
      ' : '') + - (d.reason ? ''+translate('Reason')+': ' + translate(d.reason) + '
      ' : '') + - (d.glucose ? ''+translate('BG')+': ' + d.glucose + (d.glucoseType ? ' (' + translate(d.glucoseType) + ')': '') + '
      ' : '') + - (d.enteredBy ? ''+translate('Entered By')+': ' + d.enteredBy + '
      ' : '') + - (d.targetTop ? ''+translate('Target Top')+': ' + d.targetTop + '
      ' : '') + - (d.targetBottom ? ''+translate('Target Bottom')+': ' + d.targetBottom + '
      ' : '') + - (d.duration ? ''+translate('Duration')+': ' + Math.round(d.duration) + ' min
      ' : '') + - (d.notes ? ''+translate('Notes')+': ' + d.notes : ''); - } + // bind up the focus chart data to an array of circles + // selects all our data into data and uses date function to get current max date + var focusCircles = chart().focus.selectAll('circle').data(focusData, client.entryToDate); + + function prepareFocusCircles(sel) { + var badData = []; + sel.attr('cx', function (d) { + if (!d) { + console.error('Bad data', d); + return chart().xScale(new Date(0)); + } else if (!d.mills) { + console.error('Bad data, no mills', d); + return chart().xScale(new Date(0)); + } else { + return chart().xScale(new Date(d.mills)); + } + }) + .attr('cy', function (d) { + var scaled = client.sbx.scaleEntry(d); + if (isNaN(scaled)) { + badData.push(d); + return chart().yScale(utils.scaleMgdl(450)); + } else { + return chart().yScale(scaled); + } + }) + .attr('fill', function (d) { + return d.type === 'forecast' ? 'none' : d.color; + }) + .attr('opacity', function (d) { + return d.noFade ? 100 : chart().futureOpacity(d.mills - client.latestSGV.mills); + }) + .attr('stroke-width', function (d) { + return d.type === 'mbg' ? 2 : d.type === 'forecast' ? 2 : 0; + }) + .attr('stroke', function (d) { + return (d.type === 'mbg' ? 'white' : d.color); + }) + .attr('r', function (d) { + return dotRadius(d.type); + }); + + if (badData.length > 0) { + console.warn('Bad Data: isNaN(sgv)', badData); + } - function announcementTooltip (d) { - return ''+translate('Time')+': ' + client.formatTime(new Date(d.mills)) + '
      ' + - (d.eventType ? ''+translate('Announcement')+'
      ' : '') + - (d.notes && d.notes.length > 1 ? ''+translate('Message')+': ' + d.notes + '
      ' : '') + - (d.enteredBy ? ''+translate('Entered By')+': ' + d.enteredBy + '
      ' : ''); - } + return sel; + } - //TODO: filter in oref0 instead of here and after most people upgrade take this out - var openAPSSpam = ['BasalProfileStart', 'ResultDailyTotal', 'BGReceived']; + function focusCircleTooltip (d) { + if (d.type !== 'sgv' && d.type !== 'mbg' && d.type !== 'forecast') { + return; + } - //NOTE: treatments with insulin or carbs are drawn by drawTreatment() - // bind up the focus chart data to an array of circles - var treatCircles = chart().focus.selectAll('treatment-dot').data(client.ddata.treatments.filter(function(treatment) { + function getRawbgInfo ( ) { + var info = { }; + if (d.type === 'sgv') { + info.noise = client.rawbg.noiseCodeToDisplay(d.mgdl, d.noise); + if (client.rawbg.showRawBGs(d.mgdl, d.noise, client.ddata.cal, client.sbx)) { + info.value = utils.scaleMgdl(client.rawbg.calc(d, client.ddata.cal, client.sbx)); + } + } + return info; + } - var notCarbsOrInsulin = !treatment.carbs && !treatment.insulin; - var notTempOrProfile = ! _.includes(['Temp Basal', 'Profile Switch', 'Combo Bolus', 'Temporary Target'], treatment.eventType); + var rawbgInfo = getRawbgInfo(); + + client.tooltip.transition().duration(TOOLTIP_TRANS_MS).style('opacity', .9); + client.tooltip.html('' + translate('BG')+ ': ' + client.sbx.scaleEntry( d ) + + (d.type === 'mbg' ? '
      ' + translate('Device') + ': ' + d.device : '') + + (d.type === 'forecast' ? '
      ' + translate('Forecast Type') + ': ' + d.forecastType : '') + + (rawbgInfo.value ? '
      ' + translate('Raw BG') + ': ' + rawbgInfo.value : '') + + (rawbgInfo.noise ? '
      ' + translate('Noise') + ': ' + rawbgInfo.noise : '') + + '
      ' + translate('Time') + ': ' + client.formatTime(new Date(d.mills))) + .style('left', tooltipLeft()) + .style('top', (d3.event.pageY + 15) + 'px'); + } - var notes = treatment.notes || ''; - var enteredBy = treatment.enteredBy || ''; + // if already existing then transition each circle to its new position + prepareFocusCircles(focusCircles.transition()); - var notOpenAPSSpam = enteredBy.indexOf('openaps://') === -1 || _.isUndefined(_.find(openAPSSpam, function startsWith (spam) { - return notes.indexOf(spam) === 0; - })); + // if new circle then just display + prepareFocusCircles(focusCircles.enter().append('circle')) + .on('mouseover', focusCircleTooltip) + .on('mouseout', hideTooltip); - return notCarbsOrInsulin && !treatment.duration && notTempOrProfile && notOpenAPSSpam; - })); + focusCircles.exit().remove(); + }; - function prepareTreatCircles(sel) { - function strokeColor(d) { - var color = 'white'; - if (d.isAnnouncement) { - color = 'orange'; - } else if (d.glucose) { - color = 'grey'; + renderer.addTreatmentCircles = function addTreatmentCircles ( ) { + function treatmentTooltip (d) { + return ''+translate('Time')+': ' + client.formatTime(new Date(d.mills)) + '
      ' + + (d.eventType ? ''+translate('Treatment type')+': ' + translate(client.careportal.resolveEventName(d.eventType)) + '
      ' : '') + + (d.reason ? ''+translate('Reason')+': ' + translate(d.reason) + '
      ' : '') + + (d.glucose ? ''+translate('BG')+': ' + d.glucose + (d.glucoseType ? ' (' + translate(d.glucoseType) + ')': '') + '
      ' : '') + + (d.enteredBy ? ''+translate('Entered By')+': ' + d.enteredBy + '
      ' : '') + + (d.targetTop ? ''+translate('Target Top')+': ' + d.targetTop + '
      ' : '') + + (d.targetBottom ? ''+translate('Target Bottom')+': ' + d.targetBottom + '
      ' : '') + + (d.duration ? ''+translate('Duration')+': ' + Math.round(d.duration) + ' min
      ' : '') + + (d.notes ? ''+translate('Notes')+': ' + d.notes : ''); } - return color; - } - - function fillColor(d) { - var color = 'grey'; - if (d.isAnnouncement) { - color = 'orange'; - } else if (d.glucose) { - color = 'red'; + + function announcementTooltip (d) { + return ''+translate('Time')+': ' + client.formatTime(new Date(d.mills)) + '
      ' + + (d.eventType ? ''+translate('Announcement')+'
      ' : '') + + (d.notes && d.notes.length > 1 ? ''+translate('Message')+': ' + d.notes + '
      ' : '') + + (d.enteredBy ? ''+translate('Entered By')+': ' + d.enteredBy + '
      ' : ''); } - return color; - } - - sel.attr('cx', function (d) { - return chart().xScale(new Date(d.mills)); - }) - .attr('cy', function (d) { - return chart().yScale(client.sbx.scaleEntry(d)); - }) - .attr('r', function () { - return dotRadius('mbg'); - }) - .attr('stroke-width', 2) - .attr('stroke', strokeColor) - .attr('fill', fillColor); - - return sel; - } - // if already existing then transition each circle to its new position - prepareTreatCircles(treatCircles.transition()); - - // if new circle then just display - prepareTreatCircles(treatCircles.enter().append('circle')) - .on('mouseover', function (d) { - client.tooltip.transition().duration(TOOLTIP_TRANS_MS).style('opacity', .9); - client.tooltip.html(d.isAnnouncement ? announcementTooltip(d) : treatmentTooltip(d)) - .style('left', tooltipLeft()) - .style('top', (d3.event.pageY + 15) + 'px'); - }) - .on('mouseout', hideTooltip); - - var durationTreatments = client.ddata.treatments.filter(function(treatment) { - return !treatment.carbs && !treatment.insulin && treatment.duration && - ! _.includes(['Temp Basal', 'Profile Switch', 'Combo Bolus', 'Temporary Target'], treatment.eventType); - }); - - //use the processed temp target so there are no overlaps - durationTreatments = durationTreatments.concat(client.ddata.tempTargetTreatments); - - // treatments with duration - var treatRects = chart().focus.selectAll('.g-duration').data(durationTreatments); - - function fillColor(d) { - // this is going to be updated by Event Type - var color = 'grey'; - if (d.eventType === 'Exercise') { - color = 'Violet'; - } else if (d.eventType === 'Note') { - color = 'Salmon'; - } else if (d.eventType === 'Temporary Target') { - color = 'lightgray'; - } - return color; - } + //TODO: filter in oref0 instead of here and after most people upgrade take this out + var openAPSSpam = ['BasalProfileStart', 'ResultDailyTotal', 'BGReceived']; - function rectHeight (d) { - var height = 20; - if (d.targetTop && d.targetTop > 0 && d.targetBottom && d.targetBottom > 0) { - height = Math.max(5, d.targetTop - d.targetBottom); - } - return height; - } + //NOTE: treatments with insulin or carbs are drawn by drawTreatment() + // bind up the focus chart data to an array of circles + var treatCircles = chart().focus.selectAll('treatment-dot').data(client.ddata.treatments.filter(function(treatment) { - function rectTranslate (d) { - var top = 50; - if (d.eventType === 'Temporary Target') { - top = d.targetTop === d.targetBottom ? d.targetTop + rectHeight(d) : d.targetTop; - } - return 'translate(' + chart().xScale(new Date(d.mills)) + ',' + chart().yScale(utils.scaleMgdl(top)) + ')'; - } - // if already existing then transition each rect to its new position - treatRects.transition() - .attr('transform', rectTranslate); - - chart().focus.selectAll('.g-duration-rect').transition() - .attr('width', function (d) { - return chart().xScale(new Date(d.mills + times.mins(d.duration).msecs)) - chart().xScale(new Date(d.mills)); - }); - - chart().focus.selectAll('.g-duration-text').transition() - .attr('transform', function (d) { - return 'translate(' + (chart().xScale(new Date(d.mills + times.mins(d.duration).msecs)) - chart().xScale(new Date(d.mills)))/2 + ',' + 10 + ')'; - }); - - // if new rect then just display - var gs = treatRects.enter().append('g') - .attr('class','g-duration') - .attr('transform', rectTranslate) - .on('mouseover', function (d) { - client.tooltip.transition().duration(TOOLTIP_TRANS_MS).style('opacity', .9); - client.tooltip.html(d.isAnnouncement ? announcementTooltip(d) : treatmentTooltip(d)) - .style('left', tooltipLeft()) - .style('top', (d3.event.pageY + 15) + 'px'); - }) - .on('mouseout', hideTooltip); - - gs.append('rect') - .attr('class', 'g-duration-rect') - .attr('width', function (d) { - return chart().xScale(new Date(d.mills + times.mins(d.duration).msecs)) - chart().xScale(new Date(d.mills)); - }) - .attr('height', rectHeight) - .attr('rx', 5) - .attr('ry', 5) - .attr('opacity', .2) - .attr('fill', fillColor); - - gs.append('text') - .attr('class', 'g-duration-text') - .style('font-size', 15) - .attr('fill', 'white') - .attr('text-anchor', 'middle') - .attr('dy', '.35em') - .attr('transform', function (d) { - return 'translate(' + (chart().xScale(new Date(d.mills + times.mins(d.duration).msecs)) - chart().xScale(new Date(d.mills)))/2 + ',' + 10 + ')'; - }) - .text(function (d) { - if (d.eventType === 'Temporary Target') { - return ''; + var notCarbsOrInsulin = !treatment.carbs && !treatment.insulin; + var notTempOrProfile = ! _.includes(['Temp Basal', 'Profile Switch', 'Combo Bolus', 'Temporary Target'], treatment.eventType); + + var notes = treatment.notes || ''; + var enteredBy = treatment.enteredBy || ''; + + var notOpenAPSSpam = enteredBy.indexOf('openaps://') === -1 || _.isUndefined(_.find(openAPSSpam, function startsWith (spam) { + return notes.indexOf(spam) === 0; + })); + + return notCarbsOrInsulin && !treatment.duration && notTempOrProfile && notOpenAPSSpam; + })); + + function prepareTreatCircles(sel) { + function strokeColor(d) { + var color = 'white'; + if (d.isAnnouncement) { + color = 'orange'; + } else if (d.glucose) { + color = 'grey'; + } + return color; + } + + function fillColor(d) { + var color = 'grey'; + if (d.isAnnouncement) { + color = 'orange'; + } else if (d.glucose) { + color = 'red'; + } + return color; + } + + sel.attr('cx', function (d) { + return chart().xScale(new Date(d.mills)); + }) + .attr('cy', function (d) { + return chart().yScale(client.sbx.scaleEntry(d)); + }) + .attr('r', function () { + return dotRadius('mbg'); + }) + .attr('stroke-width', 2) + .attr('stroke', strokeColor) + .attr('fill', fillColor); + + return sel; } - return d.notes || d.eventType; - }); - }; - - renderer.addContextCircles = function addContextCircles ( ) { - // bind up the context chart data to an array of circles - var contextCircles = chart().context.selectAll('circle').data(client.entries); - - function prepareContextCircles(sel) { - var badData = []; - sel.attr('cx', function (d) { return chart().xScale2(new Date(d.mills)); }) - .attr('cy', function (d) { - var scaled = client.sbx.scaleEntry(d); - if (isNaN(scaled)) { - badData.push(d); - return chart().yScale2(utils.scaleMgdl(450)); - } else { - return chart().yScale2(scaled); - } - }) - .attr('fill', function (d) { return d.color; }) - .style('opacity', function (d) { return renderer.highlightBrushPoints(d) }) - .attr('stroke-width', function (d) { return d.type === 'mbg' ? 2 : 0; }) - .attr('stroke', function ( ) { return 'white'; }) - .attr('r', function (d) { return d.type === 'mbg' ? 4 : 2; }); - - if (badData.length > 0) { - console.warn('Bad Data: isNaN(sgv)', badData); - } - - return sel; - } - // if already existing then transition each circle to its new position - prepareContextCircles(contextCircles.transition()); + // if already existing then transition each circle to its new position + prepareTreatCircles(treatCircles.transition()); - // if new circle then just display - prepareContextCircles(contextCircles.enter().append('circle')); + // if new circle then just display + prepareTreatCircles(treatCircles.enter().append('circle')) + .on('mouseover', function (d) { + client.tooltip.transition().duration(TOOLTIP_TRANS_MS).style('opacity', .9); + client.tooltip.html(d.isAnnouncement ? announcementTooltip(d) : treatmentTooltip(d)) + .style('left', tooltipLeft()) + .style('top', (d3.event.pageY + 15) + 'px'); + }) + .on('mouseout', hideTooltip); - contextCircles.exit().remove(); - }; + var durationTreatments = client.ddata.treatments.filter(function(treatment) { + return !treatment.carbs && !treatment.insulin && treatment.duration && + ! _.includes(['Temp Basal', 'Profile Switch', 'Combo Bolus', 'Temporary Target'], treatment.eventType); + }); - function calcTreatmentRadius(treatment, opts, carbratio) { - var CR = treatment.CR || carbratio || 20; - var carbs = treatment.carbs || CR; - var insulin = treatment.insulin || 1; - var carbsOrInsulin = CR; - if ( treatment.carbs ) { - carbsOrInsulin = treatment.carbs; - } else if ( treatment.insulin ) { - carbsOrInsulin = treatment.insulin * CR; - } + //use the processed temp target so there are no overlaps + durationTreatments = durationTreatments.concat(client.ddata.tempTargetTreatments); + + // treatments with duration + var treatRects = chart().focus.selectAll('.g-duration').data(durationTreatments); + + function fillColor(d) { + // this is going to be updated by Event Type + var color = 'grey'; + if (d.eventType === 'Exercise') { + color = 'Violet'; + } else if (d.eventType === 'Note') { + color = 'Salmon'; + } else if (d.eventType === 'Temporary Target') { + color = 'lightgray'; + } + return color; + } + + function rectHeight (d) { + var height = 20; + if (d.targetTop && d.targetTop > 0 && d.targetBottom && d.targetBottom > 0) { + height = Math.max(5, d.targetTop - d.targetBottom); + } + return height; + } - // R1 determines the size of the treatment dot - var R1 = Math.sqrt(2*carbsOrInsulin) / opts.scale - , R2 = R1 - // R3/R4 determine how far from the treatment dot the labels are placed - , R3 = R1 + 8 / opts.scale - , R4 = R1 + 25 / opts.scale - ; - - return { - R1: R1 - , R2: R2 - , R3: R3 - , R4: R4 - , isNaN: isNaN(R1) || isNaN(R3) || isNaN(R3) + function rectTranslate (d) { + var top = 50; + if (d.eventType === 'Temporary Target') { + top = d.targetTop === d.targetBottom ? d.targetTop + rectHeight(d) : d.targetTop; + } + return 'translate(' + chart().xScale(new Date(d.mills)) + ',' + chart().yScale(utils.scaleMgdl(top)) + ')'; + } + // if already existing then transition each rect to its new position + treatRects.transition() + .attr('transform', rectTranslate); + + chart().focus.selectAll('.g-duration-rect').transition() + .attr('width', function (d) { + return chart().xScale(new Date(d.mills + times.mins(d.duration).msecs)) - chart().xScale(new Date(d.mills)); + }); + + chart().focus.selectAll('.g-duration-text').transition() + .attr('transform', function (d) { + return 'translate(' + (chart().xScale(new Date(d.mills + times.mins(d.duration).msecs)) - chart().xScale(new Date(d.mills)))/2 + ',' + 10 + ')'; + }); + + // if new rect then just display + var gs = treatRects.enter().append('g') + .attr('class','g-duration') + .attr('transform', rectTranslate) + .on('mouseover', function (d) { + client.tooltip.transition().duration(TOOLTIP_TRANS_MS).style('opacity', .9); + client.tooltip.html(d.isAnnouncement ? announcementTooltip(d) : treatmentTooltip(d)) + .style('left', tooltipLeft()) + .style('top', (d3.event.pageY + 15) + 'px'); + }) + .on('mouseout', hideTooltip); + + gs.append('rect') + .attr('class', 'g-duration-rect') + .attr('width', function (d) { + return chart().xScale(new Date(d.mills + times.mins(d.duration).msecs)) - chart().xScale(new Date(d.mills)); + }) + .attr('height', rectHeight) + .attr('rx', 5) + .attr('ry', 5) + .attr('opacity', .2) + .attr('fill', fillColor); + + gs.append('text') + .attr('class', 'g-duration-text') + .style('font-size', 15) + .attr('fill', 'white') + .attr('text-anchor', 'middle') + .attr('dy', '.35em') + .attr('transform', function (d) { + return 'translate(' + (chart().xScale(new Date(d.mills + times.mins(d.duration).msecs)) - chart().xScale(new Date(d.mills)))/2 + ',' + 10 + ')'; + }) + .text(function (d) { + if (d.eventType === 'Temporary Target') { + return ''; + } + return d.notes || d.eventType; + }); }; - } - - function prepareArc(treatment, radius) { - var arc_data = [ - // white carb half-circle on top - { 'element': '', 'color': 'white', 'start': -1.5708, 'end': 1.5708, 'inner': 0, 'outer': radius.R1 }, - { 'element': '', 'color': 'transparent', 'start': -1.5708, 'end': 1.5708, 'inner': radius.R2, 'outer': radius.R3 }, - // blue insulin half-circle on bottom - { 'element': '', 'color': '#0099ff', 'start': 1.5708, 'end': 4.7124, 'inner': 0, 'outer': radius.R1 }, - // these form a very short transparent arc along the bottom of an insulin treatment to position the label - // these used to be semicircles from 1.5708 to 4.7124, but that made the tooltip target too big - { 'element': '', 'color': 'transparent', 'start': 3.1400, 'end': 3.1432, 'inner': radius.R2, 'outer': radius.R3 }, - { 'element': '', 'color': 'transparent', 'start': 3.1400, 'end': 3.1432, 'inner': radius.R2, 'outer': radius.R4 } - ]; - - arc_data[0].outlineOnly = !treatment.carbs; - arc_data[2].outlineOnly = !treatment.insulin; - - if (treatment.carbs > 0) { - arc_data[1].element = Math.round(treatment.carbs) + ' g'; - } - if (treatment.foodType) { - arc_data[1].element = arc_data[1].element + " " + treatment.foodType; - } + renderer.addContextCircles = function addContextCircles ( ) { + // bind up the context chart data to an array of circles + var contextCircles = chart().context.selectAll('circle').data(client.entries); + + function prepareContextCircles(sel) { + var badData = []; + sel.attr('cx', function (d) { return chart().xScale2(new Date(d.mills)); }) + .attr('cy', function (d) { + var scaled = client.sbx.scaleEntry(d); + if (isNaN(scaled)) { + badData.push(d); + return chart().yScale2(utils.scaleMgdl(450)); + } else { + return chart().yScale2(scaled); + } + }) + .attr('fill', function (d) { return d.color; }) + .style('opacity', function (d) { return renderer.highlightBrushPoints(d) }) + .attr('stroke-width', function (d) { return d.type === 'mbg' ? 2 : 0; }) + .attr('stroke', function ( ) { return 'white'; }) + .attr('r', function (d) { return d.type === 'mbg' ? 4 : 2; }); + + if (badData.length > 0) { + console.warn('Bad Data: isNaN(sgv)', badData); + } - if (treatment.insulin > 0) { - arc_data[3].element = Math.round(treatment.insulin * 100) / 100 + ' U'; - } + return sel; + } - if (treatment.status) { - arc_data[4].element = translate(treatment.status); - } + // if already existing then transition each circle to its new position + prepareContextCircles(contextCircles.transition()); + + // if new circle then just display + prepareContextCircles(contextCircles.enter().append('circle')); - var arc = d3.svg.arc() - .innerRadius(function (d) { - return 5 * d.inner; - }) - .outerRadius(function (d) { - return 5 * d.outer; - }) - .endAngle(function (d) { - return d.start; - }) - .startAngle(function (d) { - return d.end; - }); - - return { - data: arc_data - , svg: arc + contextCircles.exit().remove(); }; - } - - function isInRect(x,y,rect) { - return !(x < rect.x || x > rect.x + rect.width || y < rect.y || y > rect.y + rect.height); - } - - function appendTreatments(treatment, arc) { - - function boluscalcTooltip (treatment) { - if (!treatment.boluscalc) { - return ''; - } - var html = '
      '; - html += (treatment.boluscalc.othercorrection ? ''+translate('Other correction')+': ' + parseFloat(treatment.boluscalc.othercorrection).toFixed(2) + 'U
      ' : ''); - html += (treatment.boluscalc.profile ? ''+translate('Profile used')+': ' + treatment.boluscalc.profile + '
      ' : ''); - if (treatment.boluscalc.foods && treatment.boluscalc.foods.length) { - html += ''; - for (var fi=0; fi'; - html += ''; - html += ''; - html += ''; + + function calcTreatmentRadius(treatment, opts, carbratio) { + var CR = treatment.CR || carbratio || 20; + var carbs = treatment.carbs || CR; + var insulin = treatment.insulin || 1; + var carbsOrInsulin = CR; + if ( treatment.carbs ) { + carbsOrInsulin = treatment.carbs; + } else if ( treatment.insulin ) { + carbsOrInsulin = treatment.insulin * CR; } - html += '
      ' + translate('Food') + '
      '+ (f.portion*f.portions).toFixed(1) + ' ' + f.unit + '('+ (f.carbs*f.portions).toFixed(1) + ' g)
      '; - } - return html; - } - function treatmentTooltip() { - client.tooltip.transition().duration(TOOLTIP_TRANS_MS).style('opacity', .9); - client.tooltip.html('' + translate('Time') + ': ' + client.formatTime(new Date(treatment.mills)) + '
      ' + '' + translate('Treatment type') + ': ' + translate(client.careportal.resolveEventName(treatment.eventType)) + '
      ' + - (treatment.carbs ? '' + translate('Carbs') + ': ' + treatment.carbs + '
      ' : '') + - (treatment.absorptionTime > 0 ? '' + translate('Absorption Time') + ': ' + (Math.round( treatment.absorptionTime / 60.0 * 10) / 10) + 'h' + '
      ' : '') + - (treatment.insulin ? '' + translate('Insulin') + ': ' + treatment.insulin + '
      ' : '') + - (treatment.enteredinsulin ? '' + translate('Combo Bolus') + ': ' + treatment.enteredinsulin + 'U, ' + treatment.splitNow + '% : ' + treatment.splitExt + '%, ' + translate('Duration') + ': ' + treatment.duration + '
      ' : '') + - (treatment.glucose ? '' + translate('BG') + ': ' + treatment.glucose + (treatment.glucoseType ? ' (' + translate(treatment.glucoseType) + ')' : '') + '
      ' : '') + - (treatment.enteredBy ? '' + translate('Entered By') + ': ' + treatment.enteredBy + '
      ' : '') + - (treatment.notes ? '' + translate('Notes') + ': ' + treatment.notes : '') + - boluscalcTooltip(treatment) - ) - .style('left', tooltipLeft()) - .style('top', (d3.event.pageY + 15) + 'px'); + // R1 determines the size of the treatment dot + var R1 = Math.sqrt(2*carbsOrInsulin) / opts.scale + , R2 = R1 + // R3/R4 determine how far from the treatment dot the labels are placed + , R3 = R1 + 8 / opts.scale + , R4 = R1 + 25 / opts.scale + ; + + return { + R1: R1 + , R2: R2 + , R3: R3 + , R4: R4 + , isNaN: isNaN(R1) || isNaN(R3) || isNaN(R3) + }; } - var newTime; - var deleteRect = { x: 0, y: 0, width: 0, height: 0 }; - var insulinRect = { x: 0, y: 0, width: 0, height: 0 }; - var carbsRect = { x: 0, y: 0, width: 0, height: 0 }; - var operation; - renderer.drag = d3.behavior.drag() - .on('dragstart', function() { - //console.log(treatment); - var windowWidth = $(client.tooltip).parent().parent().width(); - var left = d3.event.x + TOOLTIP_WIDTH < windowWidth ? d3.event.x : windowWidth - TOOLTIP_WIDTH - 10; - client.tooltip.transition().duration(TOOLTIP_TRANS_MS).style('opacity', .9) - .style('left', left + 'px') - .style('top', (d3.event.pageY ? d3.event.pageY + 15 : 40) + 'px'); - - deleteRect = { - x: 0, - y: 0, - width: 50, - height: chart().yScale(chart().yScale.domain()[0]) - }; - chart().drag.append('rect') - .attr({ - class:'drag-droparea', - x: deleteRect.x, - y: deleteRect.y, - width: deleteRect.width, - height: deleteRect.height, - fill: 'red', - opacity: 0.4, - rx: 10, - ry: 10 - }); - chart().drag.append('text') - .attr({ - class:'drag-droparea', - x: deleteRect.x + deleteRect.width / 2, - y: deleteRect.y + deleteRect.height / 2, - 'font-size': 15, - 'font-weight': 'bold', - fill: 'red', - 'text-anchor': 'middle', - dy: '.35em', - transform: 'rotate(-90 ' + (deleteRect.x + deleteRect.width / 2) + ',' + (deleteRect.y + deleteRect.height / 2) + ')' - }) - .text(translate('Remove')); - - if (treatment.insulin && treatment.carbs) { - carbsRect = { - x: 0, - y: 0, - width: chart().charts.attr('width'), - height: 50 - }; - insulinRect = { - x: 0, - y: chart().yScale(chart().yScale.domain()[0]) - 50, - width: chart().charts.attr('width'), - height: 50 - }; - chart().drag.append('rect') - .attr({ - class:'drag-droparea', - x: carbsRect.x, - y: carbsRect.y, - width: carbsRect.width, - height: carbsRect.height, - fill: 'white', - opacity: 0.4, - rx: 10, - ry: 10 - }); - chart().drag.append('text') - .attr({ - class:'drag-droparea', - x: carbsRect.x + carbsRect.width / 2, - y: carbsRect.y + carbsRect.height / 2, - 'font-size': 15, - 'font-weight': 'bold', - fill: 'white', - 'text-anchor': 'middle', - dy: '.35em' - }) - .text(translate('Move carbs')); - chart().drag.append('rect') - .attr({ - class:'drag-droparea', - x: insulinRect.x, - y: insulinRect.y, - width: insulinRect.width, - height: insulinRect.height, - fill: '#0099ff', - opacity: 0.4, - rx: 10, - ry: 10 - }); - chart().drag.append('text') - .attr({ - class:'drag-droparea', - x: insulinRect.x + insulinRect.width / 2, - y: insulinRect.y + insulinRect.height / 2, - 'font-size': 15, - 'font-weight': 'bold', - fill: '#0099ff', - 'text-anchor': 'middle', - dy: '.35em' - }) - .text(translate('Move insulin')); + function prepareArc(treatment, radius) { + var arc_data = [ + // white carb half-circle on top + { 'element': '', 'color': 'white', 'start': -1.5708, 'end': 1.5708, 'inner': 0, 'outer': radius.R1 }, + { 'element': '', 'color': 'transparent', 'start': -1.5708, 'end': 1.5708, 'inner': radius.R2, 'outer': radius.R3 }, + // blue insulin half-circle on bottom + { 'element': '', 'color': '#0099ff', 'start': 1.5708, 'end': 4.7124, 'inner': 0, 'outer': radius.R1 }, + // these form a very short transparent arc along the bottom of an insulin treatment to position the label + // these used to be semicircles from 1.5708 to 4.7124, but that made the tooltip target too big + { 'element': '', 'color': 'transparent', 'start': 3.1400, 'end': 3.1432, 'inner': radius.R2, 'outer': radius.R3 }, + { 'element': '', 'color': 'transparent', 'start': 3.1400, 'end': 3.1432, 'inner': radius.R2, 'outer': radius.R4 } + ]; + + arc_data[0].outlineOnly = !treatment.carbs; + arc_data[2].outlineOnly = !treatment.insulin; + + if (treatment.carbs > 0) { + arc_data[1].element = Math.round(treatment.carbs) + ' g'; } - chart().basals.attr('display','none'); - - operation = 'Move'; - }) - .on('drag', function() { - //console.log(d3.event); - client.tooltip.transition().style('opacity', .9); - var x = Math.min(Math.max(0, d3.event.x), chart().charts.attr('width')); - var y = Math.min(Math.max(0, d3.event.y), chart().focusHeight); - - operation = 'Move'; - if (isInRect(x, y, deleteRect) && isInRect(x, y, insulinRect)) { - operation = 'Remove insulin'; - } else if (isInRect(x, y, deleteRect) && isInRect(x, y, carbsRect)) { - operation = 'Remove carbs'; - } else if (isInRect(x, y, deleteRect)) { - operation = 'Remove'; - } else if (isInRect(x, y, insulinRect)) { - operation = 'Move insulin'; - } else if (isInRect(x, y, carbsRect)) { - operation = 'Move carbs'; + if (treatment.foodType) { + arc_data[1].element = arc_data[1].element + " " + treatment.foodType; } - newTime = new Date(chart().xScale.invert(x)); - var minDiff = times.msecs(newTime.getTime() - treatment.mills).mins.toFixed(0); - client.tooltip.html( - '' + translate('Operation') + ': ' + translate(operation) + '
      ' - + '' + translate('New time') + ': ' + newTime.toLocaleTimeString() + '
      ' - + '' + translate('Difference') + ': ' + (minDiff > 0 ? '+' : '') + minDiff + ' ' + translate('mins') - ); - - chart().drag.selectAll('.arrow').remove(); - chart().drag.append('line') - .attr({ - 'class':'arrow', - 'marker-end':'url(#arrow)', - 'x1': chart().xScale(new Date(treatment.mills)), - 'y1': chart().yScale(client.sbx.scaleEntry(treatment)), - 'x2': x, - 'y2': y, - 'stroke-width': 2, - 'stroke': 'white' - }); - - }) - .on('dragend', function() { - var newTreatment; - chart().drag.selectAll('.drag-droparea').remove(); - hideTooltip(); - switch (operation) { - case 'Move': - if (window.confirm(translate('Change treatment time to %1 ?', { params: [newTime.toLocaleTimeString()] } ))) { - client.socket.emit( - 'dbUpdate', - { - collection: 'treatments', - _id: treatment._id, - data: { created_at: newTime.toISOString() } - }, - function callback(result) { - console.log(result); - chart().drag.selectAll('.arrow').transition().duration(5000).style('opacity', 0).remove(); - } - ); - } else { - chart().drag.selectAll('.arrow').remove(); - } - break; - case 'Remove insulin': - if (window.confirm(translate('Remove insulin from treatment ?'))) { - client.socket.emit( - 'dbUpdateUnset', - { - collection: 'treatments', - _id: treatment._id, - data: { insulin: 1 } - }, - function callback(result) { - console.log(result); - chart().drag.selectAll('.arrow').transition().duration(5000).style('opacity', 0).remove(); - } - ); - } else { - chart().drag.selectAll('.arrow').remove(); - } - break; - case 'Remove carbs': - if (window.confirm(translate('Remove carbs from treatment ?'))) { - client.socket.emit( - 'dbUpdateUnset', - { - collection: 'treatments', - _id: treatment._id, - data: { carbs: 1 } - }, - function callback(result) { - console.log(result); - chart().drag.selectAll('.arrow').transition().duration(5000).style('opacity', 0).remove(); - } - ); - } else { - chart().drag.selectAll('.arrow').remove(); + if ( treatment.insulin > 0) { + // remove leading zeros to avoid overlap with adjacent boluses + var units = Math.round(treatment.insulin * 100)/100; + arc_data[3].element = (units+"").replace(/^0/,""); + } + + if (treatment.status) { + arc_data[4].element = translate(treatment.status); + } + + var arc = d3.svg.arc() + .innerRadius(function (d) { + return 5 * d.inner; + }) + .outerRadius(function (d) { + return 5 * d.outer; + }) + .endAngle(function (d) { + return d.start; + }) + .startAngle(function (d) { + return d.end; + }); + + return { + data: arc_data + , svg: arc + }; + } + + function isInRect(x,y,rect) { + return !(x < rect.x || x > rect.x + rect.width || y < rect.y || y > rect.y + rect.height); + } + + function appendTreatments(treatment, arc) { + + function boluscalcTooltip (treatment) { + if (!treatment.boluscalc) { + return ''; } - break; - case 'Remove': - if (window.confirm(translate('Remove treatment ?'))) { - client.socket.emit( - 'dbRemove', - { - collection: 'treatments', - _id: treatment._id - }, - function callback(result) { - console.log(result); - chart().drag.selectAll('.arrow').transition().duration(5000).style('opacity', 0).remove(); + var html = '
      '; + html += (treatment.boluscalc.othercorrection ? ''+translate('Other correction')+': ' + parseFloat(treatment.boluscalc.othercorrection).toFixed(2) + 'U
      ' : ''); + html += (treatment.boluscalc.profile ? ''+translate('Profile used')+': ' + treatment.boluscalc.profile + '
      ' : ''); + if (treatment.boluscalc.foods && treatment.boluscalc.foods.length) { + html += ''; + for (var fi=0; fi'; + html += ''; + html += ''; + html += ''; } - ); - } else { - chart().drag.selectAll('.arrow').remove(); + html += '
      ' + translate('Food') + '
      '+ (f.portion*f.portions).toFixed(1) + ' ' + f.unit + '('+ (f.carbs*f.portions).toFixed(1) + ' g)
      '; } - break; - case 'Move insulin': - if (window.confirm(translate('Change insulin time to %1 ?', { params: [newTime.toLocaleTimeString()] } ))) { - client.socket.emit( - 'dbUpdateUnset', - { - collection: 'treatments', - _id: treatment._id, - data: { insulin: 1 } - } - ); - newTreatment = _.cloneDeep(treatment); - delete newTreatment._id; - delete newTreatment.NSCLIENT_ID; - delete newTreatment.carbs; - newTreatment.created_at = newTime.toISOString(); - client.socket.emit( - 'dbAdd', - { - collection: 'treatments', - data: newTreatment - }, - function callback(result) { - console.log(result); - chart().drag.selectAll('.arrow').transition().duration(5000).style('opacity', 0).remove(); + return html; + } + + function treatmentTooltip() { + client.tooltip.transition().duration(TOOLTIP_TRANS_MS).style('opacity', .9); + client.tooltip.html('' + translate('Time') + ': ' + client.formatTime(new Date(treatment.mills)) + '
      ' + '' + translate('Treatment type') + ': ' + translate(client.careportal.resolveEventName(treatment.eventType)) + '
      ' + + (treatment.carbs ? '' + translate('Carbs') + ': ' + treatment.carbs + '
      ' : '') + + (treatment.absorptionTime > 0 ? '' + translate('Absorption Time') + ': ' + (Math.round( treatment.absorptionTime / 60.0 * 10) / 10) + 'h' + '
      ' : '') + + (treatment.insulin ? '' + translate('Insulin') + ': ' + treatment.insulin + '
      ' : '') + + (treatment.enteredinsulin ? '' + translate('Combo Bolus') + ': ' + treatment.enteredinsulin + 'U, ' + treatment.splitNow + '% : ' + treatment.splitExt + '%, ' + translate('Duration') + ': ' + treatment.duration + '
      ' : '') + + (treatment.glucose ? '' + translate('BG') + ': ' + treatment.glucose + (treatment.glucoseType ? ' (' + translate(treatment.glucoseType) + ')' : '') + '
      ' : '') + + (treatment.enteredBy ? '' + translate('Entered By') + ': ' + treatment.enteredBy + '
      ' : '') + + (treatment.notes ? '' + translate('Notes') + ': ' + treatment.notes : '') + + boluscalcTooltip(treatment) + ) + .style('left', tooltipLeft()) + .style('top', (d3.event.pageY + 15) + 'px'); + } + + var newTime; + var deleteRect = { x: 0, y: 0, width: 0, height: 0 }; + var insulinRect = { x: 0, y: 0, width: 0, height: 0 }; + var carbsRect = { x: 0, y: 0, width: 0, height: 0 }; + var operation; + renderer.drag = d3.behavior.drag() + .on('dragstart', function() { + //console.log(treatment); + var windowWidth = $(client.tooltip).parent().parent().width(); + var left = d3.event.x + TOOLTIP_WIDTH < windowWidth ? d3.event.x : windowWidth - TOOLTIP_WIDTH - 10; + client.tooltip.transition().duration(TOOLTIP_TRANS_MS).style('opacity', .9) + .style('left', left + 'px') + .style('top', (d3.event.pageY ? d3.event.pageY + 15 : 40) + 'px'); + + deleteRect = { + x: 0, + y: 0, + width: 50, + height: chart().yScale(chart().yScale.domain()[0]) + }; + chart().drag.append('rect') + .attr({ + class:'drag-droparea', + x: deleteRect.x, + y: deleteRect.y, + width: deleteRect.width, + height: deleteRect.height, + fill: 'red', + opacity: 0.4, + rx: 10, + ry: 10 + }); + chart().drag.append('text') + .attr({ + class:'drag-droparea', + x: deleteRect.x + deleteRect.width / 2, + y: deleteRect.y + deleteRect.height / 2, + 'font-size': 15, + 'font-weight': 'bold', + fill: 'red', + 'text-anchor': 'middle', + dy: '.35em', + transform: 'rotate(-90 ' + (deleteRect.x + deleteRect.width / 2) + ',' + (deleteRect.y + deleteRect.height / 2) + ')' + }) + .text(translate('Remove')); + + if (treatment.insulin && treatment.carbs) { + carbsRect = { + x: 0, + y: 0, + width: chart().charts.attr('width'), + height: 50 + }; + insulinRect = { + x: 0, + y: chart().yScale(chart().yScale.domain()[0]) - 50, + width: chart().charts.attr('width'), + height: 50 + }; + chart().drag.append('rect') + .attr({ + class:'drag-droparea', + x: carbsRect.x, + y: carbsRect.y, + width: carbsRect.width, + height: carbsRect.height, + fill: 'white', + opacity: 0.4, + rx: 10, + ry: 10 + }); + chart().drag.append('text') + .attr({ + class:'drag-droparea', + x: carbsRect.x + carbsRect.width / 2, + y: carbsRect.y + carbsRect.height / 2, + 'font-size': 15, + 'font-weight': 'bold', + fill: 'white', + 'text-anchor': 'middle', + dy: '.35em' + }) + .text(translate('Move carbs')); + chart().drag.append('rect') + .attr({ + class:'drag-droparea', + x: insulinRect.x, + y: insulinRect.y, + width: insulinRect.width, + height: insulinRect.height, + fill: '#0099ff', + opacity: 0.4, + rx: 10, + ry: 10 + }); + chart().drag.append('text') + .attr({ + class:'drag-droparea', + x: insulinRect.x + insulinRect.width / 2, + y: insulinRect.y + insulinRect.height / 2, + 'font-size': 15, + 'font-weight': 'bold', + fill: '#0099ff', + 'text-anchor': 'middle', + dy: '.35em' + }) + .text(translate('Move insulin')); } - ); - } else { - chart().drag.selectAll('.arrow').remove(); - } - break; - case 'Move carbs': - if (window.confirm(translate('Change carbs time to %1 ?', { params: [newTime.toLocaleTimeString()] } ))) { - client.socket.emit( - 'dbUpdateUnset', - { - collection: 'treatments', - _id: treatment._id, - data: { carbs: 1 } + + chart().basals.attr('display','none'); + + operation = 'Move'; + }) + .on('drag', function() { + //console.log(d3.event); + client.tooltip.transition().style('opacity', .9); + var x = Math.min(Math.max(0, d3.event.x), chart().charts.attr('width')); + var y = Math.min(Math.max(0, d3.event.y), chart().focusHeight); + + operation = 'Move'; + if (isInRect(x, y, deleteRect) && isInRect(x, y, insulinRect)) { + operation = 'Remove insulin'; + } else if (isInRect(x, y, deleteRect) && isInRect(x, y, carbsRect)) { + operation = 'Remove carbs'; + } else if (isInRect(x, y, deleteRect)) { + operation = 'Remove'; + } else if (isInRect(x, y, insulinRect)) { + operation = 'Move insulin'; + } else if (isInRect(x, y, carbsRect)) { + operation = 'Move carbs'; } - ); - newTreatment = _.cloneDeep(treatment); - delete newTreatment._id; - delete newTreatment.NSCLIENT_ID; - delete newTreatment.insulin; - newTreatment.created_at = newTime.toISOString(); - client.socket.emit( - 'dbAdd', - { - collection: 'treatments', - data: newTreatment - }, - function callback(result) { - console.log(result); - chart().drag.selectAll('.arrow').transition().duration(5000).style('opacity', 0).remove(); + + newTime = new Date(chart().xScale.invert(x)); + var minDiff = times.msecs(newTime.getTime() - treatment.mills).mins.toFixed(0); + client.tooltip.html( + '' + translate('Operation') + ': ' + translate(operation) + '
      ' + + '' + translate('New time') + ': ' + newTime.toLocaleTimeString() + '
      ' + + '' + translate('Difference') + ': ' + (minDiff > 0 ? '+' : '') + minDiff + ' ' + translate('mins') + ); + + chart().drag.selectAll('.arrow').remove(); + chart().drag.append('line') + .attr({ + 'class':'arrow', + 'marker-end':'url(#arrow)', + 'x1': chart().xScale(new Date(treatment.mills)), + 'y1': chart().yScale(client.sbx.scaleEntry(treatment)), + 'x2': x, + 'y2': y, + 'stroke-width': 2, + 'stroke': 'white' + }); + + }) + .on('dragend', function() { + var newTreatment; + chart().drag.selectAll('.drag-droparea').remove(); + hideTooltip(); + switch (operation) { + case 'Move': + if (window.confirm(translate('Change treatment time to %1 ?', { params: [newTime.toLocaleTimeString()] } ))) { + client.socket.emit( + 'dbUpdate', + { + collection: 'treatments', + _id: treatment._id, + data: { created_at: newTime.toISOString() } + }, + function callback(result) { + console.log(result); + chart().drag.selectAll('.arrow').transition().duration(5000).style('opacity', 0).remove(); + } + ); + } else { + chart().drag.selectAll('.arrow').remove(); + } + break; + case 'Remove insulin': + if (window.confirm(translate('Remove insulin from treatment ?'))) { + client.socket.emit( + 'dbUpdateUnset', + { + collection: 'treatments', + _id: treatment._id, + data: { insulin: 1 } + }, + function callback(result) { + console.log(result); + chart().drag.selectAll('.arrow').transition().duration(5000).style('opacity', 0).remove(); + } + ); + } else { + chart().drag.selectAll('.arrow').remove(); + } + break; + case 'Remove carbs': + if (window.confirm(translate('Remove carbs from treatment ?'))) { + client.socket.emit( + 'dbUpdateUnset', + { + collection: 'treatments', + _id: treatment._id, + data: { carbs: 1 } + }, + function callback(result) { + console.log(result); + chart().drag.selectAll('.arrow').transition().duration(5000).style('opacity', 0).remove(); + } + ); + } else { + chart().drag.selectAll('.arrow').remove(); + } + break; + case 'Remove': + if (window.confirm(translate('Remove treatment ?'))) { + client.socket.emit( + 'dbRemove', + { + collection: 'treatments', + _id: treatment._id + }, + function callback(result) { + console.log(result); + chart().drag.selectAll('.arrow').transition().duration(5000).style('opacity', 0).remove(); + } + ); + } else { + chart().drag.selectAll('.arrow').remove(); + } + break; + case 'Move insulin': + if (window.confirm(translate('Change insulin time to %1 ?', { params: [newTime.toLocaleTimeString()] } ))) { + client.socket.emit( + 'dbUpdateUnset', + { + collection: 'treatments', + _id: treatment._id, + data: { insulin: 1 } + } + ); + newTreatment = _.cloneDeep(treatment); + delete newTreatment._id; + delete newTreatment.NSCLIENT_ID; + delete newTreatment.carbs; + newTreatment.created_at = newTime.toISOString(); + client.socket.emit( + 'dbAdd', + { + collection: 'treatments', + data: newTreatment + }, + function callback(result) { + console.log(result); + chart().drag.selectAll('.arrow').transition().duration(5000).style('opacity', 0).remove(); + } + ); + } else { + chart().drag.selectAll('.arrow').remove(); + } + break; + case 'Move carbs': + if (window.confirm(translate('Change carbs time to %1 ?', { params: [newTime.toLocaleTimeString()] } ))) { + client.socket.emit( + 'dbUpdateUnset', + { + collection: 'treatments', + _id: treatment._id, + data: { carbs: 1 } + } + ); + newTreatment = _.cloneDeep(treatment); + delete newTreatment._id; + delete newTreatment.NSCLIENT_ID; + delete newTreatment.insulin; + newTreatment.created_at = newTime.toISOString(); + client.socket.emit( + 'dbAdd', + { + collection: 'treatments', + data: newTreatment + }, + function callback(result) { + console.log(result); + chart().drag.selectAll('.arrow').transition().duration(5000).style('opacity', 0).remove(); + } + ); + } else { + chart().drag.selectAll('.arrow').remove(); + } + break; } - ); - } else { - chart().drag.selectAll('.arrow').remove(); - } - break; + chart().basals.attr('display',''); + }); + + var treatmentDots = chart().focus.selectAll('treatment-insulincarbs') + .data(arc.data) + .enter() + .append('g') + .attr('class', 'draggable-treatment') + .attr('transform', 'translate(' + chart().xScale(new Date(treatment.mills)) + ', ' + chart().yScale(client.sbx.scaleEntry(treatment)) + ')') + .on('mouseover', treatmentTooltip) + .on('mouseout', hideTooltip); + if (client.editMode) { + treatmentDots + .style('cursor', 'move') + .call(renderer.drag); } - chart().basals.attr('display',''); - }); - - var treatmentDots = chart().focus.selectAll('treatment-insulincarbs') - .data(arc.data) - .enter() - .append('g') - .attr('class', 'draggable-treatment') - .attr('transform', 'translate(' + chart().xScale(new Date(treatment.mills)) + ', ' + chart().yScale(client.sbx.scaleEntry(treatment)) + ')') - .on('mouseover', treatmentTooltip) - .on('mouseout', hideTooltip); - if (client.editMode) { - treatmentDots - .style('cursor', 'move') - .call(renderer.drag); - } - treatmentDots.append('path') - .attr('class', 'path') - .attr('fill', function (d) { - return d.outlineOnly ? 'transparent' : d.color; - }) - .attr('stroke-width', function (d) { - return d.outlineOnly ? 1 : 0; - }) - .attr('stroke', function (d) { - return d.color; - }) - .attr('id', function (d, i) { - return 's' + i; - }) - .attr('d', arc.svg); - - return treatmentDots; - } - - function appendLabels(treatmentDots, arc, opts) { - // labels for carbs and insulin - if (opts.showLabels) { - var label = treatmentDots.append('g') - .attr('class', 'path') - .attr('id', 'label') - .style('fill', 'white'); - - label.append('text') - // reduce the treatment label font size to make it readable with SMB - .style('font-size', 30 / opts.scale) - .style('text-shadow', '0px 0px 10px rgba(0, 0, 0, 1)') - .attr('text-anchor', 'middle') - .attr('dy', '.35em') - .attr('transform', function (d) { - d.outerRadius = d.outerRadius * 2.1; - d.innerRadius = d.outerRadius * 2.1; - return 'translate(' + arc.svg.centroid(d) + ')'; - }) - .text(function (d) { - return d.element; - }); - } - } - - renderer.drawTreatments = function drawTreatments(client) { - // add treatment bubbles - _.forEach(client.ddata.treatments, function eachTreatment (d) { - renderer.drawTreatment(d, { - scale: renderer.bubbleScale() - , showLabels: true - }, client.sbx.data.profile.getCarbRatio(new Date())); - }); - }; - - renderer.drawTreatment = function drawTreatment(treatment, opts, carbratio) { - if (!treatment.carbs && !treatment.insulin) { - return; - } + treatmentDots.append('path') + .attr('class', 'path') + .attr('fill', function (d) { + return d.outlineOnly ? 'transparent' : d.color; + }) + .attr('stroke-width', function (d) { + return d.outlineOnly ? 1 : 0; + }) + .attr('stroke', function (d) { + return d.color; + }) + .attr('id', function (d, i) { + return 's' + i; + }) + .attr('d', arc.svg); - //when the tests are run window isn't available - var innerWidth = window && window.innerWidth || -1; - // don't render the treatment if it's not visible - if (Math.abs(chart().xScale(new Date(treatment.mills))) > innerWidth) { - return; + return treatmentDots; } - var radius = calcTreatmentRadius(treatment, opts, carbratio); - if (radius.isNaN) { - console.warn('Bad Data: Found isNaN value in treatment', treatment); - return; + function appendLabels(treatmentDots, arc, opts) { + // labels for carbs and insulin + if (opts.showLabels) { + var label = treatmentDots.append('g') + .attr('class', 'path') + .attr('id', 'label') + .style('fill', 'white'); + + label.append('text') + // reduce the treatment label font size to make it readable with SMB + .style('font-size', 30 / opts.scale) + .style('text-shadow', '0px 0px 10px rgba(0, 0, 0, 1)') + .attr('text-anchor', 'middle') + .attr('dy', '.35em') + .attr('transform', function (d) { + d.outerRadius = d.outerRadius * 2.1; + d.innerRadius = d.outerRadius * 2.1; + return 'translate(' + arc.svg.centroid(d) + ')'; + }) + .text(function (d) { + return d.element; + }); + } } - var arc = prepareArc(treatment, radius); - var treatmentDots = appendTreatments(treatment, arc); - appendLabels(treatmentDots, arc, opts); - }; - - renderer.addBasals = function addBasals (client) { - - var mode = client.settings.extendedSettings.basal.render; - var profile = client.sbx.data.profile; - var linedata = []; - var notemplinedata = []; - var basalareadata = []; - var tempbasalareadata = []; - var comboareadata = []; - var from = chart().brush.extent()[0].getTime(); - var to = Math.max(chart().brush.extent()[1].getTime(), client.sbx.time) + client.forecastTime; - - var date = from; - var lastbasal = 0; - - if (!profile.activeProfileToTime(from)) { - window.alert(translate('Wrong profile setting.\nNo profile defined to displayed time.\nRedirecting to profile editor to create new profile.')); - try { - window.location.href = '/profile'; - } catch (err) { - //doesn't work when running tests, so catch and ignore - } - return; - } + renderer.drawTreatments = function drawTreatments(client) { + // add treatment bubbles + _.forEach(client.ddata.treatments, function eachTreatment (d) { + renderer.drawTreatment(d, { + scale: renderer.bubbleScale() + , showLabels: true + }, client.sbx.data.profile.getCarbRatio(new Date())); + }); + }; - while (date <= to) { - var basalvalue = profile.getTempBasal(date); - if (!_.isEqual(lastbasal, basalvalue)) { - linedata.push( { d: date, b: basalvalue.totalbasal } ); - notemplinedata.push( { d: date, b: basalvalue.basal } ); - if (basalvalue.combobolustreatment && basalvalue.combobolustreatment.relative) { - tempbasalareadata.push( { d: date, b: basalvalue.tempbasal } ); - basalareadata.push( { d: date, b: 0 } ); - comboareadata.push( { d: date, b: basalvalue.totalbasal } ); - } else if (basalvalue.treatment) { - tempbasalareadata.push( { d: date, b: basalvalue.totalbasal } ); - basalareadata.push( { d: date, b: 0 } ); - comboareadata.push( { d: date, b: 0 } ); - } else { - tempbasalareadata.push( { d: date, b: 0 } ); - basalareadata.push( { d: date, b: basalvalue.totalbasal } ); - comboareadata.push( { d: date, b: 0 } ); + renderer.drawTreatment = function drawTreatment(treatment, opts, carbratio) { + if (!treatment.carbs && !treatment.insulin) { + return; } - } - lastbasal = basalvalue; - date += times.mins(1).msecs; - } - var toTempBasal = profile.getTempBasal(to); - - linedata.push( { d: to, b: toTempBasal.totalbasal } ); - notemplinedata.push( { d: to, b: toTempBasal.basal } ); - basalareadata.push( { d: to, b: toTempBasal.basal } ); - tempbasalareadata.push( { d: to, b: toTempBasal.totalbasal } ); - comboareadata.push( { d: to, b: toTempBasal.totalbasal } ); - - var max_linedata = d3.max(linedata, function (d) { return d.b; }); - var max_notemplinedata = d3.max(notemplinedata, function (d) { return d.b; }); - var max = Math.max(max_linedata, max_notemplinedata) * ('icicle' === mode ? 1 : 1.1 ); - chart().maxBasalValue = max; - chart().yScaleBasals.domain('icicle' === mode ? [0, max] : [max, 0]); - - chart().basals.selectAll('g').remove(); - chart().basals.selectAll('.basalline').remove().data(linedata); - chart().basals.selectAll('.notempline').remove().data(notemplinedata); - chart().basals.selectAll('.basalarea').remove().data(basalareadata); - chart().basals.selectAll('.tempbasalarea').remove().data(tempbasalareadata); - chart().basals.selectAll('.comboarea').remove().data(comboareadata); - - var valueline = d3.svg.line() - .interpolate('step-after') - .x(function(d) { return chart().xScaleBasals(d.d); }) - .y(function(d) { return chart().yScaleBasals(d.b); }); - - var area = d3.svg.area() - .interpolate('step-after') - .x(function(d) { return chart().xScaleBasals(d.d); }) - .y0(chart().yScaleBasals(0)) - .y1(function(d) { return chart().yScaleBasals(d.b); }); - - var g = chart().basals.append('g'); - - g.append('path') - .attr('class', 'line basalline') - .attr('stroke', '#0099ff') - .attr('stroke-width', 1) - .attr('fill', 'none') - .attr('d', valueline(linedata)) - - g.append('path') - .attr('class', 'line notempline') - .attr('stroke', '#0099ff') - .attr('stroke-width', 1) - .attr('stroke-dasharray', ('3, 3')) - .attr('fill', 'none') - .attr('d', valueline(notemplinedata)) - - g.append('path') - .attr('class', 'area basalarea') - .datum(basalareadata) - .attr('fill', '#0099ff') - .attr('fill-opacity', .1) - .attr('stroke-width', 0) - .attr('d', area); - - g.append('path') - .attr('class', 'area tempbasalarea') - .datum(tempbasalareadata) - .attr('fill', '#0099ff') - .attr('fill-opacity', .2) - .attr('stroke-width', 1) - .attr('d', area); - - g.append('path') - .attr('class', 'area comboarea') - .datum(comboareadata) - .attr('fill', 'url(#hash)') - .attr('fill-opacity', .2) - .attr('stroke-width', 1) - .attr('d', area); - - _.forEach(client.ddata.tempbasalTreatments, function eachTemp (t) { - // only if basal and focus interval overlap and there is a chance to fit - if (t.duration && t.mills < to && t.mills + times.mins(t.duration).msecs > from) { - var text = g.append('text') - .attr('class', 'tempbasaltext') - .style('font-size', 15) - .attr('fill', '#0099ff') - .attr('text-anchor', 'middle') - .attr('dy', '.35em') - .attr('x', chart().xScaleBasals((Math.max(t.mills, from) + Math.min(t.mills + times.mins(t.duration).msecs, to))/2)) - .attr('y', 10) - .text((t.percent ? (t.percent > 0 ? '+' : '') + t.percent + '%' : '') + (isNaN(t.absolute) ? '' : Number(t.absolute).toFixed(2) + 'U') + (t.relative ? 'C: +' + t.relative + 'U' : '')); - // better hide if not fit - if (text.node().getBBox().width > chart().xScaleBasals(t.mills + times.mins(t.duration).msecs) - chart().xScaleBasals(t.mills)) { - text.attr('display', 'none'); + //when the tests are run window isn't available + var innerWidth = window && window.innerWidth || -1; + // don't render the treatment if it's not visible + if (Math.abs(chart().xScale(new Date(treatment.mills))) > innerWidth) { + return; } - } - }); - client.chart.basals.attr('display', !mode || 'none' === mode ? 'none' : ''); - }; + var radius = calcTreatmentRadius(treatment, opts, carbratio); + if (radius.isNaN) { + console.warn('Bad Data: Found isNaN value in treatment', treatment); + return; + } - renderer.addTreatmentProfiles = function addTreatmentProfiles (client) { - if (client.profilefunctions.listBasalProfiles().length < 2) { - return; // do not visualize profiles if there is only one - } + var arc = prepareArc(treatment, radius); + var treatmentDots = appendTreatments(treatment, arc); + appendLabels(treatmentDots, arc, opts); + }; - function profileTooltip (d) { - return ''+translate('Time')+': ' + client.formatTime(new Date(d.mills)) + '
      ' + - (d.eventType ? ''+translate('Treatment type')+': ' + translate(client.careportal.resolveEventName(d.eventType)) + '
      ' : '') + - (d.endprofile ? ''+translate('End of profile')+': ' + d.endprofile + '
      ' : '') + - (d.profile ? ''+translate('Profile')+': ' + d.profile + '
      ' : '') + - (d.duration ? ''+translate('Duration')+': ' + d.duration + translate('mins') + '
      ' : '') + - (d.enteredBy ? ''+translate('Entered By')+': ' + d.enteredBy + '
      ' : '') + - (d.notes ? ''+translate('Notes')+': ' + d.notes : ''); - } + renderer.addBasals = function addBasals (client) { + + var mode = client.settings.extendedSettings.basal.render; + var profile = client.sbx.data.profile; + var linedata = []; + var notemplinedata = []; + var basalareadata = []; + var tempbasalareadata = []; + var comboareadata = []; + var from = chart().brush.extent()[0].getTime(); + var to = Math.max(chart().brush.extent()[1].getTime(), client.sbx.time) + client.forecastTime; + + var date = from; + var lastbasal = 0; + + if (!profile.activeProfileToTime(from)) { + window.alert(translate('Wrong profile setting.\nNo profile defined to displayed time.\nRedirecting to profile editor to create new profile.')); + try { + window.location.href = '/profile'; + } catch (err) { + //doesn't work when running tests, so catch and ignore + } + return; + } + + while (date <= to) { + var basalvalue = profile.getTempBasal(date); + if (!_.isEqual(lastbasal, basalvalue)) { + linedata.push( { d: date, b: basalvalue.totalbasal } ); + notemplinedata.push( { d: date, b: basalvalue.basal } ); + if (basalvalue.combobolustreatment && basalvalue.combobolustreatment.relative) { + tempbasalareadata.push( { d: date, b: basalvalue.tempbasal } ); + basalareadata.push( { d: date, b: 0 } ); + comboareadata.push( { d: date, b: basalvalue.totalbasal } ); + } else if (basalvalue.treatment) { + tempbasalareadata.push( { d: date, b: basalvalue.totalbasal } ); + basalareadata.push( { d: date, b: 0 } ); + comboareadata.push( { d: date, b: 0 } ); + } else { + tempbasalareadata.push( { d: date, b: 0 } ); + basalareadata.push( { d: date, b: basalvalue.totalbasal } ); + comboareadata.push( { d: date, b: 0 } ); + } + } + lastbasal = basalvalue; + date += times.mins(1).msecs; + } + + var toTempBasal = profile.getTempBasal(to); + + linedata.push( { d: to, b: toTempBasal.totalbasal } ); + notemplinedata.push( { d: to, b: toTempBasal.basal } ); + basalareadata.push( { d: to, b: toTempBasal.basal } ); + tempbasalareadata.push( { d: to, b: toTempBasal.totalbasal } ); + comboareadata.push( { d: to, b: toTempBasal.totalbasal } ); + + var max_linedata = d3.max(linedata, function (d) { return d.b; }); + var max_notemplinedata = d3.max(notemplinedata, function (d) { return d.b; }); + var max = Math.max(max_linedata, max_notemplinedata) * ('icicle' === mode ? 1 : 1.1 ); + chart().maxBasalValue = max; + chart().yScaleBasals.domain('icicle' === mode ? [0, max] : [max, 0]); + + chart().basals.selectAll('g').remove(); + chart().basals.selectAll('.basalline').remove().data(linedata); + chart().basals.selectAll('.notempline').remove().data(notemplinedata); + chart().basals.selectAll('.basalarea').remove().data(basalareadata); + chart().basals.selectAll('.tempbasalarea').remove().data(tempbasalareadata); + chart().basals.selectAll('.comboarea').remove().data(comboareadata); + + var valueline = d3.svg.line() + .interpolate('step-after') + .x(function(d) { return chart().xScaleBasals(d.d); }) + .y(function(d) { return chart().yScaleBasals(d.b); }); + + var area = d3.svg.area() + .interpolate('step-after') + .x(function(d) { return chart().xScaleBasals(d.d); }) + .y0(chart().yScaleBasals(0)) + .y1(function(d) { return chart().yScaleBasals(d.b); }); + + var g = chart().basals.append('g'); + + g.append('path') + .attr('class', 'line basalline') + .attr('stroke', '#0099ff') + .attr('stroke-width', 1) + .attr('fill', 'none') + .attr('d', valueline(linedata)) + + g.append('path') + .attr('class', 'line notempline') + .attr('stroke', '#0099ff') + .attr('stroke-width', 1) + .attr('stroke-dasharray', ('3, 3')) + .attr('fill', 'none') + .attr('d', valueline(notemplinedata)) + + g.append('path') + .attr('class', 'area basalarea') + .datum(basalareadata) + .attr('fill', '#0099ff') + .attr('fill-opacity', .1) + .attr('stroke-width', 0) + .attr('d', area); + + g.append('path') + .attr('class', 'area tempbasalarea') + .datum(tempbasalareadata) + .attr('fill', '#0099ff') + .attr('fill-opacity', .2) + .attr('stroke-width', 1) + .attr('d', area); + + g.append('path') + .attr('class', 'area comboarea') + .datum(comboareadata) + .attr('fill', 'url(#hash)') + .attr('fill-opacity', .2) + .attr('stroke-width', 1) + .attr('d', area); + + _.forEach(client.ddata.tempbasalTreatments, function eachTemp (t) { + // only if basal and focus interval overlap and there is a chance to fit + if (t.duration && t.mills < to && t.mills + times.mins(t.duration).msecs > from) { + var text = g.append('text') + .attr('class', 'tempbasaltext') + .style('font-size', 15) + .attr('fill', '#0099ff') + .attr('text-anchor', 'middle') + .attr('dy', '.35em') + .attr('x', chart().xScaleBasals((Math.max(t.mills, from) + Math.min(t.mills + times.mins(t.duration).msecs, to))/2)) + .attr('y', 10) + .text((t.percent ? (t.percent > 0 ? '+' : '') + t.percent + '%' : '') + (isNaN(t.absolute) ? '' : Number(t.absolute).toFixed(2) + 'U') + (t.relative ? 'C: +' + t.relative + 'U' : '')); + // better hide if not fit + if (text.node().getBBox().width > chart().xScaleBasals(t.mills + times.mins(t.duration).msecs) - chart().xScaleBasals(t.mills)) { + text.attr('display', 'none'); + } + } + }); + + client.chart.basals.attr('display', !mode || 'none' === mode ? 'none' : ''); + }; + + renderer.addTreatmentProfiles = function addTreatmentProfiles (client) { + if (client.profilefunctions.listBasalProfiles().length < 2) { + return; // do not visualize profiles if there is only one + } - // calculate position of profile on left side - var from = chart().brush.extent()[0].getTime(); - var to = chart().brush.extent()[1].getTime(); - var mult = (to-from) / times.hours(24).msecs; - from += times.mins(20 * mult).msecs; - - var mode = client.settings.extendedSettings.basal.render; - var data = client.ddata.profileTreatments.slice(); - data.push({ - //eventType: 'Profile Switch' - profile: client.profilefunctions.activeProfileToTime(from) - , mills: from - , first: true - }); - - _.forEach(client.ddata.profileTreatments, function eachTreatment (d) { - if (d.duration && !d.cuttedby) { - data.push({ - cutting: d.profile - , profile: client.profilefunctions.activeProfileToTime(times.mins(d.duration).msecs + d.mills + 1) - , mills: times.mins(d.duration).msecs + d.mills - , end: true - }); - } - }); - - var treatProfiles = chart().basals.selectAll('.g-profile').data(data); - - var topOfText = ('icicle' === mode ? chart().maxBasalValue + 0.05 : -0.05); - - var generateText = function (t) { - var sign = t.first ? '▲▲▲' : '▬▬▬'; - var ret; - if (t.cutting) { - ret = sign + ' ' + client.profilefunctions.profileSwitchName(t.cutting) + ' ' + '►►►' + ' ' + client.profilefunctions.profileSwitchName(t.profile) + ' ' + sign; - } else { - ret = sign + ' ' + client.profilefunctions.profileSwitchName(t.profile) + ' ' + sign; + function profileTooltip (d) { + return ''+translate('Time')+': ' + client.formatTime(new Date(d.mills)) + '
      ' + + (d.eventType ? ''+translate('Treatment type')+': ' + translate(client.careportal.resolveEventName(d.eventType)) + '
      ' : '') + + (d.endprofile ? ''+translate('End of profile')+': ' + d.endprofile + '
      ' : '') + + (d.profile ? ''+translate('Profile')+': ' + d.profile + '
      ' : '') + + (d.duration ? ''+translate('Duration')+': ' + d.duration + translate('mins') + '
      ' : '') + + (d.enteredBy ? ''+translate('Entered By')+': ' + d.enteredBy + '
      ' : '') + + (d.notes ? ''+translate('Notes')+': ' + d.notes : ''); } - return ret; + + // calculate position of profile on left side + var from = chart().brush.extent()[0].getTime(); + var to = chart().brush.extent()[1].getTime(); + var mult = (to-from) / times.hours(24).msecs; + from += times.mins(20 * mult).msecs; + + var mode = client.settings.extendedSettings.basal.render; + var data = client.ddata.profileTreatments.slice(); + data.push({ + //eventType: 'Profile Switch' + profile: client.profilefunctions.activeProfileToTime(from) + , mills: from + , first: true + }); + + _.forEach(client.ddata.profileTreatments, function eachTreatment (d) { + if (d.duration && !d.cuttedby) { + data.push({ + cutting: d.profile + , profile: client.profilefunctions.activeProfileToTime(times.mins(d.duration).msecs + d.mills + 1) + , mills: times.mins(d.duration).msecs + d.mills + , end: true + }); + } + }); + + var treatProfiles = chart().basals.selectAll('.g-profile').data(data); + + var topOfText = ('icicle' === mode ? chart().maxBasalValue + 0.05 : -0.05); + + var generateText = function (t) { + var sign = t.first ? '▲▲▲' : '▬▬▬'; + var ret; + if (t.cutting) { + ret = sign + ' ' + t.cutting + ' ' + '►►►' + ' ' + t.profile + ' ' + sign; + } else { + ret = sign + ' ' + t.profile + ' ' + sign; + } + return ret; + }; + + treatProfiles.transition().duration(0) + .attr('transform', function (t) { + // change text of record on left side + return 'rotate(-90,' + chart().xScale(t.mills) + ',' + chart().yScaleBasals(topOfText) + ') ' + + 'translate(' + chart().xScale(t.mills) + ',' + chart().yScaleBasals(topOfText) + ')'; + }). + text(generateText); + + treatProfiles.enter().append('text') + .attr('class', 'g-profile') + .style('font-size', 15) + .style('font-weight', 'bold') + .attr('fill', '#0099ff') + .attr('text-anchor', 'end') + .attr('dy', '.35em') + .attr('transform', function (t) { + return 'rotate(-90 ' + chart().xScale(t.mills) + ',' + chart().yScaleBasals(topOfText) + ') ' + + 'translate(' + chart().xScale(t.mills) + ',' + chart().yScaleBasals(topOfText) + ')'; + }) + .text(generateText) + .on('mouseover', function (d) { + client.tooltip.transition().duration(TOOLTIP_TRANS_MS).style('opacity', .9); + client.tooltip.html(profileTooltip(d)) + .style('left', (d3.event.pageX) + 'px') + .style('top', (d3.event.pageY + 15) + 'px'); + }) + .on('mouseout', hideTooltip); + + treatProfiles.exit().remove(); }; - treatProfiles.transition().duration(0) - .attr('transform', function (t) { - // change text of record on left side - return 'rotate(-90,' + chart().xScale(t.mills) + ',' + chart().yScaleBasals(topOfText) + ') ' + - 'translate(' + chart().xScale(t.mills) + ',' + chart().yScaleBasals(topOfText) + ')'; - }). - text(generateText); - - treatProfiles.enter().append('text') - .attr('class', 'g-profile') - .style('font-size', 15) - .style('font-weight', 'bold') - .attr('fill', '#0099ff') - .attr('text-anchor', 'end') - .attr('dy', '.35em') - .attr('transform', function (t) { - return 'rotate(-90 ' + chart().xScale(t.mills) + ',' + chart().yScaleBasals(topOfText) + ') ' + - 'translate(' + chart().xScale(t.mills) + ',' + chart().yScaleBasals(topOfText) + ')'; - }) - .text(generateText) - .on('mouseover', function (d) { - client.tooltip.transition().duration(TOOLTIP_TRANS_MS).style('opacity', .9); - client.tooltip.html(profileTooltip(d)) - .style('left', (d3.event.pageX) + 'px') - .style('top', (d3.event.pageY + 15) + 'px'); - }) - .on('mouseout', hideTooltip); - - treatProfiles.exit().remove(); - }; - - return renderer; + return renderer; } -module.exports = init; +module.exports = init; \ No newline at end of file From 4a0c508688d50b9f9d1be75277889cbb4a6abe5e Mon Sep 17 00:00:00 2001 From: PieterGit Date: Fri, 27 Oct 2017 16:34:27 +0200 Subject: [PATCH 41/51] Revert "add package-lock.json to .gitignore to avoid merge conflicts" This reverts commit ec2513084594c851bf9f1d00cc6f3387e75e177b. We now use npm-shrinkwrap.json --- .gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 5370469aaa8..0274dd1f44b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ bower_components/ node_modules/ -package-lock.json bundle/bundle.out.js @@ -24,4 +23,4 @@ coverage/ npm-debug.log *.heapsnapshot -/tmp +/tmp \ No newline at end of file From 2f33b74efb4ac38170858344f8445819b18de8a4 Mon Sep 17 00:00:00 2001 From: PieterGit Date: Fri, 27 Oct 2017 20:46:23 +0200 Subject: [PATCH 42/51] fix merge errors, up version and fix test fix merge errros by reverting views/index.html and lib/client/renderer.js, up version in bower.json, npm-shrinkwrap.json and package.json fix test/client.renderer.test.js --- bower.json | 2 +- lib/client/renderer.js | 2110 ++++++++++++++++----------------- npm-shrinkwrap.json | 2 +- package.json | 2 +- tests/client.renderer.test.js | 2 +- views/index.html | 1 + 6 files changed, 1060 insertions(+), 1059 deletions(-) diff --git a/bower.json b/bower.json index 7dcdfdf6717..644033f0953 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "nightscout", - "version": "0.10.2-release-20171026", + "version": "0.10.2-release-20171027", "dependencies": { "colorbrewer": "~1.0.0", "jQuery-Storage-API": "~1.7.2", diff --git a/lib/client/renderer.js b/lib/client/renderer.js index 1a1ee5f1316..d92559926e8 100644 --- a/lib/client/renderer.js +++ b/lib/client/renderer.js @@ -4,1135 +4,1135 @@ var _ = require('lodash'); var times = require('../times'); var DEFAULT_FOCUS = times.hours(3).msecs - , WIDTH_SMALL_DOTS = 420 - , WIDTH_BIG_DOTS = 800 - , TOOLTIP_TRANS_MS = 100 // milliseconds - , TOOLTIP_WIDTH = 150 //min-width + padding -; + , WIDTH_SMALL_DOTS = 420 + , WIDTH_BIG_DOTS = 800 + , TOOLTIP_TRANS_MS = 100 // milliseconds + , TOOLTIP_WIDTH = 150 //min-width + padding + ; function init (client, d3) { - var renderer = { }; + var renderer = { }; - var utils = client.utils; - var translate = client.translate; + var utils = client.utils; + var translate = client.translate; - //chart isn't created till the client gets data, so can grab the var at init - function chart() { - return client.chart; - } - - function focusRangeAdjustment ( ) { - return client.focusRangeMS === DEFAULT_FOCUS ? 1 : 1 + ((client.focusRangeMS - DEFAULT_FOCUS) / DEFAULT_FOCUS / 8); - } - - var dotRadius = function(type) { - var radius = chart().prevChartWidth > WIDTH_BIG_DOTS ? 4 : (chart().prevChartWidth < WIDTH_SMALL_DOTS ? 2 : 3); - if (type === 'mbg') { - radius *= 2; - } else if (type === 'forecast') { - radius = Math.min(3, radius - 1); - } else if (type === 'rawbg') { - radius = Math.min(2, radius - 1); - } + //chart isn't created till the client gets data, so can grab the var at init + function chart() { + return client.chart; + } - return radius / focusRangeAdjustment(); - }; + function focusRangeAdjustment ( ) { + return client.focusRangeMS === DEFAULT_FOCUS ? 1 : 1 + ((client.focusRangeMS - DEFAULT_FOCUS) / DEFAULT_FOCUS / 8); + } - function tooltipLeft ( ) { - var windowWidth = $(client.tooltip).parent().parent().width(); - var left = d3.event.pageX + TOOLTIP_WIDTH < windowWidth ? d3.event.pageX : windowWidth - TOOLTIP_WIDTH - 10; - return left + 'px'; + var dotRadius = function(type) { + var radius = chart().prevChartWidth > WIDTH_BIG_DOTS ? 4 : (chart().prevChartWidth < WIDTH_SMALL_DOTS ? 2 : 3); + if (type === 'mbg') { + radius *= 2; + } else if (type === 'forecast') { + radius = Math.min(3, radius - 1); + } else if (type === 'rawbg') { + radius = Math.min(2, radius - 1); } - function hideTooltip ( ) { - client.tooltip.transition() - .duration(TOOLTIP_TRANS_MS) - .style('opacity', 0); + return radius / focusRangeAdjustment(); + }; + + function tooltipLeft ( ) { + var windowWidth = $(client.tooltip).parent().parent().width(); + var left = d3.event.pageX + TOOLTIP_WIDTH < windowWidth ? d3.event.pageX : windowWidth - TOOLTIP_WIDTH - 10; + return left + 'px'; + } + + function hideTooltip ( ) { + client.tooltip.transition() + .duration(TOOLTIP_TRANS_MS) + .style('opacity', 0); + } + + // get the desired opacity for context chart based on the brush extent + renderer.highlightBrushPoints = function highlightBrushPoints(data) { + if (data.mills >= chart().brush.extent()[0].getTime() && data.mills <= chart().brush.extent()[1].getTime()) { + return chart().futureOpacity(data.mills - client.latestSGV.mills); + } else { + return 0.5; + } + }; + + renderer.bubbleScale = function bubbleScale ( ) { + // a higher bubbleScale will produce smaller bubbles (it's not a radius like focusDotRadius) + return (chart().prevChartWidth < WIDTH_SMALL_DOTS ? 4 : (chart().prevChartWidth < WIDTH_BIG_DOTS ? 3 : 2)) * focusRangeAdjustment(); + }; + + renderer.addFocusCircles = function addFocusCircles ( ) { + // get slice of data so that concatenation of predictions do not interfere with subsequent updates + var focusData = client.entries.slice(); + + if (client.sbx.pluginBase.forecastPoints) { + var shownForecastPoints = _.filter(client.sbx.pluginBase.forecastPoints, function isShown(point) { + return client.settings.showForecast.indexOf(point.info.type) > -1; + }); + var maxForecastMills = _.max(_.map(shownForecastPoints, function (point) {return point.mills})); + // limit lookahead to the same as lookback + var focusHoursAheadMills = chart().brush.extent()[1].getTime() + client.focusRangeMS; + maxForecastMills = Math.min(focusHoursAheadMills, maxForecastMills); + client.forecastTime = maxForecastMills > 0 ? maxForecastMills - client.sbx.lastSGVMills() : 0; + focusData = focusData.concat(shownForecastPoints); } - // get the desired opacity for context chart based on the brush extent - renderer.highlightBrushPoints = function highlightBrushPoints(data) { - if (data.mills >= chart().brush.extent()[0].getTime() && data.mills <= chart().brush.extent()[1].getTime()) { - return chart().futureOpacity(data.mills - client.latestSGV.mills); + // bind up the focus chart data to an array of circles + // selects all our data into data and uses date function to get current max date + var focusCircles = chart().focus.selectAll('circle').data(focusData, client.entryToDate); + + function prepareFocusCircles(sel) { + var badData = []; + sel.attr('cx', function (d) { + if (!d) { + console.error('Bad data', d); + return chart().xScale(new Date(0)); + } else if (!d.mills) { + console.error('Bad data, no mills', d); + return chart().xScale(new Date(0)); } else { - return 0.5; + return chart().xScale(new Date(d.mills)); } - }; + }) + .attr('cy', function (d) { + var scaled = client.sbx.scaleEntry(d); + if (isNaN(scaled)) { + badData.push(d); + return chart().yScale(utils.scaleMgdl(450)); + } else { + return chart().yScale(scaled); + } + }) + .attr('fill', function (d) { + return d.type === 'forecast' ? 'none' : d.color; + }) + .attr('opacity', function (d) { + return d.noFade ? 100 : chart().futureOpacity(d.mills - client.latestSGV.mills); + }) + .attr('stroke-width', function (d) { + return d.type === 'mbg' ? 2 : d.type === 'forecast' ? 2 : 0; + }) + .attr('stroke', function (d) { + return (d.type === 'mbg' ? 'white' : d.color); + }) + .attr('r', function (d) { + return dotRadius(d.type); + }); - renderer.bubbleScale = function bubbleScale ( ) { - // a higher bubbleScale will produce smaller bubbles (it's not a radius like focusDotRadius) - return (chart().prevChartWidth < WIDTH_SMALL_DOTS ? 4 : (chart().prevChartWidth < WIDTH_BIG_DOTS ? 3 : 2)) * focusRangeAdjustment(); - }; + if (badData.length > 0) { + console.warn('Bad Data: isNaN(sgv)', badData); + } - renderer.addFocusCircles = function addFocusCircles ( ) { - // get slice of data so that concatenation of predictions do not interfere with subsequent updates - var focusData = client.entries.slice(); + return sel; + } - if (client.sbx.pluginBase.forecastPoints) { - var shownForecastPoints = _.filter(client.sbx.pluginBase.forecastPoints, function isShown(point) { - return client.settings.showForecast.indexOf(point.info.type) > -1; - }); - var maxForecastMills = _.max(_.map(shownForecastPoints, function (point) {return point.mills})); - // limit lookahead to the same as lookback - var focusHoursAheadMills = chart().brush.extent()[1].getTime() + client.focusRangeMS; - maxForecastMills = Math.min(focusHoursAheadMills, maxForecastMills); - client.forecastTime = maxForecastMills > 0 ? maxForecastMills - client.sbx.lastSGVMills() : 0; - focusData = focusData.concat(shownForecastPoints); + function focusCircleTooltip (d) { + if (d.type !== 'sgv' && d.type !== 'mbg' && d.type !== 'forecast') { + return; + } + + function getRawbgInfo ( ) { + var info = { }; + if (d.type === 'sgv') { + info.noise = client.rawbg.noiseCodeToDisplay(d.mgdl, d.noise); + if (client.rawbg.showRawBGs(d.mgdl, d.noise, client.ddata.cal, client.sbx)) { + info.value = utils.scaleMgdl(client.rawbg.calc(d, client.ddata.cal, client.sbx)); + } } + return info; + } + + var rawbgInfo = getRawbgInfo(); + + client.tooltip.transition().duration(TOOLTIP_TRANS_MS).style('opacity', .9); + client.tooltip.html('' + translate('BG')+ ': ' + client.sbx.scaleEntry( d ) + + (d.type === 'mbg' ? '
      ' + translate('Device') + ': ' + d.device : '') + + (d.type === 'forecast' ? '
      ' + translate('Forecast Type') + ': ' + d.forecastType : '') + + (rawbgInfo.value ? '
      ' + translate('Raw BG') + ': ' + rawbgInfo.value : '') + + (rawbgInfo.noise ? '
      ' + translate('Noise') + ': ' + rawbgInfo.noise : '') + + '
      ' + translate('Time') + ': ' + client.formatTime(new Date(d.mills))) + .style('left', tooltipLeft()) + .style('top', (d3.event.pageY + 15) + 'px'); + } - // bind up the focus chart data to an array of circles - // selects all our data into data and uses date function to get current max date - var focusCircles = chart().focus.selectAll('circle').data(focusData, client.entryToDate); - - function prepareFocusCircles(sel) { - var badData = []; - sel.attr('cx', function (d) { - if (!d) { - console.error('Bad data', d); - return chart().xScale(new Date(0)); - } else if (!d.mills) { - console.error('Bad data, no mills', d); - return chart().xScale(new Date(0)); - } else { - return chart().xScale(new Date(d.mills)); - } - }) - .attr('cy', function (d) { - var scaled = client.sbx.scaleEntry(d); - if (isNaN(scaled)) { - badData.push(d); - return chart().yScale(utils.scaleMgdl(450)); - } else { - return chart().yScale(scaled); - } - }) - .attr('fill', function (d) { - return d.type === 'forecast' ? 'none' : d.color; - }) - .attr('opacity', function (d) { - return d.noFade ? 100 : chart().futureOpacity(d.mills - client.latestSGV.mills); - }) - .attr('stroke-width', function (d) { - return d.type === 'mbg' ? 2 : d.type === 'forecast' ? 2 : 0; - }) - .attr('stroke', function (d) { - return (d.type === 'mbg' ? 'white' : d.color); - }) - .attr('r', function (d) { - return dotRadius(d.type); - }); - - if (badData.length > 0) { - console.warn('Bad Data: isNaN(sgv)', badData); - } - - return sel; - } + // if already existing then transition each circle to its new position + prepareFocusCircles(focusCircles.transition()); + + // if new circle then just display + prepareFocusCircles(focusCircles.enter().append('circle')) + .on('mouseover', focusCircleTooltip) + .on('mouseout', hideTooltip); + + focusCircles.exit().remove(); + }; + + renderer.addTreatmentCircles = function addTreatmentCircles ( ) { + function treatmentTooltip (d) { + return ''+translate('Time')+': ' + client.formatTime(new Date(d.mills)) + '
      ' + + (d.eventType ? ''+translate('Treatment type')+': ' + translate(client.careportal.resolveEventName(d.eventType)) + '
      ' : '') + + (d.reason ? ''+translate('Reason')+': ' + translate(d.reason) + '
      ' : '') + + (d.glucose ? ''+translate('BG')+': ' + d.glucose + (d.glucoseType ? ' (' + translate(d.glucoseType) + ')': '') + '
      ' : '') + + (d.enteredBy ? ''+translate('Entered By')+': ' + d.enteredBy + '
      ' : '') + + (d.targetTop ? ''+translate('Target Top')+': ' + d.targetTop + '
      ' : '') + + (d.targetBottom ? ''+translate('Target Bottom')+': ' + d.targetBottom + '
      ' : '') + + (d.duration ? ''+translate('Duration')+': ' + Math.round(d.duration) + ' min
      ' : '') + + (d.notes ? ''+translate('Notes')+': ' + d.notes : ''); + } - function focusCircleTooltip (d) { - if (d.type !== 'sgv' && d.type !== 'mbg' && d.type !== 'forecast') { - return; - } + function announcementTooltip (d) { + return ''+translate('Time')+': ' + client.formatTime(new Date(d.mills)) + '
      ' + + (d.eventType ? ''+translate('Announcement')+'
      ' : '') + + (d.notes && d.notes.length > 1 ? ''+translate('Message')+': ' + d.notes + '
      ' : '') + + (d.enteredBy ? ''+translate('Entered By')+': ' + d.enteredBy + '
      ' : ''); + } - function getRawbgInfo ( ) { - var info = { }; - if (d.type === 'sgv') { - info.noise = client.rawbg.noiseCodeToDisplay(d.mgdl, d.noise); - if (client.rawbg.showRawBGs(d.mgdl, d.noise, client.ddata.cal, client.sbx)) { - info.value = utils.scaleMgdl(client.rawbg.calc(d, client.ddata.cal, client.sbx)); - } - } - return info; - } + //TODO: filter in oref0 instead of here and after most people upgrade take this out + var openAPSSpam = ['BasalProfileStart', 'ResultDailyTotal', 'BGReceived']; - var rawbgInfo = getRawbgInfo(); - - client.tooltip.transition().duration(TOOLTIP_TRANS_MS).style('opacity', .9); - client.tooltip.html('' + translate('BG')+ ': ' + client.sbx.scaleEntry( d ) + - (d.type === 'mbg' ? '
      ' + translate('Device') + ': ' + d.device : '') + - (d.type === 'forecast' ? '
      ' + translate('Forecast Type') + ': ' + d.forecastType : '') + - (rawbgInfo.value ? '
      ' + translate('Raw BG') + ': ' + rawbgInfo.value : '') + - (rawbgInfo.noise ? '
      ' + translate('Noise') + ': ' + rawbgInfo.noise : '') + - '
      ' + translate('Time') + ': ' + client.formatTime(new Date(d.mills))) - .style('left', tooltipLeft()) - .style('top', (d3.event.pageY + 15) + 'px'); - } + //NOTE: treatments with insulin or carbs are drawn by drawTreatment() + // bind up the focus chart data to an array of circles + var treatCircles = chart().focus.selectAll('treatment-dot').data(client.ddata.treatments.filter(function(treatment) { - // if already existing then transition each circle to its new position - prepareFocusCircles(focusCircles.transition()); + var notCarbsOrInsulin = !treatment.carbs && !treatment.insulin; + var notTempOrProfile = ! _.includes(['Temp Basal', 'Profile Switch', 'Combo Bolus', 'Temporary Target'], treatment.eventType); - // if new circle then just display - prepareFocusCircles(focusCircles.enter().append('circle')) - .on('mouseover', focusCircleTooltip) - .on('mouseout', hideTooltip); + var notes = treatment.notes || ''; + var enteredBy = treatment.enteredBy || ''; - focusCircles.exit().remove(); - }; + var notOpenAPSSpam = enteredBy.indexOf('openaps://') === -1 || _.isUndefined(_.find(openAPSSpam, function startsWith (spam) { + return notes.indexOf(spam) === 0; + })); - renderer.addTreatmentCircles = function addTreatmentCircles ( ) { - function treatmentTooltip (d) { - return ''+translate('Time')+': ' + client.formatTime(new Date(d.mills)) + '
      ' + - (d.eventType ? ''+translate('Treatment type')+': ' + translate(client.careportal.resolveEventName(d.eventType)) + '
      ' : '') + - (d.reason ? ''+translate('Reason')+': ' + translate(d.reason) + '
      ' : '') + - (d.glucose ? ''+translate('BG')+': ' + d.glucose + (d.glucoseType ? ' (' + translate(d.glucoseType) + ')': '') + '
      ' : '') + - (d.enteredBy ? ''+translate('Entered By')+': ' + d.enteredBy + '
      ' : '') + - (d.targetTop ? ''+translate('Target Top')+': ' + d.targetTop + '
      ' : '') + - (d.targetBottom ? ''+translate('Target Bottom')+': ' + d.targetBottom + '
      ' : '') + - (d.duration ? ''+translate('Duration')+': ' + Math.round(d.duration) + ' min
      ' : '') + - (d.notes ? ''+translate('Notes')+': ' + d.notes : ''); - } + return notCarbsOrInsulin && !treatment.duration && notTempOrProfile && notOpenAPSSpam; + })); - function announcementTooltip (d) { - return ''+translate('Time')+': ' + client.formatTime(new Date(d.mills)) + '
      ' + - (d.eventType ? ''+translate('Announcement')+'
      ' : '') + - (d.notes && d.notes.length > 1 ? ''+translate('Message')+': ' + d.notes + '
      ' : '') + - (d.enteredBy ? ''+translate('Entered By')+': ' + d.enteredBy + '
      ' : ''); + function prepareTreatCircles(sel) { + function strokeColor(d) { + var color = 'white'; + if (d.isAnnouncement) { + color = 'orange'; + } else if (d.glucose) { + color = 'grey'; } - - //TODO: filter in oref0 instead of here and after most people upgrade take this out - var openAPSSpam = ['BasalProfileStart', 'ResultDailyTotal', 'BGReceived']; - - //NOTE: treatments with insulin or carbs are drawn by drawTreatment() - // bind up the focus chart data to an array of circles - var treatCircles = chart().focus.selectAll('treatment-dot').data(client.ddata.treatments.filter(function(treatment) { - - var notCarbsOrInsulin = !treatment.carbs && !treatment.insulin; - var notTempOrProfile = ! _.includes(['Temp Basal', 'Profile Switch', 'Combo Bolus', 'Temporary Target'], treatment.eventType); - - var notes = treatment.notes || ''; - var enteredBy = treatment.enteredBy || ''; - - var notOpenAPSSpam = enteredBy.indexOf('openaps://') === -1 || _.isUndefined(_.find(openAPSSpam, function startsWith (spam) { - return notes.indexOf(spam) === 0; - })); - - return notCarbsOrInsulin && !treatment.duration && notTempOrProfile && notOpenAPSSpam; - })); - - function prepareTreatCircles(sel) { - function strokeColor(d) { - var color = 'white'; - if (d.isAnnouncement) { - color = 'orange'; - } else if (d.glucose) { - color = 'grey'; - } - return color; - } - - function fillColor(d) { - var color = 'grey'; - if (d.isAnnouncement) { - color = 'orange'; - } else if (d.glucose) { - color = 'red'; - } - return color; - } - - sel.attr('cx', function (d) { - return chart().xScale(new Date(d.mills)); - }) - .attr('cy', function (d) { - return chart().yScale(client.sbx.scaleEntry(d)); - }) - .attr('r', function () { - return dotRadius('mbg'); - }) - .attr('stroke-width', 2) - .attr('stroke', strokeColor) - .attr('fill', fillColor); - - return sel; + return color; + } + + function fillColor(d) { + var color = 'grey'; + if (d.isAnnouncement) { + color = 'orange'; + } else if (d.glucose) { + color = 'red'; } + return color; + } + + sel.attr('cx', function (d) { + return chart().xScale(new Date(d.mills)); + }) + .attr('cy', function (d) { + return chart().yScale(client.sbx.scaleEntry(d)); + }) + .attr('r', function () { + return dotRadius('mbg'); + }) + .attr('stroke-width', 2) + .attr('stroke', strokeColor) + .attr('fill', fillColor); + + return sel; + } - // if already existing then transition each circle to its new position - prepareTreatCircles(treatCircles.transition()); - - // if new circle then just display - prepareTreatCircles(treatCircles.enter().append('circle')) - .on('mouseover', function (d) { - client.tooltip.transition().duration(TOOLTIP_TRANS_MS).style('opacity', .9); - client.tooltip.html(d.isAnnouncement ? announcementTooltip(d) : treatmentTooltip(d)) - .style('left', tooltipLeft()) - .style('top', (d3.event.pageY + 15) + 'px'); - }) - .on('mouseout', hideTooltip); - - var durationTreatments = client.ddata.treatments.filter(function(treatment) { - return !treatment.carbs && !treatment.insulin && treatment.duration && - ! _.includes(['Temp Basal', 'Profile Switch', 'Combo Bolus', 'Temporary Target'], treatment.eventType); - }); + // if already existing then transition each circle to its new position + prepareTreatCircles(treatCircles.transition()); + + // if new circle then just display + prepareTreatCircles(treatCircles.enter().append('circle')) + .on('mouseover', function (d) { + client.tooltip.transition().duration(TOOLTIP_TRANS_MS).style('opacity', .9); + client.tooltip.html(d.isAnnouncement ? announcementTooltip(d) : treatmentTooltip(d)) + .style('left', tooltipLeft()) + .style('top', (d3.event.pageY + 15) + 'px'); + }) + .on('mouseout', hideTooltip); + + var durationTreatments = client.ddata.treatments.filter(function(treatment) { + return !treatment.carbs && !treatment.insulin && treatment.duration && + ! _.includes(['Temp Basal', 'Profile Switch', 'Combo Bolus', 'Temporary Target'], treatment.eventType); + }); + + //use the processed temp target so there are no overlaps + durationTreatments = durationTreatments.concat(client.ddata.tempTargetTreatments); + + // treatments with duration + var treatRects = chart().focus.selectAll('.g-duration').data(durationTreatments); + + function fillColor(d) { + // this is going to be updated by Event Type + var color = 'grey'; + if (d.eventType === 'Exercise') { + color = 'Violet'; + } else if (d.eventType === 'Note') { + color = 'Salmon'; + } else if (d.eventType === 'Temporary Target') { + color = 'lightgray'; + } + return color; + } - //use the processed temp target so there are no overlaps - durationTreatments = durationTreatments.concat(client.ddata.tempTargetTreatments); - - // treatments with duration - var treatRects = chart().focus.selectAll('.g-duration').data(durationTreatments); - - function fillColor(d) { - // this is going to be updated by Event Type - var color = 'grey'; - if (d.eventType === 'Exercise') { - color = 'Violet'; - } else if (d.eventType === 'Note') { - color = 'Salmon'; - } else if (d.eventType === 'Temporary Target') { - color = 'lightgray'; - } - return color; - } + function rectHeight (d) { + var height = 20; + if (d.targetTop && d.targetTop > 0 && d.targetBottom && d.targetBottom > 0) { + height = Math.max(5, d.targetTop - d.targetBottom); + } + return height; + } - function rectHeight (d) { - var height = 20; - if (d.targetTop && d.targetTop > 0 && d.targetBottom && d.targetBottom > 0) { - height = Math.max(5, d.targetTop - d.targetBottom); - } - return height; + function rectTranslate (d) { + var top = 50; + if (d.eventType === 'Temporary Target') { + top = d.targetTop === d.targetBottom ? d.targetTop + rectHeight(d) : d.targetTop; + } + return 'translate(' + chart().xScale(new Date(d.mills)) + ',' + chart().yScale(utils.scaleMgdl(top)) + ')'; + } + // if already existing then transition each rect to its new position + treatRects.transition() + .attr('transform', rectTranslate); + + chart().focus.selectAll('.g-duration-rect').transition() + .attr('width', function (d) { + return chart().xScale(new Date(d.mills + times.mins(d.duration).msecs)) - chart().xScale(new Date(d.mills)); + }); + + chart().focus.selectAll('.g-duration-text').transition() + .attr('transform', function (d) { + return 'translate(' + (chart().xScale(new Date(d.mills + times.mins(d.duration).msecs)) - chart().xScale(new Date(d.mills)))/2 + ',' + 10 + ')'; + }); + + // if new rect then just display + var gs = treatRects.enter().append('g') + .attr('class','g-duration') + .attr('transform', rectTranslate) + .on('mouseover', function (d) { + client.tooltip.transition().duration(TOOLTIP_TRANS_MS).style('opacity', .9); + client.tooltip.html(d.isAnnouncement ? announcementTooltip(d) : treatmentTooltip(d)) + .style('left', tooltipLeft()) + .style('top', (d3.event.pageY + 15) + 'px'); + }) + .on('mouseout', hideTooltip); + + gs.append('rect') + .attr('class', 'g-duration-rect') + .attr('width', function (d) { + return chart().xScale(new Date(d.mills + times.mins(d.duration).msecs)) - chart().xScale(new Date(d.mills)); + }) + .attr('height', rectHeight) + .attr('rx', 5) + .attr('ry', 5) + .attr('opacity', .2) + .attr('fill', fillColor); + + gs.append('text') + .attr('class', 'g-duration-text') + .style('font-size', 15) + .attr('fill', 'white') + .attr('text-anchor', 'middle') + .attr('dy', '.35em') + .attr('transform', function (d) { + return 'translate(' + (chart().xScale(new Date(d.mills + times.mins(d.duration).msecs)) - chart().xScale(new Date(d.mills)))/2 + ',' + 10 + ')'; + }) + .text(function (d) { + if (d.eventType === 'Temporary Target') { + return ''; } + return d.notes || d.eventType; + }); + }; + + renderer.addContextCircles = function addContextCircles ( ) { + // bind up the context chart data to an array of circles + var contextCircles = chart().context.selectAll('circle').data(client.entries); + + function prepareContextCircles(sel) { + var badData = []; + sel.attr('cx', function (d) { return chart().xScale2(new Date(d.mills)); }) + .attr('cy', function (d) { + var scaled = client.sbx.scaleEntry(d); + if (isNaN(scaled)) { + badData.push(d); + return chart().yScale2(utils.scaleMgdl(450)); + } else { + return chart().yScale2(scaled); + } + }) + .attr('fill', function (d) { return d.color; }) + .style('opacity', function (d) { return renderer.highlightBrushPoints(d) }) + .attr('stroke-width', function (d) { return d.type === 'mbg' ? 2 : 0; }) + .attr('stroke', function ( ) { return 'white'; }) + .attr('r', function (d) { return d.type === 'mbg' ? 4 : 2; }); + + if (badData.length > 0) { + console.warn('Bad Data: isNaN(sgv)', badData); + } + + return sel; + } - function rectTranslate (d) { - var top = 50; - if (d.eventType === 'Temporary Target') { - top = d.targetTop === d.targetBottom ? d.targetTop + rectHeight(d) : d.targetTop; - } - return 'translate(' + chart().xScale(new Date(d.mills)) + ',' + chart().yScale(utils.scaleMgdl(top)) + ')'; - } - // if already existing then transition each rect to its new position - treatRects.transition() - .attr('transform', rectTranslate); + // if already existing then transition each circle to its new position + prepareContextCircles(contextCircles.transition()); - chart().focus.selectAll('.g-duration-rect').transition() - .attr('width', function (d) { - return chart().xScale(new Date(d.mills + times.mins(d.duration).msecs)) - chart().xScale(new Date(d.mills)); - }); + // if new circle then just display + prepareContextCircles(contextCircles.enter().append('circle')); - chart().focus.selectAll('.g-duration-text').transition() - .attr('transform', function (d) { - return 'translate(' + (chart().xScale(new Date(d.mills + times.mins(d.duration).msecs)) - chart().xScale(new Date(d.mills)))/2 + ',' + 10 + ')'; - }); + contextCircles.exit().remove(); + }; - // if new rect then just display - var gs = treatRects.enter().append('g') - .attr('class','g-duration') - .attr('transform', rectTranslate) - .on('mouseover', function (d) { - client.tooltip.transition().duration(TOOLTIP_TRANS_MS).style('opacity', .9); - client.tooltip.html(d.isAnnouncement ? announcementTooltip(d) : treatmentTooltip(d)) - .style('left', tooltipLeft()) - .style('top', (d3.event.pageY + 15) + 'px'); - }) - .on('mouseout', hideTooltip); + function calcTreatmentRadius(treatment, opts, carbratio) { + var CR = treatment.CR || carbratio || 20; + var carbs = treatment.carbs || CR; + var insulin = treatment.insulin || 1; + var carbsOrInsulin = CR; + if ( treatment.carbs ) { + carbsOrInsulin = treatment.carbs; + } else if ( treatment.insulin ) { + carbsOrInsulin = treatment.insulin * CR; + } - gs.append('rect') - .attr('class', 'g-duration-rect') - .attr('width', function (d) { - return chart().xScale(new Date(d.mills + times.mins(d.duration).msecs)) - chart().xScale(new Date(d.mills)); - }) - .attr('height', rectHeight) - .attr('rx', 5) - .attr('ry', 5) - .attr('opacity', .2) - .attr('fill', fillColor); - - gs.append('text') - .attr('class', 'g-duration-text') - .style('font-size', 15) - .attr('fill', 'white') - .attr('text-anchor', 'middle') - .attr('dy', '.35em') - .attr('transform', function (d) { - return 'translate(' + (chart().xScale(new Date(d.mills + times.mins(d.duration).msecs)) - chart().xScale(new Date(d.mills)))/2 + ',' + 10 + ')'; - }) - .text(function (d) { - if (d.eventType === 'Temporary Target') { - return ''; - } - return d.notes || d.eventType; - }); + // R1 determines the size of the treatment dot + var R1 = Math.sqrt(2*carbsOrInsulin) / opts.scale + , R2 = R1 + // R3/R4 determine how far from the treatment dot the labels are placed + , R3 = R1 + 8 / opts.scale + , R4 = R1 + 25 / opts.scale + ; + + return { + R1: R1 + , R2: R2 + , R3: R3 + , R4: R4 + , isNaN: isNaN(R1) || isNaN(R3) || isNaN(R3) }; + } + + function prepareArc(treatment, radius) { + var arc_data = [ + // white carb half-circle on top + { 'element': '', 'color': 'white', 'start': -1.5708, 'end': 1.5708, 'inner': 0, 'outer': radius.R1 }, + { 'element': '', 'color': 'transparent', 'start': -1.5708, 'end': 1.5708, 'inner': radius.R2, 'outer': radius.R3 }, + // blue insulin half-circle on bottom + { 'element': '', 'color': '#0099ff', 'start': 1.5708, 'end': 4.7124, 'inner': 0, 'outer': radius.R1 }, + // these form a very short transparent arc along the bottom of an insulin treatment to position the label + // these used to be semicircles from 1.5708 to 4.7124, but that made the tooltip target too big + { 'element': '', 'color': 'transparent', 'start': 3.1400, 'end': 3.1432, 'inner': radius.R2, 'outer': radius.R3 }, + { 'element': '', 'color': 'transparent', 'start': 3.1400, 'end': 3.1432, 'inner': radius.R2, 'outer': radius.R4 } + ]; + + arc_data[0].outlineOnly = !treatment.carbs; + arc_data[2].outlineOnly = !treatment.insulin; + + if (treatment.carbs > 0) { + arc_data[1].element = Math.round(treatment.carbs) + ' g'; + } - renderer.addContextCircles = function addContextCircles ( ) { - // bind up the context chart data to an array of circles - var contextCircles = chart().context.selectAll('circle').data(client.entries); - - function prepareContextCircles(sel) { - var badData = []; - sel.attr('cx', function (d) { return chart().xScale2(new Date(d.mills)); }) - .attr('cy', function (d) { - var scaled = client.sbx.scaleEntry(d); - if (isNaN(scaled)) { - badData.push(d); - return chart().yScale2(utils.scaleMgdl(450)); - } else { - return chart().yScale2(scaled); - } - }) - .attr('fill', function (d) { return d.color; }) - .style('opacity', function (d) { return renderer.highlightBrushPoints(d) }) - .attr('stroke-width', function (d) { return d.type === 'mbg' ? 2 : 0; }) - .attr('stroke', function ( ) { return 'white'; }) - .attr('r', function (d) { return d.type === 'mbg' ? 4 : 2; }); - - if (badData.length > 0) { - console.warn('Bad Data: isNaN(sgv)', badData); - } - - return sel; - } + if (treatment.foodType) { + arc_data[1].element = arc_data[1].element + " " + treatment.foodType; + } - // if already existing then transition each circle to its new position - prepareContextCircles(contextCircles.transition()); + if ( treatment.insulin > 0) { + // remove leading zeros to avoid overlap with adjacent boluses + var units = Math.round(treatment.insulin * 100)/100; + arc_data[3].element = (units+"").replace(/^0/,""); + } - // if new circle then just display - prepareContextCircles(contextCircles.enter().append('circle')); + if (treatment.status) { + arc_data[4].element = translate(treatment.status); + } - contextCircles.exit().remove(); + var arc = d3.svg.arc() + .innerRadius(function (d) { + return 5 * d.inner; + }) + .outerRadius(function (d) { + return 5 * d.outer; + }) + .endAngle(function (d) { + return d.start; + }) + .startAngle(function (d) { + return d.end; + }); + + return { + data: arc_data + , svg: arc }; - - function calcTreatmentRadius(treatment, opts, carbratio) { - var CR = treatment.CR || carbratio || 20; - var carbs = treatment.carbs || CR; - var insulin = treatment.insulin || 1; - var carbsOrInsulin = CR; - if ( treatment.carbs ) { - carbsOrInsulin = treatment.carbs; - } else if ( treatment.insulin ) { - carbsOrInsulin = treatment.insulin * CR; + } + + function isInRect(x,y,rect) { + return !(x < rect.x || x > rect.x + rect.width || y < rect.y || y > rect.y + rect.height); + } + + function appendTreatments(treatment, arc) { + + function boluscalcTooltip (treatment) { + if (!treatment.boluscalc) { + return ''; + } + var html = '
      '; + html += (treatment.boluscalc.othercorrection ? ''+translate('Other correction')+': ' + parseFloat(treatment.boluscalc.othercorrection).toFixed(2) + 'U
      ' : ''); + html += (treatment.boluscalc.profile ? ''+translate('Profile used')+': ' + treatment.boluscalc.profile + '
      ' : ''); + if (treatment.boluscalc.foods && treatment.boluscalc.foods.length) { + html += ''; + for (var fi=0; fi'; + html += ''; + html += ''; + html += ''; } - - // R1 determines the size of the treatment dot - var R1 = Math.sqrt(2*carbsOrInsulin) / opts.scale - , R2 = R1 - // R3/R4 determine how far from the treatment dot the labels are placed - , R3 = R1 + 8 / opts.scale - , R4 = R1 + 25 / opts.scale - ; - - return { - R1: R1 - , R2: R2 - , R3: R3 - , R4: R4 - , isNaN: isNaN(R1) || isNaN(R3) || isNaN(R3) - }; + html += '
      ' + translate('Food') + '
      '+ (f.portion*f.portions).toFixed(1) + ' ' + f.unit + '('+ (f.carbs*f.portions).toFixed(1) + ' g)
      '; + } + return html; } - function prepareArc(treatment, radius) { - var arc_data = [ - // white carb half-circle on top - { 'element': '', 'color': 'white', 'start': -1.5708, 'end': 1.5708, 'inner': 0, 'outer': radius.R1 }, - { 'element': '', 'color': 'transparent', 'start': -1.5708, 'end': 1.5708, 'inner': radius.R2, 'outer': radius.R3 }, - // blue insulin half-circle on bottom - { 'element': '', 'color': '#0099ff', 'start': 1.5708, 'end': 4.7124, 'inner': 0, 'outer': radius.R1 }, - // these form a very short transparent arc along the bottom of an insulin treatment to position the label - // these used to be semicircles from 1.5708 to 4.7124, but that made the tooltip target too big - { 'element': '', 'color': 'transparent', 'start': 3.1400, 'end': 3.1432, 'inner': radius.R2, 'outer': radius.R3 }, - { 'element': '', 'color': 'transparent', 'start': 3.1400, 'end': 3.1432, 'inner': radius.R2, 'outer': radius.R4 } - ]; - - arc_data[0].outlineOnly = !treatment.carbs; - arc_data[2].outlineOnly = !treatment.insulin; - - if (treatment.carbs > 0) { - arc_data[1].element = Math.round(treatment.carbs) + ' g'; - } - - if (treatment.foodType) { - arc_data[1].element = arc_data[1].element + " " + treatment.foodType; - } - - if ( treatment.insulin > 0) { - // remove leading zeros to avoid overlap with adjacent boluses - var units = Math.round(treatment.insulin * 100)/100; - arc_data[3].element = (units+"").replace(/^0/,""); - } - - if (treatment.status) { - arc_data[4].element = translate(treatment.status); - } + function treatmentTooltip() { + client.tooltip.transition().duration(TOOLTIP_TRANS_MS).style('opacity', .9); + client.tooltip.html('' + translate('Time') + ': ' + client.formatTime(new Date(treatment.mills)) + '
      ' + '' + translate('Treatment type') + ': ' + translate(client.careportal.resolveEventName(treatment.eventType)) + '
      ' + + (treatment.carbs ? '' + translate('Carbs') + ': ' + treatment.carbs + '
      ' : '') + + (treatment.absorptionTime > 0 ? '' + translate('Absorption Time') + ': ' + (Math.round( treatment.absorptionTime / 60.0 * 10) / 10) + 'h' + '
      ' : '') + + (treatment.insulin ? '' + translate('Insulin') + ': ' + treatment.insulin + '
      ' : '') + + (treatment.enteredinsulin ? '' + translate('Combo Bolus') + ': ' + treatment.enteredinsulin + 'U, ' + treatment.splitNow + '% : ' + treatment.splitExt + '%, ' + translate('Duration') + ': ' + treatment.duration + '
      ' : '') + + (treatment.glucose ? '' + translate('BG') + ': ' + treatment.glucose + (treatment.glucoseType ? ' (' + translate(treatment.glucoseType) + ')' : '') + '
      ' : '') + + (treatment.enteredBy ? '' + translate('Entered By') + ': ' + treatment.enteredBy + '
      ' : '') + + (treatment.notes ? '' + translate('Notes') + ': ' + treatment.notes : '') + + boluscalcTooltip(treatment) + ) + .style('left', tooltipLeft()) + .style('top', (d3.event.pageY + 15) + 'px'); + } - var arc = d3.svg.arc() - .innerRadius(function (d) { - return 5 * d.inner; - }) - .outerRadius(function (d) { - return 5 * d.outer; - }) - .endAngle(function (d) { - return d.start; + var newTime; + var deleteRect = { x: 0, y: 0, width: 0, height: 0 }; + var insulinRect = { x: 0, y: 0, width: 0, height: 0 }; + var carbsRect = { x: 0, y: 0, width: 0, height: 0 }; + var operation; + renderer.drag = d3.behavior.drag() + .on('dragstart', function() { + //console.log(treatment); + var windowWidth = $(client.tooltip).parent().parent().width(); + var left = d3.event.x + TOOLTIP_WIDTH < windowWidth ? d3.event.x : windowWidth - TOOLTIP_WIDTH - 10; + client.tooltip.transition().duration(TOOLTIP_TRANS_MS).style('opacity', .9) + .style('left', left + 'px') + .style('top', (d3.event.pageY ? d3.event.pageY + 15 : 40) + 'px'); + + deleteRect = { + x: 0, + y: 0, + width: 50, + height: chart().yScale(chart().yScale.domain()[0]) + }; + chart().drag.append('rect') + .attr({ + class:'drag-droparea', + x: deleteRect.x, + y: deleteRect.y, + width: deleteRect.width, + height: deleteRect.height, + fill: 'red', + opacity: 0.4, + rx: 10, + ry: 10 + }); + chart().drag.append('text') + .attr({ + class:'drag-droparea', + x: deleteRect.x + deleteRect.width / 2, + y: deleteRect.y + deleteRect.height / 2, + 'font-size': 15, + 'font-weight': 'bold', + fill: 'red', + 'text-anchor': 'middle', + dy: '.35em', + transform: 'rotate(-90 ' + (deleteRect.x + deleteRect.width / 2) + ',' + (deleteRect.y + deleteRect.height / 2) + ')' + }) + .text(translate('Remove')); + + if (treatment.insulin && treatment.carbs) { + carbsRect = { + x: 0, + y: 0, + width: chart().charts.attr('width'), + height: 50 + }; + insulinRect = { + x: 0, + y: chart().yScale(chart().yScale.domain()[0]) - 50, + width: chart().charts.attr('width'), + height: 50 + }; + chart().drag.append('rect') + .attr({ + class:'drag-droparea', + x: carbsRect.x, + y: carbsRect.y, + width: carbsRect.width, + height: carbsRect.height, + fill: 'white', + opacity: 0.4, + rx: 10, + ry: 10 + }); + chart().drag.append('text') + .attr({ + class:'drag-droparea', + x: carbsRect.x + carbsRect.width / 2, + y: carbsRect.y + carbsRect.height / 2, + 'font-size': 15, + 'font-weight': 'bold', + fill: 'white', + 'text-anchor': 'middle', + dy: '.35em' }) - .startAngle(function (d) { - return d.end; + .text(translate('Move carbs')); + chart().drag.append('rect') + .attr({ + class:'drag-droparea', + x: insulinRect.x, + y: insulinRect.y, + width: insulinRect.width, + height: insulinRect.height, + fill: '#0099ff', + opacity: 0.4, + rx: 10, + ry: 10 }); + chart().drag.append('text') + .attr({ + class:'drag-droparea', + x: insulinRect.x + insulinRect.width / 2, + y: insulinRect.y + insulinRect.height / 2, + 'font-size': 15, + 'font-weight': 'bold', + fill: '#0099ff', + 'text-anchor': 'middle', + dy: '.35em' + }) + .text(translate('Move insulin')); + } - return { - data: arc_data - , svg: arc - }; - } - - function isInRect(x,y,rect) { - return !(x < rect.x || x > rect.x + rect.width || y < rect.y || y > rect.y + rect.height); - } - - function appendTreatments(treatment, arc) { + chart().basals.attr('display','none'); + + operation = 'Move'; + }) + .on('drag', function() { + //console.log(d3.event); + client.tooltip.transition().style('opacity', .9); + var x = Math.min(Math.max(0, d3.event.x), chart().charts.attr('width')); + var y = Math.min(Math.max(0, d3.event.y), chart().focusHeight); + + operation = 'Move'; + if (isInRect(x, y, deleteRect) && isInRect(x, y, insulinRect)) { + operation = 'Remove insulin'; + } else if (isInRect(x, y, deleteRect) && isInRect(x, y, carbsRect)) { + operation = 'Remove carbs'; + } else if (isInRect(x, y, deleteRect)) { + operation = 'Remove'; + } else if (isInRect(x, y, insulinRect)) { + operation = 'Move insulin'; + } else if (isInRect(x, y, carbsRect)) { + operation = 'Move carbs'; + } - function boluscalcTooltip (treatment) { - if (!treatment.boluscalc) { - return ''; + newTime = new Date(chart().xScale.invert(x)); + var minDiff = times.msecs(newTime.getTime() - treatment.mills).mins.toFixed(0); + client.tooltip.html( + '' + translate('Operation') + ': ' + translate(operation) + '
      ' + + '' + translate('New time') + ': ' + newTime.toLocaleTimeString() + '
      ' + + '' + translate('Difference') + ': ' + (minDiff > 0 ? '+' : '') + minDiff + ' ' + translate('mins') + ); + + chart().drag.selectAll('.arrow').remove(); + chart().drag.append('line') + .attr({ + 'class':'arrow', + 'marker-end':'url(#arrow)', + 'x1': chart().xScale(new Date(treatment.mills)), + 'y1': chart().yScale(client.sbx.scaleEntry(treatment)), + 'x2': x, + 'y2': y, + 'stroke-width': 2, + 'stroke': 'white' + }); + + }) + .on('dragend', function() { + var newTreatment; + chart().drag.selectAll('.drag-droparea').remove(); + hideTooltip(); + switch (operation) { + case 'Move': + if (window.confirm(translate('Change treatment time to %1 ?', { params: [newTime.toLocaleTimeString()] } ))) { + client.socket.emit( + 'dbUpdate', + { + collection: 'treatments', + _id: treatment._id, + data: { created_at: newTime.toISOString() } + }, + function callback(result) { + console.log(result); + chart().drag.selectAll('.arrow').transition().duration(5000).style('opacity', 0).remove(); + } + ); + } else { + chart().drag.selectAll('.arrow').remove(); } - var html = '
      '; - html += (treatment.boluscalc.othercorrection ? ''+translate('Other correction')+': ' + parseFloat(treatment.boluscalc.othercorrection).toFixed(2) + 'U
      ' : ''); - html += (treatment.boluscalc.profile ? ''+translate('Profile used')+': ' + treatment.boluscalc.profile + '
      ' : ''); - if (treatment.boluscalc.foods && treatment.boluscalc.foods.length) { - html += ''; - for (var fi=0; fi'; - html += ''; - html += ''; - html += ''; + break; + case 'Remove insulin': + if (window.confirm(translate('Remove insulin from treatment ?'))) { + client.socket.emit( + 'dbUpdateUnset', + { + collection: 'treatments', + _id: treatment._id, + data: { insulin: 1 } + }, + function callback(result) { + console.log(result); + chart().drag.selectAll('.arrow').transition().duration(5000).style('opacity', 0).remove(); } - html += '
      ' + translate('Food') + '
      '+ (f.portion*f.portions).toFixed(1) + ' ' + f.unit + '('+ (f.carbs*f.portions).toFixed(1) + ' g)
      '; + ); + } else { + chart().drag.selectAll('.arrow').remove(); } - return html; - } - - function treatmentTooltip() { - client.tooltip.transition().duration(TOOLTIP_TRANS_MS).style('opacity', .9); - client.tooltip.html('' + translate('Time') + ': ' + client.formatTime(new Date(treatment.mills)) + '
      ' + '' + translate('Treatment type') + ': ' + translate(client.careportal.resolveEventName(treatment.eventType)) + '
      ' + - (treatment.carbs ? '' + translate('Carbs') + ': ' + treatment.carbs + '
      ' : '') + - (treatment.absorptionTime > 0 ? '' + translate('Absorption Time') + ': ' + (Math.round( treatment.absorptionTime / 60.0 * 10) / 10) + 'h' + '
      ' : '') + - (treatment.insulin ? '' + translate('Insulin') + ': ' + treatment.insulin + '
      ' : '') + - (treatment.enteredinsulin ? '' + translate('Combo Bolus') + ': ' + treatment.enteredinsulin + 'U, ' + treatment.splitNow + '% : ' + treatment.splitExt + '%, ' + translate('Duration') + ': ' + treatment.duration + '
      ' : '') + - (treatment.glucose ? '' + translate('BG') + ': ' + treatment.glucose + (treatment.glucoseType ? ' (' + translate(treatment.glucoseType) + ')' : '') + '
      ' : '') + - (treatment.enteredBy ? '' + translate('Entered By') + ': ' + treatment.enteredBy + '
      ' : '') + - (treatment.notes ? '' + translate('Notes') + ': ' + treatment.notes : '') + - boluscalcTooltip(treatment) - ) - .style('left', tooltipLeft()) - .style('top', (d3.event.pageY + 15) + 'px'); - } - - var newTime; - var deleteRect = { x: 0, y: 0, width: 0, height: 0 }; - var insulinRect = { x: 0, y: 0, width: 0, height: 0 }; - var carbsRect = { x: 0, y: 0, width: 0, height: 0 }; - var operation; - renderer.drag = d3.behavior.drag() - .on('dragstart', function() { - //console.log(treatment); - var windowWidth = $(client.tooltip).parent().parent().width(); - var left = d3.event.x + TOOLTIP_WIDTH < windowWidth ? d3.event.x : windowWidth - TOOLTIP_WIDTH - 10; - client.tooltip.transition().duration(TOOLTIP_TRANS_MS).style('opacity', .9) - .style('left', left + 'px') - .style('top', (d3.event.pageY ? d3.event.pageY + 15 : 40) + 'px'); - - deleteRect = { - x: 0, - y: 0, - width: 50, - height: chart().yScale(chart().yScale.domain()[0]) - }; - chart().drag.append('rect') - .attr({ - class:'drag-droparea', - x: deleteRect.x, - y: deleteRect.y, - width: deleteRect.width, - height: deleteRect.height, - fill: 'red', - opacity: 0.4, - rx: 10, - ry: 10 - }); - chart().drag.append('text') - .attr({ - class:'drag-droparea', - x: deleteRect.x + deleteRect.width / 2, - y: deleteRect.y + deleteRect.height / 2, - 'font-size': 15, - 'font-weight': 'bold', - fill: 'red', - 'text-anchor': 'middle', - dy: '.35em', - transform: 'rotate(-90 ' + (deleteRect.x + deleteRect.width / 2) + ',' + (deleteRect.y + deleteRect.height / 2) + ')' - }) - .text(translate('Remove')); - - if (treatment.insulin && treatment.carbs) { - carbsRect = { - x: 0, - y: 0, - width: chart().charts.attr('width'), - height: 50 - }; - insulinRect = { - x: 0, - y: chart().yScale(chart().yScale.domain()[0]) - 50, - width: chart().charts.attr('width'), - height: 50 - }; - chart().drag.append('rect') - .attr({ - class:'drag-droparea', - x: carbsRect.x, - y: carbsRect.y, - width: carbsRect.width, - height: carbsRect.height, - fill: 'white', - opacity: 0.4, - rx: 10, - ry: 10 - }); - chart().drag.append('text') - .attr({ - class:'drag-droparea', - x: carbsRect.x + carbsRect.width / 2, - y: carbsRect.y + carbsRect.height / 2, - 'font-size': 15, - 'font-weight': 'bold', - fill: 'white', - 'text-anchor': 'middle', - dy: '.35em' - }) - .text(translate('Move carbs')); - chart().drag.append('rect') - .attr({ - class:'drag-droparea', - x: insulinRect.x, - y: insulinRect.y, - width: insulinRect.width, - height: insulinRect.height, - fill: '#0099ff', - opacity: 0.4, - rx: 10, - ry: 10 - }); - chart().drag.append('text') - .attr({ - class:'drag-droparea', - x: insulinRect.x + insulinRect.width / 2, - y: insulinRect.y + insulinRect.height / 2, - 'font-size': 15, - 'font-weight': 'bold', - fill: '#0099ff', - 'text-anchor': 'middle', - dy: '.35em' - }) - .text(translate('Move insulin')); + break; + case 'Remove carbs': + if (window.confirm(translate('Remove carbs from treatment ?'))) { + client.socket.emit( + 'dbUpdateUnset', + { + collection: 'treatments', + _id: treatment._id, + data: { carbs: 1 } + }, + function callback(result) { + console.log(result); + chart().drag.selectAll('.arrow').transition().duration(5000).style('opacity', 0).remove(); } - - chart().basals.attr('display','none'); - - operation = 'Move'; - }) - .on('drag', function() { - //console.log(d3.event); - client.tooltip.transition().style('opacity', .9); - var x = Math.min(Math.max(0, d3.event.x), chart().charts.attr('width')); - var y = Math.min(Math.max(0, d3.event.y), chart().focusHeight); - - operation = 'Move'; - if (isInRect(x, y, deleteRect) && isInRect(x, y, insulinRect)) { - operation = 'Remove insulin'; - } else if (isInRect(x, y, deleteRect) && isInRect(x, y, carbsRect)) { - operation = 'Remove carbs'; - } else if (isInRect(x, y, deleteRect)) { - operation = 'Remove'; - } else if (isInRect(x, y, insulinRect)) { - operation = 'Move insulin'; - } else if (isInRect(x, y, carbsRect)) { - operation = 'Move carbs'; + ); + } else { + chart().drag.selectAll('.arrow').remove(); + } + break; + case 'Remove': + if (window.confirm(translate('Remove treatment ?'))) { + client.socket.emit( + 'dbRemove', + { + collection: 'treatments', + _id: treatment._id + }, + function callback(result) { + console.log(result); + chart().drag.selectAll('.arrow').transition().duration(5000).style('opacity', 0).remove(); } - - newTime = new Date(chart().xScale.invert(x)); - var minDiff = times.msecs(newTime.getTime() - treatment.mills).mins.toFixed(0); - client.tooltip.html( - '' + translate('Operation') + ': ' + translate(operation) + '
      ' - + '' + translate('New time') + ': ' + newTime.toLocaleTimeString() + '
      ' - + '' + translate('Difference') + ': ' + (minDiff > 0 ? '+' : '') + minDiff + ' ' + translate('mins') - ); - - chart().drag.selectAll('.arrow').remove(); - chart().drag.append('line') - .attr({ - 'class':'arrow', - 'marker-end':'url(#arrow)', - 'x1': chart().xScale(new Date(treatment.mills)), - 'y1': chart().yScale(client.sbx.scaleEntry(treatment)), - 'x2': x, - 'y2': y, - 'stroke-width': 2, - 'stroke': 'white' - }); - - }) - .on('dragend', function() { - var newTreatment; - chart().drag.selectAll('.drag-droparea').remove(); - hideTooltip(); - switch (operation) { - case 'Move': - if (window.confirm(translate('Change treatment time to %1 ?', { params: [newTime.toLocaleTimeString()] } ))) { - client.socket.emit( - 'dbUpdate', - { - collection: 'treatments', - _id: treatment._id, - data: { created_at: newTime.toISOString() } - }, - function callback(result) { - console.log(result); - chart().drag.selectAll('.arrow').transition().duration(5000).style('opacity', 0).remove(); - } - ); - } else { - chart().drag.selectAll('.arrow').remove(); - } - break; - case 'Remove insulin': - if (window.confirm(translate('Remove insulin from treatment ?'))) { - client.socket.emit( - 'dbUpdateUnset', - { - collection: 'treatments', - _id: treatment._id, - data: { insulin: 1 } - }, - function callback(result) { - console.log(result); - chart().drag.selectAll('.arrow').transition().duration(5000).style('opacity', 0).remove(); - } - ); - } else { - chart().drag.selectAll('.arrow').remove(); - } - break; - case 'Remove carbs': - if (window.confirm(translate('Remove carbs from treatment ?'))) { - client.socket.emit( - 'dbUpdateUnset', - { - collection: 'treatments', - _id: treatment._id, - data: { carbs: 1 } - }, - function callback(result) { - console.log(result); - chart().drag.selectAll('.arrow').transition().duration(5000).style('opacity', 0).remove(); - } - ); - } else { - chart().drag.selectAll('.arrow').remove(); - } - break; - case 'Remove': - if (window.confirm(translate('Remove treatment ?'))) { - client.socket.emit( - 'dbRemove', - { - collection: 'treatments', - _id: treatment._id - }, - function callback(result) { - console.log(result); - chart().drag.selectAll('.arrow').transition().duration(5000).style('opacity', 0).remove(); - } - ); - } else { - chart().drag.selectAll('.arrow').remove(); - } - break; - case 'Move insulin': - if (window.confirm(translate('Change insulin time to %1 ?', { params: [newTime.toLocaleTimeString()] } ))) { - client.socket.emit( - 'dbUpdateUnset', - { - collection: 'treatments', - _id: treatment._id, - data: { insulin: 1 } - } - ); - newTreatment = _.cloneDeep(treatment); - delete newTreatment._id; - delete newTreatment.NSCLIENT_ID; - delete newTreatment.carbs; - newTreatment.created_at = newTime.toISOString(); - client.socket.emit( - 'dbAdd', - { - collection: 'treatments', - data: newTreatment - }, - function callback(result) { - console.log(result); - chart().drag.selectAll('.arrow').transition().duration(5000).style('opacity', 0).remove(); - } - ); - } else { - chart().drag.selectAll('.arrow').remove(); - } - break; - case 'Move carbs': - if (window.confirm(translate('Change carbs time to %1 ?', { params: [newTime.toLocaleTimeString()] } ))) { - client.socket.emit( - 'dbUpdateUnset', - { - collection: 'treatments', - _id: treatment._id, - data: { carbs: 1 } - } - ); - newTreatment = _.cloneDeep(treatment); - delete newTreatment._id; - delete newTreatment.NSCLIENT_ID; - delete newTreatment.insulin; - newTreatment.created_at = newTime.toISOString(); - client.socket.emit( - 'dbAdd', - { - collection: 'treatments', - data: newTreatment - }, - function callback(result) { - console.log(result); - chart().drag.selectAll('.arrow').transition().duration(5000).style('opacity', 0).remove(); - } - ); - } else { - chart().drag.selectAll('.arrow').remove(); - } - break; + ); + } else { + chart().drag.selectAll('.arrow').remove(); + } + break; + case 'Move insulin': + if (window.confirm(translate('Change insulin time to %1 ?', { params: [newTime.toLocaleTimeString()] } ))) { + client.socket.emit( + 'dbUpdateUnset', + { + collection: 'treatments', + _id: treatment._id, + data: { insulin: 1 } } - chart().basals.attr('display',''); - }); - - var treatmentDots = chart().focus.selectAll('treatment-insulincarbs') - .data(arc.data) - .enter() - .append('g') - .attr('class', 'draggable-treatment') - .attr('transform', 'translate(' + chart().xScale(new Date(treatment.mills)) + ', ' + chart().yScale(client.sbx.scaleEntry(treatment)) + ')') - .on('mouseover', treatmentTooltip) - .on('mouseout', hideTooltip); - if (client.editMode) { - treatmentDots - .style('cursor', 'move') - .call(renderer.drag); - } - - treatmentDots.append('path') - .attr('class', 'path') - .attr('fill', function (d) { - return d.outlineOnly ? 'transparent' : d.color; - }) - .attr('stroke-width', function (d) { - return d.outlineOnly ? 1 : 0; - }) - .attr('stroke', function (d) { - return d.color; - }) - .attr('id', function (d, i) { - return 's' + i; - }) - .attr('d', arc.svg); - - return treatmentDots; - } - - function appendLabels(treatmentDots, arc, opts) { - // labels for carbs and insulin - if (opts.showLabels) { - var label = treatmentDots.append('g') - .attr('class', 'path') - .attr('id', 'label') - .style('fill', 'white'); - - label.append('text') - // reduce the treatment label font size to make it readable with SMB - .style('font-size', 30 / opts.scale) - .style('text-shadow', '0px 0px 10px rgba(0, 0, 0, 1)') - .attr('text-anchor', 'middle') - .attr('dy', '.35em') - .attr('transform', function (d) { - d.outerRadius = d.outerRadius * 2.1; - d.innerRadius = d.outerRadius * 2.1; - return 'translate(' + arc.svg.centroid(d) + ')'; - }) - .text(function (d) { - return d.element; - }); + ); + newTreatment = _.cloneDeep(treatment); + delete newTreatment._id; + delete newTreatment.NSCLIENT_ID; + delete newTreatment.carbs; + newTreatment.created_at = newTime.toISOString(); + client.socket.emit( + 'dbAdd', + { + collection: 'treatments', + data: newTreatment + }, + function callback(result) { + console.log(result); + chart().drag.selectAll('.arrow').transition().duration(5000).style('opacity', 0).remove(); + } + ); + } else { + chart().drag.selectAll('.arrow').remove(); + } + break; + case 'Move carbs': + if (window.confirm(translate('Change carbs time to %1 ?', { params: [newTime.toLocaleTimeString()] } ))) { + client.socket.emit( + 'dbUpdateUnset', + { + collection: 'treatments', + _id: treatment._id, + data: { carbs: 1 } + } + ); + newTreatment = _.cloneDeep(treatment); + delete newTreatment._id; + delete newTreatment.NSCLIENT_ID; + delete newTreatment.insulin; + newTreatment.created_at = newTime.toISOString(); + client.socket.emit( + 'dbAdd', + { + collection: 'treatments', + data: newTreatment + }, + function callback(result) { + console.log(result); + chart().drag.selectAll('.arrow').transition().duration(5000).style('opacity', 0).remove(); + } + ); + } else { + chart().drag.selectAll('.arrow').remove(); + } + break; } + chart().basals.attr('display',''); + }); + + var treatmentDots = chart().focus.selectAll('treatment-insulincarbs') + .data(arc.data) + .enter() + .append('g') + .attr('class', 'draggable-treatment') + .attr('transform', 'translate(' + chart().xScale(new Date(treatment.mills)) + ', ' + chart().yScale(client.sbx.scaleEntry(treatment)) + ')') + .on('mouseover', treatmentTooltip) + .on('mouseout', hideTooltip); + if (client.editMode) { + treatmentDots + .style('cursor', 'move') + .call(renderer.drag); } - renderer.drawTreatments = function drawTreatments(client) { - // add treatment bubbles - _.forEach(client.ddata.treatments, function eachTreatment (d) { - renderer.drawTreatment(d, { - scale: renderer.bubbleScale() - , showLabels: true - }, client.sbx.data.profile.getCarbRatio(new Date())); + treatmentDots.append('path') + .attr('class', 'path') + .attr('fill', function (d) { + return d.outlineOnly ? 'transparent' : d.color; + }) + .attr('stroke-width', function (d) { + return d.outlineOnly ? 1 : 0; + }) + .attr('stroke', function (d) { + return d.color; + }) + .attr('id', function (d, i) { + return 's' + i; + }) + .attr('d', arc.svg); + + return treatmentDots; + } + + function appendLabels(treatmentDots, arc, opts) { + // labels for carbs and insulin + if (opts.showLabels) { + var label = treatmentDots.append('g') + .attr('class', 'path') + .attr('id', 'label') + .style('fill', 'white'); + + label.append('text') + // reduce the treatment label font size to make it readable with SMB + .style('font-size', 30 / opts.scale) + .style('text-shadow', '0px 0px 10px rgba(0, 0, 0, 1)') + .attr('text-anchor', 'middle') + .attr('dy', '.35em') + .attr('transform', function (d) { + d.outerRadius = d.outerRadius * 2.1; + d.innerRadius = d.outerRadius * 2.1; + return 'translate(' + arc.svg.centroid(d) + ')'; + }) + .text(function (d) { + return d.element; }); - }; - - renderer.drawTreatment = function drawTreatment(treatment, opts, carbratio) { - if (!treatment.carbs && !treatment.insulin) { - return; - } + } + } + + renderer.drawTreatments = function drawTreatments(client) { + // add treatment bubbles + _.forEach(client.ddata.treatments, function eachTreatment (d) { + renderer.drawTreatment(d, { + scale: renderer.bubbleScale() + , showLabels: true + }, client.sbx.data.profile.getCarbRatio(new Date())); + }); + }; + + renderer.drawTreatment = function drawTreatment(treatment, opts, carbratio) { + if (!treatment.carbs && !treatment.insulin) { + return; + } - //when the tests are run window isn't available - var innerWidth = window && window.innerWidth || -1; - // don't render the treatment if it's not visible - if (Math.abs(chart().xScale(new Date(treatment.mills))) > innerWidth) { - return; - } + //when the tests are run window isn't available + var innerWidth = window && window.innerWidth || -1; + // don't render the treatment if it's not visible + if (Math.abs(chart().xScale(new Date(treatment.mills))) > innerWidth) { + return; + } - var radius = calcTreatmentRadius(treatment, opts, carbratio); - if (radius.isNaN) { - console.warn('Bad Data: Found isNaN value in treatment', treatment); - return; - } + var radius = calcTreatmentRadius(treatment, opts, carbratio); + if (radius.isNaN) { + console.warn('Bad Data: Found isNaN value in treatment', treatment); + return; + } - var arc = prepareArc(treatment, radius); - var treatmentDots = appendTreatments(treatment, arc); - appendLabels(treatmentDots, arc, opts); - }; + var arc = prepareArc(treatment, radius); + var treatmentDots = appendTreatments(treatment, arc); + appendLabels(treatmentDots, arc, opts); + }; + + renderer.addBasals = function addBasals (client) { + + var mode = client.settings.extendedSettings.basal.render; + var profile = client.sbx.data.profile; + var linedata = []; + var notemplinedata = []; + var basalareadata = []; + var tempbasalareadata = []; + var comboareadata = []; + var from = chart().brush.extent()[0].getTime(); + var to = Math.max(chart().brush.extent()[1].getTime(), client.sbx.time) + client.forecastTime; + + var date = from; + var lastbasal = 0; + + if (!profile.activeProfileToTime(from)) { + window.alert(translate('Wrong profile setting.\nNo profile defined to displayed time.\nRedirecting to profile editor to create new profile.')); + try { + window.location.href = '/profile'; + } catch (err) { + //doesn't work when running tests, so catch and ignore + } + return; + } - renderer.addBasals = function addBasals (client) { - - var mode = client.settings.extendedSettings.basal.render; - var profile = client.sbx.data.profile; - var linedata = []; - var notemplinedata = []; - var basalareadata = []; - var tempbasalareadata = []; - var comboareadata = []; - var from = chart().brush.extent()[0].getTime(); - var to = Math.max(chart().brush.extent()[1].getTime(), client.sbx.time) + client.forecastTime; - - var date = from; - var lastbasal = 0; - - if (!profile.activeProfileToTime(from)) { - window.alert(translate('Wrong profile setting.\nNo profile defined to displayed time.\nRedirecting to profile editor to create new profile.')); - try { - window.location.href = '/profile'; - } catch (err) { - //doesn't work when running tests, so catch and ignore - } - return; + while (date <= to) { + var basalvalue = profile.getTempBasal(date); + if (!_.isEqual(lastbasal, basalvalue)) { + linedata.push( { d: date, b: basalvalue.totalbasal } ); + notemplinedata.push( { d: date, b: basalvalue.basal } ); + if (basalvalue.combobolustreatment && basalvalue.combobolustreatment.relative) { + tempbasalareadata.push( { d: date, b: basalvalue.tempbasal } ); + basalareadata.push( { d: date, b: 0 } ); + comboareadata.push( { d: date, b: basalvalue.totalbasal } ); + } else if (basalvalue.treatment) { + tempbasalareadata.push( { d: date, b: basalvalue.totalbasal } ); + basalareadata.push( { d: date, b: 0 } ); + comboareadata.push( { d: date, b: 0 } ); + } else { + tempbasalareadata.push( { d: date, b: 0 } ); + basalareadata.push( { d: date, b: basalvalue.totalbasal } ); + comboareadata.push( { d: date, b: 0 } ); } + } + lastbasal = basalvalue; + date += times.mins(1).msecs; + } - while (date <= to) { - var basalvalue = profile.getTempBasal(date); - if (!_.isEqual(lastbasal, basalvalue)) { - linedata.push( { d: date, b: basalvalue.totalbasal } ); - notemplinedata.push( { d: date, b: basalvalue.basal } ); - if (basalvalue.combobolustreatment && basalvalue.combobolustreatment.relative) { - tempbasalareadata.push( { d: date, b: basalvalue.tempbasal } ); - basalareadata.push( { d: date, b: 0 } ); - comboareadata.push( { d: date, b: basalvalue.totalbasal } ); - } else if (basalvalue.treatment) { - tempbasalareadata.push( { d: date, b: basalvalue.totalbasal } ); - basalareadata.push( { d: date, b: 0 } ); - comboareadata.push( { d: date, b: 0 } ); - } else { - tempbasalareadata.push( { d: date, b: 0 } ); - basalareadata.push( { d: date, b: basalvalue.totalbasal } ); - comboareadata.push( { d: date, b: 0 } ); - } - } - lastbasal = basalvalue; - date += times.mins(1).msecs; + var toTempBasal = profile.getTempBasal(to); + + linedata.push( { d: to, b: toTempBasal.totalbasal } ); + notemplinedata.push( { d: to, b: toTempBasal.basal } ); + basalareadata.push( { d: to, b: toTempBasal.basal } ); + tempbasalareadata.push( { d: to, b: toTempBasal.totalbasal } ); + comboareadata.push( { d: to, b: toTempBasal.totalbasal } ); + + var max_linedata = d3.max(linedata, function (d) { return d.b; }); + var max_notemplinedata = d3.max(notemplinedata, function (d) { return d.b; }); + var max = Math.max(max_linedata, max_notemplinedata) * ('icicle' === mode ? 1 : 1.1 ); + chart().maxBasalValue = max; + chart().yScaleBasals.domain('icicle' === mode ? [0, max] : [max, 0]); + + chart().basals.selectAll('g').remove(); + chart().basals.selectAll('.basalline').remove().data(linedata); + chart().basals.selectAll('.notempline').remove().data(notemplinedata); + chart().basals.selectAll('.basalarea').remove().data(basalareadata); + chart().basals.selectAll('.tempbasalarea').remove().data(tempbasalareadata); + chart().basals.selectAll('.comboarea').remove().data(comboareadata); + + var valueline = d3.svg.line() + .interpolate('step-after') + .x(function(d) { return chart().xScaleBasals(d.d); }) + .y(function(d) { return chart().yScaleBasals(d.b); }); + + var area = d3.svg.area() + .interpolate('step-after') + .x(function(d) { return chart().xScaleBasals(d.d); }) + .y0(chart().yScaleBasals(0)) + .y1(function(d) { return chart().yScaleBasals(d.b); }); + + var g = chart().basals.append('g'); + + g.append('path') + .attr('class', 'line basalline') + .attr('stroke', '#0099ff') + .attr('stroke-width', 1) + .attr('fill', 'none') + .attr('d', valueline(linedata)) + + g.append('path') + .attr('class', 'line notempline') + .attr('stroke', '#0099ff') + .attr('stroke-width', 1) + .attr('stroke-dasharray', ('3, 3')) + .attr('fill', 'none') + .attr('d', valueline(notemplinedata)) + + g.append('path') + .attr('class', 'area basalarea') + .datum(basalareadata) + .attr('fill', '#0099ff') + .attr('fill-opacity', .1) + .attr('stroke-width', 0) + .attr('d', area); + + g.append('path') + .attr('class', 'area tempbasalarea') + .datum(tempbasalareadata) + .attr('fill', '#0099ff') + .attr('fill-opacity', .2) + .attr('stroke-width', 1) + .attr('d', area); + + g.append('path') + .attr('class', 'area comboarea') + .datum(comboareadata) + .attr('fill', 'url(#hash)') + .attr('fill-opacity', .2) + .attr('stroke-width', 1) + .attr('d', area); + + _.forEach(client.ddata.tempbasalTreatments, function eachTemp (t) { + // only if basal and focus interval overlap and there is a chance to fit + if (t.duration && t.mills < to && t.mills + times.mins(t.duration).msecs > from) { + var text = g.append('text') + .attr('class', 'tempbasaltext') + .style('font-size', 15) + .attr('fill', '#0099ff') + .attr('text-anchor', 'middle') + .attr('dy', '.35em') + .attr('x', chart().xScaleBasals((Math.max(t.mills, from) + Math.min(t.mills + times.mins(t.duration).msecs, to))/2)) + .attr('y', 10) + .text((t.percent ? (t.percent > 0 ? '+' : '') + t.percent + '%' : '') + (isNaN(t.absolute) ? '' : Number(t.absolute).toFixed(2) + 'U') + (t.relative ? 'C: +' + t.relative + 'U' : '')); + // better hide if not fit + if (text.node().getBBox().width > chart().xScaleBasals(t.mills + times.mins(t.duration).msecs) - chart().xScaleBasals(t.mills)) { + text.attr('display', 'none'); } + } + }); - var toTempBasal = profile.getTempBasal(to); - - linedata.push( { d: to, b: toTempBasal.totalbasal } ); - notemplinedata.push( { d: to, b: toTempBasal.basal } ); - basalareadata.push( { d: to, b: toTempBasal.basal } ); - tempbasalareadata.push( { d: to, b: toTempBasal.totalbasal } ); - comboareadata.push( { d: to, b: toTempBasal.totalbasal } ); - - var max_linedata = d3.max(linedata, function (d) { return d.b; }); - var max_notemplinedata = d3.max(notemplinedata, function (d) { return d.b; }); - var max = Math.max(max_linedata, max_notemplinedata) * ('icicle' === mode ? 1 : 1.1 ); - chart().maxBasalValue = max; - chart().yScaleBasals.domain('icicle' === mode ? [0, max] : [max, 0]); - - chart().basals.selectAll('g').remove(); - chart().basals.selectAll('.basalline').remove().data(linedata); - chart().basals.selectAll('.notempline').remove().data(notemplinedata); - chart().basals.selectAll('.basalarea').remove().data(basalareadata); - chart().basals.selectAll('.tempbasalarea').remove().data(tempbasalareadata); - chart().basals.selectAll('.comboarea').remove().data(comboareadata); - - var valueline = d3.svg.line() - .interpolate('step-after') - .x(function(d) { return chart().xScaleBasals(d.d); }) - .y(function(d) { return chart().yScaleBasals(d.b); }); - - var area = d3.svg.area() - .interpolate('step-after') - .x(function(d) { return chart().xScaleBasals(d.d); }) - .y0(chart().yScaleBasals(0)) - .y1(function(d) { return chart().yScaleBasals(d.b); }); - - var g = chart().basals.append('g'); - - g.append('path') - .attr('class', 'line basalline') - .attr('stroke', '#0099ff') - .attr('stroke-width', 1) - .attr('fill', 'none') - .attr('d', valueline(linedata)) - - g.append('path') - .attr('class', 'line notempline') - .attr('stroke', '#0099ff') - .attr('stroke-width', 1) - .attr('stroke-dasharray', ('3, 3')) - .attr('fill', 'none') - .attr('d', valueline(notemplinedata)) - - g.append('path') - .attr('class', 'area basalarea') - .datum(basalareadata) - .attr('fill', '#0099ff') - .attr('fill-opacity', .1) - .attr('stroke-width', 0) - .attr('d', area); - - g.append('path') - .attr('class', 'area tempbasalarea') - .datum(tempbasalareadata) - .attr('fill', '#0099ff') - .attr('fill-opacity', .2) - .attr('stroke-width', 1) - .attr('d', area); - - g.append('path') - .attr('class', 'area comboarea') - .datum(comboareadata) - .attr('fill', 'url(#hash)') - .attr('fill-opacity', .2) - .attr('stroke-width', 1) - .attr('d', area); - - _.forEach(client.ddata.tempbasalTreatments, function eachTemp (t) { - // only if basal and focus interval overlap and there is a chance to fit - if (t.duration && t.mills < to && t.mills + times.mins(t.duration).msecs > from) { - var text = g.append('text') - .attr('class', 'tempbasaltext') - .style('font-size', 15) - .attr('fill', '#0099ff') - .attr('text-anchor', 'middle') - .attr('dy', '.35em') - .attr('x', chart().xScaleBasals((Math.max(t.mills, from) + Math.min(t.mills + times.mins(t.duration).msecs, to))/2)) - .attr('y', 10) - .text((t.percent ? (t.percent > 0 ? '+' : '') + t.percent + '%' : '') + (isNaN(t.absolute) ? '' : Number(t.absolute).toFixed(2) + 'U') + (t.relative ? 'C: +' + t.relative + 'U' : '')); - // better hide if not fit - if (text.node().getBBox().width > chart().xScaleBasals(t.mills + times.mins(t.duration).msecs) - chart().xScaleBasals(t.mills)) { - text.attr('display', 'none'); - } - } - }); + client.chart.basals.attr('display', !mode || 'none' === mode ? 'none' : ''); + }; - client.chart.basals.attr('display', !mode || 'none' === mode ? 'none' : ''); - }; + renderer.addTreatmentProfiles = function addTreatmentProfiles (client) { + if (client.profilefunctions.listBasalProfiles().length < 2) { + return; // do not visualize profiles if there is only one + } - renderer.addTreatmentProfiles = function addTreatmentProfiles (client) { - if (client.profilefunctions.listBasalProfiles().length < 2) { - return; // do not visualize profiles if there is only one - } + function profileTooltip (d) { + return ''+translate('Time')+': ' + client.formatTime(new Date(d.mills)) + '
      ' + + (d.eventType ? ''+translate('Treatment type')+': ' + translate(client.careportal.resolveEventName(d.eventType)) + '
      ' : '') + + (d.endprofile ? ''+translate('End of profile')+': ' + d.endprofile + '
      ' : '') + + (d.profile ? ''+translate('Profile')+': ' + d.profile + '
      ' : '') + + (d.duration ? ''+translate('Duration')+': ' + d.duration + translate('mins') + '
      ' : '') + + (d.enteredBy ? ''+translate('Entered By')+': ' + d.enteredBy + '
      ' : '') + + (d.notes ? ''+translate('Notes')+': ' + d.notes : ''); + } - function profileTooltip (d) { - return ''+translate('Time')+': ' + client.formatTime(new Date(d.mills)) + '
      ' + - (d.eventType ? ''+translate('Treatment type')+': ' + translate(client.careportal.resolveEventName(d.eventType)) + '
      ' : '') + - (d.endprofile ? ''+translate('End of profile')+': ' + d.endprofile + '
      ' : '') + - (d.profile ? ''+translate('Profile')+': ' + d.profile + '
      ' : '') + - (d.duration ? ''+translate('Duration')+': ' + d.duration + translate('mins') + '
      ' : '') + - (d.enteredBy ? ''+translate('Entered By')+': ' + d.enteredBy + '
      ' : '') + - (d.notes ? ''+translate('Notes')+': ' + d.notes : ''); + // calculate position of profile on left side + var from = chart().brush.extent()[0].getTime(); + var to = chart().brush.extent()[1].getTime(); + var mult = (to-from) / times.hours(24).msecs; + from += times.mins(20 * mult).msecs; + + var mode = client.settings.extendedSettings.basal.render; + var data = client.ddata.profileTreatments.slice(); + data.push({ + //eventType: 'Profile Switch' + profile: client.profilefunctions.activeProfileToTime(from) + , mills: from + , first: true + }); + + _.forEach(client.ddata.profileTreatments, function eachTreatment (d) { + if (d.duration && !d.cuttedby) { + data.push({ + cutting: d.profile + , profile: client.profilefunctions.activeProfileToTime(times.mins(d.duration).msecs + d.mills + 1) + , mills: times.mins(d.duration).msecs + d.mills + , end: true + }); + } + }); + + var treatProfiles = chart().basals.selectAll('.g-profile').data(data); + + var topOfText = ('icicle' === mode ? chart().maxBasalValue + 0.05 : -0.05); + + var generateText = function (t) { + var sign = t.first ? '▲▲▲' : '▬▬▬'; + var ret; + if (t.cutting) { + ret = sign + ' ' + t.cutting + ' ' + '►►►' + ' ' + t.profile + ' ' + sign; + } else { + ret = sign + ' ' + t.profile + ' ' + sign; } - - // calculate position of profile on left side - var from = chart().brush.extent()[0].getTime(); - var to = chart().brush.extent()[1].getTime(); - var mult = (to-from) / times.hours(24).msecs; - from += times.mins(20 * mult).msecs; - - var mode = client.settings.extendedSettings.basal.render; - var data = client.ddata.profileTreatments.slice(); - data.push({ - //eventType: 'Profile Switch' - profile: client.profilefunctions.activeProfileToTime(from) - , mills: from - , first: true - }); - - _.forEach(client.ddata.profileTreatments, function eachTreatment (d) { - if (d.duration && !d.cuttedby) { - data.push({ - cutting: d.profile - , profile: client.profilefunctions.activeProfileToTime(times.mins(d.duration).msecs + d.mills + 1) - , mills: times.mins(d.duration).msecs + d.mills - , end: true - }); - } - }); - - var treatProfiles = chart().basals.selectAll('.g-profile').data(data); - - var topOfText = ('icicle' === mode ? chart().maxBasalValue + 0.05 : -0.05); - - var generateText = function (t) { - var sign = t.first ? '▲▲▲' : '▬▬▬'; - var ret; - if (t.cutting) { - ret = sign + ' ' + t.cutting + ' ' + '►►►' + ' ' + t.profile + ' ' + sign; - } else { - ret = sign + ' ' + t.profile + ' ' + sign; - } - return ret; - }; - - treatProfiles.transition().duration(0) - .attr('transform', function (t) { - // change text of record on left side - return 'rotate(-90,' + chart().xScale(t.mills) + ',' + chart().yScaleBasals(topOfText) + ') ' + - 'translate(' + chart().xScale(t.mills) + ',' + chart().yScaleBasals(topOfText) + ')'; - }). - text(generateText); - - treatProfiles.enter().append('text') - .attr('class', 'g-profile') - .style('font-size', 15) - .style('font-weight', 'bold') - .attr('fill', '#0099ff') - .attr('text-anchor', 'end') - .attr('dy', '.35em') - .attr('transform', function (t) { - return 'rotate(-90 ' + chart().xScale(t.mills) + ',' + chart().yScaleBasals(topOfText) + ') ' + - 'translate(' + chart().xScale(t.mills) + ',' + chart().yScaleBasals(topOfText) + ')'; - }) - .text(generateText) - .on('mouseover', function (d) { - client.tooltip.transition().duration(TOOLTIP_TRANS_MS).style('opacity', .9); - client.tooltip.html(profileTooltip(d)) - .style('left', (d3.event.pageX) + 'px') - .style('top', (d3.event.pageY + 15) + 'px'); - }) - .on('mouseout', hideTooltip); - - treatProfiles.exit().remove(); + return ret; }; - return renderer; + treatProfiles.transition().duration(0) + .attr('transform', function (t) { + // change text of record on left side + return 'rotate(-90,' + chart().xScale(t.mills) + ',' + chart().yScaleBasals(topOfText) + ') ' + + 'translate(' + chart().xScale(t.mills) + ',' + chart().yScaleBasals(topOfText) + ')'; + }). + text(generateText); + + treatProfiles.enter().append('text') + .attr('class', 'g-profile') + .style('font-size', 15) + .style('font-weight', 'bold') + .attr('fill', '#0099ff') + .attr('text-anchor', 'end') + .attr('dy', '.35em') + .attr('transform', function (t) { + return 'rotate(-90 ' + chart().xScale(t.mills) + ',' + chart().yScaleBasals(topOfText) + ') ' + + 'translate(' + chart().xScale(t.mills) + ',' + chart().yScaleBasals(topOfText) + ')'; + }) + .text(generateText) + .on('mouseover', function (d) { + client.tooltip.transition().duration(TOOLTIP_TRANS_MS).style('opacity', .9); + client.tooltip.html(profileTooltip(d)) + .style('left', (d3.event.pageX) + 'px') + .style('top', (d3.event.pageY + 15) + 'px'); + }) + .on('mouseout', hideTooltip); + + treatProfiles.exit().remove(); + }; + + return renderer; } -module.exports = init; \ No newline at end of file +module.exports = init; diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 3bf32f1760e..eab3090b3dd 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,6 +1,6 @@ { "name": "Nightscout", - "version": "0.10.2-release-20171026", + "version": "0.10.2-release-20171027", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 5fd8189df38..13f22a4cade 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "Nightscout", - "version": "0.10.2-release-20171026", + "version": "0.10.2-release-20171027", "description": "Nightscout acts as a web-based CGM (Continuous Glucose Montinor) to allow multiple caregivers to remotely view a patients glucose data in realtime.", "license": "AGPL-3.0", "author": "Nightscout Team", diff --git a/tests/client.renderer.test.js b/tests/client.renderer.test.js index ec70a627d4f..bb82ee024a1 100644 --- a/tests/client.renderer.test.js +++ b/tests/client.renderer.test.js @@ -18,7 +18,7 @@ describe('renderer', () => { let mockClient = { utils: true , chart: { prevChartWidth: prev.width } - , foucusRangeMS: true + , focusRangeMS: true }; it('scales correctly', () => { renderer(mockClient, {}).bubbleScale().should.be.approximately(prev.expectedScale, MAX_DELTA); diff --git a/views/index.html b/views/index.html index 237c0297a5c..0cc6c903834 100644 --- a/views/index.html +++ b/views/index.html @@ -148,6 +148,7 @@
        +
      • 2HR
      • 3HR
      • 6HR
      • 12HR
      • From edbf22b67e178910a76805208b4e011fa21a8ad4 Mon Sep 17 00:00:00 2001 From: PieterGit Date: Fri, 27 Oct 2017 21:18:32 +0200 Subject: [PATCH 43/51] bring back the ' U' for non-SMB's (> 1U insulin and with carbs) --- lib/client/renderer.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/client/renderer.js b/lib/client/renderer.js index d92559926e8..15bb5544e5f 100644 --- a/lib/client/renderer.js +++ b/lib/client/renderer.js @@ -444,9 +444,13 @@ function init (client, d3) { } if ( treatment.insulin > 0) { + var dosage_units = Math.round(treatment.insulin * 100)/100; + var unit_of_measurement = ' U'; // One international unit of insulin (1 IU) is shown as '1 U' + if ( treatment.insulin < 1 && !treatment.carbs ) { // don't show the unit of measurement for insulin boluses < 1 without carbs (e.g. oref0 SMB's). Otherwise lot's of small insulin only dosages are often unreadable + unit_of_measurement = ''; + } // remove leading zeros to avoid overlap with adjacent boluses - var units = Math.round(treatment.insulin * 100)/100; - arc_data[3].element = (units+"").replace(/^0/,""); + arc_data[3].element = (dosage_units+"").replace(/^0/,"")+unit_of_measurement; } if (treatment.status) { From 8f874904e773a97f9b98d615152f36a9f0d55af8 Mon Sep 17 00:00:00 2001 From: PieterGit Date: Fri, 27 Oct 2017 21:40:02 +0200 Subject: [PATCH 44/51] Revert "bring back the ' U' for non-SMB's (> 1U insulin and with carbs)" This reverts commit edbf22b67e178910a76805208b4e011fa21a8ad4. --- lib/client/renderer.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/client/renderer.js b/lib/client/renderer.js index 15bb5544e5f..d92559926e8 100644 --- a/lib/client/renderer.js +++ b/lib/client/renderer.js @@ -444,13 +444,9 @@ function init (client, d3) { } if ( treatment.insulin > 0) { - var dosage_units = Math.round(treatment.insulin * 100)/100; - var unit_of_measurement = ' U'; // One international unit of insulin (1 IU) is shown as '1 U' - if ( treatment.insulin < 1 && !treatment.carbs ) { // don't show the unit of measurement for insulin boluses < 1 without carbs (e.g. oref0 SMB's). Otherwise lot's of small insulin only dosages are often unreadable - unit_of_measurement = ''; - } // remove leading zeros to avoid overlap with adjacent boluses - arc_data[3].element = (dosage_units+"").replace(/^0/,"")+unit_of_measurement; + var units = Math.round(treatment.insulin * 100)/100; + arc_data[3].element = (units+"").replace(/^0/,""); } if (treatment.status) { From 4a3c1ebc046030e37349291954dcd479261e9e6a Mon Sep 17 00:00:00 2001 From: PieterGit Date: Fri, 27 Oct 2017 22:27:22 +0200 Subject: [PATCH 45/51] fix typo foucusRangeMS to focusRangeMS in lib/client/chart.js --- lib/client/chart.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/client/chart.js b/lib/client/chart.js index 7361c1a7098..32a15ba0155 100644 --- a/lib/client/chart.js +++ b/lib/client/chart.js @@ -511,7 +511,7 @@ function init (client, d3, $) { var updateBrush = d3.select('.brush').transition(); updateBrush - .call(chart.brush.extent([new Date(dataRange[1].getTime() - client.foucusRangeMS), dataRange[1]])); + .call(chart.brush.extent([new Date(dataRange[1].getTime() - client.focusRangeMS), dataRange[1]])); client.brushed(true); renderer.addContextCircles(); From bea449bd265f966acb9e4d7af03fa46cc4e2206b Mon Sep 17 00:00:00 2001 From: PieterGit Date: Fri, 27 Oct 2017 22:42:27 +0200 Subject: [PATCH 46/51] for some reasone change from foucusRangeMS to focusRangeMS was not implemented in lib/client/index.js This was fixed on ZT branch in https://github.com/nightscout/cgm-remote-monitor/commit/38d35398d13812cf41d43daeacd2a20c82d5b71d --- lib/client/index.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/client/index.js b/lib/client/index.js index ac801e2561e..f8ca8e56fbe 100644 --- a/lib/client/index.js +++ b/lib/client/index.js @@ -221,7 +221,7 @@ client.load = function load(serverSettings, callback) { client.hashauth.initAuthentication(client.afterAuth); - client.foucusRangeMS = times.hours(client.settings.focusHours).msecs; + client.focusRangeMS = times.hours(client.settings.focusHours).msecs; $('.focus-range li[data-hours=' + client.settings.focusHours + ']').addClass('selected'); client.brushed = brushed; client.formatTime = formatTime; @@ -365,7 +365,7 @@ client.load = function load(serverSettings, callback) { d3.select('.brush') .transition() .duration(UPDATE_TRANS_MS) - .call(chart.brush.extent([new Date(dataRange[1].getTime() - client.foucusRangeMS), dataRange[1]])); + .call(chart.brush.extent([new Date(dataRange[1].getTime() - client.focusRangeMS), dataRange[1]])); if (!skipBrushing) { brushed(); @@ -385,14 +385,14 @@ client.load = function load(serverSettings, callback) { var brushExtent = chart.brush.extent(); // ensure that brush extent is fixed at 3.5 hours - if (brushExtent[1].getTime() - brushExtent[0].getTime() !== client.foucusRangeMS) { + if (brushExtent[1].getTime() - brushExtent[0].getTime() !== client.focusRangeMS) { // ensure that brush updating is with the time range - if (brushExtent[0].getTime() + client.foucusRangeMS > client.dataExtent()[1].getTime()) { - brushExtent[0] = new Date(brushExtent[1].getTime() - client.foucusRangeMS); + if (brushExtent[0].getTime() + client.focusRangeMS > client.dataExtent()[1].getTime()) { + brushExtent[0] = new Date(brushExtent[1].getTime() - client.focusRangeMS); d3.select('.brush') .call(chart.brush.extent([brushExtent[0], brushExtent[1]])); } else { - brushExtent[1] = new Date(brushExtent[0].getTime() + client.foucusRangeMS); + brushExtent[1] = new Date(brushExtent[0].getTime() + client.focusRangeMS); d3.select('.brush') .call(chart.brush.extent([brushExtent[0], brushExtent[1]])); } @@ -868,7 +868,7 @@ client.load = function load(serverSettings, callback) { $('.focus-range li').removeClass('selected'); li.addClass('selected'); var hours = Number(li.data('hours')); - client.foucusRangeMS = times.hours(hours).msecs; + client.focusRangeMS = times.hours(hours).msecs; Storages.localStorage.set('focusHours', hours); refreshChart(); } else { From 0c171d6fa3a4f953cc1b10f4e8c988d485f760a0 Mon Sep 17 00:00:00 2001 From: PieterGit Date: Fri, 27 Oct 2017 21:18:32 +0200 Subject: [PATCH 47/51] bring back the ' U' for non-SMB's (> 1U insulin and with carbs) --- lib/client/renderer.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/client/renderer.js b/lib/client/renderer.js index d92559926e8..15bb5544e5f 100644 --- a/lib/client/renderer.js +++ b/lib/client/renderer.js @@ -444,9 +444,13 @@ function init (client, d3) { } if ( treatment.insulin > 0) { + var dosage_units = Math.round(treatment.insulin * 100)/100; + var unit_of_measurement = ' U'; // One international unit of insulin (1 IU) is shown as '1 U' + if ( treatment.insulin < 1 && !treatment.carbs ) { // don't show the unit of measurement for insulin boluses < 1 without carbs (e.g. oref0 SMB's). Otherwise lot's of small insulin only dosages are often unreadable + unit_of_measurement = ''; + } // remove leading zeros to avoid overlap with adjacent boluses - var units = Math.round(treatment.insulin * 100)/100; - arc_data[3].element = (units+"").replace(/^0/,""); + arc_data[3].element = (dosage_units+"").replace(/^0/,"")+unit_of_measurement; } if (treatment.status) { From 1fa753d85f03685c521c4916466d3f6b90e5371a Mon Sep 17 00:00:00 2001 From: Christopher Fredregill Date: Wed, 25 Oct 2017 20:59:26 -0700 Subject: [PATCH 48/51] More test coverage for /lib/client/renderer.js (highlightBrushPoints) --- tests/client.renderer.test.js | 51 ++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/tests/client.renderer.test.js b/tests/client.renderer.test.js index ec70a627d4f..96b8850850a 100644 --- a/tests/client.renderer.test.js +++ b/tests/client.renderer.test.js @@ -4,15 +4,16 @@ require('should'); let _ = require('lodash'); let renderer = require('../lib/client/renderer'); -const MAX_DELTA = 0.0001; -const PREV_CHART_WIDTHS = [ - { width: 400, expectedScale: 3.5 } - , { width: 500, expectedScale: 2.625 } - , { width: 900, expectedScale: 1.75 } -]; describe('renderer', () => { describe('bubbleScale', () => { + const MAX_DELTA = 0.0001; + const PREV_CHART_WIDTHS = [ + { width: 400, expectedScale: 3.5 } + , { width: 500, expectedScale: 2.625 } + , { width: 900, expectedScale: 1.75 } + ]; + _.forEach(PREV_CHART_WIDTHS, (prev) => { describe(`prevChartWidth < ${prev.width}`, () => { let mockClient = { @@ -26,4 +27,42 @@ describe('renderer', () => { }); }); }); + + describe('highlightBrushPoints', () => { + const BRUSH_EXTENTS = [ + { mills: 100, times: [200, 300], expectedOpacity: 0.5, expectation: 'Uses default opacity' } + , { mills: 300, times: [100, 200], expectedOpacity: 0.5, expectation: 'Uses default opacity' } + , { mills: 200, times: [100, 300], expectedOpacity: 1, expectation: 'Calculates opacity' } + ]; + + _.forEach(BRUSH_EXTENTS, (extent) => { + let mockData = { + mills: extent.mills + }; + + let mockClient = { + chart: { + brush: { + extent: () => { + let extents = []; + for (let time of extent.times) { + extents.push({ getTime: () => { + return time; + }}); + } + return extents; + } + } + , futureOpacity: (millsDifference) => { return 1; } + } + , latestSGV: { mills: 120 } + }; + + describe(`data.mills ${extent.mills} and chart().brush.extent() times ${extent.times}`, () => { + it(extent.expectation, () => { + renderer(mockClient, {}).highlightBrushPoints(mockData).should.equal(extent.expectedOpacity); + }); + }); + }); + }); }); From 9701c0351aff018d6512793ee8ae2df5facc5ccf Mon Sep 17 00:00:00 2001 From: Scott Date: Wed, 1 Nov 2017 09:17:39 -0700 Subject: [PATCH 49/51] display Sensitivity Ratio in OpenAPS pill --- lib/plugins/openaps.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/plugins/openaps.js b/lib/plugins/openaps.js index 92ad8198292..978ad6ec760 100644 --- a/lib/plugins/openaps.js +++ b/lib/plugins/openaps.js @@ -300,7 +300,7 @@ function init(ctx) { var valueParts = [ valueString('BG: ', prop.lastSuggested.bg) , valueString(', ', prop.lastSuggested.reason) - , prop.lastSuggested.mealAssist && _.includes(selectedFields, 'meal-assist') ? ' Meal Assist: ' + prop.lastSuggested.mealAssist : '' + , prop.lastSuggested.sensitivityRatio ? ' Sensitivity Ratio: ' + prop.lastSuggested.sensitivityRatio : '' ]; if (_.includes(selectedFields, 'iob')) { @@ -317,7 +317,7 @@ function init(ctx) { function concatIOB (valueParts) { if (prop.lastIOB) { valueParts = valueParts.concat([ - ' IOB: ' + ', IOB: ' , sbx.roundInsulinForDisplayFormat(prop.lastIOB.iob) + 'U' , prop.lastIOB.basaliob ? ', Basal IOB ' + sbx.roundInsulinForDisplayFormat(prop.lastIOB.basaliob) + 'U' : '' , prop.lastIOB.bolusiob ? ', Bolus IOB ' + sbx.roundInsulinForDisplayFormat(prop.lastIOB.bolusiob) + 'U' : '' From 6f830319a1d7530366101bceb193bcc02172b152 Mon Sep 17 00:00:00 2001 From: Scott Date: Wed, 1 Nov 2017 09:26:03 -0700 Subject: [PATCH 50/51] add comma --- lib/plugins/openaps.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/plugins/openaps.js b/lib/plugins/openaps.js index 978ad6ec760..267ab0b06e1 100644 --- a/lib/plugins/openaps.js +++ b/lib/plugins/openaps.js @@ -300,7 +300,7 @@ function init(ctx) { var valueParts = [ valueString('BG: ', prop.lastSuggested.bg) , valueString(', ', prop.lastSuggested.reason) - , prop.lastSuggested.sensitivityRatio ? ' Sensitivity Ratio: ' + prop.lastSuggested.sensitivityRatio : '' + , prop.lastSuggested.sensitivityRatio ? ', Sensitivity Ratio: ' + prop.lastSuggested.sensitivityRatio : '' ]; if (_.includes(selectedFields, 'iob')) { From dc3611d2342074fa03920fcc93080af7719cd350 Mon Sep 17 00:00:00 2001 From: Sulka Haro Date: Wed, 1 Nov 2017 21:42:47 +0200 Subject: [PATCH 51/51] Fix SAGE pill test failing due to summer time change --- tests/sensorage.test.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/sensorage.test.js b/tests/sensorage.test.js index 6c0165ef73e..87705866d33 100644 --- a/tests/sensorage.test.js +++ b/tests/sensorage.test.js @@ -22,8 +22,8 @@ describe('sage', function ( ) { var data = { sensorTreatments: [ - {eventType: 'Sensor Change', notes: 'Foo', mills: Date.now() - times.days(15).msecs} - , {eventType: 'Sensor Start', notes: 'Bar', mills: Date.now() - times.days(3).msecs} + {eventType: 'Sensor Change', notes: 'Foo', mills: Date.now() - times.days(2).msecs} + , {eventType: 'Sensor Start', notes: 'Bar', mills: Date.now() - times.days(1).msecs} ] }; @@ -31,12 +31,14 @@ describe('sage', function ( ) { settings: {} , pluginBase: { updatePillText: function mockedUpdatePillText(plugin, options) { - options.value.should.equal('3d0h'); + + console.log(JSON.stringify(options)); + options.value.should.equal('1d0h'); options.info[0].label.should.equal('Sensor Insert'); - options.info[1].should.match({ label: 'Duration', value: '15 days 0 hours' }); + options.info[1].should.match({ label: 'Duration', value: '2 days 0 hours' }); options.info[2].should.match({ label: 'Notes', value: 'Foo' }); options.info[3].label.should.equal('Sensor Start'); - options.info[4].should.match({ label: 'Duration', value: '3 days 0 hours' }); + options.info[4].should.match({ label: 'Duration', value: '1 days 0 hours' }); options.info[5].should.match({ label: 'Notes', value: 'Bar' }); done(); }