From 42b500263a34e26c245ae34174917ded9ecfefe1 Mon Sep 17 00:00:00 2001 From: James Allen Date: Tue, 6 May 2014 16:52:03 +0100 Subject: [PATCH 001/182] Create metrics module --- libraries/metrics/.gitignore | 1 + libraries/metrics/index.js | 2 ++ libraries/metrics/metrics.coffee | 34 +++++++++++++++++++++++++++ libraries/metrics/mongodb.coffee | 40 ++++++++++++++++++++++++++++++++ libraries/metrics/package.json | 10 ++++++++ 5 files changed, 87 insertions(+) create mode 100644 libraries/metrics/.gitignore create mode 100644 libraries/metrics/index.js create mode 100644 libraries/metrics/metrics.coffee create mode 100644 libraries/metrics/mongodb.coffee create mode 100644 libraries/metrics/package.json diff --git a/libraries/metrics/.gitignore b/libraries/metrics/.gitignore new file mode 100644 index 0000000000..3c3629e647 --- /dev/null +++ b/libraries/metrics/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/libraries/metrics/index.js b/libraries/metrics/index.js new file mode 100644 index 0000000000..26e3d9a500 --- /dev/null +++ b/libraries/metrics/index.js @@ -0,0 +1,2 @@ +require("coffee-script") +module.exports = require('./metrics'); diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee new file mode 100644 index 0000000000..e641963ddf --- /dev/null +++ b/libraries/metrics/metrics.coffee @@ -0,0 +1,34 @@ +StatsD = require('lynx') +statsd = new StatsD('localhost', 8125, {on_error:->}) + +name = "unknown" + +buildKey = (key)-> "#{name}.#{process.env.NODE_ENV or "development"}.#{key}" + +module.exports = + initialize: (options = {}) -> + name = options.name + + set : (key, value, sampleRate = 1)-> + statsd.set buildKey(key), value, sampleRate + + inc : (key, sampleRate = 1)-> + statsd.increment buildKey(key), sampleRate + + timing: (key, timeSpan, sampleRate)-> + statsd.timing(key, timeSpan, sampleRate) + + Timer : class + constructor :(key, sampleRate = 1)-> + this.start = new Date() + this.key = buildKey(key) + this.sampleRate = sampleRate + done:-> + timeSpan = new Date - this.start + statsd.timing(this.key, timeSpan, this.sampleRate) + + gauge : (key, value, sampleRate = 1)-> + statsd.gauge key, value, sampleRate + + mongodb: require "./mongodb" + diff --git a/libraries/metrics/mongodb.coffee b/libraries/metrics/mongodb.coffee new file mode 100644 index 0000000000..a75e57fd20 --- /dev/null +++ b/libraries/metrics/mongodb.coffee @@ -0,0 +1,40 @@ +_ = require("underscore") + +module.exports = + monitor: (mongodb_require_path, logger) -> + Db = require("#{mongodb_require_path}/lib/mongodb/db").Db + + Metrics = require("./metrics") + + monitorMethod = (base, method, type) -> + _method = base[method] + + base[method] = (db_command, options, callback) -> + if (typeof callback == 'undefined') + callback = options + options = {} + callback = () -> + + key = "mongo-requests.#{type}" + if db_command.query? + query = Object.keys(db_command.query).sort().join("_") + key += "." + query + + Metrics.inc key + timer = new Metrics.Timer(key) + start = new Date() + _method.call this, db_command, options, () -> + timer.done() + time = new Date() - start + logger.log + query: db_command.query + type: type + collection: db_command.collectionName + "response-time": new Date() - start + "mongo request" + callback.apply this, arguments + + monitorMethod(Db.prototype, "_executeQueryCommand", "query") + monitorMethod(Db.prototype, "_executeRemoveCommand", "remove") + monitorMethod(Db.prototype, "_executeInsertCommand", "insert") + monitorMethod(Db.prototype, "_executeUpdateCommand", "update") \ No newline at end of file diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json new file mode 100644 index 0000000000..a76929f2fa --- /dev/null +++ b/libraries/metrics/package.json @@ -0,0 +1,10 @@ +{ + "name": "metrics-sharelatex", + "version": "0.0.0", + "description": "A drop-in metrics and monitoring module for node.js apps", + "dependencies": { + "lynx": "~0.1.1", + "coffee-script": "~1.7.1", + "underscore": "~1.6.0" + } +} From 15f85494b75e0b19d85cbbd37bf39794f8a0a393 Mon Sep 17 00:00:00 2001 From: James Allen Date: Tue, 6 May 2014 17:01:41 +0100 Subject: [PATCH 002/182] Sort out initialization and ignore noisy mongo requests --- libraries/metrics/metrics.coffee | 4 ++-- libraries/metrics/mongodb.coffee | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index e641963ddf..c1507c5b11 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -6,8 +6,8 @@ name = "unknown" buildKey = (key)-> "#{name}.#{process.env.NODE_ENV or "development"}.#{key}" module.exports = - initialize: (options = {}) -> - name = options.name + initialize: (name) -> + name = name set : (key, value, sampleRate = 1)-> statsd.set buildKey(key), value, sampleRate diff --git a/libraries/metrics/mongodb.coffee b/libraries/metrics/mongodb.coffee index a75e57fd20..c4a2544c84 100644 --- a/libraries/metrics/mongodb.coffee +++ b/libraries/metrics/mongodb.coffee @@ -15,6 +15,10 @@ module.exports = options = {} callback = () -> + if db_command.query? and (db_command.query["ping"] or db_command.query["ismaster"]) + # Ignore noisy methods + return _method.call this, db_command, options, callback + key = "mongo-requests.#{type}" if db_command.query? query = Object.keys(db_command.query).sort().join("_") From 00c12ccab6477b4db0fa735072457c77269fcf9e Mon Sep 17 00:00:00 2001 From: James Allen Date: Tue, 6 May 2014 17:06:34 +0100 Subject: [PATCH 003/182] Remove redundant count --- libraries/metrics/mongodb.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/metrics/mongodb.coffee b/libraries/metrics/mongodb.coffee index c4a2544c84..b33f6a3f85 100644 --- a/libraries/metrics/mongodb.coffee +++ b/libraries/metrics/mongodb.coffee @@ -24,7 +24,6 @@ module.exports = query = Object.keys(db_command.query).sort().join("_") key += "." + query - Metrics.inc key timer = new Metrics.Timer(key) start = new Date() _method.call this, db_command, options, () -> From 125790b6049f71801e6265f636000ce789ec6292 Mon Sep 17 00:00:00 2001 From: James Allen Date: Tue, 6 May 2014 17:19:04 +0100 Subject: [PATCH 004/182] Ignore all queries --- libraries/metrics/mongodb.coffee | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/metrics/mongodb.coffee b/libraries/metrics/mongodb.coffee index b33f6a3f85..cf8710ccf9 100644 --- a/libraries/metrics/mongodb.coffee +++ b/libraries/metrics/mongodb.coffee @@ -15,8 +15,9 @@ module.exports = options = {} callback = () -> - if db_command.query? and (db_command.query["ping"] or db_command.query["ismaster"]) - # Ignore noisy methods + collection = db_command.collectionName + if collection.match(/\$cmd$/) + # Ignore noisy command methods like authenticating, ismaster and ping return _method.call this, db_command, options, callback key = "mongo-requests.#{type}" @@ -32,7 +33,7 @@ module.exports = logger.log query: db_command.query type: type - collection: db_command.collectionName + collection: collection "response-time": new Date() - start "mongo request" callback.apply this, arguments From 4da7fa43fad52a208f5dd8c5eb9dcbf3353f9760 Mon Sep 17 00:00:00 2001 From: James Allen Date: Tue, 6 May 2014 17:33:09 +0100 Subject: [PATCH 005/182] Scope name argument properly --- libraries/metrics/metrics.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index c1507c5b11..46e5f87f5c 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -6,8 +6,8 @@ name = "unknown" buildKey = (key)-> "#{name}.#{process.env.NODE_ENV or "development"}.#{key}" module.exports = - initialize: (name) -> - name = name + initialize: (_name) -> + name = _name set : (key, value, sampleRate = 1)-> statsd.set buildKey(key), value, sampleRate From f4895fb04ff9efb6a64830d1b10c9d44e905e4a1 Mon Sep 17 00:00:00 2001 From: James Allen Date: Wed, 7 May 2014 10:58:52 +0100 Subject: [PATCH 006/182] Add in http monitoring --- libraries/metrics/http.coffee | 29 +++++++++++++++++++++++++++++ libraries/metrics/metrics.coffee | 4 +++- 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 libraries/metrics/http.coffee diff --git a/libraries/metrics/http.coffee b/libraries/metrics/http.coffee new file mode 100644 index 0000000000..52379695f9 --- /dev/null +++ b/libraries/metrics/http.coffee @@ -0,0 +1,29 @@ +os = require("os") + +module.exports.monitor = (logger) -> + return (req, res, next) -> + Metrics = require("./metrics") + startTime = new Date() + end = res.end + res.end = () -> + end.apply(this, arguments) + responseTime = new Date() - startTime + routePath = req.route.path.toString().replace(/\//g, '_').replace(/\:/g, '').slice(1) + key = "#{routePath}.#{req.method}.#{res.statusCode}" + + Metrics.timing(key, responseTime) + logger.log + req: + url: req.originalUrl || req.url + method: req.method + referrer: req.headers['referer'] || req.headers['referrer'] + "remote-addr": req.ip || req.socket?.socket?.remoteAddress || req.socket?.remoteAddress + "user-agent": req.headers["user-agent"] + "content-length": req.headers["content-length"] + res: + "content-length": res._headers?["content-length"] + statusCode: res.statusCode + "response-time": responseTime + "http request" + next() + diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 46e5f87f5c..05aaa12d3d 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -2,8 +2,9 @@ StatsD = require('lynx') statsd = new StatsD('localhost', 8125, {on_error:->}) name = "unknown" +hostname = require('os').hostname() -buildKey = (key)-> "#{name}.#{process.env.NODE_ENV or "development"}.#{key}" +buildKey = (key)-> "#{name}.#{hostname}.#{key}" module.exports = initialize: (_name) -> @@ -31,4 +32,5 @@ module.exports = statsd.gauge key, value, sampleRate mongodb: require "./mongodb" + http: require "./http" From befb48a20fdb381471c2fa8b93d28f3819a5d4e0 Mon Sep 17 00:00:00 2001 From: James Allen Date: Wed, 7 May 2014 11:08:46 +0100 Subject: [PATCH 007/182] Use correct key in Metrics.timing --- libraries/metrics/metrics.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 05aaa12d3d..5079d1cdbe 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -17,12 +17,12 @@ module.exports = statsd.increment buildKey(key), sampleRate timing: (key, timeSpan, sampleRate)-> - statsd.timing(key, timeSpan, sampleRate) + statsd.timing(buildKey(key), timeSpan, sampleRate) Timer : class constructor :(key, sampleRate = 1)-> this.start = new Date() - this.key = buildKey(key) + this.key = key this.sampleRate = sampleRate done:-> timeSpan = new Date - this.start From 873297b02edd9a50359dfec605c5548d7c694071 Mon Sep 17 00:00:00 2001 From: James Allen Date: Wed, 7 May 2014 11:13:21 +0100 Subject: [PATCH 008/182] Namespace http request keys --- libraries/metrics/http.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/http.coffee b/libraries/metrics/http.coffee index 52379695f9..1f6fe20971 100644 --- a/libraries/metrics/http.coffee +++ b/libraries/metrics/http.coffee @@ -9,7 +9,7 @@ module.exports.monitor = (logger) -> end.apply(this, arguments) responseTime = new Date() - startTime routePath = req.route.path.toString().replace(/\//g, '_').replace(/\:/g, '').slice(1) - key = "#{routePath}.#{req.method}.#{res.statusCode}" + key = "http-requests.#{routePath}.#{req.method}.#{res.statusCode}" Metrics.timing(key, responseTime) logger.log From 45ec60d8a6c688c245388986c5d194b5b0a723e1 Mon Sep 17 00:00:00 2001 From: James Allen Date: Wed, 7 May 2014 11:43:46 +0100 Subject: [PATCH 009/182] Fix broken key building in timer --- libraries/metrics/metrics.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 5079d1cdbe..0e6e9908f6 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -26,7 +26,7 @@ module.exports = this.sampleRate = sampleRate done:-> timeSpan = new Date - this.start - statsd.timing(this.key, timeSpan, this.sampleRate) + statsd.timing(buildKey(this.key), timeSpan, this.sampleRate) gauge : (key, value, sampleRate = 1)-> statsd.gauge key, value, sampleRate From 86f220a2d278c88f0733bdfa5456e43d4982e74d Mon Sep 17 00:00:00 2001 From: James Allen Date: Wed, 7 May 2014 11:50:09 +0100 Subject: [PATCH 010/182] Add collection into graphite key --- libraries/metrics/mongodb.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/mongodb.coffee b/libraries/metrics/mongodb.coffee index cf8710ccf9..71529434db 100644 --- a/libraries/metrics/mongodb.coffee +++ b/libraries/metrics/mongodb.coffee @@ -20,7 +20,7 @@ module.exports = # Ignore noisy command methods like authenticating, ismaster and ping return _method.call this, db_command, options, callback - key = "mongo-requests.#{type}" + key = "mongo-requests.#{collection}.#{type}" if db_command.query? query = Object.keys(db_command.query).sort().join("_") key += "." + query From 00c0036ca5f0a333f315aab584e500f4c3b2d39a Mon Sep 17 00:00:00 2001 From: James Allen Date: Fri, 9 May 2014 13:30:12 +0100 Subject: [PATCH 011/182] Add open socket monitoring --- libraries/metrics/metrics.coffee | 1 + libraries/metrics/open_sockets.coffee | 19 +++++++++++++++++++ libraries/metrics/package.json | 2 +- 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 libraries/metrics/open_sockets.coffee diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 0e6e9908f6..2b3c418046 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -33,4 +33,5 @@ module.exports = mongodb: require "./mongodb" http: require "./http" + open_sockets: require "./open_sockets" diff --git a/libraries/metrics/open_sockets.coffee b/libraries/metrics/open_sockets.coffee new file mode 100644 index 0000000000..d74a781496 --- /dev/null +++ b/libraries/metrics/open_sockets.coffee @@ -0,0 +1,19 @@ +URL = require "url" +seconds = 1000 + +module.exports = OpenSocketsMonitor = + monitor: (logger) -> + setInterval () -> + OpenSocketsMonitor.gaugeOpenSockets() + , 5 * seconds + + gaugeOpenSockets: () -> + Metrics = require "./metrics" + for url, agents of require('http').globalAgent.sockets + url = URL.parse("http://#{url}") + hostname = url.hostname?.replace(/\./g, "_") + Metrics.gauge "open_connections.http.#{hostname}", agents.length + for url, agents of require('https').globalAgent.sockets + url = URL.parse("https://#{url}") + hostname = url.hostname?.replace(/\./g, "_") + Metrics.gauge "open_connections.https.#{hostname}", agents.length diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index a76929f2fa..23d2d2ae75 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -4,7 +4,7 @@ "description": "A drop-in metrics and monitoring module for node.js apps", "dependencies": { "lynx": "~0.1.1", - "coffee-script": "~1.7.1", + "coffee-script": "1.6.0", "underscore": "~1.6.0" } } From 284d8fb588e154f08061cfd0d18d8eef53573005 Mon Sep 17 00:00:00 2001 From: James Allen Date: Fri, 9 May 2014 13:54:33 +0100 Subject: [PATCH 012/182] Namespace gauge keys correctly --- libraries/metrics/metrics.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 2b3c418046..341b8e6ce9 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -29,7 +29,7 @@ module.exports = statsd.timing(buildKey(this.key), timeSpan, this.sampleRate) gauge : (key, value, sampleRate = 1)-> - statsd.gauge key, value, sampleRate + statsd.gauge buildKey(key), value, sampleRate mongodb: require "./mongodb" http: require "./http" From 1dea55d8f2c920721ef6b3ed94c9378115b5081c Mon Sep 17 00:00:00 2001 From: James Allen Date: Mon, 12 May 2014 15:28:09 +0100 Subject: [PATCH 013/182] Check that req.route.path is set --- libraries/metrics/http.coffee | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/libraries/metrics/http.coffee b/libraries/metrics/http.coffee index 1f6fe20971..c175f26a14 100644 --- a/libraries/metrics/http.coffee +++ b/libraries/metrics/http.coffee @@ -8,22 +8,24 @@ module.exports.monitor = (logger) -> res.end = () -> end.apply(this, arguments) responseTime = new Date() - startTime - routePath = req.route.path.toString().replace(/\//g, '_').replace(/\:/g, '').slice(1) - key = "http-requests.#{routePath}.#{req.method}.#{res.statusCode}" + if req.route?.path? + routePath = req.route.path.toString().replace(/\//g, '_').replace(/\:/g, '').slice(1) + key = "http-requests.#{routePath}.#{req.method}.#{res.statusCode}" - Metrics.timing(key, responseTime) - logger.log - req: - url: req.originalUrl || req.url - method: req.method - referrer: req.headers['referer'] || req.headers['referrer'] - "remote-addr": req.ip || req.socket?.socket?.remoteAddress || req.socket?.remoteAddress - "user-agent": req.headers["user-agent"] - "content-length": req.headers["content-length"] - res: - "content-length": res._headers?["content-length"] - statusCode: res.statusCode - "response-time": responseTime - "http request" + Metrics.timing(key, responseTime) + logger.log + req: + url: req.originalUrl || req.url + method: req.method + referrer: req.headers['referer'] || req.headers['referrer'] + "remote-addr": req.ip || req.socket?.socket?.remoteAddress || req.socket?.remoteAddress + "user-agent": req.headers["user-agent"] + "content-length": req.headers["content-length"] + res: + "content-length": res._headers?["content-length"] + statusCode: res.statusCode + "response-time": responseTime + "http request" + next() From c8fae26995e9c9080c8b642c6c557fa7c9b2fef0 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Tue, 13 May 2014 15:24:23 +0100 Subject: [PATCH 014/182] changed type to query_type as it conflicts with logstash --- libraries/metrics/mongodb.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/mongodb.coffee b/libraries/metrics/mongodb.coffee index 71529434db..045382d367 100644 --- a/libraries/metrics/mongodb.coffee +++ b/libraries/metrics/mongodb.coffee @@ -32,7 +32,7 @@ module.exports = time = new Date() - start logger.log query: db_command.query - type: type + query_type: type collection: collection "response-time": new Date() - start "mongo request" From 9acca85843ba651d3fd3f984ef80f0b3669582db Mon Sep 17 00:00:00 2001 From: James Allen Date: Tue, 19 Aug 2014 13:32:41 +0100 Subject: [PATCH 015/182] Release version 1.0.0 --- libraries/metrics/package.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 23d2d2ae75..2429dca26d 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,7 +1,11 @@ { "name": "metrics-sharelatex", - "version": "0.0.0", + "version": "1.0.0", "description": "A drop-in metrics and monitoring module for node.js apps", + "repository": { + "type": "git", + "url": "https://github.com/sharelatex/metrics-sharelatex.git" + }, "dependencies": { "lynx": "~0.1.1", "coffee-script": "1.6.0", From 60857982b6c537b01c0d25b9e9381fb4700674a1 Mon Sep 17 00:00:00 2001 From: James Allen Date: Mon, 8 Sep 2014 09:19:39 +0100 Subject: [PATCH 016/182] Create LICENSE --- libraries/metrics/LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 libraries/metrics/LICENSE diff --git a/libraries/metrics/LICENSE b/libraries/metrics/LICENSE new file mode 100644 index 0000000000..f49ce1ac14 --- /dev/null +++ b/libraries/metrics/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 ShareLaTeX + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. From 30070f23b84645d2592d287e92c1102b5e51a1bd Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Mon, 5 Jan 2015 16:45:32 +0000 Subject: [PATCH 017/182] add a close() method to terminate the module cleanly closes the statsd connection and cancels registered interval timers prevents express from hanging when trying to shutdown --- libraries/metrics/metrics.coffee | 9 +++++++++ libraries/metrics/open_sockets.coffee | 5 ++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 341b8e6ce9..59e4ee9899 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -6,10 +6,15 @@ hostname = require('os').hostname() buildKey = (key)-> "#{name}.#{hostname}.#{key}" +destructors = [] + module.exports = initialize: (_name) -> name = _name + registerDestructor: (func) -> + destructors.push func + set : (key, value, sampleRate = 1)-> statsd.set buildKey(key), value, sampleRate @@ -35,3 +40,7 @@ module.exports = http: require "./http" open_sockets: require "./open_sockets" + close: () -> + for func in destructors + func() + statsd.close() diff --git a/libraries/metrics/open_sockets.coffee b/libraries/metrics/open_sockets.coffee index d74a781496..d4a6eb6c8d 100644 --- a/libraries/metrics/open_sockets.coffee +++ b/libraries/metrics/open_sockets.coffee @@ -3,9 +3,12 @@ seconds = 1000 module.exports = OpenSocketsMonitor = monitor: (logger) -> - setInterval () -> + interval = setInterval () -> OpenSocketsMonitor.gaugeOpenSockets() , 5 * seconds + Metrics = require "./metrics" + Metrics.registerDestructor () -> + clearInterval(interval) gaugeOpenSockets: () -> Metrics = require "./metrics" From fa7e068ebbb1803a763e0f989b6f3197b5ab365f Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Mon, 5 Jan 2015 16:46:44 +0000 Subject: [PATCH 018/182] update minor version, due to addition of new close() method --- libraries/metrics/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 2429dca26d..7cbdd990e3 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "1.0.0", + "version": "1.1.0", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From 1e0a991fcd9457a560f0c32711a1081a33d05185 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Tue, 5 May 2015 10:50:59 +0100 Subject: [PATCH 019/182] reduce memory capture in http logger only capture the properties of 'req' that we need, to avoid leaking the whole req object for responses that never call res.end() --- libraries/metrics/http.coffee | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/libraries/metrics/http.coffee b/libraries/metrics/http.coffee index c175f26a14..fa8fcdaa62 100644 --- a/libraries/metrics/http.coffee +++ b/libraries/metrics/http.coffee @@ -4,23 +4,35 @@ module.exports.monitor = (logger) -> return (req, res, next) -> Metrics = require("./metrics") startTime = new Date() + + # only capture the properties of 'req' that we need, to avoid + # leaking the whole req object for responses that never call + # res.end() + url = req.originalUrl || req.url + method = req.method + referrer = req.headers['referer'] || req.headers['referrer'] + remoteAddr = req.ip || req.socket?.socket?.remoteAddress || req.socket?.remoteAddress + userAgent = req.headers["user-agent"] + contentLength = req.headers["content-length"] + path = req.route?.path + end = res.end res.end = () -> end.apply(this, arguments) responseTime = new Date() - startTime - if req.route?.path? - routePath = req.route.path.toString().replace(/\//g, '_').replace(/\:/g, '').slice(1) - key = "http-requests.#{routePath}.#{req.method}.#{res.statusCode}" + if path? + routePath = path.toString().replace(/\//g, '_').replace(/\:/g, '').slice(1) + key = "http-requests.#{routePath}.#{method}.#{res.statusCode}" Metrics.timing(key, responseTime) logger.log req: - url: req.originalUrl || req.url - method: req.method - referrer: req.headers['referer'] || req.headers['referrer'] - "remote-addr": req.ip || req.socket?.socket?.remoteAddress || req.socket?.remoteAddress - "user-agent": req.headers["user-agent"] - "content-length": req.headers["content-length"] + url: url + method: method + referrer: referrer + "remote-addr": remoteAddr + "user-agent": userAgent + "content-length": contentLength res: "content-length": res._headers?["content-length"] statusCode: res.statusCode From 9329249bc997e09392f1685635cd132fe4d63805 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Thu, 14 May 2015 16:14:24 +0100 Subject: [PATCH 020/182] Revert "reduce memory capture in http logger" This reverts commit fc2e043b20204e04f240814d4efc05762db7df96. Had to revert this because req.route.path is not set until a matching route has been hit, so it was always null inside res.end meaning statsd data was never sent over. This commit did not actually stop the memory leak so reverting it has not short term repocusion --- libraries/metrics/http.coffee | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/libraries/metrics/http.coffee b/libraries/metrics/http.coffee index fa8fcdaa62..c175f26a14 100644 --- a/libraries/metrics/http.coffee +++ b/libraries/metrics/http.coffee @@ -4,35 +4,23 @@ module.exports.monitor = (logger) -> return (req, res, next) -> Metrics = require("./metrics") startTime = new Date() - - # only capture the properties of 'req' that we need, to avoid - # leaking the whole req object for responses that never call - # res.end() - url = req.originalUrl || req.url - method = req.method - referrer = req.headers['referer'] || req.headers['referrer'] - remoteAddr = req.ip || req.socket?.socket?.remoteAddress || req.socket?.remoteAddress - userAgent = req.headers["user-agent"] - contentLength = req.headers["content-length"] - path = req.route?.path - end = res.end res.end = () -> end.apply(this, arguments) responseTime = new Date() - startTime - if path? - routePath = path.toString().replace(/\//g, '_').replace(/\:/g, '').slice(1) - key = "http-requests.#{routePath}.#{method}.#{res.statusCode}" + if req.route?.path? + routePath = req.route.path.toString().replace(/\//g, '_').replace(/\:/g, '').slice(1) + key = "http-requests.#{routePath}.#{req.method}.#{res.statusCode}" Metrics.timing(key, responseTime) logger.log req: - url: url - method: method - referrer: referrer - "remote-addr": remoteAddr - "user-agent": userAgent - "content-length": contentLength + url: req.originalUrl || req.url + method: req.method + referrer: req.headers['referer'] || req.headers['referrer'] + "remote-addr": req.ip || req.socket?.socket?.remoteAddress || req.socket?.remoteAddress + "user-agent": req.headers["user-agent"] + "content-length": req.headers["content-length"] res: "content-length": res._headers?["content-length"] statusCode: res.statusCode From ffa523bced432ddbd92f29e6f3ed2871e09768ca Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Tue, 23 Jun 2015 10:51:48 +0100 Subject: [PATCH 021/182] added monitoring of event loop time should indicate if node is blocking on libuv threads as described in https://nodejs.org/api/dns.html#dns_dns_lookup --- libraries/metrics/event_loop.coffee | 18 ++++++++++++++++++ libraries/metrics/metrics.coffee | 1 + 2 files changed, 19 insertions(+) create mode 100644 libraries/metrics/event_loop.coffee diff --git a/libraries/metrics/event_loop.coffee b/libraries/metrics/event_loop.coffee new file mode 100644 index 0000000000..ab6955afc7 --- /dev/null +++ b/libraries/metrics/event_loop.coffee @@ -0,0 +1,18 @@ +seconds = 1000 + +module.exports = EventLoopMonitor = + monitor: (logger) -> + interval = setInterval () -> + EventLoopMonitor.Delay() + , 1 * seconds + Metrics = require "./metrics" + Metrics.registerDestructor () -> + clearInterval(interval) + + Delay: () -> + Metrics = require "./metrics" + t1 = process.hrtime() + setImmediate () -> + delta = process.hrtime(t1) + responseTime = delta[0]*1e6 + delta[1]*1e-3 + Metrics.timing("event-loop-microsec", responseTime) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 59e4ee9899..a0cd3070fb 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -39,6 +39,7 @@ module.exports = mongodb: require "./mongodb" http: require "./http" open_sockets: require "./open_sockets" + event_loop: require "./event_loop" close: () -> for func in destructors From 349b499f8572906fe5781b34f6ac3d017ea1fb32 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Tue, 28 Jul 2015 16:53:55 +0100 Subject: [PATCH 022/182] add compatibility with v2 mongo driver --- libraries/metrics/mongodb.coffee | 76 ++++++++++++++++++++++++++++---- 1 file changed, 67 insertions(+), 9 deletions(-) diff --git a/libraries/metrics/mongodb.coffee b/libraries/metrics/mongodb.coffee index 045382d367..4358985101 100644 --- a/libraries/metrics/mongodb.coffee +++ b/libraries/metrics/mongodb.coffee @@ -1,15 +1,25 @@ -_ = require("underscore") - module.exports = monitor: (mongodb_require_path, logger) -> - Db = require("#{mongodb_require_path}/lib/mongodb/db").Db + + try + # for the v1 driver the methods to wrap are in the mongodb + # module in lib/mongodb/db.js + mongodb = require("#{mongodb_require_path}") + + try + # for the v2 driver the relevant methods are in the mongodb-core + # module in lib/topologies/{server,replset,mongos}.js + v2_path = mongodb_require_path.replace(/\/mongodb$/, '/mongodb-core') + mongodbCore = require(v2_path) Metrics = require("./metrics") monitorMethod = (base, method, type) -> - _method = base[method] + return unless base? + return unless (_method = base[method])? + arglen = _method.length - base[method] = (db_command, options, callback) -> + mongo_driver_v1_wrapper = (db_command, options, callback) -> if (typeof callback == 'undefined') callback = options options = {} @@ -38,7 +48,55 @@ module.exports = "mongo request" callback.apply this, arguments - monitorMethod(Db.prototype, "_executeQueryCommand", "query") - monitorMethod(Db.prototype, "_executeRemoveCommand", "remove") - monitorMethod(Db.prototype, "_executeInsertCommand", "insert") - monitorMethod(Db.prototype, "_executeUpdateCommand", "update") \ No newline at end of file + mongo_driver_v2_wrapper = (ns, ops, options, callback) -> + if (typeof callback == 'undefined') + callback = options + options = {} + callback = () -> + + if ns.match(/\$cmd$/) + # Ignore noisy command methods like authenticating, ismaster and ping + return _method.call this, ns, ops, options, callback + + key = "mongo-requests.#{ns}.#{type}" + if ops[0].q? # ops[0].q + query = Object.keys(ops[0].q).sort().join("_") + key += "." + query + + timer = new Metrics.Timer(key) + start = new Date() + _method.call this, ns, ops, options, () -> + timer.done() + time = new Date() - start + logger.log + query: ops[0].q + query_type: type + collection: ns + "response-time": new Date() - start + "mongo request" + callback.apply this, arguments + + if arglen == 3 + base[method] = mongo_driver_v1_wrapper + else if arglen == 4 + base[method] = mongo_driver_v2_wrapper + + monitorMethod(mongodb?.Db.prototype, "_executeQueryCommand", "query") + monitorMethod(mongodb?.Db.prototype, "_executeRemoveCommand", "remove") + monitorMethod(mongodb?.Db.prototype, "_executeInsertCommand", "insert") + monitorMethod(mongodb?.Db.prototype, "_executeUpdateCommand", "update") + + monitorMethod(mongodbCore?.Server.prototype, "command", "command") + monitorMethod(mongodbCore?.Server.prototype, "remove", "remove") + monitorMethod(mongodbCore?.Server.prototype, "insert", "insert") + monitorMethod(mongodbCore?.Server.prototype, "update", "update") + + monitorMethod(mongodbCore?.ReplSet.prototype, "command", "command") + monitorMethod(mongodbCore?.ReplSet.prototype, "remove", "remove") + monitorMethod(mongodbCore?.ReplSet.prototype, "insert", "insert") + monitorMethod(mongodbCore?.ReplSet.prototype, "update", "update") + + monitorMethod(mongodbCore?.Mongos.prototype, "command", "command") + monitorMethod(mongodbCore?.Mongos.prototype, "remove", "remove") + monitorMethod(mongodbCore?.Mongos.prototype, "insert", "insert") + monitorMethod(mongodbCore?.Mongos.prototype, "update", "update") From 175e3efd5f57fefd5b0240a12c7e8f69fb77090e Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Thu, 6 Aug 2015 09:40:58 +0100 Subject: [PATCH 023/182] update package version to 1.2.0 --- libraries/metrics/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 7cbdd990e3..69fe375357 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "1.1.0", + "version": "1.2.0", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From 46ec20ef9cafa20c0432f70287f309e1793ab721 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Thu, 13 Aug 2015 16:13:09 +0100 Subject: [PATCH 024/182] add memory check and periodic gc --- libraries/metrics/memory.coffee | 86 ++++++++++++++++++++++++++++++++ libraries/metrics/metrics.coffee | 1 + 2 files changed, 87 insertions(+) create mode 100644 libraries/metrics/memory.coffee diff --git a/libraries/metrics/memory.coffee b/libraries/metrics/memory.coffee new file mode 100644 index 0000000000..5b3c8f55ae --- /dev/null +++ b/libraries/metrics/memory.coffee @@ -0,0 +1,86 @@ +# record memory usage each minute and run a periodic gc(), keeping cpu +# usage within allowable range of 1ms per minute. Also, dynamically +# adjust the period between gc()'s to reach a target of the gc saving +# 4 megabytes each time. + +oneMinute = 60 * 1000 +oneMegaByte = 1024 * 1024 + +CpuTimeBucket = 100 # current cpu time allowance in milliseconds +CpuTimeBucketMax = 100 # maximum amount of cpu time allowed in bucket +CpuTimeBucketRate = 1 # add this many milliseconds per minute + +gcInterval = 1 # how many minutes between gc (parameter is dynamically adjusted) +countSinceLastGc = 0 # how many minutes since last gc +MemoryChunkSize = 4 * oneMegaByte # how much we need to free to consider gc worth doing + +readyToGc = () -> + # update allowed cpu time + CpuTimeBucket = CpuTimeBucket + CpuTimeBucketRate + CpuTimeBucket = if CpuTimeBucket < CpuTimeBucketMax then CpuTimeBucket else CpuTimeBucketMax + # update counts since last gc + countSinceLastGc = countSinceLastGc + 1 + # check there is enough time since last gc and we have enough cpu + return (countSinceLastGc > gcInterval) && (CpuTimeBucket > 0) + +executeAndTime = (fn) -> + # time the execution of fn() and subtract from cpu allowance + t0 = process.hrtime() + fn() + dt = process.hrtime(t0) + timeTaken = (dt[0] + dt[1]*1e-9) * 1e3 # in milliseconds + CpuTimeBucket -= Math.ceil timeTaken + return timeTaken + +inMegaBytes = (obj) -> + # convert process.memoryUsage hash {rss,heapTotal,heapFreed} into megabytes + result = {} + for k, v of obj + result[k] = (v / oneMegaByte).toFixed(2) + return result + +updateMemoryStats = (oldMem, newMem) -> + countSinceLastGc = 0 + delta = {} + for k of newMem + delta[k] = (newMem[k] - oldMem[k]).toFixed(2) + # take the max of all memory measures + savedMemory = Math.max -delta.rss, -delta.heapTotal, -delta.heapUsed + delta.megabytesFreed = savedMemory + # did it do any good? + if savedMemory < MemoryChunkSize + gcInterval = gcInterval + 1 # no, so wait longer next time + else + gcInterval = Math.max gcInterval - 1, 1 # yes, wait less time + return delta + +module.exports = MemoryMonitor = + monitor: (logger) -> + # use setTimeout add some randomisation of the start time + setTimeout () -> + interval = setInterval () -> + MemoryMonitor.Check(logger) + , oneMinute + , Math.floor Math.random()*oneMinute + Metrics = require "./metrics" + Metrics.registerDestructor () -> + clearInterval(interval) + + Check: (logger) -> + Metrics = require "./metrics" + memBeforeGc = mem = inMegaBytes process.memoryUsage() + Metrics.gauge("memory.rss", mem.rss) + Metrics.gauge("memory.heaptotal", mem.heapTotal) + Metrics.gauge("memory.heapused", mem.heapUsed) + Metrics.gauge("memory.gc-interval", gcInterval) + Metrics.gauge("memory.cpu-time-bucket", CpuTimeBucket) + + if global.gc? && readyToGc() + gcTime = (executeAndTime global.gc).toFixed(2) + memAfterGc = inMegaBytes process.memoryUsage() + deltaMem = updateMemoryStats(memBeforeGc, memAfterGc) + logger.log {gcTime, memBeforeGc, memAfterGc, deltaMem, gcInterval, CpuTimeBucket}, "global.gc() forced" + Metrics.timing("memory.gc-time", gcTime) + Metrics.gauge("memory.gc-rss-freed", -deltaMem.rss) + Metrics.gauge("memory.gc-heaptotal-freed", -deltaMem.heapTotal) + Metrics.gauge("memory.gc-heapused-freed", -deltaMem.heapUsed) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index a0cd3070fb..e382c8a8cd 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -40,6 +40,7 @@ module.exports = http: require "./http" open_sockets: require "./open_sockets" event_loop: require "./event_loop" + memory: require "./memory" close: () -> for func in destructors From 577a3759c06a93ecf387294e1b272987adeb03ac Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Fri, 14 Aug 2015 15:44:24 +0100 Subject: [PATCH 025/182] bugfix for memory chunk size --- libraries/metrics/memory.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/metrics/memory.coffee b/libraries/metrics/memory.coffee index 5b3c8f55ae..1b4e1ef1bb 100644 --- a/libraries/metrics/memory.coffee +++ b/libraries/metrics/memory.coffee @@ -8,11 +8,11 @@ oneMegaByte = 1024 * 1024 CpuTimeBucket = 100 # current cpu time allowance in milliseconds CpuTimeBucketMax = 100 # maximum amount of cpu time allowed in bucket -CpuTimeBucketRate = 1 # add this many milliseconds per minute +CpuTimeBucketRate = 10 # add this many milliseconds per minute gcInterval = 1 # how many minutes between gc (parameter is dynamically adjusted) countSinceLastGc = 0 # how many minutes since last gc -MemoryChunkSize = 4 * oneMegaByte # how much we need to free to consider gc worth doing +MemoryChunkSize = 4 # how many megabytes we need to free to consider gc worth doing readyToGc = () -> # update allowed cpu time From d2af7b24a0207895b7f7983171810031d23de940 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Mon, 17 Aug 2015 15:18:18 +0100 Subject: [PATCH 026/182] remove randomisation to avoid shutdown problems --- libraries/metrics/memory.coffee | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/libraries/metrics/memory.coffee b/libraries/metrics/memory.coffee index 1b4e1ef1bb..30f9379fd3 100644 --- a/libraries/metrics/memory.coffee +++ b/libraries/metrics/memory.coffee @@ -56,12 +56,9 @@ updateMemoryStats = (oldMem, newMem) -> module.exports = MemoryMonitor = monitor: (logger) -> - # use setTimeout add some randomisation of the start time - setTimeout () -> - interval = setInterval () -> - MemoryMonitor.Check(logger) - , oneMinute - , Math.floor Math.random()*oneMinute + interval = setInterval () -> + MemoryMonitor.Check(logger) + , oneMinute Metrics = require "./metrics" Metrics.registerDestructor () -> clearInterval(interval) From e3e8d8046673ee19fca13f1013217763b5f6f426 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Mon, 17 Aug 2015 15:18:57 +0100 Subject: [PATCH 027/182] remove non-working metrics from graphite --- libraries/metrics/memory.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/metrics/memory.coffee b/libraries/metrics/memory.coffee index 30f9379fd3..1822b384bb 100644 --- a/libraries/metrics/memory.coffee +++ b/libraries/metrics/memory.coffee @@ -70,14 +70,14 @@ module.exports = MemoryMonitor = Metrics.gauge("memory.heaptotal", mem.heapTotal) Metrics.gauge("memory.heapused", mem.heapUsed) Metrics.gauge("memory.gc-interval", gcInterval) - Metrics.gauge("memory.cpu-time-bucket", CpuTimeBucket) + #Metrics.gauge("memory.cpu-time-bucket", CpuTimeBucket) if global.gc? && readyToGc() gcTime = (executeAndTime global.gc).toFixed(2) memAfterGc = inMegaBytes process.memoryUsage() deltaMem = updateMemoryStats(memBeforeGc, memAfterGc) logger.log {gcTime, memBeforeGc, memAfterGc, deltaMem, gcInterval, CpuTimeBucket}, "global.gc() forced" - Metrics.timing("memory.gc-time", gcTime) + #Metrics.timing("memory.gc-time", gcTime) Metrics.gauge("memory.gc-rss-freed", -deltaMem.rss) Metrics.gauge("memory.gc-heaptotal-freed", -deltaMem.heapTotal) Metrics.gauge("memory.gc-heapused-freed", -deltaMem.heapUsed) From 27c382416acf6db518274566a802c6b691d9e581 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Mon, 17 Aug 2015 15:19:13 +0100 Subject: [PATCH 028/182] fix whitespace --- libraries/metrics/memory.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/memory.coffee b/libraries/metrics/memory.coffee index 1822b384bb..1700e6ad3d 100644 --- a/libraries/metrics/memory.coffee +++ b/libraries/metrics/memory.coffee @@ -73,7 +73,7 @@ module.exports = MemoryMonitor = #Metrics.gauge("memory.cpu-time-bucket", CpuTimeBucket) if global.gc? && readyToGc() - gcTime = (executeAndTime global.gc).toFixed(2) + gcTime = (executeAndTime global.gc).toFixed(2) memAfterGc = inMegaBytes process.memoryUsage() deltaMem = updateMemoryStats(memBeforeGc, memAfterGc) logger.log {gcTime, memBeforeGc, memAfterGc, deltaMem, gcInterval, CpuTimeBucket}, "global.gc() forced" From f237f7c3ccbf1e0934c0b3e68647dbb62c76f426 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Tue, 18 Aug 2015 11:23:10 +0100 Subject: [PATCH 029/182] remove bug in optional argument handling --- libraries/metrics/mongodb.coffee | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/metrics/mongodb.coffee b/libraries/metrics/mongodb.coffee index 4358985101..ce1ca71385 100644 --- a/libraries/metrics/mongodb.coffee +++ b/libraries/metrics/mongodb.coffee @@ -23,7 +23,6 @@ module.exports = if (typeof callback == 'undefined') callback = options options = {} - callback = () -> collection = db_command.collectionName if collection.match(/\$cmd$/) @@ -52,7 +51,6 @@ module.exports = if (typeof callback == 'undefined') callback = options options = {} - callback = () -> if ns.match(/\$cmd$/) # Ignore noisy command methods like authenticating, ismaster and ping From 0215b12a5f5f976930bc68b9057ee8cb93c90287 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Thu, 20 Aug 2015 17:03:58 +0100 Subject: [PATCH 030/182] log memory usage every minute --- libraries/metrics/memory.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/metrics/memory.coffee b/libraries/metrics/memory.coffee index 1700e6ad3d..a1e157a5bf 100644 --- a/libraries/metrics/memory.coffee +++ b/libraries/metrics/memory.coffee @@ -72,6 +72,8 @@ module.exports = MemoryMonitor = Metrics.gauge("memory.gc-interval", gcInterval) #Metrics.gauge("memory.cpu-time-bucket", CpuTimeBucket) + logger.log mem, "process.memoryUsage()" + if global.gc? && readyToGc() gcTime = (executeAndTime global.gc).toFixed(2) memAfterGc = inMegaBytes process.memoryUsage() From 738363a6dedd78db162aa9b6b2a7dd35927b5337 Mon Sep 17 00:00:00 2001 From: James Allen Date: Mon, 31 Aug 2015 14:02:03 +0100 Subject: [PATCH 031/182] Set maxSockets to Infinity for all services --- libraries/metrics/open_sockets.coffee | 6 ++++++ libraries/metrics/package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/libraries/metrics/open_sockets.coffee b/libraries/metrics/open_sockets.coffee index d4a6eb6c8d..9af019dfc8 100644 --- a/libraries/metrics/open_sockets.coffee +++ b/libraries/metrics/open_sockets.coffee @@ -1,6 +1,12 @@ URL = require "url" seconds = 1000 +# In Node 0.10 the default is 5, which means only 5 open connections at one. +# Node 0.12 has a default of Infinity. Make sure we have no limit set, +# regardless of Node version. +require("http").globalAgent.maxSockets = Infinity +require("https").globalAgent.maxSockets = Infinity + module.exports = OpenSocketsMonitor = monitor: (logger) -> interval = setInterval () -> diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 69fe375357..1f5214c3d4 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "1.2.0", + "version": "1.3.0", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From 8db30020ae5802ca7fdad6e1196756addafc34da Mon Sep 17 00:00:00 2001 From: James Allen Date: Thu, 3 Dec 2015 16:32:20 +0000 Subject: [PATCH 032/182] Monitor event loop by looking for skew If we monitor with setImmediate, we miss big blocking loops. For example, suppose we have 1000 1ms loops then a single bad 1000ms loop. setImmediate will only be called at the right time 1/1000 of the time (it has to be the loop just before the bad one). So this monitoring method gives a good average if the std dev is low, but doesn't pick up spikes. Instead, we can monitor the skew from the expected time between setIntervals. In the case above, with a setInterval for 1000ms, we will pick up a skew proportional to the amount of time that it overlaps the bad loop. So 50% change of picking up skew > 500ms, and thus getting a good sense of any spikes. --- libraries/metrics/event_loop.coffee | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/libraries/metrics/event_loop.coffee b/libraries/metrics/event_loop.coffee index ab6955afc7..4e410892bf 100644 --- a/libraries/metrics/event_loop.coffee +++ b/libraries/metrics/event_loop.coffee @@ -1,18 +1,16 @@ -seconds = 1000 - module.exports = EventLoopMonitor = - monitor: (logger) -> - interval = setInterval () -> - EventLoopMonitor.Delay() - , 1 * seconds + monitor: (logger, interval = 1000, log_threshold = 100) -> Metrics = require "./metrics" + + previous = Date.now() + intervalId = setInterval () -> + now = Date.now() + offset = now - previous - interval + if offset > log_threshold + logger.warn {offset: offset}, "slow event loop" + previous = now + Metrics.timing("event-loop-millsec", offset) + , interval + Metrics.registerDestructor () -> - clearInterval(interval) - - Delay: () -> - Metrics = require "./metrics" - t1 = process.hrtime() - setImmediate () -> - delta = process.hrtime(t1) - responseTime = delta[0]*1e6 + delta[1]*1e-3 - Metrics.timing("event-loop-microsec", responseTime) + clearInterval(intervalId) From 29177f8de861538804a43f72bb6366c18af9bcae Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Tue, 15 Mar 2016 13:52:32 +0000 Subject: [PATCH 033/182] add support for statsd count method --- libraries/metrics/metrics.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index e382c8a8cd..74ce2c05ff 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -21,6 +21,9 @@ module.exports = inc : (key, sampleRate = 1)-> statsd.increment buildKey(key), sampleRate + count : (key, count, sampleRate = 1)-> + statsd.count buildKey(key), count, sampleRate + timing: (key, timeSpan, sampleRate)-> statsd.timing(buildKey(key), timeSpan, sampleRate) From 622bbe3123ee6db1e54bb037e4789c5e4ef8252e Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Tue, 15 Mar 2016 13:52:40 +0000 Subject: [PATCH 034/182] return timeSpan from timers to allow additional calculation --- libraries/metrics/metrics.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 74ce2c05ff..efe441acdb 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -35,6 +35,7 @@ module.exports = done:-> timeSpan = new Date - this.start statsd.timing(buildKey(this.key), timeSpan, this.sampleRate) + return timeSpan gauge : (key, value, sampleRate = 1)-> statsd.gauge buildKey(key), value, sampleRate From 2df5845444a1a99e122eccbcd7c07447e238d0a3 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Thu, 17 Mar 2016 09:40:40 +0000 Subject: [PATCH 035/182] updated version to 1.5.0 --- libraries/metrics/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 1f5214c3d4..23547fa37a 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "1.3.0", + "version": "1.5.0", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From caeac717fc81eefb52b9ec96fdc62b42274433e2 Mon Sep 17 00:00:00 2001 From: James Allen Date: Mon, 24 Oct 2016 10:50:44 +0100 Subject: [PATCH 036/182] Set UV_THREADPOOL_SIZE to 128 for all processes --- libraries/metrics/metrics.coffee | 2 ++ libraries/metrics/package.json | 2 +- libraries/metrics/uv_threadpool_size.coffee | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 libraries/metrics/uv_threadpool_size.coffee diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index efe441acdb..554fa3d51d 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -8,6 +8,8 @@ buildKey = (key)-> "#{name}.#{hostname}.#{key}" destructors = [] +require "./uv_threadpool_size" + module.exports = initialize: (_name) -> name = _name diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 23547fa37a..02b1f05837 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "1.5.0", + "version": "1.6.0", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", diff --git a/libraries/metrics/uv_threadpool_size.coffee b/libraries/metrics/uv_threadpool_size.coffee new file mode 100644 index 0000000000..77978a42c5 --- /dev/null +++ b/libraries/metrics/uv_threadpool_size.coffee @@ -0,0 +1,2 @@ +process.env.UV_THREADPOOL_SIZE=128 +console.log "Set UV_THREADPOOL_SIZE=#{process.env.UV_THREADPOOL_SIZE}" \ No newline at end of file From 3cb0ab2784f6f8c00d01f1af3d160e679c901b0a Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Wed, 15 Mar 2017 15:06:54 +0000 Subject: [PATCH 037/182] Add a 'timeAsyncMethod' helper --- libraries/metrics/metrics.coffee | 4 +++- libraries/metrics/timeAsyncMethod.coffee | 30 ++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 libraries/metrics/timeAsyncMethod.coffee diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 554fa3d51d..0349ca6d11 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -10,7 +10,7 @@ destructors = [] require "./uv_threadpool_size" -module.exports = +module.exports = Metrics = initialize: (_name) -> name = _name @@ -48,6 +48,8 @@ module.exports = event_loop: require "./event_loop" memory: require "./memory" + timeAsyncMethod: require('./timeAsyncMethod') + close: () -> for func in destructors func() diff --git a/libraries/metrics/timeAsyncMethod.coffee b/libraries/metrics/timeAsyncMethod.coffee new file mode 100644 index 0000000000..59fb12ea7a --- /dev/null +++ b/libraries/metrics/timeAsyncMethod.coffee @@ -0,0 +1,30 @@ + +module.exports = (obj, methodName, key, logger) -> + metrics = require('./metrics') + + if typeof obj[methodName] != 'function' + throw new Error("[Metrics] expected object property #{methodName} to be a function") + + realMethod = obj[methodName] + key = "methods.#{key}" + + obj[methodName] = (originalArgs...) -> + + [firstArgs..., callback] = originalArgs + if !callback? || typeof callback != 'function' + throw new Error( + "[Metrics] expected wrapped method '#{methodName}' to be invoked with a callback" + ) + + timer = new Metrics.Timer(key) + start = new Date() + + realMethod.call this, firstArgs, (callbackArgs...) -> + timer.done() + elapsedTime = new Date() - start + if logger? + logger.log + key: key + time: elapsedTime + "[Metrics] timed async method call" + callback.apply this, callbackArgs From e99a7f6a8744262b616bf4aa1287225143e57971 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Wed, 15 Mar 2017 16:07:36 +0000 Subject: [PATCH 038/182] refactor --- libraries/metrics/timeAsyncMethod.coffee | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/libraries/metrics/timeAsyncMethod.coffee b/libraries/metrics/timeAsyncMethod.coffee index 59fb12ea7a..ec530fcac0 100644 --- a/libraries/metrics/timeAsyncMethod.coffee +++ b/libraries/metrics/timeAsyncMethod.coffee @@ -16,15 +16,12 @@ module.exports = (obj, methodName, key, logger) -> "[Metrics] expected wrapped method '#{methodName}' to be invoked with a callback" ) - timer = new Metrics.Timer(key) + timer = new metrics.Timer(key) start = new Date() - realMethod.call this, firstArgs, (callbackArgs...) -> + realMethod.call this, firstArgs..., (callbackArgs...) -> timer.done() elapsedTime = new Date() - start if logger? - logger.log - key: key - time: elapsedTime - "[Metrics] timed async method call" + logger.log {key, elapsedTime}, "[Metrics] timed async method call" callback.apply this, callbackArgs From c3b18618bfe72a0fe6bdf78f187d997b425e75b1 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Thu, 16 Mar 2017 09:49:45 +0000 Subject: [PATCH 039/182] Add unit tests --- libraries/metrics/.nvmrc | 1 + libraries/metrics/Gruntfile.coffee | 29 ++++++++ libraries/metrics/package.json | 12 ++++ .../unit/coffee/timeAsyncMethodTests.coffee | 49 +++++++++++++ .../test/unit/js/timeAsyncMethodTests.js | 70 +++++++++++++++++++ 5 files changed, 161 insertions(+) create mode 100644 libraries/metrics/.nvmrc create mode 100644 libraries/metrics/Gruntfile.coffee create mode 100644 libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee create mode 100644 libraries/metrics/test/unit/js/timeAsyncMethodTests.js diff --git a/libraries/metrics/.nvmrc b/libraries/metrics/.nvmrc new file mode 100644 index 0000000000..12e4141293 --- /dev/null +++ b/libraries/metrics/.nvmrc @@ -0,0 +1 @@ +6.9 diff --git a/libraries/metrics/Gruntfile.coffee b/libraries/metrics/Gruntfile.coffee new file mode 100644 index 0000000000..47f126fa70 --- /dev/null +++ b/libraries/metrics/Gruntfile.coffee @@ -0,0 +1,29 @@ +module.exports = (grunt) -> + grunt.initConfig + coffee: + unit_tests: + expand: true + cwd: "test/unit/coffee" + src: ["**/*.coffee"] + dest: "test/unit/js/" + ext: ".js" + + clean: + unit_tests: ["test/unit/js"] + + mochaTest: + unit: + options: + reporter: grunt.option('reporter') or 'spec' + grep: grunt.option("grep") + + src: ["test/unit/js/**/*.js"] + + grunt.loadNpmTasks 'grunt-contrib-coffee' + grunt.loadNpmTasks 'grunt-contrib-clean' + grunt.loadNpmTasks 'grunt-mocha-test' + grunt.loadNpmTasks 'grunt-execute' + grunt.loadNpmTasks 'grunt-bunyan' + + grunt.registerTask 'compile:unit_tests', ['clean:unit_tests', 'coffee:unit_tests'] + grunt.registerTask 'test:unit', ['compile:unit_tests', 'mochaTest:unit'] diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 02b1f05837..cf987853e7 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -10,5 +10,17 @@ "lynx": "~0.1.1", "coffee-script": "1.6.0", "underscore": "~1.6.0" + }, + "devDependencies": { + "bunyan": "^1.0.0", + "chai": "", + "grunt": "^0.4.5", + "grunt-bunyan": "^0.5.0", + "grunt-contrib-clean": "^0.6.0", + "grunt-contrib-coffee": "^0.11.0", + "grunt-execute": "^0.2.2", + "grunt-mocha-test": "^0.11.0", + "sandboxed-module": "", + "sinon": "" } } diff --git a/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee b/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee new file mode 100644 index 0000000000..69fbf2cb0f --- /dev/null +++ b/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee @@ -0,0 +1,49 @@ +require('coffee-script') +chai = require('chai') +should = chai.should() +expect = chai.expect +path = require('path') +modulePath = path.join __dirname, '../../../timeAsyncMethod.coffee' +SandboxedModule = require('sandboxed-module') +sinon = require("sinon") + + +describe 'timeAsyncMethod', -> + + beforeEach -> + @Timer = {done: sinon.stub()} + @TimerConstructor = sinon.stub().returns(@Timer) + @metrics = { + Timer: @TimerConstructor + } + @timeAsyncMethod = SandboxedModule.require modulePath, requires: + './metrics': @metrics + + @testObject = { + nextNumber: (n, callback=(err, result)->) -> + setTimeout( + () -> + callback(null, n+1) + , 100 + ) + } + + it 'should have the testObject behave correctly before wrapping', (done) -> + @testObject.nextNumber 2, (err, result) -> + expect(err).to.not.exist + expect(result).to.equal 3 + done() + + it 'should wrap method without error', (done) -> + @timeAsyncMethod @testObject, 'nextNumber', 'test.nextNumber' + done() + + it 'should transparently wrap method invocation in timer', (done) -> + @timeAsyncMethod @testObject, 'nextNumber', 'test.nextNumber' + @testObject.nextNumber 2, (err, result) => + expect(err).to.not.exist + expect(result).to.equal 3 + expect(@TimerConstructor.callCount).to.equal 1 + expect(@Timer.done.callCount).to.equal 1 + done() + diff --git a/libraries/metrics/test/unit/js/timeAsyncMethodTests.js b/libraries/metrics/test/unit/js/timeAsyncMethodTests.js new file mode 100644 index 0000000000..479de4eb4f --- /dev/null +++ b/libraries/metrics/test/unit/js/timeAsyncMethodTests.js @@ -0,0 +1,70 @@ +(function() { + var SandboxedModule, chai, expect, modulePath, path, should, sinon; + + require('coffee-script'); + + chai = require('chai'); + + should = chai.should(); + + expect = chai.expect; + + path = require('path'); + + modulePath = path.join(__dirname, '../../../timeAsyncMethod.coffee'); + + SandboxedModule = require('sandboxed-module'); + + sinon = require("sinon"); + + describe('timeAsyncMethod', function() { + beforeEach(function() { + this.Timer = { + done: sinon.stub() + }; + this.TimerConstructor = sinon.stub().returns(this.Timer); + this.metrics = { + Timer: this.TimerConstructor + }; + this.timeAsyncMethod = SandboxedModule.require(modulePath, { + requires: { + './metrics': this.metrics + } + }); + return this.testObject = { + nextNumber: function(n, callback) { + if (callback == null) { + callback = function(err, result) {}; + } + return setTimeout(function() { + return callback(null, n + 1); + }, 100); + } + }; + }); + it('should have the testObject behave correctly before wrapping', function(done) { + return this.testObject.nextNumber(2, function(err, result) { + expect(err).to.not.exist; + expect(result).to.equal(3); + return done(); + }); + }); + it('should wrap method without error', function(done) { + this.timeAsyncMethod(this.testObject, 'nextNumber', 'test.nextNumber'); + return done(); + }); + return it('should work', function(done) { + this.timeAsyncMethod(this.testObject, 'nextNumber', 'test.nextNumber'); + return this.testObject.nextNumber(2, (function(_this) { + return function(err, result) { + expect(err).to.not.exist; + expect(result).to.equal(3); + expect(_this.TimerConstructor.callCount).to.equal(1); + expect(_this.Timer.done.callCount).to.equal(1); + return done(); + }; + })(this)); + }); + }); + +}).call(this); From 40b238271d659f608b521e50280a9092d003845b Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Thu, 16 Mar 2017 09:55:07 +0000 Subject: [PATCH 040/182] Add tests for methods producing errors, and logger --- .../unit/coffee/timeAsyncMethodTests.coffee | 30 +++++++++++++ .../test/unit/js/timeAsyncMethodTests.js | 45 ++++++++++++++++++- 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee b/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee index 69fbf2cb0f..ec89aef27f 100644 --- a/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee +++ b/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee @@ -47,3 +47,33 @@ describe 'timeAsyncMethod', -> expect(@Timer.done.callCount).to.equal 1 done() + describe 'when base method produces an error', -> + beforeEach -> + @testObject.nextNumber = (n, callback=(err, result)->) -> + setTimeout( + () -> + callback(new Error('woops')) + , 100 + ) + + it 'should propagate the error transparently', (done) -> + @timeAsyncMethod @testObject, 'nextNumber', 'test.nextNumber' + @testObject.nextNumber 2, (err, result) => + expect(err).to.exist + expect(err).to.be.instanceof Error + expect(result).to.not.exist + done() + + describe 'when a logger is supplied', -> + beforeEach -> + @logger = {log: sinon.stub()} + + it 'should also call logger.log', (done) -> + @timeAsyncMethod @testObject, 'nextNumber', 'test.nextNumber', @logger + @testObject.nextNumber 2, (err, result) => + expect(err).to.not.exist + expect(result).to.equal 3 + expect(@TimerConstructor.callCount).to.equal 1 + expect(@Timer.done.callCount).to.equal 1 + expect(@logger.log.callCount).to.equal 1 + done() diff --git a/libraries/metrics/test/unit/js/timeAsyncMethodTests.js b/libraries/metrics/test/unit/js/timeAsyncMethodTests.js index 479de4eb4f..6982161cdc 100644 --- a/libraries/metrics/test/unit/js/timeAsyncMethodTests.js +++ b/libraries/metrics/test/unit/js/timeAsyncMethodTests.js @@ -53,7 +53,7 @@ this.timeAsyncMethod(this.testObject, 'nextNumber', 'test.nextNumber'); return done(); }); - return it('should work', function(done) { + it('should transparently wrap method invocation in timer', function(done) { this.timeAsyncMethod(this.testObject, 'nextNumber', 'test.nextNumber'); return this.testObject.nextNumber(2, (function(_this) { return function(err, result) { @@ -65,6 +65,49 @@ }; })(this)); }); + describe('when base method produces an error', function() { + beforeEach(function() { + return this.testObject.nextNumber = function(n, callback) { + if (callback == null) { + callback = function(err, result) {}; + } + return setTimeout(function() { + return callback(new Error('woops')); + }, 100); + }; + }); + return it('should propagate the error transparently', function(done) { + this.timeAsyncMethod(this.testObject, 'nextNumber', 'test.nextNumber'); + return this.testObject.nextNumber(2, (function(_this) { + return function(err, result) { + expect(err).to.exist; + expect(err).to.be["instanceof"](Error); + expect(result).to.not.exist; + return done(); + }; + })(this)); + }); + }); + return describe('when a logger is supplied', function() { + beforeEach(function() { + return this.logger = { + log: sinon.stub() + }; + }); + return it('should also call logger.log', function(done) { + this.timeAsyncMethod(this.testObject, 'nextNumber', 'test.nextNumber', this.logger); + return this.testObject.nextNumber(2, (function(_this) { + return function(err, result) { + expect(err).to.not.exist; + expect(result).to.equal(3); + expect(_this.TimerConstructor.callCount).to.equal(1); + expect(_this.Timer.done.callCount).to.equal(1); + expect(_this.logger.log.callCount).to.equal(1); + return done(); + }; + })(this)); + }); + }); }); }).call(this); From a5aec5b812df1d9573da19c9b6a4524c3da2fd02 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Thu, 16 Mar 2017 10:02:19 +0000 Subject: [PATCH 041/182] Test failure to wrap method --- .../test/unit/coffee/timeAsyncMethodTests.coffee | 10 ++++++++++ .../metrics/test/unit/js/timeAsyncMethodTests.js | 14 +++++++++++++- libraries/metrics/timeAsyncMethod.coffee | 2 +- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee b/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee index ec89aef27f..85af8eb9ee 100644 --- a/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee +++ b/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee @@ -77,3 +77,13 @@ describe 'timeAsyncMethod', -> expect(@Timer.done.callCount).to.equal 1 expect(@logger.log.callCount).to.equal 1 done() + + describe 'when the wrapper cannot be applied', -> + beforeEach -> + + it 'should raise an error', -> + badWrap = () => + @timeAsyncMethod @testObject, 'DEFINITELY_NOT_A_REAL_METHOD', 'test.nextNumber' + expect(badWrap).to.throw( + /^.*expected object property 'DEFINITELY_NOT_A_REAL_METHOD' to be a function.*$/ + ) diff --git a/libraries/metrics/test/unit/js/timeAsyncMethodTests.js b/libraries/metrics/test/unit/js/timeAsyncMethodTests.js index 6982161cdc..b37ac84320 100644 --- a/libraries/metrics/test/unit/js/timeAsyncMethodTests.js +++ b/libraries/metrics/test/unit/js/timeAsyncMethodTests.js @@ -88,7 +88,7 @@ })(this)); }); }); - return describe('when a logger is supplied', function() { + describe('when a logger is supplied', function() { beforeEach(function() { return this.logger = { log: sinon.stub() @@ -108,6 +108,18 @@ })(this)); }); }); + return describe('when the wrapper cannot be applied', function() { + beforeEach(function() {}); + return it('should raise an error', function() { + var badWrap; + badWrap = (function(_this) { + return function() { + return _this.timeAsyncMethod(_this.testObject, 'DEFINITELY_NOT_A_REAL_METHOD', 'test.nextNumber'); + }; + })(this); + return expect(badWrap).to["throw"](/^.*expected object property 'DEFINITELY_NOT_A_REAL_METHOD' to be a function.*$/); + }); + }); }); }).call(this); diff --git a/libraries/metrics/timeAsyncMethod.coffee b/libraries/metrics/timeAsyncMethod.coffee index ec530fcac0..7b97c54af8 100644 --- a/libraries/metrics/timeAsyncMethod.coffee +++ b/libraries/metrics/timeAsyncMethod.coffee @@ -3,7 +3,7 @@ module.exports = (obj, methodName, key, logger) -> metrics = require('./metrics') if typeof obj[methodName] != 'function' - throw new Error("[Metrics] expected object property #{methodName} to be a function") + throw new Error("[Metrics] expected object property '#{methodName}' to be a function") realMethod = obj[methodName] key = "methods.#{key}" From 772f950d7cbf3ad1bc754145d9385556142a8d91 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Thu, 16 Mar 2017 10:07:52 +0000 Subject: [PATCH 042/182] Test failure when wrapped method is not async/callback --- .../unit/coffee/timeAsyncMethodTests.coffee | 15 +++++++++++++++ .../test/unit/js/timeAsyncMethodTests.js | 19 ++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee b/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee index 85af8eb9ee..a7f3a83c94 100644 --- a/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee +++ b/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee @@ -87,3 +87,18 @@ describe 'timeAsyncMethod', -> expect(badWrap).to.throw( /^.*expected object property 'DEFINITELY_NOT_A_REAL_METHOD' to be a function.*$/ ) + + describe 'when the wrapped function is not using a callback', -> + beforeEach -> + @testObject.nextNumber = (n) -> + return n+1 + + it 'should throw an error', -> + @timeAsyncMethod @testObject, 'nextNumber', 'test.nextNumber' + badCall = () => + @testObject.nextNumber 2 + expect(badCall).to.throw( + /^.*expected wrapped method 'nextNumber' to be invoked with a callback.*$/ + ) + + diff --git a/libraries/metrics/test/unit/js/timeAsyncMethodTests.js b/libraries/metrics/test/unit/js/timeAsyncMethodTests.js index b37ac84320..528e04c2c4 100644 --- a/libraries/metrics/test/unit/js/timeAsyncMethodTests.js +++ b/libraries/metrics/test/unit/js/timeAsyncMethodTests.js @@ -108,7 +108,7 @@ })(this)); }); }); - return describe('when the wrapper cannot be applied', function() { + describe('when the wrapper cannot be applied', function() { beforeEach(function() {}); return it('should raise an error', function() { var badWrap; @@ -120,6 +120,23 @@ return expect(badWrap).to["throw"](/^.*expected object property 'DEFINITELY_NOT_A_REAL_METHOD' to be a function.*$/); }); }); + return describe('when the wrapped function is not using a callback', function() { + beforeEach(function() { + return this.testObject.nextNumber = function(n) { + return n + 1; + }; + }); + return it('should throw an error', function() { + var badCall; + this.timeAsyncMethod(this.testObject, 'nextNumber', 'test.nextNumber'); + badCall = (function(_this) { + return function() { + return _this.testObject.nextNumber(2); + }; + })(this); + return expect(badCall).to["throw"](/^.*expected wrapped method 'nextNumber' to be invoked with a callback.*$/); + }); + }); }); }).call(this); From 1f9d4950a2228c395d4f0171a5ec62b0c3f14769 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Thu, 16 Mar 2017 10:09:16 +0000 Subject: [PATCH 043/182] Update gitignore --- libraries/metrics/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/metrics/.gitignore b/libraries/metrics/.gitignore index 3c3629e647..faba053aed 100644 --- a/libraries/metrics/.gitignore +++ b/libraries/metrics/.gitignore @@ -1 +1,2 @@ node_modules +test/unit/js/* From 5ea83947dddf2bbe72ba43cc6983bbf07d92987f Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Thu, 16 Mar 2017 10:10:40 +0000 Subject: [PATCH 044/182] remove stray compiled js file --- .../test/unit/js/timeAsyncMethodTests.js | 142 ------------------ 1 file changed, 142 deletions(-) delete mode 100644 libraries/metrics/test/unit/js/timeAsyncMethodTests.js diff --git a/libraries/metrics/test/unit/js/timeAsyncMethodTests.js b/libraries/metrics/test/unit/js/timeAsyncMethodTests.js deleted file mode 100644 index 528e04c2c4..0000000000 --- a/libraries/metrics/test/unit/js/timeAsyncMethodTests.js +++ /dev/null @@ -1,142 +0,0 @@ -(function() { - var SandboxedModule, chai, expect, modulePath, path, should, sinon; - - require('coffee-script'); - - chai = require('chai'); - - should = chai.should(); - - expect = chai.expect; - - path = require('path'); - - modulePath = path.join(__dirname, '../../../timeAsyncMethod.coffee'); - - SandboxedModule = require('sandboxed-module'); - - sinon = require("sinon"); - - describe('timeAsyncMethod', function() { - beforeEach(function() { - this.Timer = { - done: sinon.stub() - }; - this.TimerConstructor = sinon.stub().returns(this.Timer); - this.metrics = { - Timer: this.TimerConstructor - }; - this.timeAsyncMethod = SandboxedModule.require(modulePath, { - requires: { - './metrics': this.metrics - } - }); - return this.testObject = { - nextNumber: function(n, callback) { - if (callback == null) { - callback = function(err, result) {}; - } - return setTimeout(function() { - return callback(null, n + 1); - }, 100); - } - }; - }); - it('should have the testObject behave correctly before wrapping', function(done) { - return this.testObject.nextNumber(2, function(err, result) { - expect(err).to.not.exist; - expect(result).to.equal(3); - return done(); - }); - }); - it('should wrap method without error', function(done) { - this.timeAsyncMethod(this.testObject, 'nextNumber', 'test.nextNumber'); - return done(); - }); - it('should transparently wrap method invocation in timer', function(done) { - this.timeAsyncMethod(this.testObject, 'nextNumber', 'test.nextNumber'); - return this.testObject.nextNumber(2, (function(_this) { - return function(err, result) { - expect(err).to.not.exist; - expect(result).to.equal(3); - expect(_this.TimerConstructor.callCount).to.equal(1); - expect(_this.Timer.done.callCount).to.equal(1); - return done(); - }; - })(this)); - }); - describe('when base method produces an error', function() { - beforeEach(function() { - return this.testObject.nextNumber = function(n, callback) { - if (callback == null) { - callback = function(err, result) {}; - } - return setTimeout(function() { - return callback(new Error('woops')); - }, 100); - }; - }); - return it('should propagate the error transparently', function(done) { - this.timeAsyncMethod(this.testObject, 'nextNumber', 'test.nextNumber'); - return this.testObject.nextNumber(2, (function(_this) { - return function(err, result) { - expect(err).to.exist; - expect(err).to.be["instanceof"](Error); - expect(result).to.not.exist; - return done(); - }; - })(this)); - }); - }); - describe('when a logger is supplied', function() { - beforeEach(function() { - return this.logger = { - log: sinon.stub() - }; - }); - return it('should also call logger.log', function(done) { - this.timeAsyncMethod(this.testObject, 'nextNumber', 'test.nextNumber', this.logger); - return this.testObject.nextNumber(2, (function(_this) { - return function(err, result) { - expect(err).to.not.exist; - expect(result).to.equal(3); - expect(_this.TimerConstructor.callCount).to.equal(1); - expect(_this.Timer.done.callCount).to.equal(1); - expect(_this.logger.log.callCount).to.equal(1); - return done(); - }; - })(this)); - }); - }); - describe('when the wrapper cannot be applied', function() { - beforeEach(function() {}); - return it('should raise an error', function() { - var badWrap; - badWrap = (function(_this) { - return function() { - return _this.timeAsyncMethod(_this.testObject, 'DEFINITELY_NOT_A_REAL_METHOD', 'test.nextNumber'); - }; - })(this); - return expect(badWrap).to["throw"](/^.*expected object property 'DEFINITELY_NOT_A_REAL_METHOD' to be a function.*$/); - }); - }); - return describe('when the wrapped function is not using a callback', function() { - beforeEach(function() { - return this.testObject.nextNumber = function(n) { - return n + 1; - }; - }); - return it('should throw an error', function() { - var badCall; - this.timeAsyncMethod(this.testObject, 'nextNumber', 'test.nextNumber'); - badCall = (function(_this) { - return function() { - return _this.testObject.nextNumber(2); - }; - })(this); - return expect(badCall).to["throw"](/^.*expected wrapped method 'nextNumber' to be invoked with a callback.*$/); - }); - }); - }); - -}).call(this); From f397678589d97d112e8863c8da81770fa27e45b7 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Thu, 16 Mar 2017 15:07:25 +0000 Subject: [PATCH 045/182] Clean up, don't allocate an extra date --- libraries/metrics/timeAsyncMethod.coffee | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/metrics/timeAsyncMethod.coffee b/libraries/metrics/timeAsyncMethod.coffee index 7b97c54af8..0b604c3683 100644 --- a/libraries/metrics/timeAsyncMethod.coffee +++ b/libraries/metrics/timeAsyncMethod.coffee @@ -17,11 +17,9 @@ module.exports = (obj, methodName, key, logger) -> ) timer = new metrics.Timer(key) - start = new Date() realMethod.call this, firstArgs..., (callbackArgs...) -> - timer.done() - elapsedTime = new Date() - start + elapsedTime = timer.done() if logger? logger.log {key, elapsedTime}, "[Metrics] timed async method call" callback.apply this, callbackArgs From e7f71a25d89acea70fcf306bb47c604ef1859c59 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Fri, 17 Mar 2017 11:47:38 +0000 Subject: [PATCH 046/182] Use an explicit prefix --- libraries/metrics/timeAsyncMethod.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/metrics/timeAsyncMethod.coffee b/libraries/metrics/timeAsyncMethod.coffee index 0b604c3683..bd4743930c 100644 --- a/libraries/metrics/timeAsyncMethod.coffee +++ b/libraries/metrics/timeAsyncMethod.coffee @@ -1,12 +1,12 @@ -module.exports = (obj, methodName, key, logger) -> +module.exports = (obj, methodName, prefix, logger) -> metrics = require('./metrics') if typeof obj[methodName] != 'function' throw new Error("[Metrics] expected object property '#{methodName}' to be a function") realMethod = obj[methodName] - key = "methods.#{key}" + key = "#{prefix}.#{methodName}" obj[methodName] = (originalArgs...) -> From be2c6a96af8256c7a56dfdddaf37efb263a26dda Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Fri, 17 Mar 2017 14:20:13 +0000 Subject: [PATCH 047/182] Log args and their indexes, if they look like object ids --- libraries/metrics/timeAsyncMethod.coffee | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/metrics/timeAsyncMethod.coffee b/libraries/metrics/timeAsyncMethod.coffee index bd4743930c..7ec64f3d41 100644 --- a/libraries/metrics/timeAsyncMethod.coffee +++ b/libraries/metrics/timeAsyncMethod.coffee @@ -21,5 +21,10 @@ module.exports = (obj, methodName, prefix, logger) -> realMethod.call this, firstArgs..., (callbackArgs...) -> elapsedTime = timer.done() if logger? - logger.log {key, elapsedTime}, "[Metrics] timed async method call" + loggableArgs = {} + try + for arg, idx in firstArgs + if arg.toString().match(/^[0-9a-f]{24}$/) + loggableArgs["#{idx}"] = arg + logger.log {key, args: loggableArgs, elapsedTime}, "[Metrics] timed async method call" callback.apply this, callbackArgs From 9846703be51ad720d7608efdcb219075b00bb25c Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Mon, 20 Mar 2017 10:17:09 +0000 Subject: [PATCH 048/182] Bump version --- libraries/metrics/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index cf987853e7..cf6dd9889f 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "1.6.0", + "version": "1.7.0", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From 31235beee5888e9f91d83271672092df74c5b7eb Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Mon, 20 Mar 2017 16:17:22 +0000 Subject: [PATCH 049/182] Don't throw error if the function is not invoked with callback. Instead, log the error and return early. --- .../metrics/test/unit/coffee/timeAsyncMethodTests.coffee | 6 ++---- libraries/metrics/timeAsyncMethod.coffee | 6 +++--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee b/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee index a7f3a83c94..c606b5f719 100644 --- a/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee +++ b/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee @@ -93,12 +93,10 @@ describe 'timeAsyncMethod', -> @testObject.nextNumber = (n) -> return n+1 - it 'should throw an error', -> + it 'should not throw an error', -> @timeAsyncMethod @testObject, 'nextNumber', 'test.nextNumber' badCall = () => @testObject.nextNumber 2 - expect(badCall).to.throw( - /^.*expected wrapped method 'nextNumber' to be invoked with a callback.*$/ - ) + expect(badCall).to.not.throw(Error) diff --git a/libraries/metrics/timeAsyncMethod.coffee b/libraries/metrics/timeAsyncMethod.coffee index 7ec64f3d41..d980ce48a0 100644 --- a/libraries/metrics/timeAsyncMethod.coffee +++ b/libraries/metrics/timeAsyncMethod.coffee @@ -11,10 +11,10 @@ module.exports = (obj, methodName, prefix, logger) -> obj[methodName] = (originalArgs...) -> [firstArgs..., callback] = originalArgs + if !callback? || typeof callback != 'function' - throw new Error( - "[Metrics] expected wrapped method '#{methodName}' to be invoked with a callback" - ) + logger.log "[Metrics] expected wrapped method '#{methodName}' to be invoked with a callback" + return timer = new metrics.Timer(key) From fbe19cd97d9677b7714d17eaa2186b7ef3b5f8ae Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Mon, 20 Mar 2017 16:25:10 +0000 Subject: [PATCH 050/182] Don't return early in case where last arg is not a function --- libraries/metrics/timeAsyncMethod.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/metrics/timeAsyncMethod.coffee b/libraries/metrics/timeAsyncMethod.coffee index d980ce48a0..b90e2b8971 100644 --- a/libraries/metrics/timeAsyncMethod.coffee +++ b/libraries/metrics/timeAsyncMethod.coffee @@ -14,7 +14,6 @@ module.exports = (obj, methodName, prefix, logger) -> if !callback? || typeof callback != 'function' logger.log "[Metrics] expected wrapped method '#{methodName}' to be invoked with a callback" - return timer = new metrics.Timer(key) From 1f77cc0fd3e57f1d201d5a75767bae4b76a4c6fb Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Mon, 20 Mar 2017 16:37:53 +0000 Subject: [PATCH 051/182] If function is called without callback, apply with original args --- .../test/unit/coffee/timeAsyncMethodTests.coffee | 11 +++++++++-- libraries/metrics/timeAsyncMethod.coffee | 4 +++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee b/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee index c606b5f719..7cb8ad7aa5 100644 --- a/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee +++ b/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee @@ -90,8 +90,8 @@ describe 'timeAsyncMethod', -> describe 'when the wrapped function is not using a callback', -> beforeEach -> - @testObject.nextNumber = (n) -> - return n+1 + @realMethod = sinon.stub().returns(42) + @testObject.nextNumber = @realMethod it 'should not throw an error', -> @timeAsyncMethod @testObject, 'nextNumber', 'test.nextNumber' @@ -99,4 +99,11 @@ describe 'timeAsyncMethod', -> @testObject.nextNumber 2 expect(badCall).to.not.throw(Error) + it 'should call the underlying method', -> + @timeAsyncMethod @testObject, 'nextNumber', 'test.nextNumber' + result = @testObject.nextNumber(12) + expect(@realMethod.callCount).to.equal 1 + expect(@realMethod.calledWith(12)).to.equal true + expect(result).to.equal 42 + diff --git a/libraries/metrics/timeAsyncMethod.coffee b/libraries/metrics/timeAsyncMethod.coffee index b90e2b8971..4134086418 100644 --- a/libraries/metrics/timeAsyncMethod.coffee +++ b/libraries/metrics/timeAsyncMethod.coffee @@ -13,7 +13,9 @@ module.exports = (obj, methodName, prefix, logger) -> [firstArgs..., callback] = originalArgs if !callback? || typeof callback != 'function' - logger.log "[Metrics] expected wrapped method '#{methodName}' to be invoked with a callback" + if logger? + logger.log "[Metrics] expected wrapped method '#{methodName}' to be invoked with a callback" + return realMethod.apply this, originalArgs timer = new metrics.Timer(key) From f2ebdd1662d39c4bed0213416240abdb23d1af5d Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Mon, 20 Mar 2017 16:54:40 +0000 Subject: [PATCH 052/182] Increment stats for success/failure of wrapped async calls --- .../unit/coffee/timeAsyncMethodTests.coffee | 31 ++++++++++++++----- libraries/metrics/timeAsyncMethod.coffee | 5 +++ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee b/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee index 7cb8ad7aa5..b6a4d3cd6b 100644 --- a/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee +++ b/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee @@ -15,6 +15,7 @@ describe 'timeAsyncMethod', -> @TimerConstructor = sinon.stub().returns(@Timer) @metrics = { Timer: @TimerConstructor + inc: sinon.stub() } @timeAsyncMethod = SandboxedModule.require modulePath, requires: './metrics': @metrics @@ -35,11 +36,11 @@ describe 'timeAsyncMethod', -> done() it 'should wrap method without error', (done) -> - @timeAsyncMethod @testObject, 'nextNumber', 'test.nextNumber' + @timeAsyncMethod @testObject, 'nextNumber', 'someContext.TestObject' done() it 'should transparently wrap method invocation in timer', (done) -> - @timeAsyncMethod @testObject, 'nextNumber', 'test.nextNumber' + @timeAsyncMethod @testObject, 'nextNumber', 'someContext.TestObject' @testObject.nextNumber 2, (err, result) => expect(err).to.not.exist expect(result).to.equal 3 @@ -47,8 +48,17 @@ describe 'timeAsyncMethod', -> expect(@Timer.done.callCount).to.equal 1 done() + it 'should increment success count', (done) -> + @metrics.inc = sinon.stub() + @timeAsyncMethod @testObject, 'nextNumber', 'someContext.TestObject' + @testObject.nextNumber 2, (err, result) => + expect(@metrics.inc.callCount).to.equal 1 + expect(@metrics.inc.calledWith('someContext.TestObject.nextNumber.success')).to.equal true + done() + describe 'when base method produces an error', -> beforeEach -> + @metrics.inc = sinon.stub() @testObject.nextNumber = (n, callback=(err, result)->) -> setTimeout( () -> @@ -57,19 +67,26 @@ describe 'timeAsyncMethod', -> ) it 'should propagate the error transparently', (done) -> - @timeAsyncMethod @testObject, 'nextNumber', 'test.nextNumber' + @timeAsyncMethod @testObject, 'nextNumber', 'someContext.TestObject' @testObject.nextNumber 2, (err, result) => expect(err).to.exist expect(err).to.be.instanceof Error expect(result).to.not.exist done() + it 'should increment failure count', (done) -> + @timeAsyncMethod @testObject, 'nextNumber', 'someContext.TestObject' + @testObject.nextNumber 2, (err, result) => + expect(@metrics.inc.callCount).to.equal 1 + expect(@metrics.inc.calledWith('someContext.TestObject.nextNumber.failure')).to.equal true + done() + describe 'when a logger is supplied', -> beforeEach -> @logger = {log: sinon.stub()} it 'should also call logger.log', (done) -> - @timeAsyncMethod @testObject, 'nextNumber', 'test.nextNumber', @logger + @timeAsyncMethod @testObject, 'nextNumber', 'someContext.TestObject', @logger @testObject.nextNumber 2, (err, result) => expect(err).to.not.exist expect(result).to.equal 3 @@ -83,7 +100,7 @@ describe 'timeAsyncMethod', -> it 'should raise an error', -> badWrap = () => - @timeAsyncMethod @testObject, 'DEFINITELY_NOT_A_REAL_METHOD', 'test.nextNumber' + @timeAsyncMethod @testObject, 'DEFINITELY_NOT_A_REAL_METHOD', 'someContext.TestObject' expect(badWrap).to.throw( /^.*expected object property 'DEFINITELY_NOT_A_REAL_METHOD' to be a function.*$/ ) @@ -94,13 +111,13 @@ describe 'timeAsyncMethod', -> @testObject.nextNumber = @realMethod it 'should not throw an error', -> - @timeAsyncMethod @testObject, 'nextNumber', 'test.nextNumber' + @timeAsyncMethod @testObject, 'nextNumber', 'someContext.TestObject' badCall = () => @testObject.nextNumber 2 expect(badCall).to.not.throw(Error) it 'should call the underlying method', -> - @timeAsyncMethod @testObject, 'nextNumber', 'test.nextNumber' + @timeAsyncMethod @testObject, 'nextNumber', 'someContext.TestObject' result = @testObject.nextNumber(12) expect(@realMethod.callCount).to.equal 1 expect(@realMethod.calledWith(12)).to.equal true diff --git a/libraries/metrics/timeAsyncMethod.coffee b/libraries/metrics/timeAsyncMethod.coffee index 4134086418..f4eefef559 100644 --- a/libraries/metrics/timeAsyncMethod.coffee +++ b/libraries/metrics/timeAsyncMethod.coffee @@ -21,6 +21,11 @@ module.exports = (obj, methodName, prefix, logger) -> realMethod.call this, firstArgs..., (callbackArgs...) -> elapsedTime = timer.done() + possibleError = callbackArgs[0] + if possibleError? && possibleError.message? && possibleError.stack? + metrics.inc "#{key}.failure" + else + metrics.inc "#{key}.success" if logger? loggableArgs = {} try From 7bdba3756b047d03756e39d664dc11b1e0f60594 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Tue, 21 Mar 2017 14:19:12 +0000 Subject: [PATCH 053/182] Don't bother checking for error properties on error object --- libraries/metrics/timeAsyncMethod.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/timeAsyncMethod.coffee b/libraries/metrics/timeAsyncMethod.coffee index f4eefef559..27e21e6e09 100644 --- a/libraries/metrics/timeAsyncMethod.coffee +++ b/libraries/metrics/timeAsyncMethod.coffee @@ -22,7 +22,7 @@ module.exports = (obj, methodName, prefix, logger) -> realMethod.call this, firstArgs..., (callbackArgs...) -> elapsedTime = timer.done() possibleError = callbackArgs[0] - if possibleError? && possibleError.message? && possibleError.stack? + if possibleError? metrics.inc "#{key}.failure" else metrics.inc "#{key}.success" From 6dbcc34df6d18fb324d0b85807f0a9e406b50ad6 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Thu, 23 Mar 2017 15:31:05 +0000 Subject: [PATCH 054/182] reduce UV thread-pool size to 16 --- libraries/metrics/uv_threadpool_size.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/metrics/uv_threadpool_size.coffee b/libraries/metrics/uv_threadpool_size.coffee index 77978a42c5..c0947fee31 100644 --- a/libraries/metrics/uv_threadpool_size.coffee +++ b/libraries/metrics/uv_threadpool_size.coffee @@ -1,2 +1,2 @@ -process.env.UV_THREADPOOL_SIZE=128 -console.log "Set UV_THREADPOOL_SIZE=#{process.env.UV_THREADPOOL_SIZE}" \ No newline at end of file +process.env.UV_THREADPOOL_SIZE=16 +console.log "Set UV_THREADPOOL_SIZE=#{process.env.UV_THREADPOOL_SIZE}" From d0eaa235a333c3dab2a09e34e76a89be91e21745 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Thu, 23 Mar 2017 15:32:12 +0000 Subject: [PATCH 055/182] bump package version --- libraries/metrics/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index cf6dd9889f..94dbb0c46d 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "1.7.0", + "version": "1.7.1", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From c8cc1e1bfe40a0e7563d60f18eb827b2c1f6dd56 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Thu, 10 May 2018 10:10:34 +0100 Subject: [PATCH 056/182] handle undefined logger in event loop monitor --- libraries/metrics/event_loop.coffee | 4 ++- libraries/metrics/package.json | 2 +- .../test/unit/coffee/event_loop.coffee | 34 +++++++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 libraries/metrics/test/unit/coffee/event_loop.coffee diff --git a/libraries/metrics/event_loop.coffee b/libraries/metrics/event_loop.coffee index 4e410892bf..01e37b96a1 100644 --- a/libraries/metrics/event_loop.coffee +++ b/libraries/metrics/event_loop.coffee @@ -1,7 +1,9 @@ module.exports = EventLoopMonitor = monitor: (logger, interval = 1000, log_threshold = 100) -> Metrics = require "./metrics" - + # check for logger on startup to avoid exceptions later if undefined + throw new Error("logger is undefined") if !logger? + # monitor delay in setInterval to detect event loop blocking previous = Date.now() intervalId = setInterval () -> now = Date.now() diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 94dbb0c46d..6a56fca60d 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "1.7.1", + "version": "1.7.2", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", diff --git a/libraries/metrics/test/unit/coffee/event_loop.coffee b/libraries/metrics/test/unit/coffee/event_loop.coffee new file mode 100644 index 0000000000..19e79cbe9a --- /dev/null +++ b/libraries/metrics/test/unit/coffee/event_loop.coffee @@ -0,0 +1,34 @@ +require('coffee-script') +chai = require('chai') +should = chai.should() +expect = chai.expect +path = require('path') +modulePath = path.join __dirname, '../../../event_loop.coffee' +SandboxedModule = require('sandboxed-module') +sinon = require("sinon") + +describe 'event_loop', -> + + before -> + @metrics = { + timing: sinon.stub() + registerDestructor: sinon.stub() + } + @logger = { + warn: sinon.stub() + } + @event_loop = SandboxedModule.require modulePath, requires: + './metrics': @metrics + + describe 'with a logger provided', -> + before -> + @event_loop.monitor(@logger) + + it 'should register a destructor with metrics', -> + @metrics.registerDestructor.called.should.equal true + + describe 'without a logger provided', -> + + it 'should throw an exception', -> + expect(@event_loop.monitor).to.throw('logger is undefined') + From 00fdea922da42004fa7c27f0d011e2a863ceb0a9 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Fri, 18 May 2018 15:09:11 +0100 Subject: [PATCH 057/182] allow a global gauge not specific to a host --- libraries/metrics/metrics.coffee | 4 ++++ libraries/metrics/package.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 0349ca6d11..6d14655e3f 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -5,6 +5,7 @@ name = "unknown" hostname = require('os').hostname() buildKey = (key)-> "#{name}.#{hostname}.#{key}" +buildGlobalKey = (key)-> "#{name}.global.#{key}" destructors = [] @@ -42,6 +43,9 @@ module.exports = Metrics = gauge : (key, value, sampleRate = 1)-> statsd.gauge buildKey(key), value, sampleRate + globalGauge: (key, value, sampleRate = 1)-> + statsd.gauge buildGlobalKey(key), value, sampleRate + mongodb: require "./mongodb" http: require "./http" open_sockets: require "./open_sockets" diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 6a56fca60d..9902d34845 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "1.7.2", + "version": "1.8.0", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From 06e8450694a26b7558dced17b46d5c9528e85726 Mon Sep 17 00:00:00 2001 From: Christopher Hoskin Date: Fri, 6 Jul 2018 13:57:52 +0100 Subject: [PATCH 058/182] Allow remote statsd to be specified by environment variable --- libraries/metrics/metrics.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 6d14655e3f..e9a25966b5 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -1,5 +1,5 @@ StatsD = require('lynx') -statsd = new StatsD('localhost', 8125, {on_error:->}) +statsd = new StatsD(process.env["STATSD_HOST"] or "localhost", 8125, {on_error:->}) name = "unknown" hostname = require('os').hostname() From 90b6e5afce3572ede74470ea2654a27802aa501d Mon Sep 17 00:00:00 2001 From: Christopher Hoskin Date: Thu, 12 Jul 2018 11:07:43 +0100 Subject: [PATCH 059/182] Release version v1.8.1 --- libraries/metrics/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 9902d34845..e19c11ddf2 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "1.8.0", + "version": "1.8.1", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From 4b075db0385087ca77a6305b3b9f0c5859061144 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Tue, 16 Oct 2018 16:47:12 +0100 Subject: [PATCH 060/182] non tested promethius counters added --- libraries/metrics/metrics.coffee | 15 +++++++++++++++ libraries/metrics/package.json | 3 ++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index e9a25966b5..d23f3ec06d 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -1,6 +1,9 @@ StatsD = require('lynx') statsd = new StatsD(process.env["STATSD_HOST"] or "localhost", 8125, {on_error:->}) +prom = require('prom-client') +collectDefaultMetrics = client.collectDefaultMetrics + name = "unknown" hostname = require('os').hostname() @@ -14,6 +17,8 @@ require "./uv_threadpool_size" module.exports = Metrics = initialize: (_name) -> name = _name + collectDefaultMetrics({ timeout: 5000, prefix: name }) + registerDestructor: (func) -> destructors.push func @@ -23,9 +28,19 @@ module.exports = Metrics = inc : (key, sampleRate = 1)-> statsd.increment buildKey(key), sampleRate + counter = new prom.Counter({ + name: key, + help: key #https://prometheus.io/docs/instrumenting/writing_exporters/#help-strings this is probably wrong + }); + counter.inc() count : (key, count, sampleRate = 1)-> statsd.count buildKey(key), count, sampleRate + counter = new prom.Counter({ + name: key, + help: key #https://prometheus.io/docs/instrumenting/writing_exporters/#help-strings this is probably wrong + }); + counter.inc(count) timing: (key, timeSpan, sampleRate)-> statsd.timing(buildKey(key), timeSpan, sampleRate) diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index e19c11ddf2..d3421a3619 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -7,8 +7,9 @@ "url": "https://github.com/sharelatex/metrics-sharelatex.git" }, "dependencies": { - "lynx": "~0.1.1", "coffee-script": "1.6.0", + "lynx": "~0.1.1", + "prom-client": "^11.1.3", "underscore": "~1.6.0" }, "devDependencies": { From 7e359c9df2955a4499bcfcc3629f6de6e79a857a Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Tue, 16 Oct 2018 17:19:21 +0100 Subject: [PATCH 061/182] add trace and debug agent to metrics --- libraries/metrics/metrics.coffee | 21 ++++++++++++++++++++- libraries/metrics/package.json | 4 +++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index d23f3ec06d..1da51b63b9 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -14,11 +14,30 @@ destructors = [] require "./uv_threadpool_size" + +traceAgent = require('@google-cloud/trace-agent') +debugAgent = require('@google-cloud/debug-agent') + +.start({ + serviceContext: { + allowExpressions: true, + service: 'filestore-readonly', + version: '0.0.1' + } +}); + module.exports = Metrics = initialize: (_name) -> name = _name collectDefaultMetrics({ timeout: 5000, prefix: name }) - + traceAgent.start() + debugAgent.start({ + serviceContext: { + allowExpressions: true, + service: name, + version: '0.0.1' + } + }) registerDestructor: (func) -> destructors.push func diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index d3421a3619..648d4d627b 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -22,6 +22,8 @@ "grunt-execute": "^0.2.2", "grunt-mocha-test": "^0.11.0", "sandboxed-module": "", - "sinon": "" + "sinon": "", + "@google-cloud/debug-agent": "^3.0.0", + "@google-cloud/trace-agent": "^3.2.0" } } From f604fb92e5007dc5f8aebc9794f15f6d6ff99369 Mon Sep 17 00:00:00 2001 From: Christopher Hoskin Date: Tue, 6 Nov 2018 11:14:26 +0000 Subject: [PATCH 062/182] Get default Prometheus metrics working --- libraries/metrics/metrics.coffee | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index e9a25966b5..d3468945a4 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -1,6 +1,10 @@ StatsD = require('lynx') statsd = new StatsD(process.env["STATSD_HOST"] or "localhost", 8125, {on_error:->}) +prom = require('prom-client') +Register = require('prom-client').register +collectDefaultMetrics = prom.collectDefaultMetrics + name = "unknown" hostname = require('os').hostname() @@ -14,10 +18,17 @@ require "./uv_threadpool_size" module.exports = Metrics = initialize: (_name) -> name = _name + collectDefaultMetrics({ timeout: 5000, prefix: name }) registerDestructor: (func) -> destructors.push func + injectMetricsRoute: (app) -> + app.get('/metrics', (req, res) -> + res.set('Content-Type', Register.contentType) + res.end(Register.metrics()) + ) + set : (key, value, sampleRate = 1)-> statsd.set buildKey(key), value, sampleRate From 6d4d05957ea92c7d0276d4b4a30742abb9634098 Mon Sep 17 00:00:00 2001 From: Christopher Hoskin Date: Tue, 6 Nov 2018 14:22:03 +0000 Subject: [PATCH 063/182] Get counter metric working --- libraries/metrics/metrics.coffee | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index d3468945a4..f40a0b3ee2 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -11,6 +11,8 @@ hostname = require('os').hostname() buildKey = (key)-> "#{name}.#{hostname}.#{key}" buildGlobalKey = (key)-> "#{name}.global.#{key}" +counters = {} + destructors = [] require "./uv_threadpool_size" @@ -34,6 +36,14 @@ module.exports = Metrics = inc : (key, sampleRate = 1)-> statsd.increment buildKey(key), sampleRate + if !counters[key] + console.log("No Metric") + counters[key] = new prom.Counter({ + name: key, + help: key #https://prometheus.io/docs/instrumenting/writing_exporters/#help-strings this is probably wrong + labelNames: ['name','host'] + }) + counters[key].inc({name: name, host: hostname}) count : (key, count, sampleRate = 1)-> statsd.count buildKey(key), count, sampleRate From 56eaae89f968325d2eceaaee7426abd27564855e Mon Sep 17 00:00:00 2001 From: Christopher Hoskin Date: Tue, 6 Nov 2018 16:15:41 +0000 Subject: [PATCH 064/182] Add Gauges --- libraries/metrics/metrics.coffee | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index f40a0b3ee2..7bc568c2de 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -12,6 +12,7 @@ buildKey = (key)-> "#{name}.#{hostname}.#{key}" buildGlobalKey = (key)-> "#{name}.global.#{key}" counters = {} +gauges = {} destructors = [] @@ -37,10 +38,9 @@ module.exports = Metrics = inc : (key, sampleRate = 1)-> statsd.increment buildKey(key), sampleRate if !counters[key] - console.log("No Metric") counters[key] = new prom.Counter({ name: key, - help: key #https://prometheus.io/docs/instrumenting/writing_exporters/#help-strings this is probably wrong + help: key, labelNames: ['name','host'] }) counters[key].inc({name: name, host: hostname}) @@ -63,9 +63,23 @@ module.exports = Metrics = gauge : (key, value, sampleRate = 1)-> statsd.gauge buildKey(key), value, sampleRate + if !gauges[key] + gauges[key] = new prom.Gauge({ + name: key, + help: key, + labelNames: ['name','host'] + }) + gauges[key].set({name: name, host: hostname},value) globalGauge: (key, value, sampleRate = 1)-> statsd.gauge buildGlobalKey(key), value, sampleRate + if !gauges[key] + gauges[key] = new prom.Gauge({ + name: key, + help: key, + labelNames: ['name','host'] + }) + gauges[key].set({name: name},value) mongodb: require "./mongodb" http: require "./http" From bb3cff5744474a4f7f2080ace3d5175f20e04496 Mon Sep 17 00:00:00 2001 From: Christopher Hoskin Date: Wed, 7 Nov 2018 11:21:45 +0000 Subject: [PATCH 065/182] Add prom-client to package.json --- libraries/metrics/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index e19c11ddf2..d3421a3619 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -7,8 +7,9 @@ "url": "https://github.com/sharelatex/metrics-sharelatex.git" }, "dependencies": { - "lynx": "~0.1.1", "coffee-script": "1.6.0", + "lynx": "~0.1.1", + "prom-client": "^11.1.3", "underscore": "~1.6.0" }, "devDependencies": { From d0e1324dba044a3cdb2c7c11130863b4773030f2 Mon Sep 17 00:00:00 2001 From: Christopher Hoskin Date: Wed, 7 Nov 2018 12:44:10 +0000 Subject: [PATCH 066/182] Sanitize metric keys for Prometheus --- libraries/metrics/metrics.coffee | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 7bc568c2de..d06cc3972c 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -32,11 +32,15 @@ module.exports = Metrics = res.end(Register.metrics()) ) + sanitizeKey: (key) -> + key.replace /[^a-zA-Z0-9]/g, "_" + set : (key, value, sampleRate = 1)-> statsd.set buildKey(key), value, sampleRate inc : (key, sampleRate = 1)-> statsd.increment buildKey(key), sampleRate + key = this.sanitizeKey(key) if !counters[key] counters[key] = new prom.Counter({ name: key, @@ -63,6 +67,7 @@ module.exports = Metrics = gauge : (key, value, sampleRate = 1)-> statsd.gauge buildKey(key), value, sampleRate + key = this.sanitizeKey(key) if !gauges[key] gauges[key] = new prom.Gauge({ name: key, @@ -73,6 +78,7 @@ module.exports = Metrics = globalGauge: (key, value, sampleRate = 1)-> statsd.gauge buildGlobalKey(key), value, sampleRate + key = this.sanitizeKey(key) if !gauges[key] gauges[key] = new prom.Gauge({ name: key, From 65fccf8abe50fe6f986b75934be76ad6bef0cb82 Mon Sep 17 00:00:00 2001 From: Christopher Hoskin Date: Wed, 7 Nov 2018 16:08:31 +0000 Subject: [PATCH 067/182] Ensure gauge values are numeric, not string --- libraries/metrics/metrics.coffee | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index d06cc3972c..63cfacf1ea 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -35,6 +35,9 @@ module.exports = Metrics = sanitizeKey: (key) -> key.replace /[^a-zA-Z0-9]/g, "_" + sanitizeValue: (value) -> + parseFloat(value) + set : (key, value, sampleRate = 1)-> statsd.set buildKey(key), value, sampleRate @@ -74,7 +77,7 @@ module.exports = Metrics = help: key, labelNames: ['name','host'] }) - gauges[key].set({name: name, host: hostname},value) + gauges[key].set({name: name, host: hostname},this.sanitizeValue(value)) globalGauge: (key, value, sampleRate = 1)-> statsd.gauge buildGlobalKey(key), value, sampleRate @@ -85,7 +88,7 @@ module.exports = Metrics = help: key, labelNames: ['name','host'] }) - gauges[key].set({name: name},value) + gauges[key].set({name: name},this.sanitizeValue(value)) mongodb: require "./mongodb" http: require "./http" From c576a86c148b0f983b2f580c5f5818c4668a4270 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Tue, 20 Nov 2018 13:50:04 +0000 Subject: [PATCH 068/182] Update metrics.coffee --- libraries/metrics/metrics.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 63cfacf1ea..22dfd22548 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -21,7 +21,7 @@ require "./uv_threadpool_size" module.exports = Metrics = initialize: (_name) -> name = _name - collectDefaultMetrics({ timeout: 5000, prefix: name }) + collectDefaultMetrics({ timeout: 5000, prefix: name + "_" }) registerDestructor: (func) -> destructors.push func From 1a3b4273158651184e34c76f2e35bf3685e4cb2f Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Tue, 20 Nov 2018 14:54:09 +0000 Subject: [PATCH 069/182] bump to 1.9.0 --- libraries/metrics/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index d3421a3619..cd47fc1466 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "1.8.1", + "version": "1.9.0", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From f4af82282fdb407eb6f121d339a497c5e8351c6e Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Tue, 20 Nov 2018 16:06:02 +0000 Subject: [PATCH 070/182] use buildKey for prefixing name and host --- libraries/metrics/metrics.coffee | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 22dfd22548..e869ca0cff 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -20,8 +20,8 @@ require "./uv_threadpool_size" module.exports = Metrics = initialize: (_name) -> - name = _name - collectDefaultMetrics({ timeout: 5000, prefix: name + "_" }) + name = _name + "_" + collectDefaultMetrics({ timeout: 5000, prefix: name+"_"}) registerDestructor: (func) -> destructors.push func @@ -46,7 +46,7 @@ module.exports = Metrics = key = this.sanitizeKey(key) if !counters[key] counters[key] = new prom.Counter({ - name: key, + name: buildKey(key), help: key, labelNames: ['name','host'] }) @@ -73,7 +73,7 @@ module.exports = Metrics = key = this.sanitizeKey(key) if !gauges[key] gauges[key] = new prom.Gauge({ - name: key, + name: buildKey(key), help: key, labelNames: ['name','host'] }) @@ -84,7 +84,7 @@ module.exports = Metrics = key = this.sanitizeKey(key) if !gauges[key] gauges[key] = new prom.Gauge({ - name: key, + name: buildKey(key), help: key, labelNames: ['name','host'] }) From 816c9348f65fc0e19af991e9d2507b4871bd7c74 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Tue, 20 Nov 2018 16:13:40 +0000 Subject: [PATCH 071/182] don't put dots in key name --- libraries/metrics/metrics.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index e869ca0cff..822496b57b 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -46,7 +46,7 @@ module.exports = Metrics = key = this.sanitizeKey(key) if !counters[key] counters[key] = new prom.Counter({ - name: buildKey(key), + name: "#{name}_#{key}", help: key, labelNames: ['name','host'] }) @@ -73,7 +73,7 @@ module.exports = Metrics = key = this.sanitizeKey(key) if !gauges[key] gauges[key] = new prom.Gauge({ - name: buildKey(key), + name: "#{name}_#{key}", help: key, labelNames: ['name','host'] }) @@ -84,7 +84,7 @@ module.exports = Metrics = key = this.sanitizeKey(key) if !gauges[key] gauges[key] = new prom.Gauge({ - name: buildKey(key), + name: "#{name}_#{key}", help: key, labelNames: ['name','host'] }) From 5039287ee432d06292083785bee8be64ca7b3a8d Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Tue, 20 Nov 2018 16:28:36 +0000 Subject: [PATCH 072/182] don't default to adding underscore to name --- libraries/metrics/metrics.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 822496b57b..50fdc1be6e 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -20,7 +20,7 @@ require "./uv_threadpool_size" module.exports = Metrics = initialize: (_name) -> - name = _name + "_" + name = _name collectDefaultMetrics({ timeout: 5000, prefix: name+"_"}) registerDestructor: (func) -> From 6f708fd26acf459303c48d9f0cbdcc80aed5babd Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Tue, 20 Nov 2018 17:17:02 +0000 Subject: [PATCH 073/182] add summaries --- libraries/metrics/metrics.coffee | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 50fdc1be6e..9cf1f49758 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -13,6 +13,7 @@ buildGlobalKey = (key)-> "#{name}.global.#{key}" counters = {} gauges = {} +summaries = {} destructors = [] @@ -44,7 +45,7 @@ module.exports = Metrics = inc : (key, sampleRate = 1)-> statsd.increment buildKey(key), sampleRate key = this.sanitizeKey(key) - if !counters[key] + if !counters[key]? counters[key] = new prom.Counter({ name: "#{name}_#{key}", help: key, @@ -66,18 +67,26 @@ module.exports = Metrics = done:-> timeSpan = new Date - this.start statsd.timing(buildKey(this.key), timeSpan, this.sampleRate) + if !summaries[key]? + summary = new client.Summary({ + name: "#{name}_#{key}", + help: key, + maxAgeSeconds: 600, + ageBuckets: 10 + }) + summaries[key].observe(timeSpan) return timeSpan gauge : (key, value, sampleRate = 1)-> statsd.gauge buildKey(key), value, sampleRate key = this.sanitizeKey(key) - if !gauges[key] + if !gauges[key]? gauges[key] = new prom.Gauge({ - name: "#{name}_#{key}", + name: "#{name}_#{key}", help: key, labelNames: ['name','host'] }) - gauges[key].set({name: name, host: hostname},this.sanitizeValue(value)) + gauges[key].set({name: name, host: hostname}, this.sanitizeValue(value)) globalGauge: (key, value, sampleRate = 1)-> statsd.gauge buildGlobalKey(key), value, sampleRate From 6854a64b73e03634fde09c104fcc5f13d9782906 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Tue, 20 Nov 2018 17:20:49 +0000 Subject: [PATCH 074/182] fix this.key --- libraries/metrics/metrics.coffee | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 9cf1f49758..9c59c9f727 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -64,17 +64,18 @@ module.exports = Metrics = this.start = new Date() this.key = key this.sampleRate = sampleRate + done:-> timeSpan = new Date - this.start statsd.timing(buildKey(this.key), timeSpan, this.sampleRate) - if !summaries[key]? + if !summaries[this.key]? summary = new client.Summary({ - name: "#{name}_#{key}", - help: key, + name: "#{name}_#{this.key}", + help: this.key, maxAgeSeconds: 600, ageBuckets: 10 }) - summaries[key].observe(timeSpan) + summaries[this.key].observe(timeSpan) return timeSpan gauge : (key, value, sampleRate = 1)-> From bd8fd1141e145c27f703244a303486dae82abb71 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Tue, 20 Nov 2018 17:25:37 +0000 Subject: [PATCH 075/182] client -> prom --- libraries/metrics/metrics.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 9c59c9f727..5b7049cc7f 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -69,7 +69,7 @@ module.exports = Metrics = timeSpan = new Date - this.start statsd.timing(buildKey(this.key), timeSpan, this.sampleRate) if !summaries[this.key]? - summary = new client.Summary({ + summary = new prom.Summary({ name: "#{name}_#{this.key}", help: this.key, maxAgeSeconds: 600, From 7fc49d1eb546357998dce7748a335754052cdf56 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Tue, 20 Nov 2018 17:50:54 +0000 Subject: [PATCH 076/182] metrics of different types can clash, share promMetrics --- libraries/metrics/metrics.coffee | 34 +++++++++++++++----------------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 5b7049cc7f..fdc45cf4f1 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -11,9 +11,7 @@ hostname = require('os').hostname() buildKey = (key)-> "#{name}.#{hostname}.#{key}" buildGlobalKey = (key)-> "#{name}.global.#{key}" -counters = {} -gauges = {} -summaries = {} +promMetrics = {} destructors = [] @@ -45,13 +43,13 @@ module.exports = Metrics = inc : (key, sampleRate = 1)-> statsd.increment buildKey(key), sampleRate key = this.sanitizeKey(key) - if !counters[key]? - counters[key] = new prom.Counter({ - name: "#{name}_#{key}", + if !promMetrics[key]? + promMetrics[key] = new prom.Counter({ + name: "#{name}_#{key}", help: key, labelNames: ['name','host'] }) - counters[key].inc({name: name, host: hostname}) + promMetrics[key].inc({name: name, host: hostname}) count : (key, count, sampleRate = 1)-> statsd.count buildKey(key), count, sampleRate @@ -68,37 +66,37 @@ module.exports = Metrics = done:-> timeSpan = new Date - this.start statsd.timing(buildKey(this.key), timeSpan, this.sampleRate) - if !summaries[this.key]? - summary = new prom.Summary({ - name: "#{name}_#{this.key}", + if !promMetrics[this.key] + promMetrics[this.key] = new prom.Summary({ + name: "#{name}_timer_#{this.key}".replace(/\./g,"_"), help: this.key, maxAgeSeconds: 600, ageBuckets: 10 }) - summaries[this.key].observe(timeSpan) + promMetrics[this.key].observe(timeSpan) return timeSpan gauge : (key, value, sampleRate = 1)-> statsd.gauge buildKey(key), value, sampleRate key = this.sanitizeKey(key) - if !gauges[key]? - gauges[key] = new prom.Gauge({ + if !promMetrics[key] + promMetrics[key] = new prom.Gauge({ name: "#{name}_#{key}", help: key, labelNames: ['name','host'] }) - gauges[key].set({name: name, host: hostname}, this.sanitizeValue(value)) + promMetrics[key].set({name: name, host: hostname}, this.sanitizeValue(value)) globalGauge: (key, value, sampleRate = 1)-> statsd.gauge buildGlobalKey(key), value, sampleRate key = this.sanitizeKey(key) - if !gauges[key] - gauges[key] = new prom.Gauge({ - name: "#{name}_#{key}", + if !promMetrics[key] + promMetrics[key] = new prom.Gauge({ + name: "#{name}_#{key}", help: key, labelNames: ['name','host'] }) - gauges[key].set({name: name},this.sanitizeValue(value)) + promMetrics[key].set({name: name},this.sanitizeValue(value)) mongodb: require "./mongodb" http: require "./http" From 5599521c098ee4707386513fc7fb02f5a01503aa Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Tue, 20 Nov 2018 21:42:34 +0000 Subject: [PATCH 077/182] consolodate on metrics.timing --- libraries/metrics/metrics.coffee | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index fdc45cf4f1..0e54936429 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -56,6 +56,14 @@ module.exports = Metrics = timing: (key, timeSpan, sampleRate)-> statsd.timing(buildKey(key), timeSpan, sampleRate) + if !promMetrics[this.key] + promMetrics[this.key] = new prom.Summary({ + name: "#{name}_timer_#{this.key}".replace(/\./g,"_"), + help: key, + maxAgeSeconds: 600, + ageBuckets: 10 + }) + promMetrics[this.key].observe(timeSpan) Timer : class constructor :(key, sampleRate = 1)-> @@ -65,15 +73,7 @@ module.exports = Metrics = done:-> timeSpan = new Date - this.start - statsd.timing(buildKey(this.key), timeSpan, this.sampleRate) - if !promMetrics[this.key] - promMetrics[this.key] = new prom.Summary({ - name: "#{name}_timer_#{this.key}".replace(/\./g,"_"), - help: this.key, - maxAgeSeconds: 600, - ageBuckets: 10 - }) - promMetrics[this.key].observe(timeSpan) + Metrics.timing(this.key, timeSpan, this.sampleRate) return timeSpan gauge : (key, value, sampleRate = 1)-> From cf920a86f747a98ebd1750e1eef42a0bdeeaf429 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Wed, 21 Nov 2018 08:50:33 +0000 Subject: [PATCH 078/182] fix metrics.this --- libraries/metrics/metrics.coffee | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 0e54936429..56356ace27 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -56,14 +56,16 @@ module.exports = Metrics = timing: (key, timeSpan, sampleRate)-> statsd.timing(buildKey(key), timeSpan, sampleRate) - if !promMetrics[this.key] - promMetrics[this.key] = new prom.Summary({ - name: "#{name}_timer_#{this.key}".replace(/\./g,"_"), + if !promMetrics[key] + k = "#{name}_timer_#{key}".replace(/\./g,"_") + console.log("sending timing", k) + promMetrics[key] = new prom.Summary({ + name: k, help: key, maxAgeSeconds: 600, ageBuckets: 10 }) - promMetrics[this.key].observe(timeSpan) + promMetrics[key].observe(timeSpan) Timer : class constructor :(key, sampleRate = 1)-> From c36e3d74b5908389ec053417ac555159cb0a3301 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Wed, 21 Nov 2018 08:57:00 +0000 Subject: [PATCH 079/182] replace - with _ --- libraries/metrics/metrics.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 56356ace27..7814dcf9bd 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -57,7 +57,7 @@ module.exports = Metrics = timing: (key, timeSpan, sampleRate)-> statsd.timing(buildKey(key), timeSpan, sampleRate) if !promMetrics[key] - k = "#{name}_timer_#{key}".replace(/\./g,"_") + k = "#{name}_timer_#{key}".replace(/\./g,"_").replace(/-/g,"_") console.log("sending timing", k) promMetrics[key] = new prom.Summary({ name: k, From 70a75113cb9bdf154bae898774461bf6fc913899 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Wed, 21 Nov 2018 10:01:03 +0000 Subject: [PATCH 080/182] refactor key building --- libraries/metrics/metrics.coffee | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 7814dcf9bd..3e7dfc60af 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -11,6 +11,8 @@ hostname = require('os').hostname() buildKey = (key)-> "#{name}.#{hostname}.#{key}" buildGlobalKey = (key)-> "#{name}.global.#{key}" + + promMetrics = {} destructors = [] @@ -20,7 +22,7 @@ require "./uv_threadpool_size" module.exports = Metrics = initialize: (_name) -> name = _name - collectDefaultMetrics({ timeout: 5000, prefix: name+"_"}) + collectDefaultMetrics({ timeout: 5000, prefix: Metrics.buildPromKey()}) registerDestructor: (func) -> destructors.push func @@ -31,6 +33,9 @@ module.exports = Metrics = res.end(Register.metrics()) ) + buildPromKey: (key = "")-> + Metrics.sanitizeKey "#{name}_#{key}" + sanitizeKey: (key) -> key.replace /[^a-zA-Z0-9]/g, "_" @@ -42,10 +47,10 @@ module.exports = Metrics = inc : (key, sampleRate = 1)-> statsd.increment buildKey(key), sampleRate - key = this.sanitizeKey(key) + key = Metrics.buildPromKey(key) if !promMetrics[key]? promMetrics[key] = new prom.Counter({ - name: "#{name}_#{key}", + name: key, help: key, labelNames: ['name','host'] }) @@ -56,11 +61,10 @@ module.exports = Metrics = timing: (key, timeSpan, sampleRate)-> statsd.timing(buildKey(key), timeSpan, sampleRate) + key = Metrics.buildPromKey("timer_#{key}") if !promMetrics[key] - k = "#{name}_timer_#{key}".replace(/\./g,"_").replace(/-/g,"_") - console.log("sending timing", k) promMetrics[key] = new prom.Summary({ - name: k, + name: key, help: key, maxAgeSeconds: 600, ageBuckets: 10 @@ -70,6 +74,7 @@ module.exports = Metrics = Timer : class constructor :(key, sampleRate = 1)-> this.start = new Date() + key = Metrics.sanitizeKey(key) this.key = key this.sampleRate = sampleRate @@ -80,10 +85,10 @@ module.exports = Metrics = gauge : (key, value, sampleRate = 1)-> statsd.gauge buildKey(key), value, sampleRate - key = this.sanitizeKey(key) + key = Metrics.buildPromKey(key) if !promMetrics[key] promMetrics[key] = new prom.Gauge({ - name: "#{name}_#{key}", + name: key, help: key, labelNames: ['name','host'] }) @@ -91,10 +96,10 @@ module.exports = Metrics = globalGauge: (key, value, sampleRate = 1)-> statsd.gauge buildGlobalKey(key), value, sampleRate - key = this.sanitizeKey(key) + key = Metrics.buildPromKey(key) if !promMetrics[key] promMetrics[key] = new prom.Gauge({ - name: "#{name}_#{key}", + name: key, help: key, labelNames: ['name','host'] }) From 32da84a1d7fbf6b5f40bae22ba028b0f97a76e01 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Wed, 21 Nov 2018 10:20:33 +0000 Subject: [PATCH 081/182] proper null check --- libraries/metrics/metrics.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 3e7dfc60af..78a512d3b5 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -62,7 +62,7 @@ module.exports = Metrics = timing: (key, timeSpan, sampleRate)-> statsd.timing(buildKey(key), timeSpan, sampleRate) key = Metrics.buildPromKey("timer_#{key}") - if !promMetrics[key] + if !promMetrics[key]? promMetrics[key] = new prom.Summary({ name: key, help: key, @@ -86,7 +86,7 @@ module.exports = Metrics = gauge : (key, value, sampleRate = 1)-> statsd.gauge buildKey(key), value, sampleRate key = Metrics.buildPromKey(key) - if !promMetrics[key] + if !promMetrics[key]? promMetrics[key] = new prom.Gauge({ name: key, help: key, @@ -97,7 +97,7 @@ module.exports = Metrics = globalGauge: (key, value, sampleRate = 1)-> statsd.gauge buildGlobalKey(key), value, sampleRate key = Metrics.buildPromKey(key) - if !promMetrics[key] + if !promMetrics[key]? promMetrics[key] = new prom.Gauge({ name: key, help: key, From d01ff95b466288eee3e108c03fb2f6b4f6a14fc4 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Wed, 21 Nov 2018 10:20:58 +0000 Subject: [PATCH 082/182] bump to 1.9.1 --- libraries/metrics/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index cd47fc1466..720bb915b8 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "1.9.0", + "version": "1.9.1", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From f63b84983d0155cc696823e45b1bd53a72ffdf0a Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Wed, 21 Nov 2018 10:28:32 +0000 Subject: [PATCH 083/182] add count to prom --- libraries/metrics/metrics.coffee | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 78a512d3b5..03cce16c74 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -58,6 +58,14 @@ module.exports = Metrics = count : (key, count, sampleRate = 1)-> statsd.count buildKey(key), count, sampleRate + key = Metrics.buildPromKey(key) + if !promMetrics[key]? + promMetrics[key] = new prom.Counter({ + name: key, + help: key, + labelNames: ['name','host'] + }) + promMetrics[key].inc({name: name, host: hostname}, count) timing: (key, timeSpan, sampleRate)-> statsd.timing(buildKey(key), timeSpan, sampleRate) From 7f3cd3c77cef3bd48903dbd43baaf9bb2b9acc5e Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Wed, 21 Nov 2018 10:30:18 +0000 Subject: [PATCH 084/182] just do debugging and tracing --- libraries/metrics/metrics.coffee | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 1da51b63b9..ea5c5f8e1d 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -1,8 +1,10 @@ StatsD = require('lynx') statsd = new StatsD(process.env["STATSD_HOST"] or "localhost", 8125, {on_error:->}) +traceAgent = require('@google-cloud/trace-agent') +debugAgent = require('@google-cloud/debug-agent') + prom = require('prom-client') -collectDefaultMetrics = client.collectDefaultMetrics name = "unknown" hostname = require('os').hostname() @@ -15,21 +17,10 @@ destructors = [] require "./uv_threadpool_size" -traceAgent = require('@google-cloud/trace-agent') -debugAgent = require('@google-cloud/debug-agent') - -.start({ - serviceContext: { - allowExpressions: true, - service: 'filestore-readonly', - version: '0.0.1' - } -}); module.exports = Metrics = initialize: (_name) -> name = _name - collectDefaultMetrics({ timeout: 5000, prefix: name }) traceAgent.start() debugAgent.start({ serviceContext: { @@ -47,19 +38,9 @@ module.exports = Metrics = inc : (key, sampleRate = 1)-> statsd.increment buildKey(key), sampleRate - counter = new prom.Counter({ - name: key, - help: key #https://prometheus.io/docs/instrumenting/writing_exporters/#help-strings this is probably wrong - }); - counter.inc() count : (key, count, sampleRate = 1)-> statsd.count buildKey(key), count, sampleRate - counter = new prom.Counter({ - name: key, - help: key #https://prometheus.io/docs/instrumenting/writing_exporters/#help-strings this is probably wrong - }); - counter.inc(count) timing: (key, timeSpan, sampleRate)-> statsd.timing(buildKey(key), timeSpan, sampleRate) From 725abdce3b629b97b9b0eaca6bc4c588021be88a Mon Sep 17 00:00:00 2001 From: Christopher Hoskin Date: Wed, 21 Nov 2018 12:42:40 +0000 Subject: [PATCH 085/182] Remove spurious blank lines --- libraries/metrics/metrics.coffee | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 0e0709d74b..7d07d6aed3 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -21,8 +21,6 @@ destructors = [] require "./uv_threadpool_size" - - module.exports = Metrics = initialize: (_name) -> name = _name From 4806e6fd87cda661fd21e2fd0b37bb75efc36ea0 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Fri, 23 Nov 2018 16:24:31 +0000 Subject: [PATCH 086/182] use lables --- libraries/metrics/http.coffee | 2 +- libraries/metrics/metrics.coffee | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/libraries/metrics/http.coffee b/libraries/metrics/http.coffee index c175f26a14..1abaede902 100644 --- a/libraries/metrics/http.coffee +++ b/libraries/metrics/http.coffee @@ -12,7 +12,7 @@ module.exports.monitor = (logger) -> routePath = req.route.path.toString().replace(/\//g, '_').replace(/\:/g, '').slice(1) key = "http-requests.#{routePath}.#{req.method}.#{res.statusCode}" - Metrics.timing(key, responseTime) + Metrics.timing("http_request", responseTime, null, {method:req.method, status_code:res.status_code, path:routePath}) logger.log req: url: req.originalUrl || req.url diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 908efb6caf..60624e4ac2 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -78,17 +78,20 @@ module.exports = Metrics = }) promMetrics[key].inc({name: name, host: hostname}, count) - timing: (key, timeSpan, sampleRate)-> + timing: (key, timeSpan, sampleRate, opts = {})-> statsd.timing(buildKey(key), timeSpan, sampleRate) - key = Metrics.buildPromKey("timer_#{key}") + key = Metrics.sanitizeKey("timer_" + key) if !promMetrics[key]? promMetrics[key] = new prom.Summary({ name: key, help: key, maxAgeSeconds: 600, - ageBuckets: 10 + ageBuckets: 10, + labelNames: ['app', 'path', 'status_code', 'method'] }) - promMetrics[key].observe(timeSpan) + opts.app = name + console.log(key, opts, "timing key") + promMetrics[key].observe(opts, timeSpan) Timer : class constructor :(key, sampleRate = 1)-> @@ -109,9 +112,9 @@ module.exports = Metrics = promMetrics[key] = new prom.Gauge({ name: key, help: key, - labelNames: ['name','host'] + labelNames: ['app','host'] }) - promMetrics[key].set({name: name, host: hostname}, this.sanitizeValue(value)) + promMetrics[key].set({app: name, host: hostname}, this.sanitizeValue(value)) globalGauge: (key, value, sampleRate = 1)-> statsd.gauge buildGlobalKey(key), value, sampleRate @@ -120,9 +123,9 @@ module.exports = Metrics = promMetrics[key] = new prom.Gauge({ name: key, help: key, - labelNames: ['name','host'] + labelNames: ['app','host'] }) - promMetrics[key].set({name: name},this.sanitizeValue(value)) + promMetrics[key].set({app: name},this.sanitizeValue(value)) mongodb: require "./mongodb" http: require "./http" From b9f3a3f987c90ba063b5e6702c1ed4ed017a01e8 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Mon, 26 Nov 2018 11:08:29 +0000 Subject: [PATCH 087/182] improve mongo metrics to be more promethious like --- libraries/metrics/http.coffee | 2 +- libraries/metrics/metrics.coffee | 8 ++++---- libraries/metrics/mongodb.coffee | 2 +- libraries/metrics/timeAsyncMethod.coffee | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/libraries/metrics/http.coffee b/libraries/metrics/http.coffee index 1abaede902..45f72b7642 100644 --- a/libraries/metrics/http.coffee +++ b/libraries/metrics/http.coffee @@ -12,7 +12,7 @@ module.exports.monitor = (logger) -> routePath = req.route.path.toString().replace(/\//g, '_').replace(/\:/g, '').slice(1) key = "http-requests.#{routePath}.#{req.method}.#{res.statusCode}" - Metrics.timing("http_request", responseTime, null, {method:req.method, status_code:res.status_code, path:routePath}) + Metrics.timing("http_request", responseTime, null, {method:req.method, status_code: res.statusCode, path:routePath}) logger.log req: url: req.originalUrl || req.url diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 60624e4ac2..7e2927e7ae 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -87,22 +87,22 @@ module.exports = Metrics = help: key, maxAgeSeconds: 600, ageBuckets: 10, - labelNames: ['app', 'path', 'status_code', 'method'] + labelNames: ['app', 'path', 'status_code', 'method', 'collection', 'query'] }) opts.app = name - console.log(key, opts, "timing key") promMetrics[key].observe(opts, timeSpan) Timer : class - constructor :(key, sampleRate = 1)-> + constructor :(key, sampleRate = 1, opts)-> this.start = new Date() key = Metrics.sanitizeKey(key) this.key = key this.sampleRate = sampleRate + this.opts = opts done:-> timeSpan = new Date - this.start - Metrics.timing(this.key, timeSpan, this.sampleRate) + Metrics.timing(this.key, timeSpan, this.sampleRate, this.opts) return timeSpan gauge : (key, value, sampleRate = 1)-> diff --git a/libraries/metrics/mongodb.coffee b/libraries/metrics/mongodb.coffee index ce1ca71385..1f54cdde9a 100644 --- a/libraries/metrics/mongodb.coffee +++ b/libraries/metrics/mongodb.coffee @@ -34,7 +34,7 @@ module.exports = query = Object.keys(db_command.query).sort().join("_") key += "." + query - timer = new Metrics.Timer(key) + timer = new Metrics.Timer("mongo", {collection: collection, query:query}) start = new Date() _method.call this, db_command, options, () -> timer.done() diff --git a/libraries/metrics/timeAsyncMethod.coffee b/libraries/metrics/timeAsyncMethod.coffee index 27e21e6e09..6986299390 100644 --- a/libraries/metrics/timeAsyncMethod.coffee +++ b/libraries/metrics/timeAsyncMethod.coffee @@ -17,7 +17,7 @@ module.exports = (obj, methodName, prefix, logger) -> logger.log "[Metrics] expected wrapped method '#{methodName}' to be invoked with a callback" return realMethod.apply this, originalArgs - timer = new metrics.Timer(key) + timer = new metrics.Timer(prefix, null, {method: methodName}) realMethod.call this, firstArgs..., (callbackArgs...) -> elapsedTime = timer.done() From fdd4db25a3ff742e95c3084c36371ff13c87c5df Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Tue, 27 Nov 2018 10:01:33 +0000 Subject: [PATCH 088/182] big refactor remoing statsd and converting keys to prom keys --- libraries/metrics/metrics.coffee | 35 ++++++++++-------------- libraries/metrics/timeAsyncMethod.coffee | 11 ++++++-- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 7e2927e7ae..80dbf3cd03 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -1,6 +1,3 @@ -StatsD = require('lynx') -statsd = new StatsD(process.env["STATSD_HOST"] or "localhost", 8125, {on_error:->}) - traceAgent = require('@google-cloud/trace-agent') debugAgent = require('@google-cloud/debug-agent') @@ -8,7 +5,7 @@ prom = require('prom-client') Register = require('prom-client').register collectDefaultMetrics = prom.collectDefaultMetrics -name = "unknown" +appname = "unknown" hostname = require('os').hostname() buildKey = (key)-> "#{name}.#{hostname}.#{key}" @@ -24,13 +21,13 @@ require "./uv_threadpool_size" module.exports = Metrics = initialize: (_name) -> - name = _name + appname = _name collectDefaultMetrics({ timeout: 5000, prefix: Metrics.buildPromKey()}) traceAgent.start() debugAgent.start({ serviceContext: { allowExpressions: true, - service: name, + service: appname, version: '0.0.1' } }) @@ -45,7 +42,7 @@ module.exports = Metrics = ) buildPromKey: (key = "")-> - Metrics.sanitizeKey "#{name}_#{key}" + Metrics.sanitizeKey key sanitizeKey: (key) -> key.replace /[^a-zA-Z0-9]/g, "_" @@ -54,32 +51,29 @@ module.exports = Metrics = parseFloat(value) set : (key, value, sampleRate = 1)-> - statsd.set buildKey(key), value, sampleRate inc : (key, sampleRate = 1)-> - statsd.increment buildKey(key), sampleRate key = Metrics.buildPromKey(key) if !promMetrics[key]? promMetrics[key] = new prom.Counter({ name: key, help: key, - labelNames: ['name','host'] + labelNames: ['app','host'] }) - promMetrics[key].inc({name: name, host: hostname}) + console.log("doing inc", key, appname) + promMetrics[key].inc({app: appname, host: hostname}) count : (key, count, sampleRate = 1)-> - statsd.count buildKey(key), count, sampleRate key = Metrics.buildPromKey(key) if !promMetrics[key]? promMetrics[key] = new prom.Counter({ name: key, help: key, - labelNames: ['name','host'] + labelNames: ['app','host'] }) - promMetrics[key].inc({name: name, host: hostname}, count) + promMetrics[key].inc({app: appname, host: hostname}, count) timing: (key, timeSpan, sampleRate, opts = {})-> - statsd.timing(buildKey(key), timeSpan, sampleRate) key = Metrics.sanitizeKey("timer_" + key) if !promMetrics[key]? promMetrics[key] = new prom.Summary({ @@ -89,12 +83,14 @@ module.exports = Metrics = ageBuckets: 10, labelNames: ['app', 'path', 'status_code', 'method', 'collection', 'query'] }) - opts.app = name + opts.app = appname + console.log("doing timing", key, opts) promMetrics[key].observe(opts, timeSpan) Timer : class constructor :(key, sampleRate = 1, opts)-> this.start = new Date() + console.log("creating new timer", key) key = Metrics.sanitizeKey(key) this.key = key this.sampleRate = sampleRate @@ -106,7 +102,6 @@ module.exports = Metrics = return timeSpan gauge : (key, value, sampleRate = 1)-> - statsd.gauge buildKey(key), value, sampleRate key = Metrics.buildPromKey(key) if !promMetrics[key]? promMetrics[key] = new prom.Gauge({ @@ -114,10 +109,9 @@ module.exports = Metrics = help: key, labelNames: ['app','host'] }) - promMetrics[key].set({app: name, host: hostname}, this.sanitizeValue(value)) + promMetrics[key].set({app: appname, host: hostname}, this.sanitizeValue(value)) globalGauge: (key, value, sampleRate = 1)-> - statsd.gauge buildGlobalKey(key), value, sampleRate key = Metrics.buildPromKey(key) if !promMetrics[key]? promMetrics[key] = new prom.Gauge({ @@ -125,7 +119,7 @@ module.exports = Metrics = help: key, labelNames: ['app','host'] }) - promMetrics[key].set({app: name},this.sanitizeValue(value)) + promMetrics[key].set({app: appname},this.sanitizeValue(value)) mongodb: require "./mongodb" http: require "./http" @@ -138,4 +132,3 @@ module.exports = Metrics = close: () -> for func in destructors func() - statsd.close() diff --git a/libraries/metrics/timeAsyncMethod.coffee b/libraries/metrics/timeAsyncMethod.coffee index 6986299390..75eb9a131f 100644 --- a/libraries/metrics/timeAsyncMethod.coffee +++ b/libraries/metrics/timeAsyncMethod.coffee @@ -6,8 +6,14 @@ module.exports = (obj, methodName, prefix, logger) -> throw new Error("[Metrics] expected object property '#{methodName}' to be a function") realMethod = obj[methodName] - key = "#{prefix}.#{methodName}" + keys = prefix.split(".") + key = keys[0].toLowerCase() + + if keys[1]? + methodName = "#{keys[1]}_#{methodName}" + + console.log "Async method", keys, methodName obj[methodName] = (originalArgs...) -> [firstArgs..., callback] = originalArgs @@ -17,7 +23,8 @@ module.exports = (obj, methodName, prefix, logger) -> logger.log "[Metrics] expected wrapped method '#{methodName}' to be invoked with a callback" return realMethod.apply this, originalArgs - timer = new metrics.Timer(prefix, null, {method: methodName}) + console.log("creating timer for async method") + timer = new metrics.Timer(key, null, {method: methodName}) realMethod.call this, firstArgs..., (callbackArgs...) -> elapsedTime = timer.done() From 2a6839f48cd3076a1c503a610ad4b1ec4f749867 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Tue, 27 Nov 2018 10:46:54 +0000 Subject: [PATCH 089/182] roll back async method for moment --- libraries/metrics/timeAsyncMethod.coffee | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/libraries/metrics/timeAsyncMethod.coffee b/libraries/metrics/timeAsyncMethod.coffee index 75eb9a131f..5248c43f79 100644 --- a/libraries/metrics/timeAsyncMethod.coffee +++ b/libraries/metrics/timeAsyncMethod.coffee @@ -5,15 +5,14 @@ module.exports = (obj, methodName, prefix, logger) -> if typeof obj[methodName] != 'function' throw new Error("[Metrics] expected object property '#{methodName}' to be a function") + key = "#{prefix}.#{methodName}" + realMethod = obj[methodName] - keys = prefix.split(".") - key = keys[0].toLowerCase() + startPrefix = prefix.split(".")[0] - - if keys[1]? - methodName = "#{keys[1]}_#{methodName}" - - console.log "Async method", keys, methodName + endPrefix = prefix.split(".")[1] + modifedMethodName = "#{endPrefix}_methodName" + console.log "Async method", prefix, key, methodName, modifedMethodName obj[methodName] = (originalArgs...) -> [firstArgs..., callback] = originalArgs @@ -23,8 +22,11 @@ module.exports = (obj, methodName, prefix, logger) -> logger.log "[Metrics] expected wrapped method '#{methodName}' to be invoked with a callback" return realMethod.apply this, originalArgs - console.log("creating timer for async method") - timer = new metrics.Timer(key, null, {method: methodName}) + console.log("creating timer for async method", prefix, startPrefix, modifedMethodName) + + + timer = new metrics.Timer(prefix, null, {method: methodName}) + console.log("changed timer for async method", prefix, methodName, key) realMethod.call this, firstArgs..., (callbackArgs...) -> elapsedTime = timer.done() From a8cfa97463c193206ef2ff744ec7b4c54baa0753 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Tue, 27 Nov 2018 11:33:45 +0000 Subject: [PATCH 090/182] use modified prefix and method name --- libraries/metrics/metrics.coffee | 8 +++++--- libraries/metrics/timeAsyncMethod.coffee | 9 ++++----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 80dbf3cd03..a603bc5327 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -52,16 +52,18 @@ module.exports = Metrics = set : (key, value, sampleRate = 1)-> - inc : (key, sampleRate = 1)-> + inc : (key, sampleRate = 1, opts)-> key = Metrics.buildPromKey(key) if !promMetrics[key]? promMetrics[key] = new prom.Counter({ name: key, help: key, - labelNames: ['app','host'] + labelNames: ['app','host','status','method'] }) console.log("doing inc", key, appname) - promMetrics[key].inc({app: appname, host: hostname}) + opts.app = appname + opts.host = hostname + promMetrics[key].inc(opts) count : (key, count, sampleRate = 1)-> key = Metrics.buildPromKey(key) diff --git a/libraries/metrics/timeAsyncMethod.coffee b/libraries/metrics/timeAsyncMethod.coffee index 5248c43f79..0bf0108e56 100644 --- a/libraries/metrics/timeAsyncMethod.coffee +++ b/libraries/metrics/timeAsyncMethod.coffee @@ -11,7 +11,7 @@ module.exports = (obj, methodName, prefix, logger) -> startPrefix = prefix.split(".")[0] endPrefix = prefix.split(".")[1] - modifedMethodName = "#{endPrefix}_methodName" + modifedMethodName = "#{endPrefix}_#{methodName}" console.log "Async method", prefix, key, methodName, modifedMethodName obj[methodName] = (originalArgs...) -> @@ -25,16 +25,15 @@ module.exports = (obj, methodName, prefix, logger) -> console.log("creating timer for async method", prefix, startPrefix, modifedMethodName) - timer = new metrics.Timer(prefix, null, {method: methodName}) - console.log("changed timer for async method", prefix, methodName, key) + timer = new metrics.Timer(startPrefix, null, {method: modifedMethodName}) realMethod.call this, firstArgs..., (callbackArgs...) -> elapsedTime = timer.done() possibleError = callbackArgs[0] if possibleError? - metrics.inc "#{key}.failure" + metrics.inc "#{startPrefix}", null, {status:"success", method: modifedMethodName} else - metrics.inc "#{key}.success" + metrics.inc "#{startPrefix}", null, {status:"failed", method: modifedMethodName} if logger? loggableArgs = {} try From 4e370ef24ddd3a7bc4814cfd44aa9806b15bddc6 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Tue, 27 Nov 2018 12:04:50 +0000 Subject: [PATCH 091/182] clean up --- libraries/metrics/metrics.coffee | 2 +- libraries/metrics/timeAsyncMethod.coffee | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index a603bc5327..1c19fa05e9 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -60,7 +60,7 @@ module.exports = Metrics = help: key, labelNames: ['app','host','status','method'] }) - console.log("doing inc", key, appname) + console.log("doing inc", key, opts) opts.app = appname opts.host = hostname promMetrics[key].inc(opts) diff --git a/libraries/metrics/timeAsyncMethod.coffee b/libraries/metrics/timeAsyncMethod.coffee index 0bf0108e56..e09e9bfa43 100644 --- a/libraries/metrics/timeAsyncMethod.coffee +++ b/libraries/metrics/timeAsyncMethod.coffee @@ -8,10 +8,14 @@ module.exports = (obj, methodName, prefix, logger) -> key = "#{prefix}.#{methodName}" realMethod = obj[methodName] - startPrefix = prefix.split(".")[0] - endPrefix = prefix.split(".")[1] - modifedMethodName = "#{endPrefix}_#{methodName}" + splitPrefix = prefix.split(".") + startPrefix = splitPrefix[0] + + if splitPrefix[1]? + modifedMethodName = "#{splitPrefix[1]}_#{methodName}" + else + modifedMethodName = methodName console.log "Async method", prefix, key, methodName, modifedMethodName obj[methodName] = (originalArgs...) -> @@ -31,9 +35,9 @@ module.exports = (obj, methodName, prefix, logger) -> elapsedTime = timer.done() possibleError = callbackArgs[0] if possibleError? - metrics.inc "#{startPrefix}", null, {status:"success", method: modifedMethodName} + metrics.inc "#{startPrefix}_result", null, {status:"failed", method: modifedMethodName} else - metrics.inc "#{startPrefix}", null, {status:"failed", method: modifedMethodName} + metrics.inc "#{startPrefix}_result", null, {status:"success", method: modifedMethodName} if logger? loggableArgs = {} try From 39f924f73cdf94f75731361984551a393ee6934c Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Tue, 27 Nov 2018 15:15:45 +0000 Subject: [PATCH 092/182] bump to 2.0.0 --- libraries/metrics/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index d51be1b107..63772e7ca1 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "1.9.1", + "version": "2.0.0", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From 8adfc49af7f863c589d80e158180fa958195455f Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Tue, 27 Nov 2018 15:48:17 +0000 Subject: [PATCH 093/182] v 2.0.1 --- libraries/metrics/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 63772e7ca1..0adf79ca3e 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "2.0.0", + "version": "2.0.1", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From 917afa3edc1ce66bce93a95ffa313f380f41eadf Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Tue, 27 Nov 2018 16:12:12 +0000 Subject: [PATCH 094/182] have default opts in inc --- libraries/metrics/metrics.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 1c19fa05e9..e5401d1c88 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -52,7 +52,7 @@ module.exports = Metrics = set : (key, value, sampleRate = 1)-> - inc : (key, sampleRate = 1, opts)-> + inc : (key, sampleRate = 1, opts = {})-> key = Metrics.buildPromKey(key) if !promMetrics[key]? promMetrics[key] = new prom.Counter({ From 9a737bef2fb4c9e94140cb3ab5a05918e2bb9c47 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Wed, 28 Nov 2018 10:45:11 +0000 Subject: [PATCH 095/182] bump to 2.0.3 --- libraries/metrics/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 0adf79ca3e..02ee3101cf 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "2.0.1", + "version": "2.0.3", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From 752541b7f104d5fa2dc6cb9223973c4da547d9f9 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Thu, 29 Nov 2018 16:10:55 +0000 Subject: [PATCH 096/182] remove logging and bump to 2.0.4 --- libraries/metrics/metrics.coffee | 3 --- libraries/metrics/package.json | 2 +- libraries/metrics/timeAsyncMethod.coffee | 4 ---- 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index e5401d1c88..3a778c052d 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -60,7 +60,6 @@ module.exports = Metrics = help: key, labelNames: ['app','host','status','method'] }) - console.log("doing inc", key, opts) opts.app = appname opts.host = hostname promMetrics[key].inc(opts) @@ -86,13 +85,11 @@ module.exports = Metrics = labelNames: ['app', 'path', 'status_code', 'method', 'collection', 'query'] }) opts.app = appname - console.log("doing timing", key, opts) promMetrics[key].observe(opts, timeSpan) Timer : class constructor :(key, sampleRate = 1, opts)-> this.start = new Date() - console.log("creating new timer", key) key = Metrics.sanitizeKey(key) this.key = key this.sampleRate = sampleRate diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 02ee3101cf..c29e059b6a 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "2.0.3", + "version": "2.0.4", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", diff --git a/libraries/metrics/timeAsyncMethod.coffee b/libraries/metrics/timeAsyncMethod.coffee index e09e9bfa43..73f69cc334 100644 --- a/libraries/metrics/timeAsyncMethod.coffee +++ b/libraries/metrics/timeAsyncMethod.coffee @@ -16,7 +16,6 @@ module.exports = (obj, methodName, prefix, logger) -> modifedMethodName = "#{splitPrefix[1]}_#{methodName}" else modifedMethodName = methodName - console.log "Async method", prefix, key, methodName, modifedMethodName obj[methodName] = (originalArgs...) -> [firstArgs..., callback] = originalArgs @@ -26,9 +25,6 @@ module.exports = (obj, methodName, prefix, logger) -> logger.log "[Metrics] expected wrapped method '#{methodName}' to be invoked with a callback" return realMethod.apply this, originalArgs - console.log("creating timer for async method", prefix, startPrefix, modifedMethodName) - - timer = new metrics.Timer(startPrefix, null, {method: modifedMethodName}) realMethod.call this, firstArgs..., (callbackArgs...) -> From 27e6db1e5130d9d40e500098f916255a337e9101 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Tue, 4 Dec 2018 15:57:19 +0000 Subject: [PATCH 097/182] inc process_startup on init --- libraries/metrics/metrics.coffee | 1 + libraries/metrics/package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 3a778c052d..068069a482 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -31,6 +31,7 @@ module.exports = Metrics = version: '0.0.1' } }) + Metrics.inc("process_startup") registerDestructor: (func) -> destructors.push func diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index c29e059b6a..07805f8f1e 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "2.0.4", + "version": "2.0.5", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From 31fa5cef517d2e39337610e0143e5c2545209cbf Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Tue, 4 Dec 2018 16:09:09 +0000 Subject: [PATCH 098/182] add logging --- libraries/metrics/metrics.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 068069a482..a644a4a405 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -54,6 +54,7 @@ module.exports = Metrics = set : (key, value, sampleRate = 1)-> inc : (key, sampleRate = 1, opts = {})-> + console.log("doing inc", key) key = Metrics.buildPromKey(key) if !promMetrics[key]? promMetrics[key] = new prom.Counter({ From 2d4283fdf06aa369cbb12a88a6079121dbe0b9ee Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Tue, 4 Dec 2018 16:20:52 +0000 Subject: [PATCH 099/182] add DEBUG_METRICS env var --- libraries/metrics/metrics.coffee | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index a644a4a405..77953b275b 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -54,7 +54,6 @@ module.exports = Metrics = set : (key, value, sampleRate = 1)-> inc : (key, sampleRate = 1, opts = {})-> - console.log("doing inc", key) key = Metrics.buildPromKey(key) if !promMetrics[key]? promMetrics[key] = new prom.Counter({ @@ -65,6 +64,8 @@ module.exports = Metrics = opts.app = appname opts.host = hostname promMetrics[key].inc(opts) + if process.env['DEBUG_METRICS'] + console.log("doing inc", key, opts) count : (key, count, sampleRate = 1)-> key = Metrics.buildPromKey(key) @@ -75,6 +76,8 @@ module.exports = Metrics = labelNames: ['app','host'] }) promMetrics[key].inc({app: appname, host: hostname}, count) + if process.env['DEBUG_METRICS'] + console.log("doing count/inc", key, opts) timing: (key, timeSpan, sampleRate, opts = {})-> key = Metrics.sanitizeKey("timer_" + key) @@ -88,6 +91,8 @@ module.exports = Metrics = }) opts.app = appname promMetrics[key].observe(opts, timeSpan) + if process.env['DEBUG_METRICS'] + console.log("doing timing", key, opts) Timer : class constructor :(key, sampleRate = 1, opts)-> @@ -111,7 +116,9 @@ module.exports = Metrics = labelNames: ['app','host'] }) promMetrics[key].set({app: appname, host: hostname}, this.sanitizeValue(value)) - + if process.env['DEBUG_METRICS'] + console.log("doing gauge", key, opts) + globalGauge: (key, value, sampleRate = 1)-> key = Metrics.buildPromKey(key) if !promMetrics[key]? From 85d4b03bcb3bb0f0bd6b53220e4e8bce4a101676 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Tue, 4 Dec 2018 16:29:09 +0000 Subject: [PATCH 100/182] bump to 2.0.6 --- libraries/metrics/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 07805f8f1e..c889b4c116 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "2.0.5", + "version": "2.0.6", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From 93f4a7eeaf05cdf9affc267027bb5c598d6757f9 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Tue, 4 Dec 2018 17:01:30 +0000 Subject: [PATCH 101/182] small cleanup --- libraries/metrics/http.coffee | 2 -- libraries/metrics/metrics.coffee | 2 -- libraries/metrics/timeAsyncMethod.coffee | 6 +++--- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/libraries/metrics/http.coffee b/libraries/metrics/http.coffee index 45f72b7642..f5e3719d53 100644 --- a/libraries/metrics/http.coffee +++ b/libraries/metrics/http.coffee @@ -10,8 +10,6 @@ module.exports.monitor = (logger) -> responseTime = new Date() - startTime if req.route?.path? routePath = req.route.path.toString().replace(/\//g, '_').replace(/\:/g, '').slice(1) - key = "http-requests.#{routePath}.#{req.method}.#{res.statusCode}" - Metrics.timing("http_request", responseTime, null, {method:req.method, status_code: res.statusCode, path:routePath}) logger.log req: diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 77953b275b..c96db21c67 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -11,8 +11,6 @@ hostname = require('os').hostname() buildKey = (key)-> "#{name}.#{hostname}.#{key}" buildGlobalKey = (key)-> "#{name}.global.#{key}" - - promMetrics = {} destructors = [] diff --git a/libraries/metrics/timeAsyncMethod.coffee b/libraries/metrics/timeAsyncMethod.coffee index 73f69cc334..8d6099d826 100644 --- a/libraries/metrics/timeAsyncMethod.coffee +++ b/libraries/metrics/timeAsyncMethod.coffee @@ -25,15 +25,15 @@ module.exports = (obj, methodName, prefix, logger) -> logger.log "[Metrics] expected wrapped method '#{methodName}' to be invoked with a callback" return realMethod.apply this, originalArgs - timer = new metrics.Timer(startPrefix, null, {method: modifedMethodName}) + timer = new metrics.Timer(startPrefix, 1, {method: modifedMethodName}) realMethod.call this, firstArgs..., (callbackArgs...) -> elapsedTime = timer.done() possibleError = callbackArgs[0] if possibleError? - metrics.inc "#{startPrefix}_result", null, {status:"failed", method: modifedMethodName} + metrics.inc "#{startPrefix}_result", 1, {status:"failed", method: modifedMethodName} else - metrics.inc "#{startPrefix}_result", null, {status:"success", method: modifedMethodName} + metrics.inc "#{startPrefix}_result", 1, {status:"success", method: modifedMethodName} if logger? loggableArgs = {} try From b2f49351c0df84917c99220ca29fb02c5524887a Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Wed, 5 Dec 2018 11:03:40 +0000 Subject: [PATCH 102/182] few tidy up changes --- libraries/metrics/metrics.coffee | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index c96db21c67..9f8df741dd 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -41,15 +41,13 @@ module.exports = Metrics = ) buildPromKey: (key = "")-> - Metrics.sanitizeKey key - - sanitizeKey: (key) -> key.replace /[^a-zA-Z0-9]/g, "_" sanitizeValue: (value) -> parseFloat(value) set : (key, value, sampleRate = 1)-> + console.log("counts are not currently supported") inc : (key, sampleRate = 1, opts = {})-> key = Metrics.buildPromKey(key) @@ -78,7 +76,7 @@ module.exports = Metrics = console.log("doing count/inc", key, opts) timing: (key, timeSpan, sampleRate, opts = {})-> - key = Metrics.sanitizeKey("timer_" + key) + key = Metrics.buildPromKey("timer_" + key) if !promMetrics[key]? promMetrics[key] = new prom.Summary({ name: key, @@ -95,7 +93,7 @@ module.exports = Metrics = Timer : class constructor :(key, sampleRate = 1, opts)-> this.start = new Date() - key = Metrics.sanitizeKey(key) + key = Metrics.buildPromKey(key) this.key = key this.sampleRate = sampleRate this.opts = opts From 02071584ae84b06cb8351966e33eb98d03ac585e Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Wed, 5 Dec 2018 12:31:16 +0000 Subject: [PATCH 103/182] bump to 2.0.7 --- libraries/metrics/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index c889b4c116..c56b67ab3d 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "2.0.6", + "version": "2.0.7", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From 7a227adaebb18314c0432c5c742a23d24f86eeee Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Wed, 5 Dec 2018 13:57:53 +0000 Subject: [PATCH 104/182] add if statment around traceagenet and bump to 2.0.8 --- libraries/metrics/metrics.coffee | 5 +++-- libraries/metrics/package.json | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 9f8df741dd..9690225645 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -1,5 +1,5 @@ -traceAgent = require('@google-cloud/trace-agent') debugAgent = require('@google-cloud/debug-agent') +traceAgent = require('@google-cloud/trace-agent') prom = require('prom-client') Register = require('prom-client').register @@ -21,7 +21,8 @@ module.exports = Metrics = initialize: (_name) -> appname = _name collectDefaultMetrics({ timeout: 5000, prefix: Metrics.buildPromKey()}) - traceAgent.start() + if process.env['ENABLE_TRACE_AGENT'] == "true" + traceAgent.start() debugAgent.start({ serviceContext: { allowExpressions: true, diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index c56b67ab3d..0d2f4010d2 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "2.0.7", + "version": "2.0.8", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From 425a6f55ffebe1d7a9844f88ea93fbf85f3e17d1 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Mon, 10 Dec 2018 22:02:25 +0000 Subject: [PATCH 105/182] set build version via env var and bump build version --- libraries/metrics/metrics.coffee | 6 ++++-- libraries/metrics/package.json | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 9690225645..85ab4bb483 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -22,12 +22,14 @@ module.exports = Metrics = appname = _name collectDefaultMetrics({ timeout: 5000, prefix: Metrics.buildPromKey()}) if process.env['ENABLE_TRACE_AGENT'] == "true" - traceAgent.start() + traceOpts = + ignoreUrls: [/^\/status/, /^\/health_check/] + traceAgent.start(traceOpts) debugAgent.start({ serviceContext: { allowExpressions: true, service: appname, - version: '0.0.1' + version: process.env['BUILD_VERSION'] } }) Metrics.inc("process_startup") diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 0d2f4010d2..455a6fc54a 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "2.0.8", + "version": "2.0.9", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From 61e6cf0493c9c1255de1ded15b9b96c4ce3ae816 Mon Sep 17 00:00:00 2001 From: Christopher Hoskin Date: Tue, 11 Dec 2018 12:01:22 +0000 Subject: [PATCH 106/182] Add host label to timing metrics --- libraries/metrics/metrics.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 85ab4bb483..71ee9f617a 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -86,9 +86,10 @@ module.exports = Metrics = help: key, maxAgeSeconds: 600, ageBuckets: 10, - labelNames: ['app', 'path', 'status_code', 'method', 'collection', 'query'] + labelNames: ['app', 'host', 'path', 'status_code', 'method', 'collection', 'query'] }) opts.app = appname + opts.host = hostname promMetrics[key].observe(opts, timeSpan) if process.env['DEBUG_METRICS'] console.log("doing timing", key, opts) From 6f8230982937732cd319d6aaee072678aa844912 Mon Sep 17 00:00:00 2001 From: Christopher Hoskin Date: Tue, 11 Dec 2018 12:52:38 +0000 Subject: [PATCH 107/182] Bump version to 2.0.10 --- libraries/metrics/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 455a6fc54a..3e1491106a 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "2.0.9", + "version": "2.0.10", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From c257482e155ee299daf1dce613ad59a2f985aa47 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Tue, 11 Dec 2018 15:46:29 +0000 Subject: [PATCH 108/182] add ENABLE_DEBUG_AGENT and don't require modules unless they are enabled --- libraries/metrics/metrics.coffee | 22 +++++++++++++--------- libraries/metrics/package.json | 2 +- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 71ee9f617a..150c77676d 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -1,5 +1,3 @@ -debugAgent = require('@google-cloud/debug-agent') -traceAgent = require('@google-cloud/trace-agent') prom = require('prom-client') Register = require('prom-client').register @@ -21,17 +19,23 @@ module.exports = Metrics = initialize: (_name) -> appname = _name collectDefaultMetrics({ timeout: 5000, prefix: Metrics.buildPromKey()}) + if process.env['ENABLE_TRACE_AGENT'] == "true" + traceAgent = require('@google-cloud/trace-agent') + traceOpts = ignoreUrls: [/^\/status/, /^\/health_check/] traceAgent.start(traceOpts) - debugAgent.start({ - serviceContext: { - allowExpressions: true, - service: appname, - version: process.env['BUILD_VERSION'] - } - }) + + if process.env['ENABLE_DEBUG_AGENT'] == "true" + debugAgent = require('@google-cloud/debug-agent') + debugAgent.start({ + serviceContext: { + allowExpressions: true, + service: appname, + version: process.env['BUILD_VERSION'] + } + }) Metrics.inc("process_startup") registerDestructor: (func) -> diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 3e1491106a..bbfcaa7f9d 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "2.0.10", + "version": "2.0.11", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From 9eac49ad84ceda1ef2e02d63a8b0fd43148fb993 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Tue, 11 Dec 2018 16:07:34 +0000 Subject: [PATCH 109/182] add some logging in --- libraries/metrics/metrics.coffee | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 150c77676d..95dad3a44f 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -19,15 +19,19 @@ module.exports = Metrics = initialize: (_name) -> appname = _name collectDefaultMetrics({ timeout: 5000, prefix: Metrics.buildPromKey()}) - + + logger.log("ENABLE_TRACE_AGENT set to #{process.env['ENABLE_TRACE_AGENT']}") if process.env['ENABLE_TRACE_AGENT'] == "true" + logger.log("starting google trace agent") traceAgent = require('@google-cloud/trace-agent') traceOpts = ignoreUrls: [/^\/status/, /^\/health_check/] traceAgent.start(traceOpts) + logger.log("ENABLE_DEBUG_AGENT set to #{process.env['ENABLE_DEBUG_AGENT']}") if process.env['ENABLE_DEBUG_AGENT'] == "true" + logger.log("starting google debug agent") debugAgent = require('@google-cloud/debug-agent') debugAgent.start({ serviceContext: { From a86c4d8abd5d23a2d382832cd84046aa1279eb42 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Wed, 12 Dec 2018 20:11:40 +0000 Subject: [PATCH 110/182] add profiler --- libraries/metrics/metrics.coffee | 13 ++++++++++++- libraries/metrics/package.json | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 95dad3a44f..17e85a5202 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -34,8 +34,19 @@ module.exports = Metrics = logger.log("starting google debug agent") debugAgent = require('@google-cloud/debug-agent') debugAgent.start({ + allowExpressions: true, + serviceContext: { + service: appname, + version: process.env['BUILD_VERSION'] + } + }) + + logger.log("ENABLE_PROFILER_AGENT set to #{process.env['ENABLE_PROFILER_AGENT']}") + if process.env['ENABLE_PROFILER_AGENT'] == "true" + logger.log("starting google profile agent") + profiler = require('@google-cloud/profiler') + profiler.start({ serviceContext: { - allowExpressions: true, service: appname, version: process.env['BUILD_VERSION'] } diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index bbfcaa7f9d..7e827f9e7e 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -12,6 +12,7 @@ "prom-client": "^11.1.3", "underscore": "~1.6.0", "@google-cloud/debug-agent": "^3.0.0", + "@google-cloud/profiler": "0.2.3", "@google-cloud/trace-agent": "^3.2.0" }, "devDependencies": { From db4ae84bda70323bcc5f12d151aaa1c7a7360ef4 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Wed, 12 Dec 2018 21:05:33 +0000 Subject: [PATCH 111/182] require logger --- libraries/metrics/metrics.coffee | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 17e85a5202..fc528b875d 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -1,4 +1,3 @@ - prom = require('prom-client') Register = require('prom-client').register collectDefaultMetrics = prom.collectDefaultMetrics @@ -19,6 +18,8 @@ module.exports = Metrics = initialize: (_name) -> appname = _name collectDefaultMetrics({ timeout: 5000, prefix: Metrics.buildPromKey()}) + + logger = require("logger-sharelatex") logger.log("ENABLE_TRACE_AGENT set to #{process.env['ENABLE_TRACE_AGENT']}") if process.env['ENABLE_TRACE_AGENT'] == "true" @@ -51,6 +52,7 @@ module.exports = Metrics = version: process.env['BUILD_VERSION'] } }) + Metrics.inc("process_startup") registerDestructor: (func) -> From 287effb13977599f74385d2b06ab23dc3e686064 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Wed, 12 Dec 2018 21:17:12 +0000 Subject: [PATCH 112/182] use ENABLE_PROFILE_AGENT --- libraries/metrics/metrics.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index fc528b875d..963c471294 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -18,7 +18,7 @@ module.exports = Metrics = initialize: (_name) -> appname = _name collectDefaultMetrics({ timeout: 5000, prefix: Metrics.buildPromKey()}) - + logger = require("logger-sharelatex") logger.log("ENABLE_TRACE_AGENT set to #{process.env['ENABLE_TRACE_AGENT']}") @@ -42,8 +42,8 @@ module.exports = Metrics = } }) - logger.log("ENABLE_PROFILER_AGENT set to #{process.env['ENABLE_PROFILER_AGENT']}") - if process.env['ENABLE_PROFILER_AGENT'] == "true" + logger.log("ENABLE_PROFILE_AGENT set to #{process.env['ENABLE_PROFILE_AGENT']}") + if process.env['ENABLE_PROFILE_AGENT'] == "true" logger.log("starting google profile agent") profiler = require('@google-cloud/profiler') profiler.start({ From 1a34f3db1be5a949e6baa985f44dd18a7eacd321 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Thu, 13 Dec 2018 08:46:58 +0000 Subject: [PATCH 113/182] Update package.json --- libraries/metrics/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 7e827f9e7e..2add09396c 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "2.0.11", + "version": "2.0.12", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From dfead32d6902d2ca95843aeba8ca719694609a02 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Thu, 13 Dec 2018 09:19:05 +0000 Subject: [PATCH 114/182] Update package.json --- libraries/metrics/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 2add09396c..5d9d068ba1 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -12,7 +12,7 @@ "prom-client": "^11.1.3", "underscore": "~1.6.0", "@google-cloud/debug-agent": "^3.0.0", - "@google-cloud/profiler": "0.2.3", + "@google-cloud/profiler": "^0.2.3", "@google-cloud/trace-agent": "^3.2.0" }, "devDependencies": { From 93bef54c39ea9fa61d0958550f286a762fbce19b Mon Sep 17 00:00:00 2001 From: Christopher Hoskin Date: Tue, 15 Jan 2019 15:36:35 +0000 Subject: [PATCH 115/182] Make register public so we can support other servers e.g. hapi --- libraries/metrics/metrics.coffee | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 963c471294..1ecba6eb5f 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -1,5 +1,5 @@ prom = require('prom-client') -Register = require('prom-client').register + collectDefaultMetrics = prom.collectDefaultMetrics appname = "unknown" @@ -15,6 +15,7 @@ destructors = [] require "./uv_threadpool_size" module.exports = Metrics = + register: require('prom-client').register initialize: (_name) -> appname = _name collectDefaultMetrics({ timeout: 5000, prefix: Metrics.buildPromKey()}) @@ -60,8 +61,8 @@ module.exports = Metrics = injectMetricsRoute: (app) -> app.get('/metrics', (req, res) -> - res.set('Content-Type', Register.contentType) - res.end(Register.metrics()) + res.set('Content-Type', register.contentType) + res.end(register.metrics()) ) buildPromKey: (key = "")-> From d4caa48118f278a291fa35d7b5948e78f8b82baa Mon Sep 17 00:00:00 2001 From: Christopher Hoskin Date: Tue, 15 Jan 2019 15:44:01 +0000 Subject: [PATCH 116/182] Bump package version --- libraries/metrics/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 5d9d068ba1..f9d374c00f 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "2.0.12", + "version": "2.0.13", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From 20e45b7a2e0710ba5228f2b191feaa7c275165fd Mon Sep 17 00:00:00 2001 From: Christopher Hoskin Date: Tue, 15 Jan 2019 16:12:15 +0000 Subject: [PATCH 117/182] Fix Register --- libraries/metrics/metrics.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 1ecba6eb5f..ed8dff5d93 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -1,4 +1,5 @@ prom = require('prom-client') +Register = require('prom-client').register collectDefaultMetrics = prom.collectDefaultMetrics @@ -15,7 +16,7 @@ destructors = [] require "./uv_threadpool_size" module.exports = Metrics = - register: require('prom-client').register + register:Register initialize: (_name) -> appname = _name collectDefaultMetrics({ timeout: 5000, prefix: Metrics.buildPromKey()}) From 02907fd2e7c6022479628e34857a3f28bead04cb Mon Sep 17 00:00:00 2001 From: Christopher Hoskin Date: Tue, 15 Jan 2019 16:16:12 +0000 Subject: [PATCH 118/182] Fix Register II --- libraries/metrics/metrics.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index ed8dff5d93..e1f46a46b2 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -62,8 +62,8 @@ module.exports = Metrics = injectMetricsRoute: (app) -> app.get('/metrics', (req, res) -> - res.set('Content-Type', register.contentType) - res.end(register.metrics()) + res.set('Content-Type', Register.contentType) + res.end(Register.metrics()) ) buildPromKey: (key = "")-> From 85011ed0e7724c2730f27c82bffa1935ddb14e9a Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Mon, 28 Jan 2019 14:37:54 +0000 Subject: [PATCH 119/182] add path into inc options --- libraries/metrics/metrics.coffee | 2 +- libraries/metrics/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index e1f46a46b2..c322f2efd9 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -81,7 +81,7 @@ module.exports = Metrics = promMetrics[key] = new prom.Counter({ name: key, help: key, - labelNames: ['app','host','status','method'] + labelNames: ['app','host','status','method', 'path'] }) opts.app = appname opts.host = hostname diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index f9d374c00f..002a92fc06 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "2.0.13", + "version": "2.0.14", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From bf18c6e513fdfeb56d7a5a7e9592aa2a8ff68cf7 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Wed, 30 Jan 2019 10:29:12 +0000 Subject: [PATCH 120/182] MVP for running both statsd and prom side by side statsd code is from v1.8.1 --- libraries/metrics/metrics.coffee | 6 ++ libraries/metrics/package.json | 2 +- libraries/metrics/statsd/event_loop.coffee | 18 ++++ libraries/metrics/statsd/http.coffee | 31 ++++++ libraries/metrics/statsd/memory.coffee | 85 +++++++++++++++ libraries/metrics/statsd/metrics.coffee | 62 +++++++++++ libraries/metrics/statsd/mongodb.coffee | 100 ++++++++++++++++++ libraries/metrics/statsd/open_sockets.coffee | 28 +++++ .../metrics/statsd/timeAsyncMethod.coffee | 36 +++++++ .../metrics/statsd/uv_threadpool_size.coffee | 2 + 10 files changed, 369 insertions(+), 1 deletion(-) create mode 100644 libraries/metrics/statsd/event_loop.coffee create mode 100644 libraries/metrics/statsd/http.coffee create mode 100644 libraries/metrics/statsd/memory.coffee create mode 100644 libraries/metrics/statsd/metrics.coffee create mode 100644 libraries/metrics/statsd/mongodb.coffee create mode 100644 libraries/metrics/statsd/open_sockets.coffee create mode 100644 libraries/metrics/statsd/timeAsyncMethod.coffee create mode 100644 libraries/metrics/statsd/uv_threadpool_size.coffee diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index c322f2efd9..94313d3aec 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -1,3 +1,9 @@ +if process.env["USE_PROM_METRICS"] != "true" + return module.exports = require("./statsd/metrics") +else + console.log("using prometheus") + + prom = require('prom-client') Register = require('prom-client').register diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 002a92fc06..97f6a3ab9d 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "2.0.14", + "version": "2.1.0", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", diff --git a/libraries/metrics/statsd/event_loop.coffee b/libraries/metrics/statsd/event_loop.coffee new file mode 100644 index 0000000000..01e37b96a1 --- /dev/null +++ b/libraries/metrics/statsd/event_loop.coffee @@ -0,0 +1,18 @@ +module.exports = EventLoopMonitor = + monitor: (logger, interval = 1000, log_threshold = 100) -> + Metrics = require "./metrics" + # check for logger on startup to avoid exceptions later if undefined + throw new Error("logger is undefined") if !logger? + # monitor delay in setInterval to detect event loop blocking + previous = Date.now() + intervalId = setInterval () -> + now = Date.now() + offset = now - previous - interval + if offset > log_threshold + logger.warn {offset: offset}, "slow event loop" + previous = now + Metrics.timing("event-loop-millsec", offset) + , interval + + Metrics.registerDestructor () -> + clearInterval(intervalId) diff --git a/libraries/metrics/statsd/http.coffee b/libraries/metrics/statsd/http.coffee new file mode 100644 index 0000000000..c175f26a14 --- /dev/null +++ b/libraries/metrics/statsd/http.coffee @@ -0,0 +1,31 @@ +os = require("os") + +module.exports.monitor = (logger) -> + return (req, res, next) -> + Metrics = require("./metrics") + startTime = new Date() + end = res.end + res.end = () -> + end.apply(this, arguments) + responseTime = new Date() - startTime + if req.route?.path? + routePath = req.route.path.toString().replace(/\//g, '_').replace(/\:/g, '').slice(1) + key = "http-requests.#{routePath}.#{req.method}.#{res.statusCode}" + + Metrics.timing(key, responseTime) + logger.log + req: + url: req.originalUrl || req.url + method: req.method + referrer: req.headers['referer'] || req.headers['referrer'] + "remote-addr": req.ip || req.socket?.socket?.remoteAddress || req.socket?.remoteAddress + "user-agent": req.headers["user-agent"] + "content-length": req.headers["content-length"] + res: + "content-length": res._headers?["content-length"] + statusCode: res.statusCode + "response-time": responseTime + "http request" + + next() + diff --git a/libraries/metrics/statsd/memory.coffee b/libraries/metrics/statsd/memory.coffee new file mode 100644 index 0000000000..a1e157a5bf --- /dev/null +++ b/libraries/metrics/statsd/memory.coffee @@ -0,0 +1,85 @@ +# record memory usage each minute and run a periodic gc(), keeping cpu +# usage within allowable range of 1ms per minute. Also, dynamically +# adjust the period between gc()'s to reach a target of the gc saving +# 4 megabytes each time. + +oneMinute = 60 * 1000 +oneMegaByte = 1024 * 1024 + +CpuTimeBucket = 100 # current cpu time allowance in milliseconds +CpuTimeBucketMax = 100 # maximum amount of cpu time allowed in bucket +CpuTimeBucketRate = 10 # add this many milliseconds per minute + +gcInterval = 1 # how many minutes between gc (parameter is dynamically adjusted) +countSinceLastGc = 0 # how many minutes since last gc +MemoryChunkSize = 4 # how many megabytes we need to free to consider gc worth doing + +readyToGc = () -> + # update allowed cpu time + CpuTimeBucket = CpuTimeBucket + CpuTimeBucketRate + CpuTimeBucket = if CpuTimeBucket < CpuTimeBucketMax then CpuTimeBucket else CpuTimeBucketMax + # update counts since last gc + countSinceLastGc = countSinceLastGc + 1 + # check there is enough time since last gc and we have enough cpu + return (countSinceLastGc > gcInterval) && (CpuTimeBucket > 0) + +executeAndTime = (fn) -> + # time the execution of fn() and subtract from cpu allowance + t0 = process.hrtime() + fn() + dt = process.hrtime(t0) + timeTaken = (dt[0] + dt[1]*1e-9) * 1e3 # in milliseconds + CpuTimeBucket -= Math.ceil timeTaken + return timeTaken + +inMegaBytes = (obj) -> + # convert process.memoryUsage hash {rss,heapTotal,heapFreed} into megabytes + result = {} + for k, v of obj + result[k] = (v / oneMegaByte).toFixed(2) + return result + +updateMemoryStats = (oldMem, newMem) -> + countSinceLastGc = 0 + delta = {} + for k of newMem + delta[k] = (newMem[k] - oldMem[k]).toFixed(2) + # take the max of all memory measures + savedMemory = Math.max -delta.rss, -delta.heapTotal, -delta.heapUsed + delta.megabytesFreed = savedMemory + # did it do any good? + if savedMemory < MemoryChunkSize + gcInterval = gcInterval + 1 # no, so wait longer next time + else + gcInterval = Math.max gcInterval - 1, 1 # yes, wait less time + return delta + +module.exports = MemoryMonitor = + monitor: (logger) -> + interval = setInterval () -> + MemoryMonitor.Check(logger) + , oneMinute + Metrics = require "./metrics" + Metrics.registerDestructor () -> + clearInterval(interval) + + Check: (logger) -> + Metrics = require "./metrics" + memBeforeGc = mem = inMegaBytes process.memoryUsage() + Metrics.gauge("memory.rss", mem.rss) + Metrics.gauge("memory.heaptotal", mem.heapTotal) + Metrics.gauge("memory.heapused", mem.heapUsed) + Metrics.gauge("memory.gc-interval", gcInterval) + #Metrics.gauge("memory.cpu-time-bucket", CpuTimeBucket) + + logger.log mem, "process.memoryUsage()" + + if global.gc? && readyToGc() + gcTime = (executeAndTime global.gc).toFixed(2) + memAfterGc = inMegaBytes process.memoryUsage() + deltaMem = updateMemoryStats(memBeforeGc, memAfterGc) + logger.log {gcTime, memBeforeGc, memAfterGc, deltaMem, gcInterval, CpuTimeBucket}, "global.gc() forced" + #Metrics.timing("memory.gc-time", gcTime) + Metrics.gauge("memory.gc-rss-freed", -deltaMem.rss) + Metrics.gauge("memory.gc-heaptotal-freed", -deltaMem.heapTotal) + Metrics.gauge("memory.gc-heapused-freed", -deltaMem.heapUsed) diff --git a/libraries/metrics/statsd/metrics.coffee b/libraries/metrics/statsd/metrics.coffee new file mode 100644 index 0000000000..e632ebc565 --- /dev/null +++ b/libraries/metrics/statsd/metrics.coffee @@ -0,0 +1,62 @@ +console.log("using statsd") + +StatsD = require('lynx') +statsd = new StatsD(process.env["STATSD_HOST"] or "localhost", 8125, {on_error:->}) + +name = "unknown" +hostname = require('os').hostname() + +buildKey = (key)-> "#{name}.#{hostname}.#{key}" +buildGlobalKey = (key)-> "#{name}.global.#{key}" + +destructors = [] + +require "./uv_threadpool_size" + +module.exports = Metrics = + initialize: (_name) -> + name = _name + + registerDestructor: (func) -> + destructors.push func + + set : (key, value, sampleRate = 1)-> + statsd.set buildKey(key), value, sampleRate + + inc : (key, sampleRate = 1)-> + statsd.increment buildKey(key), sampleRate + + count : (key, count, sampleRate = 1)-> + statsd.count buildKey(key), count, sampleRate + + timing: (key, timeSpan, sampleRate)-> + statsd.timing(buildKey(key), timeSpan, sampleRate) + + Timer : class + constructor :(key, sampleRate = 1)-> + this.start = new Date() + this.key = key + this.sampleRate = sampleRate + done:-> + timeSpan = new Date - this.start + statsd.timing(buildKey(this.key), timeSpan, this.sampleRate) + return timeSpan + + gauge : (key, value, sampleRate = 1)-> + statsd.gauge buildKey(key), value, sampleRate + + globalGauge: (key, value, sampleRate = 1)-> + statsd.gauge buildGlobalKey(key), value, sampleRate + + mongodb: require "./mongodb" + http: require "./http" + open_sockets: require "./open_sockets" + event_loop: require "./event_loop" + memory: require "./memory" + + timeAsyncMethod: require('./timeAsyncMethod') + + close: () -> + for func in destructors + func() + statsd.close() diff --git a/libraries/metrics/statsd/mongodb.coffee b/libraries/metrics/statsd/mongodb.coffee new file mode 100644 index 0000000000..ce1ca71385 --- /dev/null +++ b/libraries/metrics/statsd/mongodb.coffee @@ -0,0 +1,100 @@ +module.exports = + monitor: (mongodb_require_path, logger) -> + + try + # for the v1 driver the methods to wrap are in the mongodb + # module in lib/mongodb/db.js + mongodb = require("#{mongodb_require_path}") + + try + # for the v2 driver the relevant methods are in the mongodb-core + # module in lib/topologies/{server,replset,mongos}.js + v2_path = mongodb_require_path.replace(/\/mongodb$/, '/mongodb-core') + mongodbCore = require(v2_path) + + Metrics = require("./metrics") + + monitorMethod = (base, method, type) -> + return unless base? + return unless (_method = base[method])? + arglen = _method.length + + mongo_driver_v1_wrapper = (db_command, options, callback) -> + if (typeof callback == 'undefined') + callback = options + options = {} + + collection = db_command.collectionName + if collection.match(/\$cmd$/) + # Ignore noisy command methods like authenticating, ismaster and ping + return _method.call this, db_command, options, callback + + key = "mongo-requests.#{collection}.#{type}" + if db_command.query? + query = Object.keys(db_command.query).sort().join("_") + key += "." + query + + timer = new Metrics.Timer(key) + start = new Date() + _method.call this, db_command, options, () -> + timer.done() + time = new Date() - start + logger.log + query: db_command.query + query_type: type + collection: collection + "response-time": new Date() - start + "mongo request" + callback.apply this, arguments + + mongo_driver_v2_wrapper = (ns, ops, options, callback) -> + if (typeof callback == 'undefined') + callback = options + options = {} + + if ns.match(/\$cmd$/) + # Ignore noisy command methods like authenticating, ismaster and ping + return _method.call this, ns, ops, options, callback + + key = "mongo-requests.#{ns}.#{type}" + if ops[0].q? # ops[0].q + query = Object.keys(ops[0].q).sort().join("_") + key += "." + query + + timer = new Metrics.Timer(key) + start = new Date() + _method.call this, ns, ops, options, () -> + timer.done() + time = new Date() - start + logger.log + query: ops[0].q + query_type: type + collection: ns + "response-time": new Date() - start + "mongo request" + callback.apply this, arguments + + if arglen == 3 + base[method] = mongo_driver_v1_wrapper + else if arglen == 4 + base[method] = mongo_driver_v2_wrapper + + monitorMethod(mongodb?.Db.prototype, "_executeQueryCommand", "query") + monitorMethod(mongodb?.Db.prototype, "_executeRemoveCommand", "remove") + monitorMethod(mongodb?.Db.prototype, "_executeInsertCommand", "insert") + monitorMethod(mongodb?.Db.prototype, "_executeUpdateCommand", "update") + + monitorMethod(mongodbCore?.Server.prototype, "command", "command") + monitorMethod(mongodbCore?.Server.prototype, "remove", "remove") + monitorMethod(mongodbCore?.Server.prototype, "insert", "insert") + monitorMethod(mongodbCore?.Server.prototype, "update", "update") + + monitorMethod(mongodbCore?.ReplSet.prototype, "command", "command") + monitorMethod(mongodbCore?.ReplSet.prototype, "remove", "remove") + monitorMethod(mongodbCore?.ReplSet.prototype, "insert", "insert") + monitorMethod(mongodbCore?.ReplSet.prototype, "update", "update") + + monitorMethod(mongodbCore?.Mongos.prototype, "command", "command") + monitorMethod(mongodbCore?.Mongos.prototype, "remove", "remove") + monitorMethod(mongodbCore?.Mongos.prototype, "insert", "insert") + monitorMethod(mongodbCore?.Mongos.prototype, "update", "update") diff --git a/libraries/metrics/statsd/open_sockets.coffee b/libraries/metrics/statsd/open_sockets.coffee new file mode 100644 index 0000000000..9af019dfc8 --- /dev/null +++ b/libraries/metrics/statsd/open_sockets.coffee @@ -0,0 +1,28 @@ +URL = require "url" +seconds = 1000 + +# In Node 0.10 the default is 5, which means only 5 open connections at one. +# Node 0.12 has a default of Infinity. Make sure we have no limit set, +# regardless of Node version. +require("http").globalAgent.maxSockets = Infinity +require("https").globalAgent.maxSockets = Infinity + +module.exports = OpenSocketsMonitor = + monitor: (logger) -> + interval = setInterval () -> + OpenSocketsMonitor.gaugeOpenSockets() + , 5 * seconds + Metrics = require "./metrics" + Metrics.registerDestructor () -> + clearInterval(interval) + + gaugeOpenSockets: () -> + Metrics = require "./metrics" + for url, agents of require('http').globalAgent.sockets + url = URL.parse("http://#{url}") + hostname = url.hostname?.replace(/\./g, "_") + Metrics.gauge "open_connections.http.#{hostname}", agents.length + for url, agents of require('https').globalAgent.sockets + url = URL.parse("https://#{url}") + hostname = url.hostname?.replace(/\./g, "_") + Metrics.gauge "open_connections.https.#{hostname}", agents.length diff --git a/libraries/metrics/statsd/timeAsyncMethod.coffee b/libraries/metrics/statsd/timeAsyncMethod.coffee new file mode 100644 index 0000000000..27e21e6e09 --- /dev/null +++ b/libraries/metrics/statsd/timeAsyncMethod.coffee @@ -0,0 +1,36 @@ + +module.exports = (obj, methodName, prefix, logger) -> + metrics = require('./metrics') + + if typeof obj[methodName] != 'function' + throw new Error("[Metrics] expected object property '#{methodName}' to be a function") + + realMethod = obj[methodName] + key = "#{prefix}.#{methodName}" + + obj[methodName] = (originalArgs...) -> + + [firstArgs..., callback] = originalArgs + + if !callback? || typeof callback != 'function' + if logger? + logger.log "[Metrics] expected wrapped method '#{methodName}' to be invoked with a callback" + return realMethod.apply this, originalArgs + + timer = new metrics.Timer(key) + + realMethod.call this, firstArgs..., (callbackArgs...) -> + elapsedTime = timer.done() + possibleError = callbackArgs[0] + if possibleError? + metrics.inc "#{key}.failure" + else + metrics.inc "#{key}.success" + if logger? + loggableArgs = {} + try + for arg, idx in firstArgs + if arg.toString().match(/^[0-9a-f]{24}$/) + loggableArgs["#{idx}"] = arg + logger.log {key, args: loggableArgs, elapsedTime}, "[Metrics] timed async method call" + callback.apply this, callbackArgs diff --git a/libraries/metrics/statsd/uv_threadpool_size.coffee b/libraries/metrics/statsd/uv_threadpool_size.coffee new file mode 100644 index 0000000000..c0947fee31 --- /dev/null +++ b/libraries/metrics/statsd/uv_threadpool_size.coffee @@ -0,0 +1,2 @@ +process.env.UV_THREADPOOL_SIZE=16 +console.log "Set UV_THREADPOOL_SIZE=#{process.env.UV_THREADPOOL_SIZE}" From 15d14d8e2b95fab19d2c5161f176a7ce907b2ba7 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Thu, 7 Feb 2019 09:47:29 +0000 Subject: [PATCH 121/182] add injectMetricsRoute into statsd so it doens't blow up --- libraries/metrics/package.json | 2 +- libraries/metrics/statsd/metrics.coffee | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 97f6a3ab9d..b103976caf 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "2.1.0", + "version": "2.1.1", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", diff --git a/libraries/metrics/statsd/metrics.coffee b/libraries/metrics/statsd/metrics.coffee index e632ebc565..8e3be8c26c 100644 --- a/libraries/metrics/statsd/metrics.coffee +++ b/libraries/metrics/statsd/metrics.coffee @@ -56,6 +56,11 @@ module.exports = Metrics = timeAsyncMethod: require('./timeAsyncMethod') + injectMetricsRoute: (app) -> + app.get('/metrics', (req, res) -> + res.send("not implemented in statsd") + ) + close: () -> for func in destructors func() From d4faaaa60eeaaa50c5f1ca530c404ae7415a4e38 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Fri, 12 Apr 2019 12:34:17 +0100 Subject: [PATCH 122/182] use console.log not logger.log we don't habe verbiouse lossing enabled that early in the apps lifecycle also best not to require modules before enabling profiler --- libraries/metrics/metrics.coffee | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 94313d3aec..5a99df90ca 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -27,20 +27,19 @@ module.exports = Metrics = appname = _name collectDefaultMetrics({ timeout: 5000, prefix: Metrics.buildPromKey()}) - logger = require("logger-sharelatex") - logger.log("ENABLE_TRACE_AGENT set to #{process.env['ENABLE_TRACE_AGENT']}") + console.log("ENABLE_TRACE_AGENT set to #{process.env['ENABLE_TRACE_AGENT']}") if process.env['ENABLE_TRACE_AGENT'] == "true" - logger.log("starting google trace agent") + console.log("starting google trace agent") traceAgent = require('@google-cloud/trace-agent') traceOpts = ignoreUrls: [/^\/status/, /^\/health_check/] traceAgent.start(traceOpts) - logger.log("ENABLE_DEBUG_AGENT set to #{process.env['ENABLE_DEBUG_AGENT']}") + console.log("ENABLE_DEBUG_AGENT set to #{process.env['ENABLE_DEBUG_AGENT']}") if process.env['ENABLE_DEBUG_AGENT'] == "true" - logger.log("starting google debug agent") + console.log("starting google debug agent") debugAgent = require('@google-cloud/debug-agent') debugAgent.start({ allowExpressions: true, @@ -50,9 +49,9 @@ module.exports = Metrics = } }) - logger.log("ENABLE_PROFILE_AGENT set to #{process.env['ENABLE_PROFILE_AGENT']}") + console.log("ENABLE_PROFILE_AGENT set to #{process.env['ENABLE_PROFILE_AGENT']}") if process.env['ENABLE_PROFILE_AGENT'] == "true" - logger.log("starting google profile agent") + console.log("starting google profile agent") profiler = require('@google-cloud/profiler') profiler.start({ serviceContext: { From 816c49daf2c0ae13b6671a05378d48c324229534 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Fri, 12 Apr 2019 12:36:47 +0100 Subject: [PATCH 123/182] bump metrics to 2.1.2 --- libraries/metrics/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index b103976caf..8f8f928993 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "2.1.1", + "version": "2.1.2", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From 286eb747ad658582f91ff60fb1e404955512abc5 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Wed, 5 Jun 2019 16:38:25 +0100 Subject: [PATCH 124/182] add status label to gauges --- libraries/metrics/metrics.coffee | 12 ++++++------ libraries/metrics/package.json | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 5a99df90ca..0f65c7b1ea 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -135,27 +135,27 @@ module.exports = Metrics = Metrics.timing(this.key, timeSpan, this.sampleRate, this.opts) return timeSpan - gauge : (key, value, sampleRate = 1)-> + gauge : (key, value, sampleRate = 1, opts)-> key = Metrics.buildPromKey(key) if !promMetrics[key]? promMetrics[key] = new prom.Gauge({ name: key, help: key, - labelNames: ['app','host'] + labelNames: ['app','host', 'status'] }) - promMetrics[key].set({app: appname, host: hostname}, this.sanitizeValue(value)) + promMetrics[key].set({app: appname, host: hostname, status: opts?.status}, this.sanitizeValue(value)) if process.env['DEBUG_METRICS'] console.log("doing gauge", key, opts) - globalGauge: (key, value, sampleRate = 1)-> + globalGauge: (key, value, sampleRate = 1, opts)-> key = Metrics.buildPromKey(key) if !promMetrics[key]? promMetrics[key] = new prom.Gauge({ name: key, help: key, - labelNames: ['app','host'] + labelNames: ['app','host', 'status'] }) - promMetrics[key].set({app: appname},this.sanitizeValue(value)) + promMetrics[key].set({app: appname, status: opts?.status},this.sanitizeValue(value)) mongodb: require "./mongodb" http: require "./http" diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 8f8f928993..24daa5da46 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "2.1.2", + "version": "2.2.0", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From 07e4eb4dfb9b044a58aff277ca97cd5c5d65c201 Mon Sep 17 00:00:00 2001 From: Simon Detheridge Date: Wed, 23 Oct 2019 17:07:23 +0100 Subject: [PATCH 125/182] Add mechanism to expire old prometheus metrics Adds a wrapper around the prometheus client, which keeps track of the last time a metrics was accessed, and removes old ones once they have not been accessed for a period of time. --- libraries/metrics/metrics.coffee | 63 +++----------- libraries/metrics/package.json | 2 +- libraries/metrics/prom_wrapper.coffee | 114 ++++++++++++++++++++++++++ 3 files changed, 128 insertions(+), 51 deletions(-) create mode 100644 libraries/metrics/prom_wrapper.coffee diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 0f65c7b1ea..03e492be8e 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -3,30 +3,25 @@ if process.env["USE_PROM_METRICS"] != "true" else console.log("using prometheus") - -prom = require('prom-client') -Register = require('prom-client').register +prom = require('./prom_wrapper') collectDefaultMetrics = prom.collectDefaultMetrics appname = "unknown" hostname = require('os').hostname() -buildKey = (key)-> "#{name}.#{hostname}.#{key}" -buildGlobalKey = (key)-> "#{name}.global.#{key}" - -promMetrics = {} - destructors = [] require "./uv_threadpool_size" module.exports = Metrics = - register:Register - initialize: (_name) -> + register: prom.registry + + initialize: (_name, opts = {}) -> appname = _name collectDefaultMetrics({ timeout: 5000, prefix: Metrics.buildPromKey()}) - + if opts.ttlInMinutes + prom.ttlInMinutes = opts.ttlInMinutes console.log("ENABLE_TRACE_AGENT set to #{process.env['ENABLE_TRACE_AGENT']}") if process.env['ENABLE_TRACE_AGENT'] == "true" @@ -67,8 +62,8 @@ module.exports = Metrics = injectMetricsRoute: (app) -> app.get('/metrics', (req, res) -> - res.set('Content-Type', Register.contentType) - res.end(Register.metrics()) + res.set('Content-Type', prom.registry.contentType) + res.end(prom.registry.metrics()) ) buildPromKey: (key = "")-> @@ -82,43 +77,23 @@ module.exports = Metrics = inc : (key, sampleRate = 1, opts = {})-> key = Metrics.buildPromKey(key) - if !promMetrics[key]? - promMetrics[key] = new prom.Counter({ - name: key, - help: key, - labelNames: ['app','host','status','method', 'path'] - }) opts.app = appname opts.host = hostname - promMetrics[key].inc(opts) + prom.metric('counter', key).inc(opts) if process.env['DEBUG_METRICS'] console.log("doing inc", key, opts) count : (key, count, sampleRate = 1)-> key = Metrics.buildPromKey(key) - if !promMetrics[key]? - promMetrics[key] = new prom.Counter({ - name: key, - help: key, - labelNames: ['app','host'] - }) - promMetrics[key].inc({app: appname, host: hostname}, count) + prom.metric('counter', key).inc({app: appname, host: hostname}, count) if process.env['DEBUG_METRICS'] console.log("doing count/inc", key, opts) timing: (key, timeSpan, sampleRate, opts = {})-> key = Metrics.buildPromKey("timer_" + key) - if !promMetrics[key]? - promMetrics[key] = new prom.Summary({ - name: key, - help: key, - maxAgeSeconds: 600, - ageBuckets: 10, - labelNames: ['app', 'host', 'path', 'status_code', 'method', 'collection', 'query'] - }) opts.app = appname opts.host = hostname - promMetrics[key].observe(opts, timeSpan) + prom.metric('summary', key).observe(opts, timeSpan) if process.env['DEBUG_METRICS'] console.log("doing timing", key, opts) @@ -137,25 +112,13 @@ module.exports = Metrics = gauge : (key, value, sampleRate = 1, opts)-> key = Metrics.buildPromKey(key) - if !promMetrics[key]? - promMetrics[key] = new prom.Gauge({ - name: key, - help: key, - labelNames: ['app','host', 'status'] - }) - promMetrics[key].set({app: appname, host: hostname, status: opts?.status}, this.sanitizeValue(value)) + prom.metric('gague', key).set({app: appname, host: hostname, status: opts?.status}, this.sanitizeValue(value)) if process.env['DEBUG_METRICS'] console.log("doing gauge", key, opts) globalGauge: (key, value, sampleRate = 1, opts)-> key = Metrics.buildPromKey(key) - if !promMetrics[key]? - promMetrics[key] = new prom.Gauge({ - name: key, - help: key, - labelNames: ['app','host', 'status'] - }) - promMetrics[key].set({app: appname, status: opts?.status},this.sanitizeValue(value)) + prom.metric('gague', key).set({app: appname, status: opts?.status},this.sanitizeValue(value)) mongodb: require "./mongodb" http: require "./http" diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 24daa5da46..86f2e39a9e 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "2.2.0", + "version": "2.3.0", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", diff --git a/libraries/metrics/prom_wrapper.coffee b/libraries/metrics/prom_wrapper.coffee new file mode 100644 index 0000000000..eb2c132314 --- /dev/null +++ b/libraries/metrics/prom_wrapper.coffee @@ -0,0 +1,114 @@ +prom = require('prom-client') +registry = require('prom-client').register +metrics = {} + + +optsKey = (opts) -> + keys = Object.keys(opts) + return '' if keys.length == 0 + + keys = keys.sort() + + hash = ''; + for key in keys + hash += "," if hash.length + hash += "#{key}:#{opts[key]}" + + return hash + +extendOpts = (opts, labelNames) -> + for label in labelNames + opts[label] ||= '' + return opts + +optsAsArgs = (opts, labelNames) -> + args = [] + for label in labelNames + args.push(opts[label] || '') + return args + + +PromWrapper = + ttlInMinutes: 0 + registry: registry + + metric: (type, name) -> + registry.getSingleMetric(name) || new MetricWrapper(type, name) + + collectDefaultMetrics: prom.collectDefaultMetrics + + +class MetricWrapper + constructor: (type, name) -> + metrics[name] = this + @name = name + @instances = {} + @lastAccess = new Date() + @metric = switch type + when "counter" + new prom.Counter({ + name: name, + help: name, + labelNames: ['app','host','status','method', 'path'] + }) + when "summary" + new prom.Summary({ + name: name, + help: name, + maxAgeSeconds: 600, + ageBuckets: 10, + labelNames: ['app', 'host', 'path', 'status_code', 'method', 'collection', 'query'] + }) + when "gauge" + prom.Gauge({ + name: name, + help: name, + labelNames: ['app','host', 'status'] + }) + + inc: (opts, value) -> + @_execMethod 'inc', opts, value + + observe: (opts, value) -> + @_execMethod 'observe', opts, value + + set: (opts, value) -> + @_execMethod 'set', opts, value + + sweep: () -> + thresh = new Date(Date.now() - 1000 * 60 * PromWrapper.ttlInMinutes) + for key in Object.keys(@instances) + if thresh > @instances[key].time + if process.env['DEBUG_METRICS'] + console.log("Sweeping stale metric instance", @name, opts: @instances[key].opts, key) + @metric.remove(optsAsArgs(@instances[key].opts, @metric.labelNames)...) + + if thresh > @lastAccess + if process.env['DEBUG_METRICS'] + console.log("Sweeping stale metric", @name) + delete metrics[@name] + registry.removeSingleMetric(@name) + + _execMethod: (method, opts, value) -> + opts = extendOpts(opts, @metric.labelNames) + key = optsKey(opts) + @instances[key] = { time: new Date(), opts } unless key == '' + @lastAccess = new Date() + @metric[method](opts, value) + + +unless PromWrapper.sweepRegistered + if process.env['DEBUG_METRICS'] + console.log("Registering sweep method") + PromWrapper.sweepRegistered = true + setInterval( + () -> + if PromWrapper.ttlInMinutes + if process.env['DEBUG_METRICS'] + console.log("Sweeping metrics") + for key in Object.keys(metrics) + metrics[key].sweep() + 60000) + + +module.exports = PromWrapper From 166211b27846a96ad6c764d28c4df19aaf18e322 Mon Sep 17 00:00:00 2001 From: Eric Mc Sween Date: Thu, 24 Oct 2019 22:02:55 -0400 Subject: [PATCH 126/182] Stackdriver logging When the environment variable STACKDRIVER_LOGGING is set to true, send request logs in a format that Stackdriver knows how to interpret. Also, set the log level accordint to the status code. 4xx responses are logged as warnings and 5xx responses are logged as errors. --- libraries/metrics/http.coffee | 62 +++++++++++++++++++-------- libraries/metrics/package.json | 7 ++-- libraries/metrics/statsd/http.coffee | 63 +++++++++++++++++++--------- 3 files changed, 92 insertions(+), 40 deletions(-) diff --git a/libraries/metrics/http.coffee b/libraries/metrics/http.coffee index f5e3719d53..5b0dad072f 100644 --- a/libraries/metrics/http.coffee +++ b/libraries/metrics/http.coffee @@ -1,29 +1,55 @@ os = require("os") +yn = require("yn") + +STACKDRIVER_LOGGING = yn(process.env['STACKDRIVER_LOGGING']) module.exports.monitor = (logger) -> return (req, res, next) -> Metrics = require("./metrics") - startTime = new Date() + startTime = process.hrtime() end = res.end res.end = () -> end.apply(this, arguments) - responseTime = new Date() - startTime + responseTime = process.hrtime(startTime) + responseTimeMs = Math.round(responseTime[0] * 1000 + responseTime[1] / 1000) if req.route?.path? routePath = req.route.path.toString().replace(/\//g, '_').replace(/\:/g, '').slice(1) - Metrics.timing("http_request", responseTime, null, {method:req.method, status_code: res.statusCode, path:routePath}) - logger.log - req: - url: req.originalUrl || req.url - method: req.method - referrer: req.headers['referer'] || req.headers['referrer'] - "remote-addr": req.ip || req.socket?.socket?.remoteAddress || req.socket?.remoteAddress - "user-agent": req.headers["user-agent"] - "content-length": req.headers["content-length"] - res: - "content-length": res._headers?["content-length"] - statusCode: res.statusCode - "response-time": responseTime - "http request" - + Metrics.timing("http_request", responseTimeMs, null, {method:req.method, status_code: res.statusCode, path:routePath}) + remoteIp = req.ip || req.socket?.socket?.remoteAddress || req.socket?.remoteAddress + reqUrl = req.originalUrl || req.url + referrer = req.headers['referer'] || req.headers['referrer'] + if STACKDRIVER_LOGGING + info = + httpRequest: + requestMethod: req.method + requestUrl: reqUrl + requestSize: req.headers["content-length"] + status: res.statusCode + responseSize: res._headers?["content-length"] + userAgent: req.headers["user-agent"] + remoteIp: remoteIp + referer: referrer + latency: + seconds: responseTime[0] + nanos: responseTime[1] + protocol: req.protocol + else + info = + req: + url: reqUrl + method: req.method + referrer: referrer + "remote-addr": remoteIp + "user-agent": req.headers["user-agent"] + "content-length": req.headers["content-length"] + res: + "content-length": res._headers?["content-length"] + statusCode: res.statusCode + "response-time": responseTimeMs + if res.statusCode >= 500 + logger.error(info, "%s %s", req.method, reqUrl) + else if res.statusCode >= 400 and res.statusCode < 500 + logger.warn(info, "%s %s", req.method, reqUrl) + else + logger.info(info, "%s %s", req.method, reqUrl) next() - diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 24daa5da46..d206cf8886 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -7,13 +7,14 @@ "url": "https://github.com/sharelatex/metrics-sharelatex.git" }, "dependencies": { + "@google-cloud/debug-agent": "^3.0.0", + "@google-cloud/profiler": "^0.2.3", + "@google-cloud/trace-agent": "^3.2.0", "coffee-script": "1.6.0", "lynx": "~0.1.1", "prom-client": "^11.1.3", "underscore": "~1.6.0", - "@google-cloud/debug-agent": "^3.0.0", - "@google-cloud/profiler": "^0.2.3", - "@google-cloud/trace-agent": "^3.2.0" + "yn": "^3.1.1" }, "devDependencies": { "bunyan": "^1.0.0", diff --git a/libraries/metrics/statsd/http.coffee b/libraries/metrics/statsd/http.coffee index c175f26a14..f9320ed758 100644 --- a/libraries/metrics/statsd/http.coffee +++ b/libraries/metrics/statsd/http.coffee @@ -1,31 +1,56 @@ os = require("os") +yn = require("yn") + +STACKDRIVER_LOGGING = yn(process.env['STACKDRIVER_LOGGING']) module.exports.monitor = (logger) -> return (req, res, next) -> Metrics = require("./metrics") - startTime = new Date() + startTime = process.hrtime() end = res.end res.end = () -> end.apply(this, arguments) - responseTime = new Date() - startTime + responseTime = process.hrtime(startTime) + responseTimeMs = Math.round(responseTime[0] * 1000 + responseTime[1] / 1000) if req.route?.path? routePath = req.route.path.toString().replace(/\//g, '_').replace(/\:/g, '').slice(1) key = "http-requests.#{routePath}.#{req.method}.#{res.statusCode}" - - Metrics.timing(key, responseTime) - logger.log - req: - url: req.originalUrl || req.url - method: req.method - referrer: req.headers['referer'] || req.headers['referrer'] - "remote-addr": req.ip || req.socket?.socket?.remoteAddress || req.socket?.remoteAddress - "user-agent": req.headers["user-agent"] - "content-length": req.headers["content-length"] - res: - "content-length": res._headers?["content-length"] - statusCode: res.statusCode - "response-time": responseTime - "http request" - + Metrics.timing(key, responseTimeMs) + remoteIp = req.ip || req.socket?.socket?.remoteAddress || req.socket?.remoteAddress + reqUrl = req.originalUrl || req.url + referrer = req.headers['referer'] || req.headers['referrer'] + if STACKDRIVER_LOGGING + info = + httpRequest: + requestMethod: req.method + requestUrl: reqUrl + requestSize: req.headers["content-length"] + status: res.statusCode + responseSize: res._headers?["content-length"] + userAgent: req.headers["user-agent"] + remoteIp: remoteIp + referer: referrer + latency: + seconds: responseTime[0] + nanos: responseTime[1] + protocol: req.protocol + else + info = + req: + url: reqUrl + method: req.method + referrer: referrer + "remote-addr": remoteIp + "user-agent": req.headers["user-agent"] + "content-length": req.headers["content-length"] + res: + "content-length": res._headers?["content-length"] + statusCode: res.statusCode + "response-time": responseTimeMs + if res.statusCode >= 500 + logger.error(info, "%s %s", req.method, reqUrl) + else if res.statusCode >= 400 and res.statusCode < 500 + logger.warn(info, "%s %s", req.method, reqUrl) + else + logger.info(info, "%s %s", req.method, reqUrl) next() - From 7b7b6d079344a47e12175eb5c3c5bd989bb5b5d1 Mon Sep 17 00:00:00 2001 From: Eric Mc Sween Date: Fri, 25 Oct 2019 07:17:43 -0400 Subject: [PATCH 127/182] 2.3.0 --- libraries/metrics/package-lock.json | 13 +++++++++++++ libraries/metrics/package.json | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 libraries/metrics/package-lock.json diff --git a/libraries/metrics/package-lock.json b/libraries/metrics/package-lock.json new file mode 100644 index 0000000000..bd9ef9dd9e --- /dev/null +++ b/libraries/metrics/package-lock.json @@ -0,0 +1,13 @@ +{ + "name": "metrics-sharelatex", + "version": "2.3.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==" + } + } +} diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index d206cf8886..f14f3c2f90 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "2.2.0", + "version": "2.3.0", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From e0cf10a88684434dcb2004d8ede293ce000293b2 Mon Sep 17 00:00:00 2001 From: Simon Detheridge Date: Mon, 28 Oct 2019 12:34:04 +0000 Subject: [PATCH 128/182] Fix typo, gague -> gauge --- libraries/metrics/metrics.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 03e492be8e..256eb3a854 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -112,13 +112,13 @@ module.exports = Metrics = gauge : (key, value, sampleRate = 1, opts)-> key = Metrics.buildPromKey(key) - prom.metric('gague', key).set({app: appname, host: hostname, status: opts?.status}, this.sanitizeValue(value)) + prom.metric('gauge', key).set({app: appname, host: hostname, status: opts?.status}, this.sanitizeValue(value)) if process.env['DEBUG_METRICS'] console.log("doing gauge", key, opts) globalGauge: (key, value, sampleRate = 1, opts)-> key = Metrics.buildPromKey(key) - prom.metric('gague', key).set({app: appname, status: opts?.status},this.sanitizeValue(value)) + prom.metric('gauge', key).set({app: appname, status: opts?.status},this.sanitizeValue(value)) mongodb: require "./mongodb" http: require "./http" From feecda8ea8efa71e3bac8aac0ca2e402500e6873 Mon Sep 17 00:00:00 2001 From: Simon Detheridge Date: Mon, 28 Oct 2019 12:40:12 +0000 Subject: [PATCH 129/182] Use map instead of hash for metrics --- libraries/metrics/prom_wrapper.coffee | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/libraries/metrics/prom_wrapper.coffee b/libraries/metrics/prom_wrapper.coffee index eb2c132314..cfcca4c8e4 100644 --- a/libraries/metrics/prom_wrapper.coffee +++ b/libraries/metrics/prom_wrapper.coffee @@ -1,6 +1,6 @@ prom = require('prom-client') registry = require('prom-client').register -metrics = {} +metrics = new Map() optsKey = (opts) -> @@ -33,16 +33,16 @@ PromWrapper = registry: registry metric: (type, name) -> - registry.getSingleMetric(name) || new MetricWrapper(type, name) + metrics.get(name) || new MetricWrapper(type, name) collectDefaultMetrics: prom.collectDefaultMetrics class MetricWrapper constructor: (type, name) -> - metrics[name] = this + metrics.set(name, this) @name = name - @instances = {} + @instances = new Map() @lastAccess = new Date() @metric = switch type when "counter" @@ -77,22 +77,22 @@ class MetricWrapper sweep: () -> thresh = new Date(Date.now() - 1000 * 60 * PromWrapper.ttlInMinutes) - for key in Object.keys(@instances) - if thresh > @instances[key].time + @instances.forEach (instance, key) => + if thresh > instance.time if process.env['DEBUG_METRICS'] - console.log("Sweeping stale metric instance", @name, opts: @instances[key].opts, key) - @metric.remove(optsAsArgs(@instances[key].opts, @metric.labelNames)...) + console.log("Sweeping stale metric instance", @name, opts: instance.opts, key) + @metric.remove(optsAsArgs(instance.opts, @metric.labelNames)...) if thresh > @lastAccess if process.env['DEBUG_METRICS'] - console.log("Sweeping stale metric", @name) - delete metrics[@name] + console.log("Sweeping stale metric", @name, thresh, @lastAccess) + metrics.delete(@name) registry.removeSingleMetric(@name) _execMethod: (method, opts, value) -> opts = extendOpts(opts, @metric.labelNames) key = optsKey(opts) - @instances[key] = { time: new Date(), opts } unless key == '' + @instances.set(key, { time: new Date(), opts }) unless key == '' @lastAccess = new Date() @metric[method](opts, value) @@ -106,8 +106,8 @@ unless PromWrapper.sweepRegistered if PromWrapper.ttlInMinutes if process.env['DEBUG_METRICS'] console.log("Sweeping metrics") - for key in Object.keys(metrics) - metrics[key].sweep() + metrics.forEach (metric, key) => + metric.sweep() 60000) From 93df87eff35bb8f075c8a230996c6d8703901f2a Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Mon, 16 Dec 2019 10:18:30 +0000 Subject: [PATCH 130/182] allow options for count --- libraries/metrics/metrics.coffee | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 256eb3a854..8f72e778dc 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -83,9 +83,11 @@ module.exports = Metrics = if process.env['DEBUG_METRICS'] console.log("doing inc", key, opts) - count : (key, count, sampleRate = 1)-> + count : (key, count, sampleRate = 1, opts = {})-> key = Metrics.buildPromKey(key) - prom.metric('counter', key).inc({app: appname, host: hostname}, count) + opts.app = appname + opts.host = hostname + prom.metric('counter', key).inc(opts, count) if process.env['DEBUG_METRICS'] console.log("doing count/inc", key, opts) From 3a5374c6f999875bc73ddd089753bc6c228b354b Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Mon, 16 Dec 2019 10:22:50 +0000 Subject: [PATCH 131/182] increase minor version for backwards compatible addition --- libraries/metrics/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index f14f3c2f90..46ad38078c 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "2.3.0", + "version": "2.4.0", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From 2273978e7ba5c2e56687dd2c087a78835d47dc82 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Mon, 16 Dec 2019 11:32:47 +0000 Subject: [PATCH 132/182] fix gauge usage --- libraries/metrics/prom_wrapper.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/prom_wrapper.coffee b/libraries/metrics/prom_wrapper.coffee index cfcca4c8e4..26cc1b8cc1 100644 --- a/libraries/metrics/prom_wrapper.coffee +++ b/libraries/metrics/prom_wrapper.coffee @@ -60,7 +60,7 @@ class MetricWrapper labelNames: ['app', 'host', 'path', 'status_code', 'method', 'collection', 'query'] }) when "gauge" - prom.Gauge({ + new prom.Gauge({ name: name, help: name, labelNames: ['app','host', 'status'] From 9a8cddbbb626afaea007860c4338c5634432d901 Mon Sep 17 00:00:00 2001 From: Simon Detheridge Date: Tue, 3 Mar 2020 17:09:35 +0000 Subject: [PATCH 133/182] Don't set UV_THREADPOOL_SIZE if already set --- libraries/metrics/uv_threadpool_size.coffee | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/metrics/uv_threadpool_size.coffee b/libraries/metrics/uv_threadpool_size.coffee index c0947fee31..36b7466248 100644 --- a/libraries/metrics/uv_threadpool_size.coffee +++ b/libraries/metrics/uv_threadpool_size.coffee @@ -1,2 +1,3 @@ -process.env.UV_THREADPOOL_SIZE=16 -console.log "Set UV_THREADPOOL_SIZE=#{process.env.UV_THREADPOOL_SIZE}" +unless process.env.UV_THREADPOOL_SIZE + process.env.UV_THREADPOOL_SIZE=16 + console.log "Set UV_THREADPOOL_SIZE=#{process.env.UV_THREADPOOL_SIZE}" From 74c2afc12d866c9b676eb46a1082d47012249764 Mon Sep 17 00:00:00 2001 From: Simon Detheridge Date: Wed, 4 Mar 2020 10:30:36 +0000 Subject: [PATCH 134/182] Bump package version --- libraries/metrics/package-lock.json | 1889 ++++++++++++++++++++++++++- libraries/metrics/package.json | 2 +- 2 files changed, 1889 insertions(+), 2 deletions(-) diff --git a/libraries/metrics/package-lock.json b/libraries/metrics/package-lock.json index bd9ef9dd9e..5879ca0dbb 100644 --- a/libraries/metrics/package-lock.json +++ b/libraries/metrics/package-lock.json @@ -1,9 +1,1896 @@ { "name": "metrics-sharelatex", - "version": "2.3.0", + "version": "2.5.0", "lockfileVersion": 1, "requires": true, "dependencies": { + "@google-cloud/common": { + "version": "0.32.1", + "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-0.32.1.tgz", + "integrity": "sha512-bLdPzFvvBMtVkwsoBtygE9oUm3yrNmPa71gvOgucYI/GqvNP2tb6RYsDHPq98kvignhcgHGDI5wyNgxaCo8bKQ==", + "requires": { + "@google-cloud/projectify": "^0.3.3", + "@google-cloud/promisify": "^0.4.0", + "@types/request": "^2.48.1", + "arrify": "^2.0.0", + "duplexify": "^3.6.0", + "ent": "^2.2.0", + "extend": "^3.0.2", + "google-auth-library": "^3.1.1", + "pify": "^4.0.1", + "retry-request": "^4.0.0", + "teeny-request": "^3.11.3" + } + }, + "@google-cloud/debug-agent": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@google-cloud/debug-agent/-/debug-agent-3.2.0.tgz", + "integrity": "sha512-fP87kYbS6aeDna08BivwQ1J260mwJGchRi99XdWCgqbRwuFac8ul0OT5i2wEeDSc5QaDX8ZuWQQ0igZvh1rTyQ==", + "requires": { + "@google-cloud/common": "^0.32.0", + "@sindresorhus/is": "^0.15.0", + "acorn": "^6.0.0", + "coffeescript": "^2.0.0", + "console-log-level": "^1.4.0", + "extend": "^3.0.1", + "findit2": "^2.2.3", + "gcp-metadata": "^1.0.0", + "lodash.pickby": "^4.6.0", + "p-limit": "^2.2.0", + "pify": "^4.0.1", + "semver": "^6.0.0", + "source-map": "^0.6.1", + "split": "^1.0.0" + }, + "dependencies": { + "coffeescript": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-2.5.1.tgz", + "integrity": "sha512-J2jRPX0eeFh5VKyVnoLrfVFgLZtnnmp96WQSLAS8OrLm2wtQLcnikYKe1gViJKDH7vucjuhHvBKKBP3rKcD1tQ==" + } + } + }, + "@google-cloud/profiler": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@google-cloud/profiler/-/profiler-0.2.3.tgz", + "integrity": "sha512-rNvtrFtIebIxZEJ/O0t8n7HciZGIXBo8DvHxWqAmsCaeLvkTtsaL6HmPkwxrNQ1IhbYWAxF+E/DwCiHyhKmgTg==", + "requires": { + "@google-cloud/common": "^0.26.0", + "@types/console-log-level": "^1.4.0", + "@types/semver": "^5.5.0", + "bindings": "^1.2.1", + "console-log-level": "^1.4.0", + "delay": "^4.0.1", + "extend": "^3.0.1", + "gcp-metadata": "^0.9.0", + "nan": "^2.11.1", + "parse-duration": "^0.1.1", + "pify": "^4.0.0", + "pretty-ms": "^4.0.0", + "protobufjs": "~6.8.6", + "semver": "^5.5.0", + "teeny-request": "^3.3.0" + }, + "dependencies": { + "@google-cloud/common": { + "version": "0.26.2", + "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-0.26.2.tgz", + "integrity": "sha512-xJ2M/q3MrUbnYZuFlpF01caAlEhAUoRn0NXp93Hn3pkFpfSOG8YfbKbpBAHvcKVbBOAKVIwPsleNtuyuabUwLQ==", + "requires": { + "@google-cloud/projectify": "^0.3.2", + "@google-cloud/promisify": "^0.3.0", + "@types/duplexify": "^3.5.0", + "@types/request": "^2.47.0", + "arrify": "^1.0.1", + "duplexify": "^3.6.0", + "ent": "^2.2.0", + "extend": "^3.0.1", + "google-auth-library": "^2.0.0", + "pify": "^4.0.0", + "retry-request": "^4.0.0", + "through2": "^3.0.0" + } + }, + "@google-cloud/promisify": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-0.3.1.tgz", + "integrity": "sha512-QzB0/IMvB0eFxFK7Eqh+bfC8NLv3E9ScjWQrPOk6GgfNroxcVITdTlT8NRsRrcp5+QQJVPLkRqKG0PUdaWXmHw==" + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" + }, + "gcp-metadata": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-0.9.3.tgz", + "integrity": "sha512-caV4S84xAjENtpezLCT/GILEAF5h/bC4cNqZFmt/tjTn8t+JBtTkQrgBrJu3857YdsnlM8rxX/PMcKGtE8hUlw==", + "requires": { + "gaxios": "^1.0.2", + "json-bigint": "^0.3.0" + } + }, + "google-auth-library": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-2.0.2.tgz", + "integrity": "sha512-FURxmo1hBVmcfLauuMRKOPYAPKht3dGuI2wjeJFalDUThO0HoYVjr4yxt5cgYSFm1dgUpmN9G/poa7ceTFAIiA==", + "requires": { + "axios": "^0.18.0", + "gcp-metadata": "^0.7.0", + "gtoken": "^2.3.0", + "https-proxy-agent": "^2.2.1", + "jws": "^3.1.5", + "lru-cache": "^5.0.0", + "semver": "^5.5.0" + }, + "dependencies": { + "gcp-metadata": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-0.7.0.tgz", + "integrity": "sha512-ffjC09amcDWjh3VZdkDngIo7WoluyC5Ag9PAYxZbmQLOLNI8lvPtoKTSCyU54j2gwy5roZh6sSMTfkY2ct7K3g==", + "requires": { + "axios": "^0.18.0", + "extend": "^3.0.1", + "retry-axios": "0.3.2" + } + } + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "@google-cloud/projectify": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-0.3.3.tgz", + "integrity": "sha512-7522YHQ4IhaafgSunsFF15nG0TGVmxgXidy9cITMe+256RgqfcrfWphiMufW+Ou4kqagW/u3yxwbzVEW3dk2Uw==" + }, + "@google-cloud/promisify": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-0.4.0.tgz", + "integrity": "sha512-4yAHDC52TEMCNcMzVC8WlqnKKKq+Ssi2lXoUg9zWWkZ6U6tq9ZBRYLHHCRdfU+EU9YJsVmivwGcKYCjRGjnf4Q==" + }, + "@google-cloud/trace-agent": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@google-cloud/trace-agent/-/trace-agent-3.6.1.tgz", + "integrity": "sha512-KDo85aPN4gSxJ7oEIOlKd7aGENZFXAM1kbIn1Ds+61gh/K1CQWSyepgJo3nUpAwH6D1ezDWV7Iaf8ueoITc8Uw==", + "requires": { + "@google-cloud/common": "^0.32.1", + "builtin-modules": "^3.0.0", + "console-log-level": "^1.4.0", + "continuation-local-storage": "^3.2.1", + "extend": "^3.0.0", + "gcp-metadata": "^1.0.0", + "hex2dec": "^1.0.1", + "is": "^3.2.0", + "methods": "^1.1.1", + "require-in-the-middle": "^4.0.0", + "semver": "^6.0.0", + "shimmer": "^1.2.0", + "uuid": "^3.0.1" + } + }, + "@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" + }, + "@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" + }, + "@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", + "requires": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" + }, + "@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" + }, + "@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" + }, + "@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" + }, + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" + }, + "@sindresorhus/is": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.15.0.tgz", + "integrity": "sha512-lu8BpxjAtRCAo5ifytTpCPCj99LF7o/2Myn+NXyNCBqvPYn7Pjd76AMmUB5l7XF1U6t0hcWrlEM5ESufW7wAeA==" + }, + "@sinonjs/commons": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.7.1.tgz", + "integrity": "sha512-Debi3Baff1Qu1Unc3mjJ96MgpbwTn43S1+9yJ0llWygPwDNu2aaWBD6yc9y/Z8XDRNhx7U+u2UDg2OGQXkclUQ==", + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.0.tgz", + "integrity": "sha512-atR1J/jRXvQAb47gfzSK8zavXy7BcpnYq21ALon0U99etu99vsir0trzIO3wpeLtW+LLVY6X7EkfVTbjGSH8Ww==", + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@sinonjs/formatio": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-5.0.1.tgz", + "integrity": "sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==", + "requires": { + "@sinonjs/commons": "^1", + "@sinonjs/samsam": "^5.0.2" + } + }, + "@sinonjs/samsam": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.0.3.tgz", + "integrity": "sha512-QucHkc2uMJ0pFGjJUDP3F9dq5dx8QIaqISl9QgwLOh6P9yv877uONPGXh/OH/0zmM3tW1JjuJltAZV2l7zU+uQ==", + "requires": { + "@sinonjs/commons": "^1.6.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "@sinonjs/text-encoding": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==" + }, + "@types/caseless": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", + "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==" + }, + "@types/console-log-level": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@types/console-log-level/-/console-log-level-1.4.0.tgz", + "integrity": "sha512-x+OscEQwcx5Biair4enH7ov9W+clcqUWaZRaxn5IkT4yNWWjRr2oiYDkY/x1uXSTVZOQ2xlbFQySaQGB+VdXGQ==" + }, + "@types/duplexify": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@types/duplexify/-/duplexify-3.6.0.tgz", + "integrity": "sha512-5zOA53RUlzN74bvrSGwjudssD9F3a797sDZQkiYpUOxW+WHaXTCPz4/d5Dgi6FKnOqZ2CpaTo0DhgIfsXAOE/A==", + "requires": { + "@types/node": "*" + } + }, + "@types/long": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" + }, + "@types/node": { + "version": "13.7.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.7.7.tgz", + "integrity": "sha512-Uo4chgKbnPNlxQwoFmYIwctkQVkMMmsAoGGU4JKwLuvBefF0pCq4FybNSnfkfRCpC7ZW7kttcC/TrRtAJsvGtg==" + }, + "@types/request": { + "version": "2.48.4", + "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.4.tgz", + "integrity": "sha512-W1t1MTKYR8PxICH+A4HgEIPuAC3sbljoEVfyZbeFJJDbr30guDspJri2XOaM2E+Un7ZjrihaDi7cf6fPa2tbgw==", + "requires": { + "@types/caseless": "*", + "@types/node": "*", + "@types/tough-cookie": "*", + "form-data": "^2.5.0" + } + }, + "@types/semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-41qEJgBH/TWgo5NFSvBCJ1qkoi3Q6ONSF2avrHq1LVEZfYpdHmj0y9SuTK+u9ZhG1sYQKBL1AWXKyLWP4RaUoQ==" + }, + "@types/tough-cookie": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.6.tgz", + "integrity": "sha512-wHNBMnkoEBiRAd3s8KTKwIuO9biFtTf0LehITzBhSco+HQI0xkXZbLOD55SW3Aqw3oUkHstkm5SPv58yaAdFPQ==" + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "requires": { + "event-target-shim": "^5.0.0" + } + }, + "acorn": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.0.tgz", + "integrity": "sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw==" + }, + "agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "requires": { + "es6-promisify": "^5.0.0" + } + }, + "ansi-regex": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz", + "integrity": "sha1-DY6UaWej2BQ/k+JOKYUl/BsiNfk=", + "dev": true + }, + "ansi-styles": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz", + "integrity": "sha1-6uy/Zs1waIJ2Cy9GkVgrj1XXp94=", + "dev": true + }, + "argparse": { + "version": "0.1.16", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-0.1.16.tgz", + "integrity": "sha1-z9AeD7uj1srtBJ+9dY1A9lGW9Xw=", + "dev": true, + "requires": { + "underscore": "~1.7.0", + "underscore.string": "~2.4.0" + }, + "dependencies": { + "underscore": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", + "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=", + "dev": true + }, + "underscore.string": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.4.0.tgz", + "integrity": "sha1-jN2PusTi0uoefi6Al8QvRCKA+Fs=", + "dev": true + } + } + }, + "arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==" + }, + "async": { + "version": "0.1.22", + "resolved": "https://registry.npmjs.org/async/-/async-0.1.22.tgz", + "integrity": "sha1-D8GqoIig4+8Ovi2IMbqw3PiEUGE=", + "dev": true + }, + "async-listener": { + "version": "0.6.10", + "resolved": "https://registry.npmjs.org/async-listener/-/async-listener-0.6.10.tgz", + "integrity": "sha512-gpuo6xOyF4D5DE5WvyqZdPA3NGhiT6Qf07l7DCB0wwDEsLvDIbCr6j9S5aj5Ch96dLace5tXVzWBZkxU/c5ohw==", + "requires": { + "semver": "^5.3.0", + "shimmer": "^1.1.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "axios": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.1.tgz", + "integrity": "sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==", + "requires": { + "follow-redirects": "1.5.10", + "is-buffer": "^2.0.2" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" + }, + "bignumber.js": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz", + "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==" + }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "bintrees": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.1.tgz", + "integrity": "sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ=" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, + "builtin-modules": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz", + "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==" + }, + "bunyan": { + "version": "1.8.12", + "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.12.tgz", + "integrity": "sha1-8VDw9nSKvdcq6uhPBEA74u8RN5c=", + "dev": true, + "requires": { + "dtrace-provider": "~0.8", + "moment": "^2.10.6", + "mv": "~2", + "safe-json-stringify": "~1" + } + }, + "chai": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", + "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.0", + "type-detect": "^4.0.5" + } + }, + "chalk": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz", + "integrity": "sha1-Zjs6ZItotV0EaQ1JFnqoN4WPIXQ=", + "dev": true, + "requires": { + "ansi-styles": "^1.1.0", + "escape-string-regexp": "^1.0.0", + "has-ansi": "^0.1.0", + "strip-ansi": "^0.3.0", + "supports-color": "^0.2.0" + } + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=" + }, + "coffee-script": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.6.0.tgz", + "integrity": "sha1-gIs5bhEPU9AhoZpO8fZb4OjjX6M=" + }, + "colors": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", + "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.0.0.tgz", + "integrity": "sha1-0bhvkB+LZL2UG96tr5JFMDk76Sg=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "console-log-level": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/console-log-level/-/console-log-level-1.4.1.tgz", + "integrity": "sha512-VZzbIORbP+PPcN/gg3DXClTLPLg5Slwd5fL2MIc+o1qZ4BXBvWyc6QxPk6T/Mkr6IVjRpoAGf32XxP3ZWMVRcQ==" + }, + "continuation-local-storage": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/continuation-local-storage/-/continuation-local-storage-3.2.1.tgz", + "integrity": "sha512-jx44cconVqkCEEyLSKWwkvUXwO561jXMa3LPjTPsm5QR22PA0/mhe33FT4Xb5y74JDvt/Cq+5lm8S8rskLv9ZA==", + "requires": { + "async-listener": "^0.6.0", + "emitter-listener": "^1.1.1" + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "dateformat": { + "version": "1.0.2-1.2.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.2-1.2.3.tgz", + "integrity": "sha1-sCIMAt6YYXQztyhRz0fePfLNvuk=", + "dev": true + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "requires": { + "type-detect": "^4.0.0" + } + }, + "delay": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/delay/-/delay-4.3.0.tgz", + "integrity": "sha512-Lwaf3zVFDMBop1yDuFZ19F9WyGcZcGacsbdlZtWjQmM50tOcMntm1njF/Nb/Vjij3KaSvCF+sEYGKrrjObu2NA==" + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "diff": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/diff/-/diff-1.0.7.tgz", + "integrity": "sha1-JLuwAcSn1VIhaefKvbLCgU7ZHPQ=", + "dev": true + }, + "dtrace-provider": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.8.tgz", + "integrity": "sha512-b7Z7cNtHPhH9EJhNNbbeqTcXB8LGFFZhq1PGgEvpeHlzd36bhbdTWoE/Ba/YguqpBSlAPKnARWhVlhunCMwfxg==", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.14.0" + } + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "emitter-listener": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/emitter-listener/-/emitter-listener-1.1.2.tgz", + "integrity": "sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ==", + "requires": { + "shimmer": "^1.2.0" + } + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=" + }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "requires": { + "es6-promise": "^4.0.3" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "esprima": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", + "integrity": "sha1-n1V+CPw7TSbs6d00+Pv0drYlha0=", + "dev": true + }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" + }, + "eventemitter2": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", + "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=", + "dev": true + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "fast-text-encoding": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.0.tgz", + "integrity": "sha512-R9bHCvweUxxwkDwhjav5vxpFvdPGlVngtqmx4pIZfSUhM/Q4NiIUHB456BAf+Q1Nwu3HEZYONtu+Rya+af4jiQ==" + }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + }, + "findit2": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/findit2/-/findit2-2.2.3.tgz", + "integrity": "sha1-WKRmaX34piBc39vzlVNri9d3pfY=" + }, + "findup-sync": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.1.3.tgz", + "integrity": "sha1-fz56l7gjksZTvwZYm9hRkOk8NoM=", + "dev": true, + "requires": { + "glob": "~3.2.9", + "lodash": "~2.4.1" + }, + "dependencies": { + "glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", + "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", + "dev": true, + "requires": { + "inherits": "2", + "minimatch": "0.3" + } + }, + "lodash": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", + "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=", + "dev": true + }, + "lru-cache": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", + "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", + "dev": true + }, + "minimatch": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", + "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", + "dev": true, + "requires": { + "lru-cache": "2", + "sigmund": "~1.0.0" + } + } + } + }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "requires": { + "debug": "=3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "form-data": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "fs-extra": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.9.1.tgz", + "integrity": "sha1-h9v8ATg6jdzn2dVJbzYIVkiJ8VY=", + "dev": true, + "requires": { + "jsonfile": "~1.1.0", + "mkdirp": "^0.5.0", + "ncp": "^0.5.1", + "rimraf": "^2.2.8" + }, + "dependencies": { + "ncp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/ncp/-/ncp-0.5.1.tgz", + "integrity": "sha1-dDmFMW49tFkoG1hxaehFc1oFQ58=", + "dev": true + } + } + }, + "gaxios": { + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-1.8.4.tgz", + "integrity": "sha512-BoENMnu1Gav18HcpV9IleMPZ9exM+AvUjrAOV4Mzs/vfz2Lu/ABv451iEXByKiMPn2M140uul1txXCg83sAENw==", + "requires": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^2.2.1", + "node-fetch": "^2.3.0" + } + }, + "gcp-metadata": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-1.0.0.tgz", + "integrity": "sha512-Q6HrgfrCQeEircnNP3rCcEgiDv7eF9+1B+1MMgpE190+/+0mjQR8PxeOaRgxZWmdDAF9EIryHB9g1moPiw1SbQ==", + "requires": { + "gaxios": "^1.0.2", + "json-bigint": "^0.3.0" + } + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=" + }, + "getobject": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz", + "integrity": "sha1-BHpEl4n6Fg0Bj1SG7ZEyC27HiFw=", + "dev": true + }, + "glob": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", + "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "dev": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "google-auth-library": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-3.1.2.tgz", + "integrity": "sha512-cDQMzTotwyWMrg5jRO7q0A4TL/3GWBgO7I7q5xGKNiiFf9SmGY/OJ1YsLMgI2MVHHsEGyrqYnbnmV1AE+Z6DnQ==", + "requires": { + "base64-js": "^1.3.0", + "fast-text-encoding": "^1.0.0", + "gaxios": "^1.2.1", + "gcp-metadata": "^1.0.0", + "gtoken": "^2.3.2", + "https-proxy-agent": "^2.2.1", + "jws": "^3.1.5", + "lru-cache": "^5.0.0", + "semver": "^5.5.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "google-p12-pem": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-1.0.4.tgz", + "integrity": "sha512-SwLAUJqUfTB2iS+wFfSS/G9p7bt4eWcc2LyfvmUXe7cWp6p3mpxDo6LLI29MXdU6wvPcQ/up298X7GMC5ylAlA==", + "requires": { + "node-forge": "^0.8.0", + "pify": "^4.0.0" + } + }, + "graceful-fs": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", + "integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q=", + "dev": true + }, + "growl": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.7.0.tgz", + "integrity": "sha1-3i1mE20ALhErpw8/EMMc98NQsto=", + "dev": true + }, + "grunt": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/grunt/-/grunt-0.4.5.tgz", + "integrity": "sha1-VpN81RlDJK3/bSB2MYMqnWuk5/A=", + "dev": true, + "requires": { + "async": "~0.1.22", + "coffee-script": "~1.3.3", + "colors": "~0.6.2", + "dateformat": "1.0.2-1.2.3", + "eventemitter2": "~0.4.13", + "exit": "~0.1.1", + "findup-sync": "~0.1.2", + "getobject": "~0.1.0", + "glob": "~3.1.21", + "grunt-legacy-log": "~0.1.0", + "grunt-legacy-util": "~0.2.0", + "hooker": "~0.2.3", + "iconv-lite": "~0.2.11", + "js-yaml": "~2.0.5", + "lodash": "~0.9.2", + "minimatch": "~0.2.12", + "nopt": "~1.0.10", + "rimraf": "~2.2.8", + "underscore.string": "~2.2.1", + "which": "~1.0.5" + }, + "dependencies": { + "coffee-script": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.3.3.tgz", + "integrity": "sha1-FQ1rTLUiiUNp7+1qIQHCC8f0pPQ=", + "dev": true + }, + "glob": { + "version": "3.1.21", + "resolved": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz", + "integrity": "sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=", + "dev": true, + "requires": { + "graceful-fs": "~1.2.0", + "inherits": "1", + "minimatch": "~0.2.11" + } + }, + "inherits": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz", + "integrity": "sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js=", + "dev": true + }, + "lru-cache": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", + "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", + "dev": true + }, + "minimatch": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", + "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", + "dev": true, + "requires": { + "lru-cache": "2", + "sigmund": "~1.0.0" + } + }, + "rimraf": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", + "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=", + "dev": true + } + } + }, + "grunt-bunyan": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/grunt-bunyan/-/grunt-bunyan-0.5.0.tgz", + "integrity": "sha1-aCnXbgGZQ9owQTk2MaNuKsgpsWw=", + "dev": true, + "requires": { + "lodash": "~2.4.1" + }, + "dependencies": { + "lodash": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", + "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=", + "dev": true + } + } + }, + "grunt-contrib-clean": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/grunt-contrib-clean/-/grunt-contrib-clean-0.6.0.tgz", + "integrity": "sha1-9TLbpLghJnTHwBPhRr2mY4uQSPY=", + "dev": true, + "requires": { + "rimraf": "~2.2.1" + }, + "dependencies": { + "rimraf": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", + "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=", + "dev": true + } + } + }, + "grunt-contrib-coffee": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/grunt-contrib-coffee/-/grunt-contrib-coffee-0.11.1.tgz", + "integrity": "sha1-+v48nuikQryNF9WlwZ/I5i2fP0U=", + "dev": true, + "requires": { + "chalk": "~0.5.0", + "coffee-script": "~1.7.0", + "lodash": "~2.4.1" + }, + "dependencies": { + "coffee-script": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.7.1.tgz", + "integrity": "sha1-YplqhheAx15tUGnROCJyO3NAS/w=", + "dev": true, + "requires": { + "mkdirp": "~0.3.5" + } + }, + "lodash": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", + "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=", + "dev": true + }, + "mkdirp": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", + "integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc=", + "dev": true + } + } + }, + "grunt-execute": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/grunt-execute/-/grunt-execute-0.2.2.tgz", + "integrity": "sha1-TpRf5XlZzA3neZCDtrQq7ZYWNQo=", + "dev": true + }, + "grunt-legacy-log": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-0.1.3.tgz", + "integrity": "sha1-7ClCboAwIa9ZAp+H0vnNczWgVTE=", + "dev": true, + "requires": { + "colors": "~0.6.2", + "grunt-legacy-log-utils": "~0.1.1", + "hooker": "~0.2.3", + "lodash": "~2.4.1", + "underscore.string": "~2.3.3" + }, + "dependencies": { + "lodash": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", + "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=", + "dev": true + }, + "underscore.string": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz", + "integrity": "sha1-ccCL9rQosRM/N+ePo6Icgvcymw0=", + "dev": true + } + } + }, + "grunt-legacy-log-utils": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-0.1.1.tgz", + "integrity": "sha1-wHBrndkGThFvNvI/5OawSGcsD34=", + "dev": true, + "requires": { + "colors": "~0.6.2", + "lodash": "~2.4.1", + "underscore.string": "~2.3.3" + }, + "dependencies": { + "lodash": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", + "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=", + "dev": true + }, + "underscore.string": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz", + "integrity": "sha1-ccCL9rQosRM/N+ePo6Icgvcymw0=", + "dev": true + } + } + }, + "grunt-legacy-util": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-0.2.0.tgz", + "integrity": "sha1-kzJIhNv343qf98Am3/RR2UqeVUs=", + "dev": true, + "requires": { + "async": "~0.1.22", + "exit": "~0.1.1", + "getobject": "~0.1.0", + "hooker": "~0.2.3", + "lodash": "~0.9.2", + "underscore.string": "~2.2.1", + "which": "~1.0.5" + } + }, + "grunt-mocha-test": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/grunt-mocha-test/-/grunt-mocha-test-0.11.0.tgz", + "integrity": "sha1-deQboQdZDkrL0phgklwBLkQ8oyI=", + "dev": true, + "requires": { + "fs-extra": "~0.9.1", + "hooker": "~0.2.3", + "mocha": "~1.20.0" + } + }, + "gtoken": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-2.3.3.tgz", + "integrity": "sha512-EaB49bu/TCoNeQjhCYKI/CurooBKkGxIqFHsWABW0b25fobBYVTMe84A8EBVVZhl8emiUdNypil9huMOTmyAnw==", + "requires": { + "gaxios": "^1.0.4", + "google-p12-pem": "^1.0.0", + "jws": "^3.1.5", + "mime": "^2.2.0", + "pify": "^4.0.0" + } + }, + "has-ansi": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz", + "integrity": "sha1-hPJlqujA5qiKEtcCKJS3VoiUxi4=", + "dev": true, + "requires": { + "ansi-regex": "^0.2.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "hex2dec": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/hex2dec/-/hex2dec-1.1.2.tgz", + "integrity": "sha512-Yu+q/XWr2fFQ11tHxPq4p4EiNkb2y+lAacJNhAdRXVfRIcDH6gi7htWFnnlIzvqHMHoWeIsfXlNAjZInpAOJDA==" + }, + "hooker": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz", + "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=", + "dev": true + }, + "https-proxy-agent": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "requires": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + } + }, + "iconv-lite": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.2.11.tgz", + "integrity": "sha1-HOYKOleGSiktEyH/RgnKS7llrcg=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "is": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/is/-/is-3.3.0.tgz", + "integrity": "sha512-nW24QBoPcFGGHJGUwnfpI7Yc5CdqWNdsyHQszVE/z2pKHXzh7FZ5GWhJqSyaQ9wMkQnsTx+kAI8bHlCX4tKdbg==" + }, + "is-buffer": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "jade": { + "version": "0.26.3", + "resolved": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz", + "integrity": "sha1-jxDXl32NefL2/4YqgbBRPMslaGw=", + "dev": true, + "requires": { + "commander": "0.6.1", + "mkdirp": "0.3.0" + }, + "dependencies": { + "commander": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", + "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=", + "dev": true + }, + "mkdirp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", + "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=", + "dev": true + } + } + }, + "js-yaml": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-2.0.5.tgz", + "integrity": "sha1-olrmUJmZ6X3yeMZxnaEb0Gh3Q6g=", + "dev": true, + "requires": { + "argparse": "~ 0.1.11", + "esprima": "~ 1.0.2" + } + }, + "json-bigint": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-0.3.0.tgz", + "integrity": "sha1-DM2RLEuCcNBfBW+9E4FLU9OCWx4=", + "requires": { + "bignumber.js": "^7.0.0" + } + }, + "jsonfile": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-1.1.1.tgz", + "integrity": "sha1-2k/WrXfxolUgPqY8e8Mtwx72RDM=", + "dev": true + }, + "just-extend": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.0.tgz", + "integrity": "sha512-ApcjaOdVTJ7y4r08xI5wIqpvwS48Q0PBG4DJROcEkH1f8MdAiNFyFxz3xoL0LWAVwjrwPYZdVHHxhRHcx/uGLA==" + }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "lodash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-0.9.2.tgz", + "integrity": "sha1-jzSZxSRdNG1oLlsNO0B2fgnxqSw=", + "dev": true + }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" + }, + "lodash.pickby": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz", + "integrity": "sha1-feoh2MGNdwOifHBMFdO4SmfjOv8=" + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, + "lynx": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/lynx/-/lynx-0.1.1.tgz", + "integrity": "sha1-Mxjc7xaQi4KG6Bisz9sxzXQkj50=", + "requires": { + "mersenne": "~0.0.3", + "statsd-parser": "~0.0.4" + } + }, + "mersenne": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/mersenne/-/mersenne-0.0.4.tgz", + "integrity": "sha1-QB/ex+whzbngPNPTAhOY2iGycIU=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", + "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==" + }, + "mime-db": { + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", + "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==" + }, + "mime-types": { + "version": "2.1.26", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", + "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", + "requires": { + "mime-db": "1.43.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-1.20.1.tgz", + "integrity": "sha1-80ODLZ/gx9l8ZPxwRI9RNt+f7Vs=", + "dev": true, + "requires": { + "commander": "2.0.0", + "debug": "*", + "diff": "1.0.7", + "glob": "3.2.3", + "growl": "1.7.x", + "jade": "0.26.3", + "mkdirp": "0.3.5" + }, + "dependencies": { + "glob": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.3.tgz", + "integrity": "sha1-4xPusknHr/qlxHUoaw4RW1mDlGc=", + "dev": true, + "requires": { + "graceful-fs": "~2.0.0", + "inherits": "2", + "minimatch": "~0.2.11" + } + }, + "graceful-fs": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz", + "integrity": "sha1-fNLNsiiko/Nule+mzBQt59GhNtA=", + "dev": true + }, + "lru-cache": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", + "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", + "dev": true + }, + "minimatch": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", + "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", + "dev": true, + "requires": { + "lru-cache": "2", + "sigmund": "~1.0.0" + } + }, + "mkdirp": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", + "integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc=", + "dev": true + } + } + }, + "module-details-from-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.3.tgz", + "integrity": "sha1-EUyUlnPiqKNenTV4hSeqN7Z52is=" + }, + "moment": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", + "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==", + "dev": true, + "optional": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "mv": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", + "integrity": "sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI=", + "dev": true, + "optional": true, + "requires": { + "mkdirp": "~0.5.1", + "ncp": "~2.0.0", + "rimraf": "~2.4.0" + } + }, + "nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" + }, + "ncp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", + "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=", + "dev": true, + "optional": true + }, + "nise": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nise/-/nise-4.0.3.tgz", + "integrity": "sha512-EGlhjm7/4KvmmE6B/UFsKh7eHykRl9VH+au8dduHLCyWUO/hr7+N+WtTvDUwc9zHuM1IaIJs/0lQ6Ag1jDkQSg==", + "requires": { + "@sinonjs/commons": "^1.7.0", + "@sinonjs/fake-timers": "^6.0.0", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + } + }, + "node-fetch": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", + "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" + }, + "node-forge": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.8.5.tgz", + "integrity": "sha512-vFMQIWt+J/7FLNyKouZ9TazT74PRV3wgv9UT4cRjC8BffxFbKXkgIWR42URCPSnHm/QDz6BOlb2Q0U4+VQT67Q==" + }, + "nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "p-limit": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", + "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "parse-duration": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/parse-duration/-/parse-duration-0.1.2.tgz", + "integrity": "sha512-0qfMZyjOUFBeEIvJ5EayfXJqaEXxQ+Oj2b7tWJM3hvEXvXsYCk05EDVI23oYnEw2NaFYUWdABEVPBvBMh8L/pA==" + }, + "parse-ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-2.1.0.tgz", + "integrity": "sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "requires": { + "isarray": "0.0.1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + } + } + }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=" + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + }, + "pretty-ms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-4.0.0.tgz", + "integrity": "sha512-qG66ahoLCwpLXD09ZPHSCbUWYTqdosB7SMP4OffgTgL2PBKXMuUsrk5Bwg8q4qPkjTXsKBMr+YK3Ltd/6F9s/Q==", + "requires": { + "parse-ms": "^2.0.0" + } + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "prom-client": { + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/prom-client/-/prom-client-11.5.3.tgz", + "integrity": "sha512-iz22FmTbtkyL2vt0MdDFY+kWof+S9UB/NACxSn2aJcewtw+EERsen0urSkZ2WrHseNdydsvcxCTAnPcSMZZv4Q==", + "requires": { + "tdigest": "^0.1.1" + } + }, + "protobufjs": { + "version": "6.8.8", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.8.8.tgz", + "integrity": "sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.0", + "@types/node": "^10.1.0", + "long": "^4.0.0" + }, + "dependencies": { + "@types/node": { + "version": "10.17.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.17.tgz", + "integrity": "sha512-gpNnRnZP3VWzzj5k3qrpRC6Rk3H/uclhAVo1aIvwzK5p5cOrs9yEyQ8H/HBsBY0u5rrWxXEiVPQ0dEB6pkjE8Q==" + } + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "require-in-the-middle": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-4.0.1.tgz", + "integrity": "sha512-EfkM2zANyGkrfIExsECMeNn/uzjvHrE9h36yLXSavmrDiH4tgDNvltAmEKnt4PNLbqKPHZz+uszW2wTKrLUX0w==", + "requires": { + "debug": "^4.1.1", + "module-details-from-path": "^1.0.3", + "resolve": "^1.12.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "require-like": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/require-like/-/require-like-0.1.2.tgz", + "integrity": "sha1-rW8wwTvs15cBDEaK+ndcDAprR/o=" + }, + "resolve": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", + "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", + "requires": { + "path-parse": "^1.0.6" + } + }, + "retry-axios": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/retry-axios/-/retry-axios-0.3.2.tgz", + "integrity": "sha512-jp4YlI0qyDFfXiXGhkCOliBN1G7fRH03Nqy8YdShzGqbY5/9S2x/IR6C88ls2DFkbWuL3ASkP7QD3pVrNpPgwQ==" + }, + "retry-request": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-4.1.1.tgz", + "integrity": "sha512-BINDzVtLI2BDukjWmjAIRZ0oglnCAkpP2vQjM3jdLhmT62h0xnQgciPwBRDAvHqpkPT2Wo1XuUyLyn6nbGrZQQ==", + "requires": { + "debug": "^4.1.1", + "through2": "^3.0.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "rimraf": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", + "integrity": "sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto=", + "dev": true, + "requires": { + "glob": "^6.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safe-json-stringify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz", + "integrity": "sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==", + "dev": true, + "optional": true + }, + "sandboxed-module": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/sandboxed-module/-/sandboxed-module-2.0.3.tgz", + "integrity": "sha1-x+VFkzm7y6KMUwPusz9ug4e/upY=", + "requires": { + "require-like": "0.1.2", + "stack-trace": "0.0.9" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "shimmer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", + "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" + }, + "sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", + "dev": true + }, + "sinon": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.0.0.tgz", + "integrity": "sha512-c4bREcvuK5VuEGyMW/Oim9I3Rq49Vzb0aMdxouFaA44QCFpilc5LJOugrX+mkrvikbqCimxuK+4cnHVNnLR41g==", + "requires": { + "@sinonjs/commons": "^1.7.0", + "@sinonjs/fake-timers": "^6.0.0", + "@sinonjs/formatio": "^5.0.0", + "@sinonjs/samsam": "^5.0.1", + "diff": "^4.0.2", + "nise": "^4.0.1", + "supports-color": "^7.1.0" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "requires": { + "through": "2" + } + }, + "stack-trace": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.9.tgz", + "integrity": "sha1-qPbq7KkGdMMz58Q5U/J1tFFRBpU=" + }, + "statsd-parser": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/statsd-parser/-/statsd-parser-0.0.4.tgz", + "integrity": "sha1-y9JDlTzELv/VSLXSI4jtaJ7GOb0=" + }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz", + "integrity": "sha1-JfSOoiynkYfzF0pNuHWTR7sSYiA=", + "dev": true, + "requires": { + "ansi-regex": "^0.2.1" + } + }, + "supports-color": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz", + "integrity": "sha1-2S3iaU6z9nMjlz1649i1W0wiGQo=", + "dev": true + }, + "tdigest": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.1.tgz", + "integrity": "sha1-Ljyyw56kSeVdHmzZEReszKRYgCE=", + "requires": { + "bintrees": "1.0.1" + } + }, + "teeny-request": { + "version": "3.11.3", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-3.11.3.tgz", + "integrity": "sha512-CKncqSF7sH6p4rzCgkb/z/Pcos5efl0DmolzvlqRQUNcpRIruOhY9+T1FsIlyEbfWd7MsFpodROOwHYh2BaXzw==", + "requires": { + "https-proxy-agent": "^2.2.1", + "node-fetch": "^2.2.0", + "uuid": "^3.3.2" + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "through2": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", + "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", + "requires": { + "readable-stream": "2 || 3" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" + }, + "underscore": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=" + }, + "underscore.string": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.2.1.tgz", + "integrity": "sha1-18D6KvXVoaZ/QlPa7pgTLnM/Dxk=", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + }, + "which": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/which/-/which-1.0.9.tgz", + "integrity": "sha1-RgwdoPgQED0DIam2M6+eV15kSG8=", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, "yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 46ad38078c..c2d7cd939d 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "2.4.0", + "version": "2.5.0", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From 03e81153db9fe73736bb54cc246d119818bf8c62 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Tue, 10 Mar 2020 15:00:10 +0000 Subject: [PATCH 135/182] avoid step effects in summary metrics reduce the window size from 10 minutes to 1 minute, so that short spikes do not cause a 10 minute long "table" graph. --- libraries/metrics/package.json | 2 +- libraries/metrics/prom_wrapper.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index c2d7cd939d..2d976634ee 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "2.5.0", + "version": "2.5.1", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", diff --git a/libraries/metrics/prom_wrapper.coffee b/libraries/metrics/prom_wrapper.coffee index 26cc1b8cc1..690838a4a2 100644 --- a/libraries/metrics/prom_wrapper.coffee +++ b/libraries/metrics/prom_wrapper.coffee @@ -55,7 +55,7 @@ class MetricWrapper new prom.Summary({ name: name, help: name, - maxAgeSeconds: 600, + maxAgeSeconds: 60, ageBuckets: 10, labelNames: ['app', 'host', 'path', 'status_code', 'method', 'collection', 'query'] }) From 4a92be80ea05b451bab719fb5ac7bb91f74c92ef Mon Sep 17 00:00:00 2001 From: Eric Mc Sween Date: Wed, 11 Mar 2020 16:25:33 -0400 Subject: [PATCH 136/182] Send HTTP request size metric The metric is a "summary" called http_request_size_bytes. --- libraries/metrics/http.coffee | 5 ++++- libraries/metrics/metrics.coffee | 8 ++++++++ libraries/metrics/package.json | 2 +- libraries/metrics/statsd/metrics.coffee | 3 +++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/libraries/metrics/http.coffee b/libraries/metrics/http.coffee index 5b0dad072f..c4e16fde75 100644 --- a/libraries/metrics/http.coffee +++ b/libraries/metrics/http.coffee @@ -12,9 +12,12 @@ module.exports.monitor = (logger) -> end.apply(this, arguments) responseTime = process.hrtime(startTime) responseTimeMs = Math.round(responseTime[0] * 1000 + responseTime[1] / 1000) + requestSize = parseInt(req.headers["content-length"], 10) if req.route?.path? routePath = req.route.path.toString().replace(/\//g, '_').replace(/\:/g, '').slice(1) Metrics.timing("http_request", responseTimeMs, null, {method:req.method, status_code: res.statusCode, path:routePath}) + if requestSize + Metrics.summary("http_request_size_bytes", requestSize, {method:req.method, path:routePath}) remoteIp = req.ip || req.socket?.socket?.remoteAddress || req.socket?.remoteAddress reqUrl = req.originalUrl || req.url referrer = req.headers['referer'] || req.headers['referrer'] @@ -23,7 +26,7 @@ module.exports.monitor = (logger) -> httpRequest: requestMethod: req.method requestUrl: reqUrl - requestSize: req.headers["content-length"] + requestSize: requestSize status: res.statusCode responseSize: res._headers?["content-length"] userAgent: req.headers["user-agent"] diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index 8f72e778dc..a939f1bfba 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -91,6 +91,14 @@ module.exports = Metrics = if process.env['DEBUG_METRICS'] console.log("doing count/inc", key, opts) + summary : (key, value, opts = {})-> + key = Metrics.buildPromKey(key) + opts.app = appname + opts.host = hostname + prom.metric('summary', key).observe(opts, value) + if process.env['DEBUG_METRICS'] + console.log("doing summary", key, value, opts) + timing: (key, timeSpan, sampleRate, opts = {})-> key = Metrics.buildPromKey("timer_" + key) opts.app = appname diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 2d976634ee..de6c86b37e 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "2.5.1", + "version": "2.6.0", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", diff --git a/libraries/metrics/statsd/metrics.coffee b/libraries/metrics/statsd/metrics.coffee index 8e3be8c26c..ac072627f3 100644 --- a/libraries/metrics/statsd/metrics.coffee +++ b/libraries/metrics/statsd/metrics.coffee @@ -29,6 +29,9 @@ module.exports = Metrics = count : (key, count, sampleRate = 1)-> statsd.count buildKey(key), count, sampleRate + summary : (key, value)-> + # not supported + timing: (key, timeSpan, sampleRate)-> statsd.timing(buildKey(key), timeSpan, sampleRate) From 62e82d74696438b643d9282962914c3a6a2e4203 Mon Sep 17 00:00:00 2001 From: Eric Mc Sween Date: Thu, 12 Mar 2020 06:24:46 -0400 Subject: [PATCH 137/182] Send the status code with the HTTP request size metric --- libraries/metrics/http.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/http.coffee b/libraries/metrics/http.coffee index c4e16fde75..e3097c8c72 100644 --- a/libraries/metrics/http.coffee +++ b/libraries/metrics/http.coffee @@ -17,7 +17,7 @@ module.exports.monitor = (logger) -> routePath = req.route.path.toString().replace(/\//g, '_').replace(/\:/g, '').slice(1) Metrics.timing("http_request", responseTimeMs, null, {method:req.method, status_code: res.statusCode, path:routePath}) if requestSize - Metrics.summary("http_request_size_bytes", requestSize, {method:req.method, path:routePath}) + Metrics.summary("http_request_size_bytes", requestSize, {method:req.method, status_code: res.statusCode, path:routePath}) remoteIp = req.ip || req.socket?.socket?.remoteAddress || req.socket?.remoteAddress reqUrl = req.originalUrl || req.url referrer = req.headers['referer'] || req.headers['referrer'] From 25448bfef41c3c14a3dd20bdcbc021d75f7a9e2c Mon Sep 17 00:00:00 2001 From: Eric Mc Sween Date: Wed, 18 Mar 2020 08:41:11 -0400 Subject: [PATCH 138/182] Downgrade all request logs to INFO Commit 9056143fe36f1347a1ff985ef8592a1de7d798dd added logic to log requests with different error levels depending on the status code. The intention was to make the 5xx and 4xx requests stand out in Stackdriver. Unfortunately, this also creates a lot of noise in Sentry since we log the errors separately from the requests. This commit brings back the former behaviour of logging all requests at the INFO level. We can revisit this if we integrate the strategy implemented in filestore of logging once per request. --- libraries/metrics/http.coffee | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/libraries/metrics/http.coffee b/libraries/metrics/http.coffee index e3097c8c72..db7d56b2da 100644 --- a/libraries/metrics/http.coffee +++ b/libraries/metrics/http.coffee @@ -49,10 +49,5 @@ module.exports.monitor = (logger) -> "content-length": res._headers?["content-length"] statusCode: res.statusCode "response-time": responseTimeMs - if res.statusCode >= 500 - logger.error(info, "%s %s", req.method, reqUrl) - else if res.statusCode >= 400 and res.statusCode < 500 - logger.warn(info, "%s %s", req.method, reqUrl) - else - logger.info(info, "%s %s", req.method, reqUrl) + logger.info(info, "%s %s", req.method, reqUrl) next() From a17843f3bf372465d2b61a690f962b8eaa1987f1 Mon Sep 17 00:00:00 2001 From: Eric Mc Sween Date: Fri, 20 Mar 2020 07:47:05 -0400 Subject: [PATCH 139/182] 2.6.1 --- libraries/metrics/package-lock.json | 2 +- libraries/metrics/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/metrics/package-lock.json b/libraries/metrics/package-lock.json index 5879ca0dbb..6e06da433b 100644 --- a/libraries/metrics/package-lock.json +++ b/libraries/metrics/package-lock.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "2.5.0", + "version": "2.6.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index de6c86b37e..9bf50d9c35 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "2.6.0", + "version": "2.6.1", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From ef7e3b0e7a2f56dd816ca4e532cc655ba6f668e6 Mon Sep 17 00:00:00 2001 From: Eric Mc Sween Date: Wed, 25 Mar 2020 09:39:21 -0400 Subject: [PATCH 140/182] Fix HTTP request timing metrics The conversion between high resolution time and milliseconds was incorrect. --- libraries/metrics/http.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/http.coffee b/libraries/metrics/http.coffee index db7d56b2da..0d32dd59ab 100644 --- a/libraries/metrics/http.coffee +++ b/libraries/metrics/http.coffee @@ -11,7 +11,7 @@ module.exports.monitor = (logger) -> res.end = () -> end.apply(this, arguments) responseTime = process.hrtime(startTime) - responseTimeMs = Math.round(responseTime[0] * 1000 + responseTime[1] / 1000) + responseTimeMs = Math.round(responseTime[0] * 1000 + responseTime[1] / 1000000) requestSize = parseInt(req.headers["content-length"], 10) if req.route?.path? routePath = req.route.path.toString().replace(/\//g, '_').replace(/\:/g, '').slice(1) From 8131c5ac914d0cddf201e151a3cb73a11318cd84 Mon Sep 17 00:00:00 2001 From: Eric Mc Sween Date: Wed, 25 Mar 2020 09:53:54 -0400 Subject: [PATCH 141/182] 2.6.2 --- libraries/metrics/package-lock.json | 2 +- libraries/metrics/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/metrics/package-lock.json b/libraries/metrics/package-lock.json index 6e06da433b..0f78670c39 100644 --- a/libraries/metrics/package-lock.json +++ b/libraries/metrics/package-lock.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "2.6.1", + "version": "2.6.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 9bf50d9c35..94899978f0 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "2.6.1", + "version": "2.6.2", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From ea767920fc2242451199a49ad0afd00fd4044326 Mon Sep 17 00:00:00 2001 From: Jakob Ackermann Date: Wed, 1 Apr 2020 16:39:00 +0200 Subject: [PATCH 142/182] [misc] fix unit tests --- .../metrics/test/unit/coffee/timeAsyncMethodTests.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee b/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee index b6a4d3cd6b..67348e8ea1 100644 --- a/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee +++ b/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee @@ -53,7 +53,7 @@ describe 'timeAsyncMethod', -> @timeAsyncMethod @testObject, 'nextNumber', 'someContext.TestObject' @testObject.nextNumber 2, (err, result) => expect(@metrics.inc.callCount).to.equal 1 - expect(@metrics.inc.calledWith('someContext.TestObject.nextNumber.success')).to.equal true + expect(@metrics.inc.calledWith('someContext_result', 1, { method: 'TestObject_nextNumber', status: 'success'})).to.equal true done() describe 'when base method produces an error', -> @@ -78,7 +78,7 @@ describe 'timeAsyncMethod', -> @timeAsyncMethod @testObject, 'nextNumber', 'someContext.TestObject' @testObject.nextNumber 2, (err, result) => expect(@metrics.inc.callCount).to.equal 1 - expect(@metrics.inc.calledWith('someContext.TestObject.nextNumber.failure')).to.equal true + expect(@metrics.inc.calledWith('someContext_result', 1, { method: 'TestObject_nextNumber', status: 'failed'})).to.equal true done() describe 'when a logger is supplied', -> From d69195eaa9f27e320d69a84b4867973b866fb32d Mon Sep 17 00:00:00 2001 From: Eric Mc Sween Date: Fri, 3 Jul 2020 16:38:29 -0400 Subject: [PATCH 143/182] Log requests that don't have a route property The v1 history service has its routes set up via swagger-tools, which doesn't write a route property on the request. This prevents us to send request metrics based on the route, but we can still log the request. --- libraries/metrics/http.coffee | 64 +++++++++++++++++------------------ 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/libraries/metrics/http.coffee b/libraries/metrics/http.coffee index 0d32dd59ab..fdfd492fc4 100644 --- a/libraries/metrics/http.coffee +++ b/libraries/metrics/http.coffee @@ -18,36 +18,36 @@ module.exports.monitor = (logger) -> Metrics.timing("http_request", responseTimeMs, null, {method:req.method, status_code: res.statusCode, path:routePath}) if requestSize Metrics.summary("http_request_size_bytes", requestSize, {method:req.method, status_code: res.statusCode, path:routePath}) - remoteIp = req.ip || req.socket?.socket?.remoteAddress || req.socket?.remoteAddress - reqUrl = req.originalUrl || req.url - referrer = req.headers['referer'] || req.headers['referrer'] - if STACKDRIVER_LOGGING - info = - httpRequest: - requestMethod: req.method - requestUrl: reqUrl - requestSize: requestSize - status: res.statusCode - responseSize: res._headers?["content-length"] - userAgent: req.headers["user-agent"] - remoteIp: remoteIp - referer: referrer - latency: - seconds: responseTime[0] - nanos: responseTime[1] - protocol: req.protocol - else - info = - req: - url: reqUrl - method: req.method - referrer: referrer - "remote-addr": remoteIp - "user-agent": req.headers["user-agent"] - "content-length": req.headers["content-length"] - res: - "content-length": res._headers?["content-length"] - statusCode: res.statusCode - "response-time": responseTimeMs - logger.info(info, "%s %s", req.method, reqUrl) + remoteIp = req.ip || req.socket?.socket?.remoteAddress || req.socket?.remoteAddress + reqUrl = req.originalUrl || req.url + referrer = req.headers['referer'] || req.headers['referrer'] + if STACKDRIVER_LOGGING + info = + httpRequest: + requestMethod: req.method + requestUrl: reqUrl + requestSize: requestSize + status: res.statusCode + responseSize: res._headers?["content-length"] + userAgent: req.headers["user-agent"] + remoteIp: remoteIp + referer: referrer + latency: + seconds: responseTime[0] + nanos: responseTime[1] + protocol: req.protocol + else + info = + req: + url: reqUrl + method: req.method + referrer: referrer + "remote-addr": remoteIp + "user-agent": req.headers["user-agent"] + "content-length": req.headers["content-length"] + res: + "content-length": res._headers?["content-length"] + statusCode: res.statusCode + "response-time": responseTimeMs + logger.info(info, "%s %s", req.method, reqUrl) next() From e197e4dc111845d6715f832fd560a262b53c6195 Mon Sep 17 00:00:00 2001 From: Eric Mc Sween Date: Mon, 6 Jul 2020 08:20:02 -0400 Subject: [PATCH 144/182] 2.7.0 --- libraries/metrics/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 94899978f0..10dc25fe35 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "2.6.2", + "version": "2.7.0", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From e31a8196367a7ee666629a3ca44931bff51dc92f Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Fri, 17 Jul 2020 15:36:37 +0100 Subject: [PATCH 145/182] remove statsd --- libraries/metrics/metrics.coffee | 11 +- libraries/metrics/package-lock.json | 21 +--- libraries/metrics/package.json | 3 +- libraries/metrics/statsd/event_loop.coffee | 18 ---- libraries/metrics/statsd/http.coffee | 56 ---------- libraries/metrics/statsd/memory.coffee | 85 --------------- libraries/metrics/statsd/metrics.coffee | 70 ------------ libraries/metrics/statsd/mongodb.coffee | 100 ------------------ libraries/metrics/statsd/open_sockets.coffee | 28 ----- .../metrics/statsd/timeAsyncMethod.coffee | 36 ------- .../metrics/statsd/uv_threadpool_size.coffee | 2 - 11 files changed, 6 insertions(+), 424 deletions(-) delete mode 100644 libraries/metrics/statsd/event_loop.coffee delete mode 100644 libraries/metrics/statsd/http.coffee delete mode 100644 libraries/metrics/statsd/memory.coffee delete mode 100644 libraries/metrics/statsd/metrics.coffee delete mode 100644 libraries/metrics/statsd/mongodb.coffee delete mode 100644 libraries/metrics/statsd/open_sockets.coffee delete mode 100644 libraries/metrics/statsd/timeAsyncMethod.coffee delete mode 100644 libraries/metrics/statsd/uv_threadpool_size.coffee diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee index a939f1bfba..3aa40c8d25 100644 --- a/libraries/metrics/metrics.coffee +++ b/libraries/metrics/metrics.coffee @@ -1,7 +1,4 @@ -if process.env["USE_PROM_METRICS"] != "true" - return module.exports = require("./statsd/metrics") -else - console.log("using prometheus") +console.log("using prometheus") prom = require('./prom_wrapper') @@ -29,7 +26,7 @@ module.exports = Metrics = traceAgent = require('@google-cloud/trace-agent') traceOpts = - ignoreUrls: [/^\/status/, /^\/health_check/] + ignoreUrls: [/^\/status/, /^\/health_check/] traceAgent.start(traceOpts) console.log("ENABLE_DEBUG_AGENT set to #{process.env['ENABLE_DEBUG_AGENT']}") @@ -61,7 +58,7 @@ module.exports = Metrics = destructors.push func injectMetricsRoute: (app) -> - app.get('/metrics', (req, res) -> + app.get('/metrics', (req, res) -> res.set('Content-Type', prom.registry.contentType) res.end(prom.registry.metrics()) ) @@ -125,7 +122,7 @@ module.exports = Metrics = prom.metric('gauge', key).set({app: appname, host: hostname, status: opts?.status}, this.sanitizeValue(value)) if process.env['DEBUG_METRICS'] console.log("doing gauge", key, opts) - + globalGauge: (key, value, sampleRate = 1, opts)-> key = Metrics.buildPromKey(key) prom.metric('gauge', key).set({app: appname, status: opts?.status},this.sanitizeValue(value)) diff --git a/libraries/metrics/package-lock.json b/libraries/metrics/package-lock.json index 0f78670c39..4477cd1f40 100644 --- a/libraries/metrics/package-lock.json +++ b/libraries/metrics/package-lock.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "2.6.2", + "version": "3.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1317,20 +1317,6 @@ "yallist": "^3.0.2" } }, - "lynx": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/lynx/-/lynx-0.1.1.tgz", - "integrity": "sha1-Mxjc7xaQi4KG6Bisz9sxzXQkj50=", - "requires": { - "mersenne": "~0.0.3", - "statsd-parser": "~0.0.4" - } - }, - "mersenne": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/mersenne/-/mersenne-0.0.4.tgz", - "integrity": "sha1-QB/ex+whzbngPNPTAhOY2iGycIU=" - }, "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -1785,11 +1771,6 @@ "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.9.tgz", "integrity": "sha1-qPbq7KkGdMMz58Q5U/J1tFFRBpU=" }, - "statsd-parser": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/statsd-parser/-/statsd-parser-0.0.4.tgz", - "integrity": "sha1-y9JDlTzELv/VSLXSI4jtaJ7GOb0=" - }, "stream-shift": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 10dc25fe35..9e4209ae9d 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "metrics-sharelatex", - "version": "2.7.0", + "version": "3.0.0", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", @@ -11,7 +11,6 @@ "@google-cloud/profiler": "^0.2.3", "@google-cloud/trace-agent": "^3.2.0", "coffee-script": "1.6.0", - "lynx": "~0.1.1", "prom-client": "^11.1.3", "underscore": "~1.6.0", "yn": "^3.1.1" diff --git a/libraries/metrics/statsd/event_loop.coffee b/libraries/metrics/statsd/event_loop.coffee deleted file mode 100644 index 01e37b96a1..0000000000 --- a/libraries/metrics/statsd/event_loop.coffee +++ /dev/null @@ -1,18 +0,0 @@ -module.exports = EventLoopMonitor = - monitor: (logger, interval = 1000, log_threshold = 100) -> - Metrics = require "./metrics" - # check for logger on startup to avoid exceptions later if undefined - throw new Error("logger is undefined") if !logger? - # monitor delay in setInterval to detect event loop blocking - previous = Date.now() - intervalId = setInterval () -> - now = Date.now() - offset = now - previous - interval - if offset > log_threshold - logger.warn {offset: offset}, "slow event loop" - previous = now - Metrics.timing("event-loop-millsec", offset) - , interval - - Metrics.registerDestructor () -> - clearInterval(intervalId) diff --git a/libraries/metrics/statsd/http.coffee b/libraries/metrics/statsd/http.coffee deleted file mode 100644 index f9320ed758..0000000000 --- a/libraries/metrics/statsd/http.coffee +++ /dev/null @@ -1,56 +0,0 @@ -os = require("os") -yn = require("yn") - -STACKDRIVER_LOGGING = yn(process.env['STACKDRIVER_LOGGING']) - -module.exports.monitor = (logger) -> - return (req, res, next) -> - Metrics = require("./metrics") - startTime = process.hrtime() - end = res.end - res.end = () -> - end.apply(this, arguments) - responseTime = process.hrtime(startTime) - responseTimeMs = Math.round(responseTime[0] * 1000 + responseTime[1] / 1000) - if req.route?.path? - routePath = req.route.path.toString().replace(/\//g, '_').replace(/\:/g, '').slice(1) - key = "http-requests.#{routePath}.#{req.method}.#{res.statusCode}" - Metrics.timing(key, responseTimeMs) - remoteIp = req.ip || req.socket?.socket?.remoteAddress || req.socket?.remoteAddress - reqUrl = req.originalUrl || req.url - referrer = req.headers['referer'] || req.headers['referrer'] - if STACKDRIVER_LOGGING - info = - httpRequest: - requestMethod: req.method - requestUrl: reqUrl - requestSize: req.headers["content-length"] - status: res.statusCode - responseSize: res._headers?["content-length"] - userAgent: req.headers["user-agent"] - remoteIp: remoteIp - referer: referrer - latency: - seconds: responseTime[0] - nanos: responseTime[1] - protocol: req.protocol - else - info = - req: - url: reqUrl - method: req.method - referrer: referrer - "remote-addr": remoteIp - "user-agent": req.headers["user-agent"] - "content-length": req.headers["content-length"] - res: - "content-length": res._headers?["content-length"] - statusCode: res.statusCode - "response-time": responseTimeMs - if res.statusCode >= 500 - logger.error(info, "%s %s", req.method, reqUrl) - else if res.statusCode >= 400 and res.statusCode < 500 - logger.warn(info, "%s %s", req.method, reqUrl) - else - logger.info(info, "%s %s", req.method, reqUrl) - next() diff --git a/libraries/metrics/statsd/memory.coffee b/libraries/metrics/statsd/memory.coffee deleted file mode 100644 index a1e157a5bf..0000000000 --- a/libraries/metrics/statsd/memory.coffee +++ /dev/null @@ -1,85 +0,0 @@ -# record memory usage each minute and run a periodic gc(), keeping cpu -# usage within allowable range of 1ms per minute. Also, dynamically -# adjust the period between gc()'s to reach a target of the gc saving -# 4 megabytes each time. - -oneMinute = 60 * 1000 -oneMegaByte = 1024 * 1024 - -CpuTimeBucket = 100 # current cpu time allowance in milliseconds -CpuTimeBucketMax = 100 # maximum amount of cpu time allowed in bucket -CpuTimeBucketRate = 10 # add this many milliseconds per minute - -gcInterval = 1 # how many minutes between gc (parameter is dynamically adjusted) -countSinceLastGc = 0 # how many minutes since last gc -MemoryChunkSize = 4 # how many megabytes we need to free to consider gc worth doing - -readyToGc = () -> - # update allowed cpu time - CpuTimeBucket = CpuTimeBucket + CpuTimeBucketRate - CpuTimeBucket = if CpuTimeBucket < CpuTimeBucketMax then CpuTimeBucket else CpuTimeBucketMax - # update counts since last gc - countSinceLastGc = countSinceLastGc + 1 - # check there is enough time since last gc and we have enough cpu - return (countSinceLastGc > gcInterval) && (CpuTimeBucket > 0) - -executeAndTime = (fn) -> - # time the execution of fn() and subtract from cpu allowance - t0 = process.hrtime() - fn() - dt = process.hrtime(t0) - timeTaken = (dt[0] + dt[1]*1e-9) * 1e3 # in milliseconds - CpuTimeBucket -= Math.ceil timeTaken - return timeTaken - -inMegaBytes = (obj) -> - # convert process.memoryUsage hash {rss,heapTotal,heapFreed} into megabytes - result = {} - for k, v of obj - result[k] = (v / oneMegaByte).toFixed(2) - return result - -updateMemoryStats = (oldMem, newMem) -> - countSinceLastGc = 0 - delta = {} - for k of newMem - delta[k] = (newMem[k] - oldMem[k]).toFixed(2) - # take the max of all memory measures - savedMemory = Math.max -delta.rss, -delta.heapTotal, -delta.heapUsed - delta.megabytesFreed = savedMemory - # did it do any good? - if savedMemory < MemoryChunkSize - gcInterval = gcInterval + 1 # no, so wait longer next time - else - gcInterval = Math.max gcInterval - 1, 1 # yes, wait less time - return delta - -module.exports = MemoryMonitor = - monitor: (logger) -> - interval = setInterval () -> - MemoryMonitor.Check(logger) - , oneMinute - Metrics = require "./metrics" - Metrics.registerDestructor () -> - clearInterval(interval) - - Check: (logger) -> - Metrics = require "./metrics" - memBeforeGc = mem = inMegaBytes process.memoryUsage() - Metrics.gauge("memory.rss", mem.rss) - Metrics.gauge("memory.heaptotal", mem.heapTotal) - Metrics.gauge("memory.heapused", mem.heapUsed) - Metrics.gauge("memory.gc-interval", gcInterval) - #Metrics.gauge("memory.cpu-time-bucket", CpuTimeBucket) - - logger.log mem, "process.memoryUsage()" - - if global.gc? && readyToGc() - gcTime = (executeAndTime global.gc).toFixed(2) - memAfterGc = inMegaBytes process.memoryUsage() - deltaMem = updateMemoryStats(memBeforeGc, memAfterGc) - logger.log {gcTime, memBeforeGc, memAfterGc, deltaMem, gcInterval, CpuTimeBucket}, "global.gc() forced" - #Metrics.timing("memory.gc-time", gcTime) - Metrics.gauge("memory.gc-rss-freed", -deltaMem.rss) - Metrics.gauge("memory.gc-heaptotal-freed", -deltaMem.heapTotal) - Metrics.gauge("memory.gc-heapused-freed", -deltaMem.heapUsed) diff --git a/libraries/metrics/statsd/metrics.coffee b/libraries/metrics/statsd/metrics.coffee deleted file mode 100644 index ac072627f3..0000000000 --- a/libraries/metrics/statsd/metrics.coffee +++ /dev/null @@ -1,70 +0,0 @@ -console.log("using statsd") - -StatsD = require('lynx') -statsd = new StatsD(process.env["STATSD_HOST"] or "localhost", 8125, {on_error:->}) - -name = "unknown" -hostname = require('os').hostname() - -buildKey = (key)-> "#{name}.#{hostname}.#{key}" -buildGlobalKey = (key)-> "#{name}.global.#{key}" - -destructors = [] - -require "./uv_threadpool_size" - -module.exports = Metrics = - initialize: (_name) -> - name = _name - - registerDestructor: (func) -> - destructors.push func - - set : (key, value, sampleRate = 1)-> - statsd.set buildKey(key), value, sampleRate - - inc : (key, sampleRate = 1)-> - statsd.increment buildKey(key), sampleRate - - count : (key, count, sampleRate = 1)-> - statsd.count buildKey(key), count, sampleRate - - summary : (key, value)-> - # not supported - - timing: (key, timeSpan, sampleRate)-> - statsd.timing(buildKey(key), timeSpan, sampleRate) - - Timer : class - constructor :(key, sampleRate = 1)-> - this.start = new Date() - this.key = key - this.sampleRate = sampleRate - done:-> - timeSpan = new Date - this.start - statsd.timing(buildKey(this.key), timeSpan, this.sampleRate) - return timeSpan - - gauge : (key, value, sampleRate = 1)-> - statsd.gauge buildKey(key), value, sampleRate - - globalGauge: (key, value, sampleRate = 1)-> - statsd.gauge buildGlobalKey(key), value, sampleRate - - mongodb: require "./mongodb" - http: require "./http" - open_sockets: require "./open_sockets" - event_loop: require "./event_loop" - memory: require "./memory" - - timeAsyncMethod: require('./timeAsyncMethod') - - injectMetricsRoute: (app) -> - app.get('/metrics', (req, res) -> - res.send("not implemented in statsd") - ) - - close: () -> - for func in destructors - func() - statsd.close() diff --git a/libraries/metrics/statsd/mongodb.coffee b/libraries/metrics/statsd/mongodb.coffee deleted file mode 100644 index ce1ca71385..0000000000 --- a/libraries/metrics/statsd/mongodb.coffee +++ /dev/null @@ -1,100 +0,0 @@ -module.exports = - monitor: (mongodb_require_path, logger) -> - - try - # for the v1 driver the methods to wrap are in the mongodb - # module in lib/mongodb/db.js - mongodb = require("#{mongodb_require_path}") - - try - # for the v2 driver the relevant methods are in the mongodb-core - # module in lib/topologies/{server,replset,mongos}.js - v2_path = mongodb_require_path.replace(/\/mongodb$/, '/mongodb-core') - mongodbCore = require(v2_path) - - Metrics = require("./metrics") - - monitorMethod = (base, method, type) -> - return unless base? - return unless (_method = base[method])? - arglen = _method.length - - mongo_driver_v1_wrapper = (db_command, options, callback) -> - if (typeof callback == 'undefined') - callback = options - options = {} - - collection = db_command.collectionName - if collection.match(/\$cmd$/) - # Ignore noisy command methods like authenticating, ismaster and ping - return _method.call this, db_command, options, callback - - key = "mongo-requests.#{collection}.#{type}" - if db_command.query? - query = Object.keys(db_command.query).sort().join("_") - key += "." + query - - timer = new Metrics.Timer(key) - start = new Date() - _method.call this, db_command, options, () -> - timer.done() - time = new Date() - start - logger.log - query: db_command.query - query_type: type - collection: collection - "response-time": new Date() - start - "mongo request" - callback.apply this, arguments - - mongo_driver_v2_wrapper = (ns, ops, options, callback) -> - if (typeof callback == 'undefined') - callback = options - options = {} - - if ns.match(/\$cmd$/) - # Ignore noisy command methods like authenticating, ismaster and ping - return _method.call this, ns, ops, options, callback - - key = "mongo-requests.#{ns}.#{type}" - if ops[0].q? # ops[0].q - query = Object.keys(ops[0].q).sort().join("_") - key += "." + query - - timer = new Metrics.Timer(key) - start = new Date() - _method.call this, ns, ops, options, () -> - timer.done() - time = new Date() - start - logger.log - query: ops[0].q - query_type: type - collection: ns - "response-time": new Date() - start - "mongo request" - callback.apply this, arguments - - if arglen == 3 - base[method] = mongo_driver_v1_wrapper - else if arglen == 4 - base[method] = mongo_driver_v2_wrapper - - monitorMethod(mongodb?.Db.prototype, "_executeQueryCommand", "query") - monitorMethod(mongodb?.Db.prototype, "_executeRemoveCommand", "remove") - monitorMethod(mongodb?.Db.prototype, "_executeInsertCommand", "insert") - monitorMethod(mongodb?.Db.prototype, "_executeUpdateCommand", "update") - - monitorMethod(mongodbCore?.Server.prototype, "command", "command") - monitorMethod(mongodbCore?.Server.prototype, "remove", "remove") - monitorMethod(mongodbCore?.Server.prototype, "insert", "insert") - monitorMethod(mongodbCore?.Server.prototype, "update", "update") - - monitorMethod(mongodbCore?.ReplSet.prototype, "command", "command") - monitorMethod(mongodbCore?.ReplSet.prototype, "remove", "remove") - monitorMethod(mongodbCore?.ReplSet.prototype, "insert", "insert") - monitorMethod(mongodbCore?.ReplSet.prototype, "update", "update") - - monitorMethod(mongodbCore?.Mongos.prototype, "command", "command") - monitorMethod(mongodbCore?.Mongos.prototype, "remove", "remove") - monitorMethod(mongodbCore?.Mongos.prototype, "insert", "insert") - monitorMethod(mongodbCore?.Mongos.prototype, "update", "update") diff --git a/libraries/metrics/statsd/open_sockets.coffee b/libraries/metrics/statsd/open_sockets.coffee deleted file mode 100644 index 9af019dfc8..0000000000 --- a/libraries/metrics/statsd/open_sockets.coffee +++ /dev/null @@ -1,28 +0,0 @@ -URL = require "url" -seconds = 1000 - -# In Node 0.10 the default is 5, which means only 5 open connections at one. -# Node 0.12 has a default of Infinity. Make sure we have no limit set, -# regardless of Node version. -require("http").globalAgent.maxSockets = Infinity -require("https").globalAgent.maxSockets = Infinity - -module.exports = OpenSocketsMonitor = - monitor: (logger) -> - interval = setInterval () -> - OpenSocketsMonitor.gaugeOpenSockets() - , 5 * seconds - Metrics = require "./metrics" - Metrics.registerDestructor () -> - clearInterval(interval) - - gaugeOpenSockets: () -> - Metrics = require "./metrics" - for url, agents of require('http').globalAgent.sockets - url = URL.parse("http://#{url}") - hostname = url.hostname?.replace(/\./g, "_") - Metrics.gauge "open_connections.http.#{hostname}", agents.length - for url, agents of require('https').globalAgent.sockets - url = URL.parse("https://#{url}") - hostname = url.hostname?.replace(/\./g, "_") - Metrics.gauge "open_connections.https.#{hostname}", agents.length diff --git a/libraries/metrics/statsd/timeAsyncMethod.coffee b/libraries/metrics/statsd/timeAsyncMethod.coffee deleted file mode 100644 index 27e21e6e09..0000000000 --- a/libraries/metrics/statsd/timeAsyncMethod.coffee +++ /dev/null @@ -1,36 +0,0 @@ - -module.exports = (obj, methodName, prefix, logger) -> - metrics = require('./metrics') - - if typeof obj[methodName] != 'function' - throw new Error("[Metrics] expected object property '#{methodName}' to be a function") - - realMethod = obj[methodName] - key = "#{prefix}.#{methodName}" - - obj[methodName] = (originalArgs...) -> - - [firstArgs..., callback] = originalArgs - - if !callback? || typeof callback != 'function' - if logger? - logger.log "[Metrics] expected wrapped method '#{methodName}' to be invoked with a callback" - return realMethod.apply this, originalArgs - - timer = new metrics.Timer(key) - - realMethod.call this, firstArgs..., (callbackArgs...) -> - elapsedTime = timer.done() - possibleError = callbackArgs[0] - if possibleError? - metrics.inc "#{key}.failure" - else - metrics.inc "#{key}.success" - if logger? - loggableArgs = {} - try - for arg, idx in firstArgs - if arg.toString().match(/^[0-9a-f]{24}$/) - loggableArgs["#{idx}"] = arg - logger.log {key, args: loggableArgs, elapsedTime}, "[Metrics] timed async method call" - callback.apply this, callbackArgs diff --git a/libraries/metrics/statsd/uv_threadpool_size.coffee b/libraries/metrics/statsd/uv_threadpool_size.coffee deleted file mode 100644 index c0947fee31..0000000000 --- a/libraries/metrics/statsd/uv_threadpool_size.coffee +++ /dev/null @@ -1,2 +0,0 @@ -process.env.UV_THREADPOOL_SIZE=16 -console.log "Set UV_THREADPOOL_SIZE=#{process.env.UV_THREADPOOL_SIZE}" From 747a80b545b0278e1d8a9299038ebe9fa233b5a0 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Fri, 17 Jul 2020 16:01:58 +0100 Subject: [PATCH 146/182] decaffeinate --- libraries/metrics/Gruntfile.coffee | 29 --- libraries/metrics/Gruntfile.js | 41 ++++ libraries/metrics/event_loop.coffee | 18 -- libraries/metrics/event_loop.js | 30 +++ libraries/metrics/http.coffee | 53 ----- libraries/metrics/http.js | 77 +++++++ libraries/metrics/index.js | 2 - libraries/metrics/memory.coffee | 85 -------- libraries/metrics/memory.js | 103 ++++++++++ libraries/metrics/metrics.coffee | 140 ------------- libraries/metrics/metrics.js | 188 ++++++++++++++++++ libraries/metrics/mongodb.coffee | 100 ---------- libraries/metrics/mongodb.js | 128 ++++++++++++ libraries/metrics/open_sockets.coffee | 28 --- libraries/metrics/open_sockets.js | 48 +++++ libraries/metrics/prom_wrapper.coffee | 114 ----------- libraries/metrics/prom_wrapper.js | 148 ++++++++++++++ .../test/unit/coffee/event_loop.coffee | 34 ---- .../unit/coffee/timeAsyncMethodTests.coffee | 126 ------------ libraries/metrics/timeAsyncMethod.coffee | 44 ---- libraries/metrics/timeAsyncMethod.js | 66 ++++++ libraries/metrics/uv_threadpool_size.coffee | 3 - libraries/metrics/uv_threadpool_size.js | 4 + 23 files changed, 833 insertions(+), 776 deletions(-) delete mode 100644 libraries/metrics/Gruntfile.coffee create mode 100644 libraries/metrics/Gruntfile.js delete mode 100644 libraries/metrics/event_loop.coffee create mode 100644 libraries/metrics/event_loop.js delete mode 100644 libraries/metrics/http.coffee create mode 100644 libraries/metrics/http.js delete mode 100644 libraries/metrics/index.js delete mode 100644 libraries/metrics/memory.coffee create mode 100644 libraries/metrics/memory.js delete mode 100644 libraries/metrics/metrics.coffee create mode 100644 libraries/metrics/metrics.js delete mode 100644 libraries/metrics/mongodb.coffee create mode 100644 libraries/metrics/mongodb.js delete mode 100644 libraries/metrics/open_sockets.coffee create mode 100644 libraries/metrics/open_sockets.js delete mode 100644 libraries/metrics/prom_wrapper.coffee create mode 100644 libraries/metrics/prom_wrapper.js delete mode 100644 libraries/metrics/test/unit/coffee/event_loop.coffee delete mode 100644 libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee delete mode 100644 libraries/metrics/timeAsyncMethod.coffee create mode 100644 libraries/metrics/timeAsyncMethod.js delete mode 100644 libraries/metrics/uv_threadpool_size.coffee create mode 100644 libraries/metrics/uv_threadpool_size.js diff --git a/libraries/metrics/Gruntfile.coffee b/libraries/metrics/Gruntfile.coffee deleted file mode 100644 index 47f126fa70..0000000000 --- a/libraries/metrics/Gruntfile.coffee +++ /dev/null @@ -1,29 +0,0 @@ -module.exports = (grunt) -> - grunt.initConfig - coffee: - unit_tests: - expand: true - cwd: "test/unit/coffee" - src: ["**/*.coffee"] - dest: "test/unit/js/" - ext: ".js" - - clean: - unit_tests: ["test/unit/js"] - - mochaTest: - unit: - options: - reporter: grunt.option('reporter') or 'spec' - grep: grunt.option("grep") - - src: ["test/unit/js/**/*.js"] - - grunt.loadNpmTasks 'grunt-contrib-coffee' - grunt.loadNpmTasks 'grunt-contrib-clean' - grunt.loadNpmTasks 'grunt-mocha-test' - grunt.loadNpmTasks 'grunt-execute' - grunt.loadNpmTasks 'grunt-bunyan' - - grunt.registerTask 'compile:unit_tests', ['clean:unit_tests', 'coffee:unit_tests'] - grunt.registerTask 'test:unit', ['compile:unit_tests', 'mochaTest:unit'] diff --git a/libraries/metrics/Gruntfile.js b/libraries/metrics/Gruntfile.js new file mode 100644 index 0000000000..c775dcb9ec --- /dev/null +++ b/libraries/metrics/Gruntfile.js @@ -0,0 +1,41 @@ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +module.exports = function(grunt) { + grunt.initConfig({ + coffee: { + unit_tests: { + expand: true, + cwd: "test/unit/coffee", + src: ["**/*.coffee"], + dest: "test/unit/js/", + ext: ".js" + } + }, + + clean: { + unit_tests: ["test/unit/js"] + }, + + mochaTest: { + unit: { + options: { + reporter: grunt.option('reporter') || 'spec', + grep: grunt.option("grep") + }, + + src: ["test/unit/js/**/*.js"] + } + }}); + + grunt.loadNpmTasks('grunt-contrib-coffee'); + grunt.loadNpmTasks('grunt-contrib-clean'); + grunt.loadNpmTasks('grunt-mocha-test'); + grunt.loadNpmTasks('grunt-execute'); + grunt.loadNpmTasks('grunt-bunyan'); + + grunt.registerTask('compile:unit_tests', ['clean:unit_tests', 'coffee:unit_tests']); + return grunt.registerTask('test:unit', ['compile:unit_tests', 'mochaTest:unit']); +}; diff --git a/libraries/metrics/event_loop.coffee b/libraries/metrics/event_loop.coffee deleted file mode 100644 index 01e37b96a1..0000000000 --- a/libraries/metrics/event_loop.coffee +++ /dev/null @@ -1,18 +0,0 @@ -module.exports = EventLoopMonitor = - monitor: (logger, interval = 1000, log_threshold = 100) -> - Metrics = require "./metrics" - # check for logger on startup to avoid exceptions later if undefined - throw new Error("logger is undefined") if !logger? - # monitor delay in setInterval to detect event loop blocking - previous = Date.now() - intervalId = setInterval () -> - now = Date.now() - offset = now - previous - interval - if offset > log_threshold - logger.warn {offset: offset}, "slow event loop" - previous = now - Metrics.timing("event-loop-millsec", offset) - , interval - - Metrics.registerDestructor () -> - clearInterval(intervalId) diff --git a/libraries/metrics/event_loop.js b/libraries/metrics/event_loop.js new file mode 100644 index 0000000000..58b0c732d2 --- /dev/null +++ b/libraries/metrics/event_loop.js @@ -0,0 +1,30 @@ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +let EventLoopMonitor; +module.exports = (EventLoopMonitor = { + monitor(logger, interval, log_threshold) { + if (interval == null) { interval = 1000; } + if (log_threshold == null) { log_threshold = 100; } + const Metrics = require("./metrics"); + // check for logger on startup to avoid exceptions later if undefined + if ((logger == null)) { throw new Error("logger is undefined"); } + // monitor delay in setInterval to detect event loop blocking + let previous = Date.now(); + const intervalId = setInterval(function() { + const now = Date.now(); + const offset = now - previous - interval; + if (offset > log_threshold) { + logger.warn({offset}, "slow event loop"); + } + previous = now; + return Metrics.timing("event-loop-millsec", offset); + } + , interval); + + return Metrics.registerDestructor(() => clearInterval(intervalId)); + } +}); diff --git a/libraries/metrics/http.coffee b/libraries/metrics/http.coffee deleted file mode 100644 index fdfd492fc4..0000000000 --- a/libraries/metrics/http.coffee +++ /dev/null @@ -1,53 +0,0 @@ -os = require("os") -yn = require("yn") - -STACKDRIVER_LOGGING = yn(process.env['STACKDRIVER_LOGGING']) - -module.exports.monitor = (logger) -> - return (req, res, next) -> - Metrics = require("./metrics") - startTime = process.hrtime() - end = res.end - res.end = () -> - end.apply(this, arguments) - responseTime = process.hrtime(startTime) - responseTimeMs = Math.round(responseTime[0] * 1000 + responseTime[1] / 1000000) - requestSize = parseInt(req.headers["content-length"], 10) - if req.route?.path? - routePath = req.route.path.toString().replace(/\//g, '_').replace(/\:/g, '').slice(1) - Metrics.timing("http_request", responseTimeMs, null, {method:req.method, status_code: res.statusCode, path:routePath}) - if requestSize - Metrics.summary("http_request_size_bytes", requestSize, {method:req.method, status_code: res.statusCode, path:routePath}) - remoteIp = req.ip || req.socket?.socket?.remoteAddress || req.socket?.remoteAddress - reqUrl = req.originalUrl || req.url - referrer = req.headers['referer'] || req.headers['referrer'] - if STACKDRIVER_LOGGING - info = - httpRequest: - requestMethod: req.method - requestUrl: reqUrl - requestSize: requestSize - status: res.statusCode - responseSize: res._headers?["content-length"] - userAgent: req.headers["user-agent"] - remoteIp: remoteIp - referer: referrer - latency: - seconds: responseTime[0] - nanos: responseTime[1] - protocol: req.protocol - else - info = - req: - url: reqUrl - method: req.method - referrer: referrer - "remote-addr": remoteIp - "user-agent": req.headers["user-agent"] - "content-length": req.headers["content-length"] - res: - "content-length": res._headers?["content-length"] - statusCode: res.statusCode - "response-time": responseTimeMs - logger.info(info, "%s %s", req.method, reqUrl) - next() diff --git a/libraries/metrics/http.js b/libraries/metrics/http.js new file mode 100644 index 0000000000..34fde3c247 --- /dev/null +++ b/libraries/metrics/http.js @@ -0,0 +1,77 @@ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * DS103: Rewrite code to no longer use __guard__ + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const os = require("os"); +const yn = require("yn"); + +const STACKDRIVER_LOGGING = yn(process.env['STACKDRIVER_LOGGING']); + +module.exports.monitor = logger => (function(req, res, next) { + const Metrics = require("./metrics"); + const startTime = process.hrtime(); + const { + end + } = res; + res.end = function() { + let info; + end.apply(this, arguments); + const responseTime = process.hrtime(startTime); + const responseTimeMs = Math.round((responseTime[0] * 1000) + (responseTime[1] / 1000000)); + const requestSize = parseInt(req.headers["content-length"], 10); + if ((req.route != null ? req.route.path : undefined) != null) { + const routePath = req.route.path.toString().replace(/\//g, '_').replace(/\:/g, '').slice(1); + Metrics.timing("http_request", responseTimeMs, null, {method:req.method, status_code: res.statusCode, path:routePath}); + if (requestSize) { + Metrics.summary("http_request_size_bytes", requestSize, {method:req.method, status_code: res.statusCode, path:routePath}); + } + } + const remoteIp = req.ip || __guard__(req.socket != null ? req.socket.socket : undefined, x => x.remoteAddress) || (req.socket != null ? req.socket.remoteAddress : undefined); + const reqUrl = req.originalUrl || req.url; + const referrer = req.headers['referer'] || req.headers['referrer']; + if (STACKDRIVER_LOGGING) { + info = { + httpRequest: { + requestMethod: req.method, + requestUrl: reqUrl, + requestSize, + status: res.statusCode, + responseSize: (res._headers != null ? res._headers["content-length"] : undefined), + userAgent: req.headers["user-agent"], + remoteIp, + referer: referrer, + latency: { + seconds: responseTime[0], + nanos: responseTime[1] + }, + protocol: req.protocol + } + }; + } else { + info = { + req: { + url: reqUrl, + method: req.method, + referrer, + "remote-addr": remoteIp, + "user-agent": req.headers["user-agent"], + "content-length": req.headers["content-length"] + }, + res: { + "content-length": (res._headers != null ? res._headers["content-length"] : undefined), + statusCode: res.statusCode + }, + "response-time": responseTimeMs + }; + } + return logger.info(info, "%s %s", req.method, reqUrl); + }; + return next(); +}); + +function __guard__(value, transform) { + return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined; +} \ No newline at end of file diff --git a/libraries/metrics/index.js b/libraries/metrics/index.js deleted file mode 100644 index 26e3d9a500..0000000000 --- a/libraries/metrics/index.js +++ /dev/null @@ -1,2 +0,0 @@ -require("coffee-script") -module.exports = require('./metrics'); diff --git a/libraries/metrics/memory.coffee b/libraries/metrics/memory.coffee deleted file mode 100644 index a1e157a5bf..0000000000 --- a/libraries/metrics/memory.coffee +++ /dev/null @@ -1,85 +0,0 @@ -# record memory usage each minute and run a periodic gc(), keeping cpu -# usage within allowable range of 1ms per minute. Also, dynamically -# adjust the period between gc()'s to reach a target of the gc saving -# 4 megabytes each time. - -oneMinute = 60 * 1000 -oneMegaByte = 1024 * 1024 - -CpuTimeBucket = 100 # current cpu time allowance in milliseconds -CpuTimeBucketMax = 100 # maximum amount of cpu time allowed in bucket -CpuTimeBucketRate = 10 # add this many milliseconds per minute - -gcInterval = 1 # how many minutes between gc (parameter is dynamically adjusted) -countSinceLastGc = 0 # how many minutes since last gc -MemoryChunkSize = 4 # how many megabytes we need to free to consider gc worth doing - -readyToGc = () -> - # update allowed cpu time - CpuTimeBucket = CpuTimeBucket + CpuTimeBucketRate - CpuTimeBucket = if CpuTimeBucket < CpuTimeBucketMax then CpuTimeBucket else CpuTimeBucketMax - # update counts since last gc - countSinceLastGc = countSinceLastGc + 1 - # check there is enough time since last gc and we have enough cpu - return (countSinceLastGc > gcInterval) && (CpuTimeBucket > 0) - -executeAndTime = (fn) -> - # time the execution of fn() and subtract from cpu allowance - t0 = process.hrtime() - fn() - dt = process.hrtime(t0) - timeTaken = (dt[0] + dt[1]*1e-9) * 1e3 # in milliseconds - CpuTimeBucket -= Math.ceil timeTaken - return timeTaken - -inMegaBytes = (obj) -> - # convert process.memoryUsage hash {rss,heapTotal,heapFreed} into megabytes - result = {} - for k, v of obj - result[k] = (v / oneMegaByte).toFixed(2) - return result - -updateMemoryStats = (oldMem, newMem) -> - countSinceLastGc = 0 - delta = {} - for k of newMem - delta[k] = (newMem[k] - oldMem[k]).toFixed(2) - # take the max of all memory measures - savedMemory = Math.max -delta.rss, -delta.heapTotal, -delta.heapUsed - delta.megabytesFreed = savedMemory - # did it do any good? - if savedMemory < MemoryChunkSize - gcInterval = gcInterval + 1 # no, so wait longer next time - else - gcInterval = Math.max gcInterval - 1, 1 # yes, wait less time - return delta - -module.exports = MemoryMonitor = - monitor: (logger) -> - interval = setInterval () -> - MemoryMonitor.Check(logger) - , oneMinute - Metrics = require "./metrics" - Metrics.registerDestructor () -> - clearInterval(interval) - - Check: (logger) -> - Metrics = require "./metrics" - memBeforeGc = mem = inMegaBytes process.memoryUsage() - Metrics.gauge("memory.rss", mem.rss) - Metrics.gauge("memory.heaptotal", mem.heapTotal) - Metrics.gauge("memory.heapused", mem.heapUsed) - Metrics.gauge("memory.gc-interval", gcInterval) - #Metrics.gauge("memory.cpu-time-bucket", CpuTimeBucket) - - logger.log mem, "process.memoryUsage()" - - if global.gc? && readyToGc() - gcTime = (executeAndTime global.gc).toFixed(2) - memAfterGc = inMegaBytes process.memoryUsage() - deltaMem = updateMemoryStats(memBeforeGc, memAfterGc) - logger.log {gcTime, memBeforeGc, memAfterGc, deltaMem, gcInterval, CpuTimeBucket}, "global.gc() forced" - #Metrics.timing("memory.gc-time", gcTime) - Metrics.gauge("memory.gc-rss-freed", -deltaMem.rss) - Metrics.gauge("memory.gc-heaptotal-freed", -deltaMem.heapTotal) - Metrics.gauge("memory.gc-heapused-freed", -deltaMem.heapUsed) diff --git a/libraries/metrics/memory.js b/libraries/metrics/memory.js new file mode 100644 index 0000000000..a068cad71d --- /dev/null +++ b/libraries/metrics/memory.js @@ -0,0 +1,103 @@ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +// record memory usage each minute and run a periodic gc(), keeping cpu +// usage within allowable range of 1ms per minute. Also, dynamically +// adjust the period between gc()'s to reach a target of the gc saving +// 4 megabytes each time. + +let MemoryMonitor; +const oneMinute = 60 * 1000; +const oneMegaByte = 1024 * 1024; + +let CpuTimeBucket = 100; // current cpu time allowance in milliseconds +const CpuTimeBucketMax = 100; // maximum amount of cpu time allowed in bucket +const CpuTimeBucketRate = 10; // add this many milliseconds per minute + +let gcInterval = 1; // how many minutes between gc (parameter is dynamically adjusted) +let countSinceLastGc = 0; // how many minutes since last gc +const MemoryChunkSize = 4; // how many megabytes we need to free to consider gc worth doing + +const readyToGc = function() { + // update allowed cpu time + CpuTimeBucket = CpuTimeBucket + CpuTimeBucketRate; + CpuTimeBucket = CpuTimeBucket < CpuTimeBucketMax ? CpuTimeBucket : CpuTimeBucketMax; + // update counts since last gc + countSinceLastGc = countSinceLastGc + 1; + // check there is enough time since last gc and we have enough cpu + return (countSinceLastGc > gcInterval) && (CpuTimeBucket > 0); +}; + +const executeAndTime = function(fn) { + // time the execution of fn() and subtract from cpu allowance + const t0 = process.hrtime(); + fn(); + const dt = process.hrtime(t0); + const timeTaken = (dt[0] + (dt[1]*1e-9)) * 1e3; // in milliseconds + CpuTimeBucket -= Math.ceil(timeTaken); + return timeTaken; +}; + +const inMegaBytes = function(obj) { + // convert process.memoryUsage hash {rss,heapTotal,heapFreed} into megabytes + const result = {}; + for (let k in obj) { + const v = obj[k]; + result[k] = (v / oneMegaByte).toFixed(2); + } + return result; +}; + +const updateMemoryStats = function(oldMem, newMem) { + countSinceLastGc = 0; + const delta = {}; + for (let k in newMem) { + delta[k] = (newMem[k] - oldMem[k]).toFixed(2); + } + // take the max of all memory measures + const savedMemory = Math.max(-delta.rss, -delta.heapTotal, -delta.heapUsed); + delta.megabytesFreed = savedMemory; + // did it do any good? + if (savedMemory < MemoryChunkSize) { + gcInterval = gcInterval + 1; // no, so wait longer next time + } else { + gcInterval = Math.max(gcInterval - 1, 1); // yes, wait less time + } + return delta; +}; + +module.exports = (MemoryMonitor = { + monitor(logger) { + const interval = setInterval(() => MemoryMonitor.Check(logger) + , oneMinute); + const Metrics = require("./metrics"); + return Metrics.registerDestructor(() => clearInterval(interval)); + }, + + Check(logger) { + let mem; + const Metrics = require("./metrics"); + const memBeforeGc = (mem = inMegaBytes(process.memoryUsage())); + Metrics.gauge("memory.rss", mem.rss); + Metrics.gauge("memory.heaptotal", mem.heapTotal); + Metrics.gauge("memory.heapused", mem.heapUsed); + Metrics.gauge("memory.gc-interval", gcInterval); + //Metrics.gauge("memory.cpu-time-bucket", CpuTimeBucket) + + logger.log(mem, "process.memoryUsage()"); + + if ((global.gc != null) && readyToGc()) { + const gcTime = (executeAndTime(global.gc)).toFixed(2); + const memAfterGc = inMegaBytes(process.memoryUsage()); + const deltaMem = updateMemoryStats(memBeforeGc, memAfterGc); + logger.log({gcTime, memBeforeGc, memAfterGc, deltaMem, gcInterval, CpuTimeBucket}, "global.gc() forced"); + //Metrics.timing("memory.gc-time", gcTime) + Metrics.gauge("memory.gc-rss-freed", -deltaMem.rss); + Metrics.gauge("memory.gc-heaptotal-freed", -deltaMem.heapTotal); + return Metrics.gauge("memory.gc-heapused-freed", -deltaMem.heapUsed); + } + } +}); diff --git a/libraries/metrics/metrics.coffee b/libraries/metrics/metrics.coffee deleted file mode 100644 index 3aa40c8d25..0000000000 --- a/libraries/metrics/metrics.coffee +++ /dev/null @@ -1,140 +0,0 @@ -console.log("using prometheus") - -prom = require('./prom_wrapper') - -collectDefaultMetrics = prom.collectDefaultMetrics - -appname = "unknown" -hostname = require('os').hostname() - -destructors = [] - -require "./uv_threadpool_size" - -module.exports = Metrics = - register: prom.registry - - initialize: (_name, opts = {}) -> - appname = _name - collectDefaultMetrics({ timeout: 5000, prefix: Metrics.buildPromKey()}) - if opts.ttlInMinutes - prom.ttlInMinutes = opts.ttlInMinutes - - console.log("ENABLE_TRACE_AGENT set to #{process.env['ENABLE_TRACE_AGENT']}") - if process.env['ENABLE_TRACE_AGENT'] == "true" - console.log("starting google trace agent") - traceAgent = require('@google-cloud/trace-agent') - - traceOpts = - ignoreUrls: [/^\/status/, /^\/health_check/] - traceAgent.start(traceOpts) - - console.log("ENABLE_DEBUG_AGENT set to #{process.env['ENABLE_DEBUG_AGENT']}") - if process.env['ENABLE_DEBUG_AGENT'] == "true" - console.log("starting google debug agent") - debugAgent = require('@google-cloud/debug-agent') - debugAgent.start({ - allowExpressions: true, - serviceContext: { - service: appname, - version: process.env['BUILD_VERSION'] - } - }) - - console.log("ENABLE_PROFILE_AGENT set to #{process.env['ENABLE_PROFILE_AGENT']}") - if process.env['ENABLE_PROFILE_AGENT'] == "true" - console.log("starting google profile agent") - profiler = require('@google-cloud/profiler') - profiler.start({ - serviceContext: { - service: appname, - version: process.env['BUILD_VERSION'] - } - }) - - Metrics.inc("process_startup") - - registerDestructor: (func) -> - destructors.push func - - injectMetricsRoute: (app) -> - app.get('/metrics', (req, res) -> - res.set('Content-Type', prom.registry.contentType) - res.end(prom.registry.metrics()) - ) - - buildPromKey: (key = "")-> - key.replace /[^a-zA-Z0-9]/g, "_" - - sanitizeValue: (value) -> - parseFloat(value) - - set : (key, value, sampleRate = 1)-> - console.log("counts are not currently supported") - - inc : (key, sampleRate = 1, opts = {})-> - key = Metrics.buildPromKey(key) - opts.app = appname - opts.host = hostname - prom.metric('counter', key).inc(opts) - if process.env['DEBUG_METRICS'] - console.log("doing inc", key, opts) - - count : (key, count, sampleRate = 1, opts = {})-> - key = Metrics.buildPromKey(key) - opts.app = appname - opts.host = hostname - prom.metric('counter', key).inc(opts, count) - if process.env['DEBUG_METRICS'] - console.log("doing count/inc", key, opts) - - summary : (key, value, opts = {})-> - key = Metrics.buildPromKey(key) - opts.app = appname - opts.host = hostname - prom.metric('summary', key).observe(opts, value) - if process.env['DEBUG_METRICS'] - console.log("doing summary", key, value, opts) - - timing: (key, timeSpan, sampleRate, opts = {})-> - key = Metrics.buildPromKey("timer_" + key) - opts.app = appname - opts.host = hostname - prom.metric('summary', key).observe(opts, timeSpan) - if process.env['DEBUG_METRICS'] - console.log("doing timing", key, opts) - - Timer : class - constructor :(key, sampleRate = 1, opts)-> - this.start = new Date() - key = Metrics.buildPromKey(key) - this.key = key - this.sampleRate = sampleRate - this.opts = opts - - done:-> - timeSpan = new Date - this.start - Metrics.timing(this.key, timeSpan, this.sampleRate, this.opts) - return timeSpan - - gauge : (key, value, sampleRate = 1, opts)-> - key = Metrics.buildPromKey(key) - prom.metric('gauge', key).set({app: appname, host: hostname, status: opts?.status}, this.sanitizeValue(value)) - if process.env['DEBUG_METRICS'] - console.log("doing gauge", key, opts) - - globalGauge: (key, value, sampleRate = 1, opts)-> - key = Metrics.buildPromKey(key) - prom.metric('gauge', key).set({app: appname, status: opts?.status},this.sanitizeValue(value)) - - mongodb: require "./mongodb" - http: require "./http" - open_sockets: require "./open_sockets" - event_loop: require "./event_loop" - memory: require "./memory" - - timeAsyncMethod: require('./timeAsyncMethod') - - close: () -> - for func in destructors - func() diff --git a/libraries/metrics/metrics.js b/libraries/metrics/metrics.js new file mode 100644 index 0000000000..54950e0008 --- /dev/null +++ b/libraries/metrics/metrics.js @@ -0,0 +1,188 @@ +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +let Metrics; +console.log("using prometheus"); + +const prom = require('./prom_wrapper'); + +const { + collectDefaultMetrics +} = prom; + +let appname = "unknown"; +const hostname = require('os').hostname(); + +const destructors = []; + +require("./uv_threadpool_size"); + +module.exports = (Metrics = { + register: prom.registry, + + initialize(_name, opts) { + if (opts == null) { opts = {}; } + appname = _name; + collectDefaultMetrics({ timeout: 5000, prefix: Metrics.buildPromKey()}); + if (opts.ttlInMinutes) { + prom.ttlInMinutes = opts.ttlInMinutes; + } + + console.log(`ENABLE_TRACE_AGENT set to ${process.env['ENABLE_TRACE_AGENT']}`); + if (process.env['ENABLE_TRACE_AGENT'] === "true") { + console.log("starting google trace agent"); + const traceAgent = require('@google-cloud/trace-agent'); + + const traceOpts = + {ignoreUrls: [/^\/status/, /^\/health_check/]}; + traceAgent.start(traceOpts); + } + + console.log(`ENABLE_DEBUG_AGENT set to ${process.env['ENABLE_DEBUG_AGENT']}`); + if (process.env['ENABLE_DEBUG_AGENT'] === "true") { + console.log("starting google debug agent"); + const debugAgent = require('@google-cloud/debug-agent'); + debugAgent.start({ + allowExpressions: true, + serviceContext: { + service: appname, + version: process.env['BUILD_VERSION'] + } + }); + } + + console.log(`ENABLE_PROFILE_AGENT set to ${process.env['ENABLE_PROFILE_AGENT']}`); + if (process.env['ENABLE_PROFILE_AGENT'] === "true") { + console.log("starting google profile agent"); + const profiler = require('@google-cloud/profiler'); + profiler.start({ + serviceContext: { + service: appname, + version: process.env['BUILD_VERSION'] + } + }); + } + + return Metrics.inc("process_startup"); + }, + + registerDestructor(func) { + return destructors.push(func); + }, + + injectMetricsRoute(app) { + return app.get('/metrics', function(req, res) { + res.set('Content-Type', prom.registry.contentType); + return res.end(prom.registry.metrics()); + }); + }, + + buildPromKey(key){ + if (key == null) { key = ""; } + return key.replace(/[^a-zA-Z0-9]/g, "_"); + }, + + sanitizeValue(value) { + return parseFloat(value); + }, + + set(key, value, sampleRate){ + if (sampleRate == null) { sampleRate = 1; } + return console.log("counts are not currently supported"); + }, + + inc(key, sampleRate, opts){ + if (sampleRate == null) { sampleRate = 1; } + if (opts == null) { opts = {}; } + key = Metrics.buildPromKey(key); + opts.app = appname; + opts.host = hostname; + prom.metric('counter', key).inc(opts); + if (process.env['DEBUG_METRICS']) { + return console.log("doing inc", key, opts); + } + }, + + count(key, count, sampleRate, opts){ + if (sampleRate == null) { sampleRate = 1; } + if (opts == null) { opts = {}; } + key = Metrics.buildPromKey(key); + opts.app = appname; + opts.host = hostname; + prom.metric('counter', key).inc(opts, count); + if (process.env['DEBUG_METRICS']) { + return console.log("doing count/inc", key, opts); + } + }, + + summary(key, value, opts){ + if (opts == null) { opts = {}; } + key = Metrics.buildPromKey(key); + opts.app = appname; + opts.host = hostname; + prom.metric('summary', key).observe(opts, value); + if (process.env['DEBUG_METRICS']) { + return console.log("doing summary", key, value, opts); + } + }, + + timing(key, timeSpan, sampleRate, opts){ + if (opts == null) { opts = {}; } + key = Metrics.buildPromKey("timer_" + key); + opts.app = appname; + opts.host = hostname; + prom.metric('summary', key).observe(opts, timeSpan); + if (process.env['DEBUG_METRICS']) { + return console.log("doing timing", key, opts); + } + }, + + Timer : class { + constructor(key, sampleRate, opts){ + if (sampleRate == null) { sampleRate = 1; } + this.start = new Date(); + key = Metrics.buildPromKey(key); + this.key = key; + this.sampleRate = sampleRate; + this.opts = opts; + } + + done() { + const timeSpan = new Date - this.start; + Metrics.timing(this.key, timeSpan, this.sampleRate, this.opts); + return timeSpan; + } + }, + + gauge(key, value, sampleRate, opts){ + if (sampleRate == null) { sampleRate = 1; } + key = Metrics.buildPromKey(key); + prom.metric('gauge', key).set({app: appname, host: hostname, status: (opts != null ? opts.status : undefined)}, this.sanitizeValue(value)); + if (process.env['DEBUG_METRICS']) { + return console.log("doing gauge", key, opts); + } + }, + + globalGauge(key, value, sampleRate, opts){ + if (sampleRate == null) { sampleRate = 1; } + key = Metrics.buildPromKey(key); + return prom.metric('gauge', key).set({app: appname, status: (opts != null ? opts.status : undefined)},this.sanitizeValue(value)); + }, + + mongodb: require("./mongodb"), + http: require("./http"), + open_sockets: require("./open_sockets"), + event_loop: require("./event_loop"), + memory: require("./memory"), + + timeAsyncMethod: require('./timeAsyncMethod'), + + close() { + return Array.from(destructors).map((func) => + func()); + } +}); diff --git a/libraries/metrics/mongodb.coffee b/libraries/metrics/mongodb.coffee deleted file mode 100644 index 1f54cdde9a..0000000000 --- a/libraries/metrics/mongodb.coffee +++ /dev/null @@ -1,100 +0,0 @@ -module.exports = - monitor: (mongodb_require_path, logger) -> - - try - # for the v1 driver the methods to wrap are in the mongodb - # module in lib/mongodb/db.js - mongodb = require("#{mongodb_require_path}") - - try - # for the v2 driver the relevant methods are in the mongodb-core - # module in lib/topologies/{server,replset,mongos}.js - v2_path = mongodb_require_path.replace(/\/mongodb$/, '/mongodb-core') - mongodbCore = require(v2_path) - - Metrics = require("./metrics") - - monitorMethod = (base, method, type) -> - return unless base? - return unless (_method = base[method])? - arglen = _method.length - - mongo_driver_v1_wrapper = (db_command, options, callback) -> - if (typeof callback == 'undefined') - callback = options - options = {} - - collection = db_command.collectionName - if collection.match(/\$cmd$/) - # Ignore noisy command methods like authenticating, ismaster and ping - return _method.call this, db_command, options, callback - - key = "mongo-requests.#{collection}.#{type}" - if db_command.query? - query = Object.keys(db_command.query).sort().join("_") - key += "." + query - - timer = new Metrics.Timer("mongo", {collection: collection, query:query}) - start = new Date() - _method.call this, db_command, options, () -> - timer.done() - time = new Date() - start - logger.log - query: db_command.query - query_type: type - collection: collection - "response-time": new Date() - start - "mongo request" - callback.apply this, arguments - - mongo_driver_v2_wrapper = (ns, ops, options, callback) -> - if (typeof callback == 'undefined') - callback = options - options = {} - - if ns.match(/\$cmd$/) - # Ignore noisy command methods like authenticating, ismaster and ping - return _method.call this, ns, ops, options, callback - - key = "mongo-requests.#{ns}.#{type}" - if ops[0].q? # ops[0].q - query = Object.keys(ops[0].q).sort().join("_") - key += "." + query - - timer = new Metrics.Timer(key) - start = new Date() - _method.call this, ns, ops, options, () -> - timer.done() - time = new Date() - start - logger.log - query: ops[0].q - query_type: type - collection: ns - "response-time": new Date() - start - "mongo request" - callback.apply this, arguments - - if arglen == 3 - base[method] = mongo_driver_v1_wrapper - else if arglen == 4 - base[method] = mongo_driver_v2_wrapper - - monitorMethod(mongodb?.Db.prototype, "_executeQueryCommand", "query") - monitorMethod(mongodb?.Db.prototype, "_executeRemoveCommand", "remove") - monitorMethod(mongodb?.Db.prototype, "_executeInsertCommand", "insert") - monitorMethod(mongodb?.Db.prototype, "_executeUpdateCommand", "update") - - monitorMethod(mongodbCore?.Server.prototype, "command", "command") - monitorMethod(mongodbCore?.Server.prototype, "remove", "remove") - monitorMethod(mongodbCore?.Server.prototype, "insert", "insert") - monitorMethod(mongodbCore?.Server.prototype, "update", "update") - - monitorMethod(mongodbCore?.ReplSet.prototype, "command", "command") - monitorMethod(mongodbCore?.ReplSet.prototype, "remove", "remove") - monitorMethod(mongodbCore?.ReplSet.prototype, "insert", "insert") - monitorMethod(mongodbCore?.ReplSet.prototype, "update", "update") - - monitorMethod(mongodbCore?.Mongos.prototype, "command", "command") - monitorMethod(mongodbCore?.Mongos.prototype, "remove", "remove") - monitorMethod(mongodbCore?.Mongos.prototype, "insert", "insert") - monitorMethod(mongodbCore?.Mongos.prototype, "update", "update") diff --git a/libraries/metrics/mongodb.js b/libraries/metrics/mongodb.js new file mode 100644 index 0000000000..edec01e421 --- /dev/null +++ b/libraries/metrics/mongodb.js @@ -0,0 +1,128 @@ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +module.exports = { + monitor(mongodb_require_path, logger) { + + let mongodb, mongodbCore; + try { + // for the v1 driver the methods to wrap are in the mongodb + // module in lib/mongodb/db.js + mongodb = require(`${mongodb_require_path}`); + } catch (error) {} + + try { + // for the v2 driver the relevant methods are in the mongodb-core + // module in lib/topologies/{server,replset,mongos}.js + const v2_path = mongodb_require_path.replace(/\/mongodb$/, '/mongodb-core'); + mongodbCore = require(v2_path); + } catch (error1) {} + + const Metrics = require("./metrics"); + + const monitorMethod = function(base, method, type) { + let _method; + if (base == null) { return; } + if ((_method = base[method]) == null) { return; } + const arglen = _method.length; + + const mongo_driver_v1_wrapper = function(db_command, options, callback) { + let query; + if (typeof callback === 'undefined') { + callback = options; + options = {}; + } + + const collection = db_command.collectionName; + if (collection.match(/\$cmd$/)) { + // Ignore noisy command methods like authenticating, ismaster and ping + return _method.call(this, db_command, options, callback); + } + + let key = `mongo-requests.${collection}.${type}`; + if (db_command.query != null) { + query = Object.keys(db_command.query).sort().join("_"); + key += "." + query; + } + + const timer = new Metrics.Timer("mongo", {collection, query}); + const start = new Date(); + return _method.call(this, db_command, options, function() { + timer.done(); + const time = new Date() - start; + logger.log({ + query: db_command.query, + query_type: type, + collection, + "response-time": new Date() - start + }, + "mongo request"); + return callback.apply(this, arguments); + }); + }; + + const mongo_driver_v2_wrapper = function(ns, ops, options, callback) { + let query; + if (typeof callback === 'undefined') { + callback = options; + options = {}; + } + + if (ns.match(/\$cmd$/)) { + // Ignore noisy command methods like authenticating, ismaster and ping + return _method.call(this, ns, ops, options, callback); + } + + let key = `mongo-requests.${ns}.${type}`; + if (ops[0].q != null) { // ops[0].q + query = Object.keys(ops[0].q).sort().join("_"); + key += "." + query; + } + + const timer = new Metrics.Timer(key); + const start = new Date(); + return _method.call(this, ns, ops, options, function() { + timer.done(); + const time = new Date() - start; + logger.log({ + query: ops[0].q, + query_type: type, + collection: ns, + "response-time": new Date() - start + }, + "mongo request"); + return callback.apply(this, arguments); + }); + }; + + if (arglen === 3) { + return base[method] = mongo_driver_v1_wrapper; + } else if (arglen === 4) { + return base[method] = mongo_driver_v2_wrapper; + } + }; + + monitorMethod(mongodb != null ? mongodb.Db.prototype : undefined, "_executeQueryCommand", "query"); + monitorMethod(mongodb != null ? mongodb.Db.prototype : undefined, "_executeRemoveCommand", "remove"); + monitorMethod(mongodb != null ? mongodb.Db.prototype : undefined, "_executeInsertCommand", "insert"); + monitorMethod(mongodb != null ? mongodb.Db.prototype : undefined, "_executeUpdateCommand", "update"); + + monitorMethod(mongodbCore != null ? mongodbCore.Server.prototype : undefined, "command", "command"); + monitorMethod(mongodbCore != null ? mongodbCore.Server.prototype : undefined, "remove", "remove"); + monitorMethod(mongodbCore != null ? mongodbCore.Server.prototype : undefined, "insert", "insert"); + monitorMethod(mongodbCore != null ? mongodbCore.Server.prototype : undefined, "update", "update"); + + monitorMethod(mongodbCore != null ? mongodbCore.ReplSet.prototype : undefined, "command", "command"); + monitorMethod(mongodbCore != null ? mongodbCore.ReplSet.prototype : undefined, "remove", "remove"); + monitorMethod(mongodbCore != null ? mongodbCore.ReplSet.prototype : undefined, "insert", "insert"); + monitorMethod(mongodbCore != null ? mongodbCore.ReplSet.prototype : undefined, "update", "update"); + + monitorMethod(mongodbCore != null ? mongodbCore.Mongos.prototype : undefined, "command", "command"); + monitorMethod(mongodbCore != null ? mongodbCore.Mongos.prototype : undefined, "remove", "remove"); + monitorMethod(mongodbCore != null ? mongodbCore.Mongos.prototype : undefined, "insert", "insert"); + return monitorMethod(mongodbCore != null ? mongodbCore.Mongos.prototype : undefined, "update", "update"); + } +}; diff --git a/libraries/metrics/open_sockets.coffee b/libraries/metrics/open_sockets.coffee deleted file mode 100644 index 9af019dfc8..0000000000 --- a/libraries/metrics/open_sockets.coffee +++ /dev/null @@ -1,28 +0,0 @@ -URL = require "url" -seconds = 1000 - -# In Node 0.10 the default is 5, which means only 5 open connections at one. -# Node 0.12 has a default of Infinity. Make sure we have no limit set, -# regardless of Node version. -require("http").globalAgent.maxSockets = Infinity -require("https").globalAgent.maxSockets = Infinity - -module.exports = OpenSocketsMonitor = - monitor: (logger) -> - interval = setInterval () -> - OpenSocketsMonitor.gaugeOpenSockets() - , 5 * seconds - Metrics = require "./metrics" - Metrics.registerDestructor () -> - clearInterval(interval) - - gaugeOpenSockets: () -> - Metrics = require "./metrics" - for url, agents of require('http').globalAgent.sockets - url = URL.parse("http://#{url}") - hostname = url.hostname?.replace(/\./g, "_") - Metrics.gauge "open_connections.http.#{hostname}", agents.length - for url, agents of require('https').globalAgent.sockets - url = URL.parse("https://#{url}") - hostname = url.hostname?.replace(/\./g, "_") - Metrics.gauge "open_connections.https.#{hostname}", agents.length diff --git a/libraries/metrics/open_sockets.js b/libraries/metrics/open_sockets.js new file mode 100644 index 0000000000..3232a8a851 --- /dev/null +++ b/libraries/metrics/open_sockets.js @@ -0,0 +1,48 @@ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * DS205: Consider reworking code to avoid use of IIFEs + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +let OpenSocketsMonitor; +const URL = require("url"); +const seconds = 1000; + +// In Node 0.10 the default is 5, which means only 5 open connections at one. +// Node 0.12 has a default of Infinity. Make sure we have no limit set, +// regardless of Node version. +require("http").globalAgent.maxSockets = Infinity; +require("https").globalAgent.maxSockets = Infinity; + +module.exports = (OpenSocketsMonitor = { + monitor(logger) { + const interval = setInterval(() => OpenSocketsMonitor.gaugeOpenSockets() + , 5 * seconds); + const Metrics = require("./metrics"); + return Metrics.registerDestructor(() => clearInterval(interval)); + }, + + gaugeOpenSockets() { + let agents, hostname, url; + const Metrics = require("./metrics"); + const object = require('http').globalAgent.sockets; + for (url in object) { + agents = object[url]; + url = URL.parse(`http://${url}`); + hostname = url.hostname != null ? url.hostname.replace(/\./g, "_") : undefined; + Metrics.gauge(`open_connections.http.${hostname}`, agents.length); + } + return (() => { + const result = []; + const object1 = require('https').globalAgent.sockets; + for (url in object1) { + agents = object1[url]; + url = URL.parse(`https://${url}`); + hostname = url.hostname != null ? url.hostname.replace(/\./g, "_") : undefined; + result.push(Metrics.gauge(`open_connections.https.${hostname}`, agents.length)); + } + return result; + })(); + } +}); diff --git a/libraries/metrics/prom_wrapper.coffee b/libraries/metrics/prom_wrapper.coffee deleted file mode 100644 index 690838a4a2..0000000000 --- a/libraries/metrics/prom_wrapper.coffee +++ /dev/null @@ -1,114 +0,0 @@ -prom = require('prom-client') -registry = require('prom-client').register -metrics = new Map() - - -optsKey = (opts) -> - keys = Object.keys(opts) - return '' if keys.length == 0 - - keys = keys.sort() - - hash = ''; - for key in keys - hash += "," if hash.length - hash += "#{key}:#{opts[key]}" - - return hash - -extendOpts = (opts, labelNames) -> - for label in labelNames - opts[label] ||= '' - return opts - -optsAsArgs = (opts, labelNames) -> - args = [] - for label in labelNames - args.push(opts[label] || '') - return args - - -PromWrapper = - ttlInMinutes: 0 - registry: registry - - metric: (type, name) -> - metrics.get(name) || new MetricWrapper(type, name) - - collectDefaultMetrics: prom.collectDefaultMetrics - - -class MetricWrapper - constructor: (type, name) -> - metrics.set(name, this) - @name = name - @instances = new Map() - @lastAccess = new Date() - @metric = switch type - when "counter" - new prom.Counter({ - name: name, - help: name, - labelNames: ['app','host','status','method', 'path'] - }) - when "summary" - new prom.Summary({ - name: name, - help: name, - maxAgeSeconds: 60, - ageBuckets: 10, - labelNames: ['app', 'host', 'path', 'status_code', 'method', 'collection', 'query'] - }) - when "gauge" - new prom.Gauge({ - name: name, - help: name, - labelNames: ['app','host', 'status'] - }) - - inc: (opts, value) -> - @_execMethod 'inc', opts, value - - observe: (opts, value) -> - @_execMethod 'observe', opts, value - - set: (opts, value) -> - @_execMethod 'set', opts, value - - sweep: () -> - thresh = new Date(Date.now() - 1000 * 60 * PromWrapper.ttlInMinutes) - @instances.forEach (instance, key) => - if thresh > instance.time - if process.env['DEBUG_METRICS'] - console.log("Sweeping stale metric instance", @name, opts: instance.opts, key) - @metric.remove(optsAsArgs(instance.opts, @metric.labelNames)...) - - if thresh > @lastAccess - if process.env['DEBUG_METRICS'] - console.log("Sweeping stale metric", @name, thresh, @lastAccess) - metrics.delete(@name) - registry.removeSingleMetric(@name) - - _execMethod: (method, opts, value) -> - opts = extendOpts(opts, @metric.labelNames) - key = optsKey(opts) - @instances.set(key, { time: new Date(), opts }) unless key == '' - @lastAccess = new Date() - @metric[method](opts, value) - - -unless PromWrapper.sweepRegistered - if process.env['DEBUG_METRICS'] - console.log("Registering sweep method") - PromWrapper.sweepRegistered = true - setInterval( - () -> - if PromWrapper.ttlInMinutes - if process.env['DEBUG_METRICS'] - console.log("Sweeping metrics") - metrics.forEach (metric, key) => - metric.sweep() - 60000) - - -module.exports = PromWrapper diff --git a/libraries/metrics/prom_wrapper.js b/libraries/metrics/prom_wrapper.js new file mode 100644 index 0000000000..64870ef746 --- /dev/null +++ b/libraries/metrics/prom_wrapper.js @@ -0,0 +1,148 @@ +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS205: Consider reworking code to avoid use of IIFEs + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const prom = require('prom-client'); +const registry = require('prom-client').register; +const metrics = new Map(); + + +const optsKey = function(opts) { + let keys = Object.keys(opts); + if (keys.length === 0) { return ''; } + + keys = keys.sort(); + + let hash = ''; + for (let key of Array.from(keys)) { + if (hash.length) { hash += ","; } + hash += `${key}:${opts[key]}`; + } + + return hash; +}; + +const extendOpts = function(opts, labelNames) { + for (let label of Array.from(labelNames)) { + if (!opts[label]) { opts[label] = ''; } + } + return opts; +}; + +const optsAsArgs = function(opts, labelNames) { + const args = []; + for (let label of Array.from(labelNames)) { + args.push(opts[label] || ''); + } + return args; +}; + + +const PromWrapper = { + ttlInMinutes: 0, + registry, + + metric(type, name) { + return metrics.get(name) || new MetricWrapper(type, name); + }, + + collectDefaultMetrics: prom.collectDefaultMetrics +}; + + +class MetricWrapper { + constructor(type, name) { + metrics.set(name, this); + this.name = name; + this.instances = new Map(); + this.lastAccess = new Date(); + this.metric = (() => { switch (type) { + case "counter": + return new prom.Counter({ + name, + help: name, + labelNames: ['app','host','status','method', 'path'] + }); + case "summary": + return new prom.Summary({ + name, + help: name, + maxAgeSeconds: 60, + ageBuckets: 10, + labelNames: ['app', 'host', 'path', 'status_code', 'method', 'collection', 'query'] + }); + case "gauge": + return new prom.Gauge({ + name, + help: name, + labelNames: ['app','host', 'status'] + }); + } })(); + } + + inc(opts, value) { + return this._execMethod('inc', opts, value); + } + + observe(opts, value) { + return this._execMethod('observe', opts, value); + } + + set(opts, value) { + return this._execMethod('set', opts, value); + } + + sweep() { + const thresh = new Date(Date.now() - (1000 * 60 * PromWrapper.ttlInMinutes)); + this.instances.forEach((instance, key) => { + if (thresh > instance.time) { + if (process.env['DEBUG_METRICS']) { + console.log("Sweeping stale metric instance", this.name, {opts: instance.opts}, key); + } + return this.metric.remove(...Array.from(optsAsArgs(instance.opts, this.metric.labelNames) || [])); + } + }); + + if (thresh > this.lastAccess) { + if (process.env['DEBUG_METRICS']) { + console.log("Sweeping stale metric", this.name, thresh, this.lastAccess); + } + metrics.delete(this.name); + return registry.removeSingleMetric(this.name); + } + } + + _execMethod(method, opts, value) { + opts = extendOpts(opts, this.metric.labelNames); + const key = optsKey(opts); + if (key !== '') { this.instances.set(key, { time: new Date(), opts }); } + this.lastAccess = new Date(); + return this.metric[method](opts, value); + } +} + + +if (!PromWrapper.sweepRegistered) { + if (process.env['DEBUG_METRICS']) { + console.log("Registering sweep method"); + } + PromWrapper.sweepRegistered = true; + setInterval( + function() { + if (PromWrapper.ttlInMinutes) { + if (process.env['DEBUG_METRICS']) { + console.log("Sweeping metrics"); + } + return metrics.forEach((metric, key) => { + return metric.sweep(); + }); + } + }, + 60000); +} + + +module.exports = PromWrapper; diff --git a/libraries/metrics/test/unit/coffee/event_loop.coffee b/libraries/metrics/test/unit/coffee/event_loop.coffee deleted file mode 100644 index 19e79cbe9a..0000000000 --- a/libraries/metrics/test/unit/coffee/event_loop.coffee +++ /dev/null @@ -1,34 +0,0 @@ -require('coffee-script') -chai = require('chai') -should = chai.should() -expect = chai.expect -path = require('path') -modulePath = path.join __dirname, '../../../event_loop.coffee' -SandboxedModule = require('sandboxed-module') -sinon = require("sinon") - -describe 'event_loop', -> - - before -> - @metrics = { - timing: sinon.stub() - registerDestructor: sinon.stub() - } - @logger = { - warn: sinon.stub() - } - @event_loop = SandboxedModule.require modulePath, requires: - './metrics': @metrics - - describe 'with a logger provided', -> - before -> - @event_loop.monitor(@logger) - - it 'should register a destructor with metrics', -> - @metrics.registerDestructor.called.should.equal true - - describe 'without a logger provided', -> - - it 'should throw an exception', -> - expect(@event_loop.monitor).to.throw('logger is undefined') - diff --git a/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee b/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee deleted file mode 100644 index 67348e8ea1..0000000000 --- a/libraries/metrics/test/unit/coffee/timeAsyncMethodTests.coffee +++ /dev/null @@ -1,126 +0,0 @@ -require('coffee-script') -chai = require('chai') -should = chai.should() -expect = chai.expect -path = require('path') -modulePath = path.join __dirname, '../../../timeAsyncMethod.coffee' -SandboxedModule = require('sandboxed-module') -sinon = require("sinon") - - -describe 'timeAsyncMethod', -> - - beforeEach -> - @Timer = {done: sinon.stub()} - @TimerConstructor = sinon.stub().returns(@Timer) - @metrics = { - Timer: @TimerConstructor - inc: sinon.stub() - } - @timeAsyncMethod = SandboxedModule.require modulePath, requires: - './metrics': @metrics - - @testObject = { - nextNumber: (n, callback=(err, result)->) -> - setTimeout( - () -> - callback(null, n+1) - , 100 - ) - } - - it 'should have the testObject behave correctly before wrapping', (done) -> - @testObject.nextNumber 2, (err, result) -> - expect(err).to.not.exist - expect(result).to.equal 3 - done() - - it 'should wrap method without error', (done) -> - @timeAsyncMethod @testObject, 'nextNumber', 'someContext.TestObject' - done() - - it 'should transparently wrap method invocation in timer', (done) -> - @timeAsyncMethod @testObject, 'nextNumber', 'someContext.TestObject' - @testObject.nextNumber 2, (err, result) => - expect(err).to.not.exist - expect(result).to.equal 3 - expect(@TimerConstructor.callCount).to.equal 1 - expect(@Timer.done.callCount).to.equal 1 - done() - - it 'should increment success count', (done) -> - @metrics.inc = sinon.stub() - @timeAsyncMethod @testObject, 'nextNumber', 'someContext.TestObject' - @testObject.nextNumber 2, (err, result) => - expect(@metrics.inc.callCount).to.equal 1 - expect(@metrics.inc.calledWith('someContext_result', 1, { method: 'TestObject_nextNumber', status: 'success'})).to.equal true - done() - - describe 'when base method produces an error', -> - beforeEach -> - @metrics.inc = sinon.stub() - @testObject.nextNumber = (n, callback=(err, result)->) -> - setTimeout( - () -> - callback(new Error('woops')) - , 100 - ) - - it 'should propagate the error transparently', (done) -> - @timeAsyncMethod @testObject, 'nextNumber', 'someContext.TestObject' - @testObject.nextNumber 2, (err, result) => - expect(err).to.exist - expect(err).to.be.instanceof Error - expect(result).to.not.exist - done() - - it 'should increment failure count', (done) -> - @timeAsyncMethod @testObject, 'nextNumber', 'someContext.TestObject' - @testObject.nextNumber 2, (err, result) => - expect(@metrics.inc.callCount).to.equal 1 - expect(@metrics.inc.calledWith('someContext_result', 1, { method: 'TestObject_nextNumber', status: 'failed'})).to.equal true - done() - - describe 'when a logger is supplied', -> - beforeEach -> - @logger = {log: sinon.stub()} - - it 'should also call logger.log', (done) -> - @timeAsyncMethod @testObject, 'nextNumber', 'someContext.TestObject', @logger - @testObject.nextNumber 2, (err, result) => - expect(err).to.not.exist - expect(result).to.equal 3 - expect(@TimerConstructor.callCount).to.equal 1 - expect(@Timer.done.callCount).to.equal 1 - expect(@logger.log.callCount).to.equal 1 - done() - - describe 'when the wrapper cannot be applied', -> - beforeEach -> - - it 'should raise an error', -> - badWrap = () => - @timeAsyncMethod @testObject, 'DEFINITELY_NOT_A_REAL_METHOD', 'someContext.TestObject' - expect(badWrap).to.throw( - /^.*expected object property 'DEFINITELY_NOT_A_REAL_METHOD' to be a function.*$/ - ) - - describe 'when the wrapped function is not using a callback', -> - beforeEach -> - @realMethod = sinon.stub().returns(42) - @testObject.nextNumber = @realMethod - - it 'should not throw an error', -> - @timeAsyncMethod @testObject, 'nextNumber', 'someContext.TestObject' - badCall = () => - @testObject.nextNumber 2 - expect(badCall).to.not.throw(Error) - - it 'should call the underlying method', -> - @timeAsyncMethod @testObject, 'nextNumber', 'someContext.TestObject' - result = @testObject.nextNumber(12) - expect(@realMethod.callCount).to.equal 1 - expect(@realMethod.calledWith(12)).to.equal true - expect(result).to.equal 42 - - diff --git a/libraries/metrics/timeAsyncMethod.coffee b/libraries/metrics/timeAsyncMethod.coffee deleted file mode 100644 index 8d6099d826..0000000000 --- a/libraries/metrics/timeAsyncMethod.coffee +++ /dev/null @@ -1,44 +0,0 @@ - -module.exports = (obj, methodName, prefix, logger) -> - metrics = require('./metrics') - - if typeof obj[methodName] != 'function' - throw new Error("[Metrics] expected object property '#{methodName}' to be a function") - - key = "#{prefix}.#{methodName}" - - realMethod = obj[methodName] - - splitPrefix = prefix.split(".") - startPrefix = splitPrefix[0] - - if splitPrefix[1]? - modifedMethodName = "#{splitPrefix[1]}_#{methodName}" - else - modifedMethodName = methodName - obj[methodName] = (originalArgs...) -> - - [firstArgs..., callback] = originalArgs - - if !callback? || typeof callback != 'function' - if logger? - logger.log "[Metrics] expected wrapped method '#{methodName}' to be invoked with a callback" - return realMethod.apply this, originalArgs - - timer = new metrics.Timer(startPrefix, 1, {method: modifedMethodName}) - - realMethod.call this, firstArgs..., (callbackArgs...) -> - elapsedTime = timer.done() - possibleError = callbackArgs[0] - if possibleError? - metrics.inc "#{startPrefix}_result", 1, {status:"failed", method: modifedMethodName} - else - metrics.inc "#{startPrefix}_result", 1, {status:"success", method: modifedMethodName} - if logger? - loggableArgs = {} - try - for arg, idx in firstArgs - if arg.toString().match(/^[0-9a-f]{24}$/) - loggableArgs["#{idx}"] = arg - logger.log {key, args: loggableArgs, elapsedTime}, "[Metrics] timed async method call" - callback.apply this, callbackArgs diff --git a/libraries/metrics/timeAsyncMethod.js b/libraries/metrics/timeAsyncMethod.js new file mode 100644 index 0000000000..ddb2149859 --- /dev/null +++ b/libraries/metrics/timeAsyncMethod.js @@ -0,0 +1,66 @@ +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS201: Simplify complex destructure assignments + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ + +module.exports = function(obj, methodName, prefix, logger) { + let modifedMethodName; + const metrics = require('./metrics'); + + if (typeof obj[methodName] !== 'function') { + throw new Error(`[Metrics] expected object property '${methodName}' to be a function`); + } + + const key = `${prefix}.${methodName}`; + + const realMethod = obj[methodName]; + + const splitPrefix = prefix.split("."); + const startPrefix = splitPrefix[0]; + + if (splitPrefix[1] != null) { + modifedMethodName = `${splitPrefix[1]}_${methodName}`; + } else { + modifedMethodName = methodName; + } + return obj[methodName] = function(...originalArgs) { + + const adjustedLength = Math.max(originalArgs.length, 1), firstArgs = originalArgs.slice(0, adjustedLength - 1), callback = originalArgs[adjustedLength - 1]; + + if ((callback == null) || (typeof callback !== 'function')) { + if (logger != null) { + logger.log(`[Metrics] expected wrapped method '${methodName}' to be invoked with a callback`); + } + return realMethod.apply(this, originalArgs); + } + + const timer = new metrics.Timer(startPrefix, 1, {method: modifedMethodName}); + + return realMethod.call(this, ...Array.from(firstArgs), function(...callbackArgs) { + const elapsedTime = timer.done(); + const possibleError = callbackArgs[0]; + if (possibleError != null) { + metrics.inc(`${startPrefix}_result`, 1, {status:"failed", method: modifedMethodName}); + } else { + metrics.inc(`${startPrefix}_result`, 1, {status:"success", method: modifedMethodName}); + } + if (logger != null) { + const loggableArgs = {}; + try { + for (let idx = 0; idx < firstArgs.length; idx++) { + const arg = firstArgs[idx]; + if (arg.toString().match(/^[0-9a-f]{24}$/)) { + loggableArgs[`${idx}`] = arg; + } + } + } catch (error) {} + logger.log({key, args: loggableArgs, elapsedTime}, "[Metrics] timed async method call"); + } + return callback.apply(this, callbackArgs); + }); + }; +}; diff --git a/libraries/metrics/uv_threadpool_size.coffee b/libraries/metrics/uv_threadpool_size.coffee deleted file mode 100644 index 36b7466248..0000000000 --- a/libraries/metrics/uv_threadpool_size.coffee +++ /dev/null @@ -1,3 +0,0 @@ -unless process.env.UV_THREADPOOL_SIZE - process.env.UV_THREADPOOL_SIZE=16 - console.log "Set UV_THREADPOOL_SIZE=#{process.env.UV_THREADPOOL_SIZE}" diff --git a/libraries/metrics/uv_threadpool_size.js b/libraries/metrics/uv_threadpool_size.js new file mode 100644 index 0000000000..bc8204e0b1 --- /dev/null +++ b/libraries/metrics/uv_threadpool_size.js @@ -0,0 +1,4 @@ +if (!process.env.UV_THREADPOOL_SIZE) { + process.env.UV_THREADPOOL_SIZE=16; + console.log(`Set UV_THREADPOOL_SIZE=${process.env.UV_THREADPOOL_SIZE}`); +} From a0f856cff234843591f81056820033720059e989 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Fri, 17 Jul 2020 16:17:18 +0100 Subject: [PATCH 147/182] fix tests --- libraries/metrics/.gitignore | 1 - libraries/metrics/package-lock.json | 1574 ++++++++++------- libraries/metrics/package.json | 17 +- libraries/metrics/test/unit/js/event_loop.js | 47 + .../test/unit/js/timeAsyncMethodTests.js | 163 ++ 5 files changed, 1167 insertions(+), 635 deletions(-) create mode 100644 libraries/metrics/test/unit/js/event_loop.js create mode 100644 libraries/metrics/test/unit/js/timeAsyncMethodTests.js diff --git a/libraries/metrics/.gitignore b/libraries/metrics/.gitignore index faba053aed..3c3629e647 100644 --- a/libraries/metrics/.gitignore +++ b/libraries/metrics/.gitignore @@ -1,2 +1 @@ node_modules -test/unit/js/* diff --git a/libraries/metrics/package-lock.json b/libraries/metrics/package-lock.json index 4477cd1f40..f38eb81cf8 100644 --- a/libraries/metrics/package-lock.json +++ b/libraries/metrics/package-lock.json @@ -7,7 +7,7 @@ "@google-cloud/common": { "version": "0.32.1", "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-0.32.1.tgz", - "integrity": "sha512-bLdPzFvvBMtVkwsoBtygE9oUm3yrNmPa71gvOgucYI/GqvNP2tb6RYsDHPq98kvignhcgHGDI5wyNgxaCo8bKQ==", + "integrity": "sha1-ajLDQBcs6j22Z00ODjTnh0CgBz8=", "requires": { "@google-cloud/projectify": "^0.3.3", "@google-cloud/promisify": "^0.4.0", @@ -25,7 +25,7 @@ "@google-cloud/debug-agent": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/@google-cloud/debug-agent/-/debug-agent-3.2.0.tgz", - "integrity": "sha512-fP87kYbS6aeDna08BivwQ1J260mwJGchRi99XdWCgqbRwuFac8ul0OT5i2wEeDSc5QaDX8ZuWQQ0igZvh1rTyQ==", + "integrity": "sha1-2qdjWhaYpWY31dxXzhED536uKdM=", "requires": { "@google-cloud/common": "^0.32.0", "@sindresorhus/is": "^0.15.0", @@ -53,7 +53,7 @@ "@google-cloud/profiler": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/@google-cloud/profiler/-/profiler-0.2.3.tgz", - "integrity": "sha512-rNvtrFtIebIxZEJ/O0t8n7HciZGIXBo8DvHxWqAmsCaeLvkTtsaL6HmPkwxrNQ1IhbYWAxF+E/DwCiHyhKmgTg==", + "integrity": "sha1-Fj3738Mwuug1X+RuHlvgZTV7H1w=", "requires": { "@google-cloud/common": "^0.26.0", "@types/console-log-level": "^1.4.0", @@ -75,7 +75,7 @@ "@google-cloud/common": { "version": "0.26.2", "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-0.26.2.tgz", - "integrity": "sha512-xJ2M/q3MrUbnYZuFlpF01caAlEhAUoRn0NXp93Hn3pkFpfSOG8YfbKbpBAHvcKVbBOAKVIwPsleNtuyuabUwLQ==", + "integrity": "sha1-nFTiRxqEqgMelaJIJJduCA8lVkU=", "requires": { "@google-cloud/projectify": "^0.3.2", "@google-cloud/promisify": "^0.3.0", @@ -94,7 +94,7 @@ "@google-cloud/promisify": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-0.3.1.tgz", - "integrity": "sha512-QzB0/IMvB0eFxFK7Eqh+bfC8NLv3E9ScjWQrPOk6GgfNroxcVITdTlT8NRsRrcp5+QQJVPLkRqKG0PUdaWXmHw==" + "integrity": "sha1-9kHm2USo4KBe4MsQkd+mAIm+zbo=" }, "arrify": { "version": "1.0.1", @@ -104,7 +104,7 @@ "gcp-metadata": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-0.9.3.tgz", - "integrity": "sha512-caV4S84xAjENtpezLCT/GILEAF5h/bC4cNqZFmt/tjTn8t+JBtTkQrgBrJu3857YdsnlM8rxX/PMcKGtE8hUlw==", + "integrity": "sha1-H510lfdGChRSZIHynhFZbdVj3SY=", "requires": { "gaxios": "^1.0.2", "json-bigint": "^0.3.0" @@ -113,7 +113,7 @@ "google-auth-library": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-2.0.2.tgz", - "integrity": "sha512-FURxmo1hBVmcfLauuMRKOPYAPKht3dGuI2wjeJFalDUThO0HoYVjr4yxt5cgYSFm1dgUpmN9G/poa7ceTFAIiA==", + "integrity": "sha1-ejFdIDZ0Svavyth7IQ7mY4tA9Xs=", "requires": { "axios": "^0.18.0", "gcp-metadata": "^0.7.0", @@ -127,7 +127,7 @@ "gcp-metadata": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-0.7.0.tgz", - "integrity": "sha512-ffjC09amcDWjh3VZdkDngIo7WoluyC5Ag9PAYxZbmQLOLNI8lvPtoKTSCyU54j2gwy5roZh6sSMTfkY2ct7K3g==", + "integrity": "sha1-bDXbtSvaMqQnu5yY9UI33dG1QG8=", "requires": { "axios": "^0.18.0", "extend": "^3.0.1", @@ -146,17 +146,17 @@ "@google-cloud/projectify": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-0.3.3.tgz", - "integrity": "sha512-7522YHQ4IhaafgSunsFF15nG0TGVmxgXidy9cITMe+256RgqfcrfWphiMufW+Ou4kqagW/u3yxwbzVEW3dk2Uw==" + "integrity": "sha1-vekQPVCyCj6jM334xng6dm5w1B0=" }, "@google-cloud/promisify": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-0.4.0.tgz", - "integrity": "sha512-4yAHDC52TEMCNcMzVC8WlqnKKKq+Ssi2lXoUg9zWWkZ6U6tq9ZBRYLHHCRdfU+EU9YJsVmivwGcKYCjRGjnf4Q==" + "integrity": "sha1-T7/PTYW7ai5MzwWqY9KxDWyarZs=" }, "@google-cloud/trace-agent": { "version": "3.6.1", "resolved": "https://registry.npmjs.org/@google-cloud/trace-agent/-/trace-agent-3.6.1.tgz", - "integrity": "sha512-KDo85aPN4gSxJ7oEIOlKd7aGENZFXAM1kbIn1Ds+61gh/K1CQWSyepgJo3nUpAwH6D1ezDWV7Iaf8ueoITc8Uw==", + "integrity": "sha1-W+dEE5TQ6ldY8o25IqUAT/PwO+w=", "requires": { "@google-cloud/common": "^0.32.1", "builtin-modules": "^3.0.0", @@ -181,12 +181,12 @@ "@protobufjs/base64": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + "integrity": "sha1-TIVzDlm5ofHzSQR9vyQpYDS7JzU=" }, "@protobufjs/codegen": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + "integrity": "sha1-fvN/DQEPsCitGtWXIuUG2SYoFcs=" }, "@protobufjs/eventemitter": { "version": "1.1.0", @@ -230,20 +230,22 @@ "@sindresorhus/is": { "version": "0.15.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.15.0.tgz", - "integrity": "sha512-lu8BpxjAtRCAo5ifytTpCPCj99LF7o/2Myn+NXyNCBqvPYn7Pjd76AMmUB5l7XF1U6t0hcWrlEM5ESufW7wAeA==" + "integrity": "sha1-lpFbqgXmpqHRN7rfSYTT/AWCC7Y=" }, "@sinonjs/commons": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.7.1.tgz", - "integrity": "sha512-Debi3Baff1Qu1Unc3mjJ96MgpbwTn43S1+9yJ0llWygPwDNu2aaWBD6yc9y/Z8XDRNhx7U+u2UDg2OGQXkclUQ==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz", + "integrity": "sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==", + "dev": true, "requires": { "type-detect": "4.0.8" } }, "@sinonjs/fake-timers": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.0.tgz", - "integrity": "sha512-atR1J/jRXvQAb47gfzSK8zavXy7BcpnYq21ALon0U99etu99vsir0trzIO3wpeLtW+LLVY6X7EkfVTbjGSH8Ww==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", + "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", + "dev": true, "requires": { "@sinonjs/commons": "^1.7.0" } @@ -252,6 +254,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-5.0.1.tgz", "integrity": "sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==", + "dev": true, "requires": { "@sinonjs/commons": "^1", "@sinonjs/samsam": "^5.0.2" @@ -261,6 +264,7 @@ "version": "5.0.3", "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.0.3.tgz", "integrity": "sha512-QucHkc2uMJ0pFGjJUDP3F9dq5dx8QIaqISl9QgwLOh6P9yv877uONPGXh/OH/0zmM3tW1JjuJltAZV2l7zU+uQ==", + "dev": true, "requires": { "@sinonjs/commons": "^1.6.0", "lodash.get": "^4.4.2", @@ -270,22 +274,23 @@ "@sinonjs/text-encoding": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", - "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==" + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", + "dev": true }, "@types/caseless": { "version": "0.12.2", "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", - "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==" + "integrity": "sha1-9l09Y4ngHutFi9VNyPUrlalGO8g=" }, "@types/console-log-level": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@types/console-log-level/-/console-log-level-1.4.0.tgz", - "integrity": "sha512-x+OscEQwcx5Biair4enH7ov9W+clcqUWaZRaxn5IkT4yNWWjRr2oiYDkY/x1uXSTVZOQ2xlbFQySaQGB+VdXGQ==" + "integrity": "sha1-7/ccQa689RyLpa2LBdfVQkviuPM=" }, "@types/duplexify": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/@types/duplexify/-/duplexify-3.6.0.tgz", - "integrity": "sha512-5zOA53RUlzN74bvrSGwjudssD9F3a797sDZQkiYpUOxW+WHaXTCPz4/d5Dgi6FKnOqZ2CpaTo0DhgIfsXAOE/A==", + "integrity": "sha1-38grZL06IWj1vSZESvFlvwI33Ng=", "requires": { "@types/node": "*" } @@ -314,23 +319,17 @@ "@types/semver": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-41qEJgBH/TWgo5NFSvBCJ1qkoi3Q6ONSF2avrHq1LVEZfYpdHmj0y9SuTK+u9ZhG1sYQKBL1AWXKyLWP4RaUoQ==" + "integrity": "sha1-FGwqKe59O65L8vyydGNuJkyBPEU=" }, "@types/tough-cookie": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.6.tgz", "integrity": "sha512-wHNBMnkoEBiRAd3s8KTKwIuO9biFtTf0LehITzBhSco+HQI0xkXZbLOD55SW3Aqw3oUkHstkm5SPv58yaAdFPQ==" }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, "abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "integrity": "sha1-6vVNU7YrrkE46AnKIlyEOabvs5I=", "requires": { "event-target-shim": "^5.0.0" } @@ -343,67 +342,78 @@ "agent-base": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "integrity": "sha1-gWXwHENgCbzK0LHRIvBe13Dvxu4=", "requires": { "es6-promisify": "^5.0.0" } }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, "ansi-regex": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz", - "integrity": "sha1-DY6UaWej2BQ/k+JOKYUl/BsiNfk=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, "ansi-styles": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz", - "integrity": "sha1-6uy/Zs1waIJ2Cy9GkVgrj1XXp94=", - "dev": true - }, - "argparse": { - "version": "0.1.16", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-0.1.16.tgz", - "integrity": "sha1-z9AeD7uj1srtBJ+9dY1A9lGW9Xw=", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "underscore": "~1.7.0", - "underscore.string": "~2.4.0" - }, - "dependencies": { - "underscore": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", - "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=", - "dev": true - }, - "underscore.string": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.4.0.tgz", - "integrity": "sha1-jN2PusTi0uoefi6Al8QvRCKA+Fs=", - "dev": true - } + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array.prototype.map": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.2.tgz", + "integrity": "sha512-Az3OYxgsa1g7xDYp86l0nnN4bcmuEITGe1rbdEBVkrqkzMgDcbdQ2R7r41pNzti+4NMces3H8gMmuioZUilLgw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.4" } }, "arrify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", - "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" + "integrity": "sha1-yWVekzHgq81YjSp8rX6ZVvZnAfo=" }, "assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==" - }, - "async": { - "version": "0.1.22", - "resolved": "https://registry.npmjs.org/async/-/async-0.1.22.tgz", - "integrity": "sha1-D8GqoIig4+8Ovi2IMbqw3PiEUGE=", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "dev": true }, "async-listener": { "version": "0.6.10", "resolved": "https://registry.npmjs.org/async-listener/-/async-listener-0.6.10.tgz", - "integrity": "sha512-gpuo6xOyF4D5DE5WvyqZdPA3NGhiT6Qf07l7DCB0wwDEsLvDIbCr6j9S5aj5Ch96dLace5tXVzWBZkxU/c5ohw==", + "integrity": "sha1-p8l6vlcLpgLXgic8DeYKUePhfLw=", "requires": { "semver": "^5.3.0", "shimmer": "^1.1.0" @@ -424,7 +434,7 @@ "axios": { "version": "0.18.1", "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.1.tgz", - "integrity": "sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==", + "integrity": "sha1-/z8N4ue10YDnV62YAA8Qgbh7zqM=", "requires": { "follow-redirects": "1.5.10", "is-buffer": "^2.0.2" @@ -444,12 +454,18 @@ "bignumber.js": { "version": "7.2.1", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz", - "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==" + "integrity": "sha1-gMBIdZ2CaACAfEv9Uh5Q7bulel8=" + }, + "binary-extensions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", + "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", + "dev": true }, "bindings": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "integrity": "sha1-EDU8npRTNLwFEabZCzj7x8nFBN8=", "requires": { "file-uri-to-path": "1.0.0" } @@ -462,13 +478,28 @@ "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, "buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", @@ -477,7 +508,7 @@ "builtin-modules": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz", - "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==" + "integrity": "sha1-qtl8FRMet2tltQ7yCOdYTNdqdIQ=" }, "bunyan": { "version": "1.8.12", @@ -491,10 +522,17 @@ "safe-json-stringify": "~1" } }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, "chai": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "dev": true, "requires": { "assertion-error": "^1.1.0", "check-error": "^1.0.2", @@ -505,32 +543,101 @@ } }, "chalk": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz", - "integrity": "sha1-Zjs6ZItotV0EaQ1JFnqoN4WPIXQ=", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { - "ansi-styles": "^1.1.0", - "escape-string-regexp": "^1.0.0", - "has-ansi": "^0.1.0", - "strip-ansi": "^0.3.0", - "supports-color": "^0.2.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, "check-error": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=" + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true }, - "coffee-script": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.6.0.tgz", - "integrity": "sha1-gIs5bhEPU9AhoZpO8fZb4OjjX6M=" + "chokidar": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.1.tgz", + "integrity": "sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.3.0" + } }, - "colors": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", - "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=", + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, "combined-stream": { @@ -541,12 +648,6 @@ "delayed-stream": "~1.0.0" } }, - "commander": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.0.0.tgz", - "integrity": "sha1-0bhvkB+LZL2UG96tr5JFMDk76Sg=", - "dev": true - }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -556,12 +657,12 @@ "console-log-level": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/console-log-level/-/console-log-level-1.4.1.tgz", - "integrity": "sha512-VZzbIORbP+PPcN/gg3DXClTLPLg5Slwd5fL2MIc+o1qZ4BXBvWyc6QxPk6T/Mkr6IVjRpoAGf32XxP3ZWMVRcQ==" + "integrity": "sha1-nFprue8e9lsFq6gwKLD/iUzfYwo=" }, "continuation-local-storage": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/continuation-local-storage/-/continuation-local-storage-3.2.1.tgz", - "integrity": "sha512-jx44cconVqkCEEyLSKWwkvUXwO561jXMa3LPjTPsm5QR22PA0/mhe33FT4Xb5y74JDvt/Cq+5lm8S8rskLv9ZA==", + "integrity": "sha1-EfYT906RT+mzTJKtLSj+auHbf/s=", "requires": { "async-listener": "^0.6.0", "emitter-listener": "^1.1.1" @@ -572,28 +673,38 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, - "dateformat": { - "version": "1.0.2-1.2.3", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.2-1.2.3.tgz", - "integrity": "sha1-sCIMAt6YYXQztyhRz0fePfLNvuk=", - "dev": true - }, "debug": { "version": "3.2.6", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "integrity": "sha1-6D0X3hbYp++3cX7b5fsQE17uYps=", "requires": { "ms": "^2.1.1" } }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, "deep-eql": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, "requires": { "type-detect": "^4.0.0" } }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, "delay": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/delay/-/delay-4.3.0.tgz", @@ -605,9 +716,9 @@ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, "diff": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/diff/-/diff-1.0.7.tgz", - "integrity": "sha1-JLuwAcSn1VIhaefKvbLCgU7ZHPQ=", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true }, "dtrace-provider": { @@ -623,7 +734,7 @@ "duplexify": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "integrity": "sha1-Kk31MX9sz9kfhtb9JdjYoQO4gwk=", "requires": { "end-of-stream": "^1.0.0", "inherits": "^2.0.1", @@ -634,7 +745,7 @@ "ecdsa-sig-formatter": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "integrity": "sha1-rg8PothQRe8UqBfao86azQSJ5b8=", "requires": { "safe-buffer": "^5.0.1" } @@ -642,11 +753,17 @@ "emitter-listener": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/emitter-listener/-/emitter-listener-1.1.2.tgz", - "integrity": "sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ==", + "integrity": "sha1-VrFA6PaZI3Wz18ssqxzHQy2WMug=", "requires": { "shimmer": "^1.2.0" } }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, "end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -660,6 +777,65 @@ "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=" }, + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", + "dev": true + }, + "es-get-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.0.tgz", + "integrity": "sha512-UfrmHuWQlNMTs35e1ypnvikg6jCz3SK8v8ImvmDsh36fCVUR1MqoFDiyn0/k52C8NqO3YsO8Oe0azeesNuqSsQ==", + "dev": true, + "requires": { + "es-abstract": "^1.17.4", + "has-symbols": "^1.0.1", + "is-arguments": "^1.0.4", + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-string": "^1.0.5", + "isarray": "^2.0.5" + }, + "dependencies": { + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + } + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, "es6-promise": { "version": "4.2.8", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", @@ -680,96 +856,68 @@ "dev": true }, "esprima": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", - "integrity": "sha1-n1V+CPw7TSbs6d00+Pv0drYlha0=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, "event-target-shim": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" - }, - "eventemitter2": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", - "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=", - "dev": true - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true + "integrity": "sha1-XU0+vflYPWOlMzzi3rdICrKwV4k=" }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + "integrity": "sha1-+LETa0Bx+9jrFAr/hYsQGewpFfo=" }, "fast-text-encoding": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.0.tgz", - "integrity": "sha512-R9bHCvweUxxwkDwhjav5vxpFvdPGlVngtqmx4pIZfSUhM/Q4NiIUHB456BAf+Q1Nwu3HEZYONtu+Rya+af4jiQ==" + "integrity": "sha1-PlzoKTQJz6pxd6cbnKhOGx5vJe8=" }, "file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + "integrity": "sha1-VTp7hEb/b2hDWcRF8eN6BdrMM90=" + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } }, "findit2": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/findit2/-/findit2-2.2.3.tgz", "integrity": "sha1-WKRmaX34piBc39vzlVNri9d3pfY=" }, - "findup-sync": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.1.3.tgz", - "integrity": "sha1-fz56l7gjksZTvwZYm9hRkOk8NoM=", + "flat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", + "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", "dev": true, "requires": { - "glob": "~3.2.9", - "lodash": "~2.4.1" - }, - "dependencies": { - "glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", - "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", - "dev": true, - "requires": { - "inherits": "2", - "minimatch": "0.3" - } - }, - "lodash": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", - "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=", - "dev": true - }, - "lru-cache": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", - "dev": true - }, - "minimatch": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", - "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", - "dev": true, - "requires": { - "lru-cache": "2", - "sigmund": "~1.0.0" - } - } + "is-buffer": "~2.0.3" } }, "follow-redirects": { "version": "1.5.10", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", - "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "integrity": "sha1-e3qfmuov3/NnhqlP9kPtB/T/Xio=", "requires": { "debug": "=3.1.0" }, @@ -777,7 +925,7 @@ "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", "requires": { "ms": "2.0.0" } @@ -799,30 +947,29 @@ "mime-types": "^2.1.12" } }, - "fs-extra": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.9.1.tgz", - "integrity": "sha1-h9v8ATg6jdzn2dVJbzYIVkiJ8VY=", + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", "dev": true, - "requires": { - "jsonfile": "~1.1.0", - "mkdirp": "^0.5.0", - "ncp": "^0.5.1", - "rimraf": "^2.2.8" - }, - "dependencies": { - "ncp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/ncp/-/ncp-0.5.1.tgz", - "integrity": "sha1-dDmFMW49tFkoG1hxaehFc1oFQ58=", - "dev": true - } - } + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true }, "gaxios": { "version": "1.8.4", "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-1.8.4.tgz", - "integrity": "sha512-BoENMnu1Gav18HcpV9IleMPZ9exM+AvUjrAOV4Mzs/vfz2Lu/ABv451iEXByKiMPn2M140uul1txXCg83sAENw==", + "integrity": "sha1-4Iw0/pPAqbZ6Ure556ZOZDX5ozk=", "requires": { "abort-controller": "^3.0.0", "extend": "^3.0.2", @@ -833,21 +980,22 @@ "gcp-metadata": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-1.0.0.tgz", - "integrity": "sha512-Q6HrgfrCQeEircnNP3rCcEgiDv7eF9+1B+1MMgpE190+/+0mjQR8PxeOaRgxZWmdDAF9EIryHB9g1moPiw1SbQ==", + "integrity": "sha1-UhJEAin6CZ/C98KlzcuVV16bLKY=", "requires": { "gaxios": "^1.0.2", "json-bigint": "^0.3.0" } }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, "get-func-name": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=" - }, - "getobject": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz", - "integrity": "sha1-BHpEl4n6Fg0Bj1SG7ZEyC27HiFw=", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", "dev": true }, "glob": { @@ -855,6 +1003,7 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", "dev": true, + "optional": true, "requires": { "inflight": "^1.0.4", "inherits": "2", @@ -863,10 +1012,19 @@ "path-is-absolute": "^1.0.0" } }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, "google-auth-library": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-3.1.2.tgz", - "integrity": "sha512-cDQMzTotwyWMrg5jRO7q0A4TL/3GWBgO7I7q5xGKNiiFf9SmGY/OJ1YsLMgI2MVHHsEGyrqYnbnmV1AE+Z6DnQ==", + "integrity": "sha1-/y+IzVzSEYpXvT1a08CTyIN/w1A=", "requires": { "base64-js": "^1.3.0", "fast-text-encoding": "^1.0.0", @@ -889,255 +1047,22 @@ "google-p12-pem": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-1.0.4.tgz", - "integrity": "sha512-SwLAUJqUfTB2iS+wFfSS/G9p7bt4eWcc2LyfvmUXe7cWp6p3mpxDo6LLI29MXdU6wvPcQ/up298X7GMC5ylAlA==", + "integrity": "sha1-t3+4M6Lrn388aJ4uVPCVJ293dgU=", "requires": { "node-forge": "^0.8.0", "pify": "^4.0.0" } }, - "graceful-fs": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", - "integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q=", - "dev": true - }, "growl": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.7.0.tgz", - "integrity": "sha1-3i1mE20ALhErpw8/EMMc98NQsto=", + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", "dev": true }, - "grunt": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/grunt/-/grunt-0.4.5.tgz", - "integrity": "sha1-VpN81RlDJK3/bSB2MYMqnWuk5/A=", - "dev": true, - "requires": { - "async": "~0.1.22", - "coffee-script": "~1.3.3", - "colors": "~0.6.2", - "dateformat": "1.0.2-1.2.3", - "eventemitter2": "~0.4.13", - "exit": "~0.1.1", - "findup-sync": "~0.1.2", - "getobject": "~0.1.0", - "glob": "~3.1.21", - "grunt-legacy-log": "~0.1.0", - "grunt-legacy-util": "~0.2.0", - "hooker": "~0.2.3", - "iconv-lite": "~0.2.11", - "js-yaml": "~2.0.5", - "lodash": "~0.9.2", - "minimatch": "~0.2.12", - "nopt": "~1.0.10", - "rimraf": "~2.2.8", - "underscore.string": "~2.2.1", - "which": "~1.0.5" - }, - "dependencies": { - "coffee-script": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.3.3.tgz", - "integrity": "sha1-FQ1rTLUiiUNp7+1qIQHCC8f0pPQ=", - "dev": true - }, - "glob": { - "version": "3.1.21", - "resolved": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz", - "integrity": "sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=", - "dev": true, - "requires": { - "graceful-fs": "~1.2.0", - "inherits": "1", - "minimatch": "~0.2.11" - } - }, - "inherits": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz", - "integrity": "sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js=", - "dev": true - }, - "lru-cache": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", - "dev": true - }, - "minimatch": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", - "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", - "dev": true, - "requires": { - "lru-cache": "2", - "sigmund": "~1.0.0" - } - }, - "rimraf": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", - "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=", - "dev": true - } - } - }, - "grunt-bunyan": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/grunt-bunyan/-/grunt-bunyan-0.5.0.tgz", - "integrity": "sha1-aCnXbgGZQ9owQTk2MaNuKsgpsWw=", - "dev": true, - "requires": { - "lodash": "~2.4.1" - }, - "dependencies": { - "lodash": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", - "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=", - "dev": true - } - } - }, - "grunt-contrib-clean": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/grunt-contrib-clean/-/grunt-contrib-clean-0.6.0.tgz", - "integrity": "sha1-9TLbpLghJnTHwBPhRr2mY4uQSPY=", - "dev": true, - "requires": { - "rimraf": "~2.2.1" - }, - "dependencies": { - "rimraf": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", - "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=", - "dev": true - } - } - }, - "grunt-contrib-coffee": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/grunt-contrib-coffee/-/grunt-contrib-coffee-0.11.1.tgz", - "integrity": "sha1-+v48nuikQryNF9WlwZ/I5i2fP0U=", - "dev": true, - "requires": { - "chalk": "~0.5.0", - "coffee-script": "~1.7.0", - "lodash": "~2.4.1" - }, - "dependencies": { - "coffee-script": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.7.1.tgz", - "integrity": "sha1-YplqhheAx15tUGnROCJyO3NAS/w=", - "dev": true, - "requires": { - "mkdirp": "~0.3.5" - } - }, - "lodash": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", - "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=", - "dev": true - }, - "mkdirp": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", - "integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc=", - "dev": true - } - } - }, - "grunt-execute": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/grunt-execute/-/grunt-execute-0.2.2.tgz", - "integrity": "sha1-TpRf5XlZzA3neZCDtrQq7ZYWNQo=", - "dev": true - }, - "grunt-legacy-log": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-0.1.3.tgz", - "integrity": "sha1-7ClCboAwIa9ZAp+H0vnNczWgVTE=", - "dev": true, - "requires": { - "colors": "~0.6.2", - "grunt-legacy-log-utils": "~0.1.1", - "hooker": "~0.2.3", - "lodash": "~2.4.1", - "underscore.string": "~2.3.3" - }, - "dependencies": { - "lodash": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", - "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=", - "dev": true - }, - "underscore.string": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz", - "integrity": "sha1-ccCL9rQosRM/N+ePo6Icgvcymw0=", - "dev": true - } - } - }, - "grunt-legacy-log-utils": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-0.1.1.tgz", - "integrity": "sha1-wHBrndkGThFvNvI/5OawSGcsD34=", - "dev": true, - "requires": { - "colors": "~0.6.2", - "lodash": "~2.4.1", - "underscore.string": "~2.3.3" - }, - "dependencies": { - "lodash": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", - "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=", - "dev": true - }, - "underscore.string": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz", - "integrity": "sha1-ccCL9rQosRM/N+ePo6Icgvcymw0=", - "dev": true - } - } - }, - "grunt-legacy-util": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-0.2.0.tgz", - "integrity": "sha1-kzJIhNv343qf98Am3/RR2UqeVUs=", - "dev": true, - "requires": { - "async": "~0.1.22", - "exit": "~0.1.1", - "getobject": "~0.1.0", - "hooker": "~0.2.3", - "lodash": "~0.9.2", - "underscore.string": "~2.2.1", - "which": "~1.0.5" - } - }, - "grunt-mocha-test": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/grunt-mocha-test/-/grunt-mocha-test-0.11.0.tgz", - "integrity": "sha1-deQboQdZDkrL0phgklwBLkQ8oyI=", - "dev": true, - "requires": { - "fs-extra": "~0.9.1", - "hooker": "~0.2.3", - "mocha": "~1.20.0" - } - }, "gtoken": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-2.3.3.tgz", - "integrity": "sha512-EaB49bu/TCoNeQjhCYKI/CurooBKkGxIqFHsWABW0b25fobBYVTMe84A8EBVVZhl8emiUdNypil9huMOTmyAnw==", + "integrity": "sha1-in/hVcXODEtxyIbPsoKpBg2UpkE=", "requires": { "gaxios": "^1.0.4", "google-p12-pem": "^1.0.0", @@ -1146,30 +1071,37 @@ "pify": "^4.0.0" } }, - "has-ansi": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz", - "integrity": "sha1-hPJlqujA5qiKEtcCKJS3VoiUxi4=", + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, "requires": { - "ansi-regex": "^0.2.0" + "function-bind": "^1.1.1" } }, "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true }, "hex2dec": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/hex2dec/-/hex2dec-1.1.2.tgz", - "integrity": "sha512-Yu+q/XWr2fFQ11tHxPq4p4EiNkb2y+lAacJNhAdRXVfRIcDH6gi7htWFnnlIzvqHMHoWeIsfXlNAjZInpAOJDA==" - }, - "hooker": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz", - "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=", - "dev": true + "integrity": "sha1-jhzkvvNqdPfVcjw/swkMKGAHczg=" }, "https-proxy-agent": { "version": "2.2.4", @@ -1180,12 +1112,6 @@ "debug": "^3.1.0" } }, - "iconv-lite": { - "version": "0.2.11", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.2.11.tgz", - "integrity": "sha1-HOYKOleGSiktEyH/RgnKS7llrcg=", - "dev": true - }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -1204,50 +1130,138 @@ "is": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/is/-/is-3.3.0.tgz", - "integrity": "sha512-nW24QBoPcFGGHJGUwnfpI7Yc5CdqWNdsyHQszVE/z2pKHXzh7FZ5GWhJqSyaQ9wMkQnsTx+kAI8bHlCX4tKdbg==" + "integrity": "sha1-Yc/23TxBk9uUo9YlggcrROVkXXk=" + }, + "is-arguments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", + "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } }, "is-buffer": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==" }, + "is-callable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", + "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", + "dev": true + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.1.tgz", + "integrity": "sha512-T/S49scO8plUiAOA2DBTBG3JHpn1yiw0kRp6dgiZ0v2/6twi5eiB0rHtHFH9ZIrvlWc6+4O+m4zg5+Z833aXgw==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz", + "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-set": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.1.tgz", + "integrity": "sha512-eJEzOtVyenDs1TMzSQ3kU3K+E0GUS9sno+F0OBT97xsgcJsF9nXMBtkT9/kut5JEpM7oL7X/0qxR17K3mcwIAA==", + "dev": true + }, + "is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, - "jade": { - "version": "0.26.3", - "resolved": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz", - "integrity": "sha1-jxDXl32NefL2/4YqgbBRPMslaGw=", + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "iterate-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.1.tgz", + "integrity": "sha512-3Q6tudGN05kbkDQDI4CqjaBf4qf85w6W6GnuZDtUVYwKgtC1q8yxYX7CZed7N+tLzQqS6roujWvszf13T+n9aw==", + "dev": true + }, + "iterate-value": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/iterate-value/-/iterate-value-1.0.2.tgz", + "integrity": "sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==", "dev": true, "requires": { - "commander": "0.6.1", - "mkdirp": "0.3.0" - }, - "dependencies": { - "commander": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", - "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=", - "dev": true - }, - "mkdirp": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", - "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=", - "dev": true - } + "es-get-iterator": "^1.0.2", + "iterate-iterator": "^1.0.1" } }, "js-yaml": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-2.0.5.tgz", - "integrity": "sha1-olrmUJmZ6X3yeMZxnaEb0Gh3Q6g=", + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", "dev": true, "requires": { - "argparse": "~ 0.1.11", - "esprima": "~ 1.0.2" + "argparse": "^1.0.7", + "esprima": "^4.0.0" } }, "json-bigint": { @@ -1258,21 +1272,16 @@ "bignumber.js": "^7.0.0" } }, - "jsonfile": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-1.1.1.tgz", - "integrity": "sha1-2k/WrXfxolUgPqY8e8Mtwx72RDM=", - "dev": true - }, "just-extend": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.0.tgz", - "integrity": "sha512-ApcjaOdVTJ7y4r08xI5wIqpvwS48Q0PBG4DJROcEkH1f8MdAiNFyFxz3xoL0LWAVwjrwPYZdVHHxhRHcx/uGLA==" + "integrity": "sha512-ApcjaOdVTJ7y4r08xI5wIqpvwS48Q0PBG4DJROcEkH1f8MdAiNFyFxz3xoL0LWAVwjrwPYZdVHHxhRHcx/uGLA==", + "dev": true }, "jwa": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "integrity": "sha1-dDwymFy56YZVUw1TZBtmyGRbA5o=", "requires": { "buffer-equal-constant-time": "1.0.1", "ecdsa-sig-formatter": "1.0.11", @@ -1282,37 +1291,56 @@ "jws": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "integrity": "sha1-ABCZ82OUaMlBQADpmZX6UvtHgwQ=", "requires": { "jwa": "^1.4.1", "safe-buffer": "^5.0.1" } }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, "lodash": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-0.9.2.tgz", - "integrity": "sha1-jzSZxSRdNG1oLlsNO0B2fgnxqSw=", + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", "dev": true }, "lodash.get": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "dev": true }, "lodash.pickby": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz", "integrity": "sha1-feoh2MGNdwOifHBMFdO4SmfjOv8=" }, + "log-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2" + } + }, "long": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + "integrity": "sha1-mntxz7fTYaGU6lVSQckvdGjVvyg=" }, "lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "integrity": "sha1-HaJ+ZxAnGUdpXa9oSOhH8B2EuSA=", "requires": { "yallist": "^3.0.2" } @@ -1343,7 +1371,7 @@ "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", "dev": true, "requires": { "brace-expansion": "^1.1.7" @@ -1353,70 +1381,65 @@ "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true + "dev": true, + "optional": true }, "mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } }, "mocha": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-1.20.1.tgz", - "integrity": "sha1-80ODLZ/gx9l8ZPxwRI9RNt+f7Vs=", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.0.1.tgz", + "integrity": "sha512-vefaXfdYI8+Yo8nPZQQi0QO2o+5q9UIMX1jZ1XMmK3+4+CQjc7+B0hPdUeglXiTlr8IHMVRo63IhO9Mzt6fxOg==", "dev": true, "requires": { - "commander": "2.0.0", - "debug": "*", - "diff": "1.0.7", - "glob": "3.2.3", - "growl": "1.7.x", - "jade": "0.26.3", - "mkdirp": "0.3.5" + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.3.1", + "debug": "3.2.6", + "diff": "4.0.2", + "escape-string-regexp": "1.0.5", + "find-up": "4.1.0", + "glob": "7.1.6", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "3.0.0", + "minimatch": "3.0.4", + "ms": "2.1.2", + "object.assign": "4.1.0", + "promise.allsettled": "1.0.2", + "serialize-javascript": "3.0.0", + "strip-json-comments": "3.0.1", + "supports-color": "7.1.0", + "which": "2.0.2", + "wide-align": "1.1.3", + "workerpool": "6.0.0", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "1.6.0" }, "dependencies": { "glob": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.3.tgz", - "integrity": "sha1-4xPusknHr/qlxHUoaw4RW1mDlGc=", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "dev": true, "requires": { - "graceful-fs": "~2.0.0", + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", "inherits": "2", - "minimatch": "~0.2.11" + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } - }, - "graceful-fs": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz", - "integrity": "sha1-fNLNsiiko/Nule+mzBQt59GhNtA=", - "dev": true - }, - "lru-cache": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", - "dev": true - }, - "minimatch": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", - "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", - "dev": true, - "requires": { - "lru-cache": "2", - "sigmund": "~1.0.0" - } - }, - "mkdirp": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", - "integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc=", - "dev": true } } }, @@ -1428,7 +1451,7 @@ "moment": { "version": "2.24.0", "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", - "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==", + "integrity": "sha1-DQVdU/UFKqZTyfbraLtdEr9cK1s=", "dev": true, "optional": true }, @@ -1452,7 +1475,7 @@ "nan": { "version": "2.14.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" + "integrity": "sha1-eBj3IgJ7JFmobwKV1DTR/CM2xSw=" }, "ncp": { "version": "2.0.0", @@ -1462,9 +1485,10 @@ "optional": true }, "nise": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/nise/-/nise-4.0.3.tgz", - "integrity": "sha512-EGlhjm7/4KvmmE6B/UFsKh7eHykRl9VH+au8dduHLCyWUO/hr7+N+WtTvDUwc9zHuM1IaIJs/0lQ6Ag1jDkQSg==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/nise/-/nise-4.0.4.tgz", + "integrity": "sha512-bTTRUNlemx6deJa+ZyoCUTRvH3liK5+N6VQZ4NIw90AgDXY6iPnsqplNFf6STcj+ePk0H/xqxnP75Lr0J0Fq3A==", + "dev": true, "requires": { "@sinonjs/commons": "^1.7.0", "@sinonjs/fake-timers": "^6.0.0", @@ -1476,20 +1500,41 @@ "node-fetch": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", - "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" + "integrity": "sha1-5jNFY4bUqlWGP2dqerDaqP3ssP0=" }, "node-forge": { "version": "0.8.5", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.8.5.tgz", "integrity": "sha512-vFMQIWt+J/7FLNyKouZ9TazT74PRV3wgv9UT4cRjC8BffxFbKXkgIWR42URCPSnHm/QDz6BOlb2Q0U4+VQT67Q==" }, - "nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "object-inspect": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", + "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", "dev": true, "requires": { - "abbrev": "1" + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" } }, "once": { @@ -1508,10 +1553,19 @@ "p-try": "^2.0.0" } }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + "integrity": "sha1-yyhoVA4xPWHeWPr741zpAE1VQOY=" }, "parse-duration": { "version": "0.1.2", @@ -1521,7 +1575,13 @@ "parse-ms": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-2.1.0.tgz", - "integrity": "sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==" + "integrity": "sha1-NIVlp1PUOR+lJAKZVrFyy3dTCX0=" + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true }, "path-is-absolute": { "version": "1.0.1", @@ -1532,12 +1592,13 @@ "path-parse": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + "integrity": "sha1-1i27VnlAXXLEc37FhgDp3c8G0kw=" }, "path-to-regexp": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, "requires": { "isarray": "0.0.1" }, @@ -1545,24 +1606,32 @@ "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true } } }, "pathval": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", - "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=" + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "dev": true + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true }, "pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + "integrity": "sha1-SyzSXFDVmHNcUCkiJP2MbfQeMjE=" }, "pretty-ms": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-4.0.0.tgz", - "integrity": "sha512-qG66ahoLCwpLXD09ZPHSCbUWYTqdosB7SMP4OffgTgL2PBKXMuUsrk5Bwg8q4qPkjTXsKBMr+YK3Ltd/6F9s/Q==", + "integrity": "sha1-Mbr0G5T9AiJwmKqgO9YmCOsNbpI=", "requires": { "parse-ms": "^2.0.0" } @@ -1580,10 +1649,23 @@ "tdigest": "^0.1.1" } }, + "promise.allsettled": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/promise.allsettled/-/promise.allsettled-1.0.2.tgz", + "integrity": "sha512-UpcYW5S1RaNKT6pd+s9jp9K9rlQge1UXKskec0j6Mmuq7UJCvlS2J2/s/yuPN8ehftf9HXMxWlKiPbGGUzpoRg==", + "dev": true, + "requires": { + "array.prototype.map": "^1.0.1", + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "iterate-value": "^1.0.0" + } + }, "protobufjs": { "version": "6.8.8", "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.8.8.tgz", - "integrity": "sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw==", + "integrity": "sha1-yLTxKC/XqQ5vWxCe0RyEr4KQjnw=", "requires": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", @@ -1621,6 +1703,21 @@ "util-deprecate": "~1.0.1" } }, + "readdirp": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.3.0.tgz", + "integrity": "sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==", + "dev": true, + "requires": { + "picomatch": "^2.0.7" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, "require-in-the-middle": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-4.0.1.tgz", @@ -1634,7 +1731,7 @@ "debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=", "requires": { "ms": "^2.1.1" } @@ -1644,7 +1741,14 @@ "require-like": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/require-like/-/require-like-0.1.2.tgz", - "integrity": "sha1-rW8wwTvs15cBDEaK+ndcDAprR/o=" + "integrity": "sha1-rW8wwTvs15cBDEaK+ndcDAprR/o=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true }, "resolve": { "version": "1.15.1", @@ -1657,7 +1761,7 @@ "retry-axios": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/retry-axios/-/retry-axios-0.3.2.tgz", - "integrity": "sha512-jp4YlI0qyDFfXiXGhkCOliBN1G7fRH03Nqy8YdShzGqbY5/9S2x/IR6C88ls2DFkbWuL3ASkP7QD3pVrNpPgwQ==" + "integrity": "sha1-V1fID1hbTMTEmGqi/9R6YMbTXhM=" }, "retry-request": { "version": "4.1.1", @@ -1683,6 +1787,7 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", "integrity": "sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto=", "dev": true, + "optional": true, "requires": { "glob": "^6.0.1" } @@ -1690,19 +1795,20 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=" }, "safe-json-stringify": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz", - "integrity": "sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==", + "integrity": "sha1-NW5EvJjx+TzkXfFLzXwBzahuCv0=", "dev": true, "optional": true }, "sandboxed-module": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/sandboxed-module/-/sandboxed-module-2.0.3.tgz", - "integrity": "sha1-x+VFkzm7y6KMUwPusz9ug4e/upY=", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/sandboxed-module/-/sandboxed-module-2.0.4.tgz", + "integrity": "sha512-AwEPOdO8mg/wJjr876yCHP2DHqVN0MaggEXhp6IIf3bcI5cYoQl9QrrCHSrvToHjvdEiS5x4TVZRgjD2bEmNTA==", + "dev": true, "requires": { "require-like": "0.1.2", "stack-trace": "0.0.9" @@ -1713,92 +1819,138 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" }, + "serialize-javascript": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-3.0.0.tgz", + "integrity": "sha512-skZcHYw2vEX4bw90nAr2iTTsz6x2SrHEnfxgKYmZlvJYBEZrvbKtobJWlQ20zczKb3bsHHXXTYt48zBA7ni9cw==", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, "shimmer": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", - "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" - }, - "sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", - "dev": true + "integrity": "sha1-YQhZ994ye1h+/r9QH7QxF/mv8zc=" }, "sinon": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.0.0.tgz", - "integrity": "sha512-c4bREcvuK5VuEGyMW/Oim9I3Rq49Vzb0aMdxouFaA44QCFpilc5LJOugrX+mkrvikbqCimxuK+4cnHVNnLR41g==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.0.2.tgz", + "integrity": "sha512-0uF8Q/QHkizNUmbK3LRFqx5cpTttEVXudywY9Uwzy8bTfZUhljZ7ARzSxnRHWYWtVTeh4Cw+tTb3iU21FQVO9A==", + "dev": true, "requires": { - "@sinonjs/commons": "^1.7.0", - "@sinonjs/fake-timers": "^6.0.0", - "@sinonjs/formatio": "^5.0.0", - "@sinonjs/samsam": "^5.0.1", + "@sinonjs/commons": "^1.7.2", + "@sinonjs/fake-timers": "^6.0.1", + "@sinonjs/formatio": "^5.0.1", + "@sinonjs/samsam": "^5.0.3", "diff": "^4.0.2", "nise": "^4.0.1", "supports-color": "^7.1.0" - }, - "dependencies": { - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "requires": { - "has-flag": "^4.0.0" - } - } } }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=" }, "split": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "integrity": "sha1-YFvZvjA6pZ+zX5Ip++oN3snqB9k=", "requires": { "through": "2" } }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, "stack-trace": { "version": "0.0.9", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.9.tgz", - "integrity": "sha1-qPbq7KkGdMMz58Q5U/J1tFFRBpU=" + "integrity": "sha1-qPbq7KkGdMMz58Q5U/J1tFFRBpU=", + "dev": true }, "stream-shift": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", "requires": { "safe-buffer": "~5.1.0" } }, "strip-ansi": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz", - "integrity": "sha1-JfSOoiynkYfzF0pNuHWTR7sSYiA=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "ansi-regex": "^0.2.1" + "ansi-regex": "^3.0.0" } }, - "supports-color": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz", - "integrity": "sha1-2S3iaU6z9nMjlz1649i1W0wiGQo=", + "strip-json-comments": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", + "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", "dev": true }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + } + } + }, "tdigest": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.1.tgz", @@ -1810,7 +1962,7 @@ "teeny-request": { "version": "3.11.3", "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-3.11.3.tgz", - "integrity": "sha512-CKncqSF7sH6p4rzCgkb/z/Pcos5efl0DmolzvlqRQUNcpRIruOhY9+T1FsIlyEbfWd7MsFpodROOwHYh2BaXzw==", + "integrity": "sha1-M1xin3ZF5dZZk2LfLzIwxMvCOlU=", "requires": { "https-proxy-agent": "^2.2.1", "node-fetch": "^2.2.0", @@ -1830,22 +1982,26 @@ "readable-stream": "2 || 3" } }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, "type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" + "integrity": "sha1-dkb7XxiHHPu3dJ5pvTmmOI63RQw=", + "dev": true }, "underscore": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=" }, - "underscore.string": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.2.1.tgz", - "integrity": "sha1-18D6KvXVoaZ/QlPa7pgTLnM/Dxk=", - "dev": true - }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -1857,21 +2013,191 @@ "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" }, "which": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/which/-/which-1.0.9.tgz", - "integrity": "sha1-RgwdoPgQED0DIam2M6+eV15kSG8=", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "workerpool": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.0.0.tgz", + "integrity": "sha512-fU2OcNA/GVAJLLyKUoHkAgIhKb0JoCpSjLC/G2vYKxUjVmQwGbRVeoPJ1a8U4pnVofz4AQV5Y/NEw8oKqxEBtA==", + "dev": true + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, "yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yargs-unparser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "dev": true, + "requires": { + "flat": "^4.1.0", + "lodash": "^4.17.15", + "yargs": "^13.3.0" + } + }, "yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 9e4209ae9d..102e16eeb6 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -10,21 +10,18 @@ "@google-cloud/debug-agent": "^3.0.0", "@google-cloud/profiler": "^0.2.3", "@google-cloud/trace-agent": "^3.2.0", - "coffee-script": "1.6.0", "prom-client": "^11.1.3", "underscore": "~1.6.0", "yn": "^3.1.1" }, "devDependencies": { "bunyan": "^1.0.0", - "chai": "", - "grunt": "^0.4.5", - "grunt-bunyan": "^0.5.0", - "grunt-contrib-clean": "^0.6.0", - "grunt-contrib-coffee": "^0.11.0", - "grunt-execute": "^0.2.2", - "grunt-mocha-test": "^0.11.0", - "sandboxed-module": "", - "sinon": "" + "chai": "^4.2.0", + "mocha": "^8.0.1", + "sandboxed-module": "^2.0.4", + "sinon": "^9.0.2" + }, + "scripts": { + "test": "mocha --reporter spec --recursive --exit --grep=$MOCHA_GREP test/unit" } } diff --git a/libraries/metrics/test/unit/js/event_loop.js b/libraries/metrics/test/unit/js/event_loop.js new file mode 100644 index 0000000000..7135287486 --- /dev/null +++ b/libraries/metrics/test/unit/js/event_loop.js @@ -0,0 +1,47 @@ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const chai = require('chai'); +const should = chai.should(); +const { + expect +} = chai; +const path = require('path'); +const modulePath = path.join(__dirname, '../../../event_loop.js'); +const SandboxedModule = require('sandboxed-module'); +const sinon = require("sinon"); + +describe('event_loop', function() { + + before(function() { + this.metrics = { + timing: sinon.stub(), + registerDestructor: sinon.stub() + }; + this.logger = { + warn: sinon.stub() + }; + return this.event_loop = SandboxedModule.require(modulePath, { requires: { + './metrics': this.metrics + } + } + ); + }); + + describe('with a logger provided', function() { + before(function() { + return this.event_loop.monitor(this.logger); + }); + + return it('should register a destructor with metrics', function() { + return this.metrics.registerDestructor.called.should.equal(true); + }); + }); + + return describe('without a logger provided', () => it('should throw an exception', function() { + return expect(this.event_loop.monitor).to.throw('logger is undefined'); + })); +}); + diff --git a/libraries/metrics/test/unit/js/timeAsyncMethodTests.js b/libraries/metrics/test/unit/js/timeAsyncMethodTests.js new file mode 100644 index 0000000000..36bdb02cfa --- /dev/null +++ b/libraries/metrics/test/unit/js/timeAsyncMethodTests.js @@ -0,0 +1,163 @@ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const chai = require('chai'); +const should = chai.should(); +const { + expect +} = chai; +const path = require('path'); +const modulePath = path.join(__dirname, '../../../timeAsyncMethod.js'); +const SandboxedModule = require('sandboxed-module'); +const sinon = require("sinon"); + + +describe('timeAsyncMethod', function() { + + beforeEach(function() { + this.Timer = {done: sinon.stub()}; + this.TimerConstructor = sinon.stub().returns(this.Timer); + this.metrics = { + Timer: this.TimerConstructor, + inc: sinon.stub() + }; + this.timeAsyncMethod = SandboxedModule.require(modulePath, { requires: { + './metrics': this.metrics + } + } + ); + + return this.testObject = { + nextNumber(n, callback) { + if (callback == null) { callback = function(err, result){}; } + return setTimeout( + () => callback(null, n+1) + , 100 + ); + } + };}); + + it('should have the testObject behave correctly before wrapping', function(done) { + return this.testObject.nextNumber(2, function(err, result) { + expect(err).to.not.exist; + expect(result).to.equal(3); + return done(); + }); + }); + + it('should wrap method without error', function(done) { + this.timeAsyncMethod(this.testObject, 'nextNumber', 'someContext.TestObject'); + return done(); + }); + + it('should transparently wrap method invocation in timer', function(done) { + this.timeAsyncMethod(this.testObject, 'nextNumber', 'someContext.TestObject'); + return this.testObject.nextNumber(2, (err, result) => { + expect(err).to.not.exist; + expect(result).to.equal(3); + expect(this.TimerConstructor.callCount).to.equal(1); + expect(this.Timer.done.callCount).to.equal(1); + return done(); + }); + }); + + it('should increment success count', function(done) { + this.metrics.inc = sinon.stub(); + this.timeAsyncMethod(this.testObject, 'nextNumber', 'someContext.TestObject'); + return this.testObject.nextNumber(2, (err, result) => { + expect(this.metrics.inc.callCount).to.equal(1); + expect(this.metrics.inc.calledWith('someContext_result', 1, { method: 'TestObject_nextNumber', status: 'success'})).to.equal(true); + return done(); + }); + }); + + describe('when base method produces an error', function() { + beforeEach(function() { + this.metrics.inc = sinon.stub(); + return this.testObject.nextNumber = function(n, callback) { + if (callback == null) { callback = function(err, result){}; } + return setTimeout( + () => callback(new Error('woops')) + , 100 + ); + }; + }); + + it('should propagate the error transparently', function(done) { + this.timeAsyncMethod(this.testObject, 'nextNumber', 'someContext.TestObject'); + return this.testObject.nextNumber(2, (err, result) => { + expect(err).to.exist; + expect(err).to.be.instanceof(Error); + expect(result).to.not.exist; + return done(); + }); + }); + + return it('should increment failure count', function(done) { + this.timeAsyncMethod(this.testObject, 'nextNumber', 'someContext.TestObject'); + return this.testObject.nextNumber(2, (err, result) => { + expect(this.metrics.inc.callCount).to.equal(1); + expect(this.metrics.inc.calledWith('someContext_result', 1, { method: 'TestObject_nextNumber', status: 'failed'})).to.equal(true); + return done(); + }); + }); + }); + + describe('when a logger is supplied', function() { + beforeEach(function() { + return this.logger = {log: sinon.stub()};}); + + return it('should also call logger.log', function(done) { + this.timeAsyncMethod(this.testObject, 'nextNumber', 'someContext.TestObject', this.logger); + return this.testObject.nextNumber(2, (err, result) => { + expect(err).to.not.exist; + expect(result).to.equal(3); + expect(this.TimerConstructor.callCount).to.equal(1); + expect(this.Timer.done.callCount).to.equal(1); + expect(this.logger.log.callCount).to.equal(1); + return done(); + }); + }); + }); + + describe('when the wrapper cannot be applied', function() { + beforeEach(function() {}); + + return it('should raise an error', function() { + const badWrap = () => { + return this.timeAsyncMethod(this.testObject, 'DEFINITELY_NOT_A_REAL_METHOD', 'someContext.TestObject'); + }; + return expect(badWrap).to.throw( + /^.*expected object property 'DEFINITELY_NOT_A_REAL_METHOD' to be a function.*$/ + ); + }); + }); + + return describe('when the wrapped function is not using a callback', function() { + beforeEach(function() { + this.realMethod = sinon.stub().returns(42); + return this.testObject.nextNumber = this.realMethod; + }); + + it('should not throw an error', function() { + this.timeAsyncMethod(this.testObject, 'nextNumber', 'someContext.TestObject'); + const badCall = () => { + return this.testObject.nextNumber(2); + }; + return expect(badCall).to.not.throw(Error); + }); + + return it('should call the underlying method', function() { + this.timeAsyncMethod(this.testObject, 'nextNumber', 'someContext.TestObject'); + const result = this.testObject.nextNumber(12); + expect(this.realMethod.callCount).to.equal(1); + expect(this.realMethod.calledWith(12)).to.equal(true); + return expect(result).to.equal(42); + }); + }); +}); + + From 671c243025400082143107392fd9cd76fc55057b Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Fri, 17 Jul 2020 16:19:44 +0100 Subject: [PATCH 148/182] npm audit fix --- libraries/metrics/package-lock.json | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/libraries/metrics/package-lock.json b/libraries/metrics/package-lock.json index f38eb81cf8..436b7eb4b5 100644 --- a/libraries/metrics/package-lock.json +++ b/libraries/metrics/package-lock.json @@ -335,9 +335,9 @@ } }, "acorn": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.0.tgz", - "integrity": "sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw==" + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", + "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==" }, "agent-base": { "version": "4.3.0", @@ -1378,20 +1378,20 @@ } }, "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true, "optional": true }, "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", "dev": true, "optional": true, "requires": { - "minimist": "0.0.8" + "minimist": "^1.2.5" } }, "mocha": { From d415ae0cbefbe23cd89f694e68b7b0cd467def78 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Fri, 17 Jul 2020 16:23:01 +0100 Subject: [PATCH 149/182] remove gruntfile --- libraries/metrics/Gruntfile.js | 41 ---------------------------------- 1 file changed, 41 deletions(-) delete mode 100644 libraries/metrics/Gruntfile.js diff --git a/libraries/metrics/Gruntfile.js b/libraries/metrics/Gruntfile.js deleted file mode 100644 index c775dcb9ec..0000000000 --- a/libraries/metrics/Gruntfile.js +++ /dev/null @@ -1,41 +0,0 @@ -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ -module.exports = function(grunt) { - grunt.initConfig({ - coffee: { - unit_tests: { - expand: true, - cwd: "test/unit/coffee", - src: ["**/*.coffee"], - dest: "test/unit/js/", - ext: ".js" - } - }, - - clean: { - unit_tests: ["test/unit/js"] - }, - - mochaTest: { - unit: { - options: { - reporter: grunt.option('reporter') || 'spec', - grep: grunt.option("grep") - }, - - src: ["test/unit/js/**/*.js"] - } - }}); - - grunt.loadNpmTasks('grunt-contrib-coffee'); - grunt.loadNpmTasks('grunt-contrib-clean'); - grunt.loadNpmTasks('grunt-mocha-test'); - grunt.loadNpmTasks('grunt-execute'); - grunt.loadNpmTasks('grunt-bunyan'); - - grunt.registerTask('compile:unit_tests', ['clean:unit_tests', 'coffee:unit_tests']); - return grunt.registerTask('test:unit', ['compile:unit_tests', 'mochaTest:unit']); -}; From 5b39d49358934553bf2734008c6c9fe8f208bf4c Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Wed, 5 Aug 2020 11:25:21 +0100 Subject: [PATCH 150/182] use scoped package name @overleaf/metrics --- libraries/metrics/package-lock.json | 2 +- libraries/metrics/package.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/metrics/package-lock.json b/libraries/metrics/package-lock.json index f38eb81cf8..e5b30e1180 100644 --- a/libraries/metrics/package-lock.json +++ b/libraries/metrics/package-lock.json @@ -1,5 +1,5 @@ { - "name": "metrics-sharelatex", + "name": "@overleaf/metrics", "version": "3.0.0", "lockfileVersion": 1, "requires": true, diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 102e16eeb6..b22b6996cc 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,10 +1,10 @@ { - "name": "metrics-sharelatex", + "name": "@overleaf/metrics", "version": "3.0.0", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", - "url": "https://github.com/sharelatex/metrics-sharelatex.git" + "url": "https://github.com/overleaf/metrics-module.git" }, "dependencies": { "@google-cloud/debug-agent": "^3.0.0", From e5747fefd28309858613353ba3440bc03f676457 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Thu, 6 Aug 2020 14:52:07 +0100 Subject: [PATCH 151/182] remove package-lock.json (not needed for library) --- libraries/metrics/package-lock.json | 2207 --------------------------- 1 file changed, 2207 deletions(-) delete mode 100644 libraries/metrics/package-lock.json diff --git a/libraries/metrics/package-lock.json b/libraries/metrics/package-lock.json deleted file mode 100644 index e5b30e1180..0000000000 --- a/libraries/metrics/package-lock.json +++ /dev/null @@ -1,2207 +0,0 @@ -{ - "name": "@overleaf/metrics", - "version": "3.0.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@google-cloud/common": { - "version": "0.32.1", - "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-0.32.1.tgz", - "integrity": "sha1-ajLDQBcs6j22Z00ODjTnh0CgBz8=", - "requires": { - "@google-cloud/projectify": "^0.3.3", - "@google-cloud/promisify": "^0.4.0", - "@types/request": "^2.48.1", - "arrify": "^2.0.0", - "duplexify": "^3.6.0", - "ent": "^2.2.0", - "extend": "^3.0.2", - "google-auth-library": "^3.1.1", - "pify": "^4.0.1", - "retry-request": "^4.0.0", - "teeny-request": "^3.11.3" - } - }, - "@google-cloud/debug-agent": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@google-cloud/debug-agent/-/debug-agent-3.2.0.tgz", - "integrity": "sha1-2qdjWhaYpWY31dxXzhED536uKdM=", - "requires": { - "@google-cloud/common": "^0.32.0", - "@sindresorhus/is": "^0.15.0", - "acorn": "^6.0.0", - "coffeescript": "^2.0.0", - "console-log-level": "^1.4.0", - "extend": "^3.0.1", - "findit2": "^2.2.3", - "gcp-metadata": "^1.0.0", - "lodash.pickby": "^4.6.0", - "p-limit": "^2.2.0", - "pify": "^4.0.1", - "semver": "^6.0.0", - "source-map": "^0.6.1", - "split": "^1.0.0" - }, - "dependencies": { - "coffeescript": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-2.5.1.tgz", - "integrity": "sha512-J2jRPX0eeFh5VKyVnoLrfVFgLZtnnmp96WQSLAS8OrLm2wtQLcnikYKe1gViJKDH7vucjuhHvBKKBP3rKcD1tQ==" - } - } - }, - "@google-cloud/profiler": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@google-cloud/profiler/-/profiler-0.2.3.tgz", - "integrity": "sha1-Fj3738Mwuug1X+RuHlvgZTV7H1w=", - "requires": { - "@google-cloud/common": "^0.26.0", - "@types/console-log-level": "^1.4.0", - "@types/semver": "^5.5.0", - "bindings": "^1.2.1", - "console-log-level": "^1.4.0", - "delay": "^4.0.1", - "extend": "^3.0.1", - "gcp-metadata": "^0.9.0", - "nan": "^2.11.1", - "parse-duration": "^0.1.1", - "pify": "^4.0.0", - "pretty-ms": "^4.0.0", - "protobufjs": "~6.8.6", - "semver": "^5.5.0", - "teeny-request": "^3.3.0" - }, - "dependencies": { - "@google-cloud/common": { - "version": "0.26.2", - "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-0.26.2.tgz", - "integrity": "sha1-nFTiRxqEqgMelaJIJJduCA8lVkU=", - "requires": { - "@google-cloud/projectify": "^0.3.2", - "@google-cloud/promisify": "^0.3.0", - "@types/duplexify": "^3.5.0", - "@types/request": "^2.47.0", - "arrify": "^1.0.1", - "duplexify": "^3.6.0", - "ent": "^2.2.0", - "extend": "^3.0.1", - "google-auth-library": "^2.0.0", - "pify": "^4.0.0", - "retry-request": "^4.0.0", - "through2": "^3.0.0" - } - }, - "@google-cloud/promisify": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-0.3.1.tgz", - "integrity": "sha1-9kHm2USo4KBe4MsQkd+mAIm+zbo=" - }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" - }, - "gcp-metadata": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-0.9.3.tgz", - "integrity": "sha1-H510lfdGChRSZIHynhFZbdVj3SY=", - "requires": { - "gaxios": "^1.0.2", - "json-bigint": "^0.3.0" - } - }, - "google-auth-library": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-2.0.2.tgz", - "integrity": "sha1-ejFdIDZ0Svavyth7IQ7mY4tA9Xs=", - "requires": { - "axios": "^0.18.0", - "gcp-metadata": "^0.7.0", - "gtoken": "^2.3.0", - "https-proxy-agent": "^2.2.1", - "jws": "^3.1.5", - "lru-cache": "^5.0.0", - "semver": "^5.5.0" - }, - "dependencies": { - "gcp-metadata": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-0.7.0.tgz", - "integrity": "sha1-bDXbtSvaMqQnu5yY9UI33dG1QG8=", - "requires": { - "axios": "^0.18.0", - "extend": "^3.0.1", - "retry-axios": "0.3.2" - } - } - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } - } - }, - "@google-cloud/projectify": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-0.3.3.tgz", - "integrity": "sha1-vekQPVCyCj6jM334xng6dm5w1B0=" - }, - "@google-cloud/promisify": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-0.4.0.tgz", - "integrity": "sha1-T7/PTYW7ai5MzwWqY9KxDWyarZs=" - }, - "@google-cloud/trace-agent": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@google-cloud/trace-agent/-/trace-agent-3.6.1.tgz", - "integrity": "sha1-W+dEE5TQ6ldY8o25IqUAT/PwO+w=", - "requires": { - "@google-cloud/common": "^0.32.1", - "builtin-modules": "^3.0.0", - "console-log-level": "^1.4.0", - "continuation-local-storage": "^3.2.1", - "extend": "^3.0.0", - "gcp-metadata": "^1.0.0", - "hex2dec": "^1.0.1", - "is": "^3.2.0", - "methods": "^1.1.1", - "require-in-the-middle": "^4.0.0", - "semver": "^6.0.0", - "shimmer": "^1.2.0", - "uuid": "^3.0.1" - } - }, - "@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" - }, - "@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha1-TIVzDlm5ofHzSQR9vyQpYDS7JzU=" - }, - "@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha1-fvN/DQEPsCitGtWXIuUG2SYoFcs=" - }, - "@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" - }, - "@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", - "requires": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" - }, - "@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" - }, - "@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" - }, - "@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" - }, - "@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" - }, - "@sindresorhus/is": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.15.0.tgz", - "integrity": "sha1-lpFbqgXmpqHRN7rfSYTT/AWCC7Y=" - }, - "@sinonjs/commons": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz", - "integrity": "sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "@sinonjs/fake-timers": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", - "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.0" - } - }, - "@sinonjs/formatio": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-5.0.1.tgz", - "integrity": "sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1", - "@sinonjs/samsam": "^5.0.2" - } - }, - "@sinonjs/samsam": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.0.3.tgz", - "integrity": "sha512-QucHkc2uMJ0pFGjJUDP3F9dq5dx8QIaqISl9QgwLOh6P9yv877uONPGXh/OH/0zmM3tW1JjuJltAZV2l7zU+uQ==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.6.0", - "lodash.get": "^4.4.2", - "type-detect": "^4.0.8" - } - }, - "@sinonjs/text-encoding": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", - "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", - "dev": true - }, - "@types/caseless": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", - "integrity": "sha1-9l09Y4ngHutFi9VNyPUrlalGO8g=" - }, - "@types/console-log-level": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@types/console-log-level/-/console-log-level-1.4.0.tgz", - "integrity": "sha1-7/ccQa689RyLpa2LBdfVQkviuPM=" - }, - "@types/duplexify": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@types/duplexify/-/duplexify-3.6.0.tgz", - "integrity": "sha1-38grZL06IWj1vSZESvFlvwI33Ng=", - "requires": { - "@types/node": "*" - } - }, - "@types/long": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", - "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" - }, - "@types/node": { - "version": "13.7.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-13.7.7.tgz", - "integrity": "sha512-Uo4chgKbnPNlxQwoFmYIwctkQVkMMmsAoGGU4JKwLuvBefF0pCq4FybNSnfkfRCpC7ZW7kttcC/TrRtAJsvGtg==" - }, - "@types/request": { - "version": "2.48.4", - "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.4.tgz", - "integrity": "sha512-W1t1MTKYR8PxICH+A4HgEIPuAC3sbljoEVfyZbeFJJDbr30guDspJri2XOaM2E+Un7ZjrihaDi7cf6fPa2tbgw==", - "requires": { - "@types/caseless": "*", - "@types/node": "*", - "@types/tough-cookie": "*", - "form-data": "^2.5.0" - } - }, - "@types/semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-5.5.0.tgz", - "integrity": "sha1-FGwqKe59O65L8vyydGNuJkyBPEU=" - }, - "@types/tough-cookie": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.6.tgz", - "integrity": "sha512-wHNBMnkoEBiRAd3s8KTKwIuO9biFtTf0LehITzBhSco+HQI0xkXZbLOD55SW3Aqw3oUkHstkm5SPv58yaAdFPQ==" - }, - "abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha1-6vVNU7YrrkE46AnKIlyEOabvs5I=", - "requires": { - "event-target-shim": "^5.0.0" - } - }, - "acorn": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.0.tgz", - "integrity": "sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw==" - }, - "agent-base": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha1-gWXwHENgCbzK0LHRIvBe13Dvxu4=", - "requires": { - "es6-promisify": "^5.0.0" - } - }, - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - }, - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "array.prototype.map": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.2.tgz", - "integrity": "sha512-Az3OYxgsa1g7xDYp86l0nnN4bcmuEITGe1rbdEBVkrqkzMgDcbdQ2R7r41pNzti+4NMces3H8gMmuioZUilLgw==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1", - "es-array-method-boxes-properly": "^1.0.0", - "is-string": "^1.0.4" - } - }, - "arrify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", - "integrity": "sha1-yWVekzHgq81YjSp8rX6ZVvZnAfo=" - }, - "assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true - }, - "async-listener": { - "version": "0.6.10", - "resolved": "https://registry.npmjs.org/async-listener/-/async-listener-0.6.10.tgz", - "integrity": "sha1-p8l6vlcLpgLXgic8DeYKUePhfLw=", - "requires": { - "semver": "^5.3.0", - "shimmer": "^1.1.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } - } - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "axios": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.1.tgz", - "integrity": "sha1-/z8N4ue10YDnV62YAA8Qgbh7zqM=", - "requires": { - "follow-redirects": "1.5.10", - "is-buffer": "^2.0.2" - } - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "base64-js": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", - "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" - }, - "bignumber.js": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz", - "integrity": "sha1-gMBIdZ2CaACAfEv9Uh5Q7bulel8=" - }, - "binary-extensions": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", - "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", - "dev": true - }, - "bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha1-EDU8npRTNLwFEabZCzj7x8nFBN8=", - "requires": { - "file-uri-to-path": "1.0.0" - } - }, - "bintrees": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.1.tgz", - "integrity": "sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ=" - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" - }, - "builtin-modules": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz", - "integrity": "sha1-qtl8FRMet2tltQ7yCOdYTNdqdIQ=" - }, - "bunyan": { - "version": "1.8.12", - "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.12.tgz", - "integrity": "sha1-8VDw9nSKvdcq6uhPBEA74u8RN5c=", - "dev": true, - "requires": { - "dtrace-provider": "~0.8", - "moment": "^2.10.6", - "mv": "~2", - "safe-json-stringify": "~1" - } - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "chai": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", - "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", - "dev": true, - "requires": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^3.0.1", - "get-func-name": "^2.0.0", - "pathval": "^1.1.0", - "type-detect": "^4.0.5" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", - "dev": true - }, - "chokidar": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.1.tgz", - "integrity": "sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==", - "dev": true, - "requires": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "fsevents": "~2.1.2", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.3.0" - } - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dev": true, - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "console-log-level": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/console-log-level/-/console-log-level-1.4.1.tgz", - "integrity": "sha1-nFprue8e9lsFq6gwKLD/iUzfYwo=" - }, - "continuation-local-storage": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/continuation-local-storage/-/continuation-local-storage-3.2.1.tgz", - "integrity": "sha1-EfYT906RT+mzTJKtLSj+auHbf/s=", - "requires": { - "async-listener": "^0.6.0", - "emitter-listener": "^1.1.1" - } - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha1-6D0X3hbYp++3cX7b5fsQE17uYps=", - "requires": { - "ms": "^2.1.1" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, - "deep-eql": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", - "dev": true, - "requires": { - "type-detect": "^4.0.0" - } - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "requires": { - "object-keys": "^1.0.12" - } - }, - "delay": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/delay/-/delay-4.3.0.tgz", - "integrity": "sha512-Lwaf3zVFDMBop1yDuFZ19F9WyGcZcGacsbdlZtWjQmM50tOcMntm1njF/Nb/Vjij3KaSvCF+sEYGKrrjObu2NA==" - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - }, - "dtrace-provider": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.8.tgz", - "integrity": "sha512-b7Z7cNtHPhH9EJhNNbbeqTcXB8LGFFZhq1PGgEvpeHlzd36bhbdTWoE/Ba/YguqpBSlAPKnARWhVlhunCMwfxg==", - "dev": true, - "optional": true, - "requires": { - "nan": "^2.14.0" - } - }, - "duplexify": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha1-Kk31MX9sz9kfhtb9JdjYoQO4gwk=", - "requires": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - } - }, - "ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha1-rg8PothQRe8UqBfao86azQSJ5b8=", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "emitter-listener": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/emitter-listener/-/emitter-listener-1.1.2.tgz", - "integrity": "sha1-VrFA6PaZI3Wz18ssqxzHQy2WMug=", - "requires": { - "shimmer": "^1.2.0" - } - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "requires": { - "once": "^1.4.0" - } - }, - "ent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=" - }, - "es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", - "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - }, - "es-array-method-boxes-properly": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", - "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", - "dev": true - }, - "es-get-iterator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.0.tgz", - "integrity": "sha512-UfrmHuWQlNMTs35e1ypnvikg6jCz3SK8v8ImvmDsh36fCVUR1MqoFDiyn0/k52C8NqO3YsO8Oe0azeesNuqSsQ==", - "dev": true, - "requires": { - "es-abstract": "^1.17.4", - "has-symbols": "^1.0.1", - "is-arguments": "^1.0.4", - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-string": "^1.0.5", - "isarray": "^2.0.5" - }, - "dependencies": { - "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - } - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" - }, - "es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", - "requires": { - "es6-promise": "^4.0.3" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha1-XU0+vflYPWOlMzzi3rdICrKwV4k=" - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha1-+LETa0Bx+9jrFAr/hYsQGewpFfo=" - }, - "fast-text-encoding": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.0.tgz", - "integrity": "sha1-PlzoKTQJz6pxd6cbnKhOGx5vJe8=" - }, - "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha1-VTp7hEb/b2hDWcRF8eN6BdrMM90=" - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "findit2": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/findit2/-/findit2-2.2.3.tgz", - "integrity": "sha1-WKRmaX34piBc39vzlVNri9d3pfY=" - }, - "flat": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", - "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", - "dev": true, - "requires": { - "is-buffer": "~2.0.3" - } - }, - "follow-redirects": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", - "integrity": "sha1-e3qfmuov3/NnhqlP9kPtB/T/Xio=", - "requires": { - "debug": "=3.1.0" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "form-data": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", - "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "gaxios": { - "version": "1.8.4", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-1.8.4.tgz", - "integrity": "sha1-4Iw0/pPAqbZ6Ure556ZOZDX5ozk=", - "requires": { - "abort-controller": "^3.0.0", - "extend": "^3.0.2", - "https-proxy-agent": "^2.2.1", - "node-fetch": "^2.3.0" - } - }, - "gcp-metadata": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-1.0.0.tgz", - "integrity": "sha1-UhJEAin6CZ/C98KlzcuVV16bLKY=", - "requires": { - "gaxios": "^1.0.2", - "json-bigint": "^0.3.0" - } - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", - "dev": true - }, - "glob": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", - "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", - "dev": true, - "optional": true, - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "google-auth-library": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-3.1.2.tgz", - "integrity": "sha1-/y+IzVzSEYpXvT1a08CTyIN/w1A=", - "requires": { - "base64-js": "^1.3.0", - "fast-text-encoding": "^1.0.0", - "gaxios": "^1.2.1", - "gcp-metadata": "^1.0.0", - "gtoken": "^2.3.2", - "https-proxy-agent": "^2.2.1", - "jws": "^3.1.5", - "lru-cache": "^5.0.0", - "semver": "^5.5.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } - } - }, - "google-p12-pem": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-1.0.4.tgz", - "integrity": "sha1-t3+4M6Lrn388aJ4uVPCVJ293dgU=", - "requires": { - "node-forge": "^0.8.0", - "pify": "^4.0.0" - } - }, - "growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true - }, - "gtoken": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-2.3.3.tgz", - "integrity": "sha1-in/hVcXODEtxyIbPsoKpBg2UpkE=", - "requires": { - "gaxios": "^1.0.4", - "google-p12-pem": "^1.0.0", - "jws": "^3.1.5", - "mime": "^2.2.0", - "pify": "^4.0.0" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, - "hex2dec": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/hex2dec/-/hex2dec-1.1.2.tgz", - "integrity": "sha1-jhzkvvNqdPfVcjw/swkMKGAHczg=" - }, - "https-proxy-agent": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", - "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", - "requires": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" - } - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "is": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/is/-/is-3.3.0.tgz", - "integrity": "sha1-Yc/23TxBk9uUo9YlggcrROVkXXk=" - }, - "is-arguments": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", - "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==", - "dev": true - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-buffer": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", - "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==" - }, - "is-callable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", - "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", - "dev": true - }, - "is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-map": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.1.tgz", - "integrity": "sha512-T/S49scO8plUiAOA2DBTBG3JHpn1yiw0kRp6dgiZ0v2/6twi5eiB0rHtHFH9ZIrvlWc6+4O+m4zg5+Z833aXgw==", - "dev": true - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz", - "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==", - "dev": true, - "requires": { - "has-symbols": "^1.0.1" - } - }, - "is-set": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.1.tgz", - "integrity": "sha512-eJEzOtVyenDs1TMzSQ3kU3K+E0GUS9sno+F0OBT97xsgcJsF9nXMBtkT9/kut5JEpM7oL7X/0qxR17K3mcwIAA==", - "dev": true - }, - "is-string": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", - "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", - "dev": true - }, - "is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "dev": true, - "requires": { - "has-symbols": "^1.0.1" - } - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "iterate-iterator": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.1.tgz", - "integrity": "sha512-3Q6tudGN05kbkDQDI4CqjaBf4qf85w6W6GnuZDtUVYwKgtC1q8yxYX7CZed7N+tLzQqS6roujWvszf13T+n9aw==", - "dev": true - }, - "iterate-value": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/iterate-value/-/iterate-value-1.0.2.tgz", - "integrity": "sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==", - "dev": true, - "requires": { - "es-get-iterator": "^1.0.2", - "iterate-iterator": "^1.0.1" - } - }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "json-bigint": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-0.3.0.tgz", - "integrity": "sha1-DM2RLEuCcNBfBW+9E4FLU9OCWx4=", - "requires": { - "bignumber.js": "^7.0.0" - } - }, - "just-extend": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.0.tgz", - "integrity": "sha512-ApcjaOdVTJ7y4r08xI5wIqpvwS48Q0PBG4DJROcEkH1f8MdAiNFyFxz3xoL0LWAVwjrwPYZdVHHxhRHcx/uGLA==", - "dev": true - }, - "jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha1-dDwymFy56YZVUw1TZBtmyGRbA5o=", - "requires": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha1-ABCZ82OUaMlBQADpmZX6UvtHgwQ=", - "requires": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", - "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", - "dev": true - }, - "lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", - "dev": true - }, - "lodash.pickby": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz", - "integrity": "sha1-feoh2MGNdwOifHBMFdO4SmfjOv8=" - }, - "log-symbols": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", - "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", - "dev": true, - "requires": { - "chalk": "^2.4.2" - } - }, - "long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha1-mntxz7fTYaGU6lVSQckvdGjVvyg=" - }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha1-HaJ+ZxAnGUdpXa9oSOhH8B2EuSA=", - "requires": { - "yallist": "^3.0.2" - } - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" - }, - "mime": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", - "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==" - }, - "mime-db": { - "version": "1.43.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", - "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==" - }, - "mime-types": { - "version": "2.1.26", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", - "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", - "requires": { - "mime-db": "1.43.0" - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true, - "optional": true - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, - "optional": true, - "requires": { - "minimist": "0.0.8" - } - }, - "mocha": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.0.1.tgz", - "integrity": "sha512-vefaXfdYI8+Yo8nPZQQi0QO2o+5q9UIMX1jZ1XMmK3+4+CQjc7+B0hPdUeglXiTlr8IHMVRo63IhO9Mzt6fxOg==", - "dev": true, - "requires": { - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.3.1", - "debug": "3.2.6", - "diff": "4.0.2", - "escape-string-regexp": "1.0.5", - "find-up": "4.1.0", - "glob": "7.1.6", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "3.13.1", - "log-symbols": "3.0.0", - "minimatch": "3.0.4", - "ms": "2.1.2", - "object.assign": "4.1.0", - "promise.allsettled": "1.0.2", - "serialize-javascript": "3.0.0", - "strip-json-comments": "3.0.1", - "supports-color": "7.1.0", - "which": "2.0.2", - "wide-align": "1.1.3", - "workerpool": "6.0.0", - "yargs": "13.3.2", - "yargs-parser": "13.1.2", - "yargs-unparser": "1.6.0" - }, - "dependencies": { - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } - } - }, - "module-details-from-path": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.3.tgz", - "integrity": "sha1-EUyUlnPiqKNenTV4hSeqN7Z52is=" - }, - "moment": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", - "integrity": "sha1-DQVdU/UFKqZTyfbraLtdEr9cK1s=", - "dev": true, - "optional": true - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "mv": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", - "integrity": "sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI=", - "dev": true, - "optional": true, - "requires": { - "mkdirp": "~0.5.1", - "ncp": "~2.0.0", - "rimraf": "~2.4.0" - } - }, - "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha1-eBj3IgJ7JFmobwKV1DTR/CM2xSw=" - }, - "ncp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", - "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=", - "dev": true, - "optional": true - }, - "nise": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/nise/-/nise-4.0.4.tgz", - "integrity": "sha512-bTTRUNlemx6deJa+ZyoCUTRvH3liK5+N6VQZ4NIw90AgDXY6iPnsqplNFf6STcj+ePk0H/xqxnP75Lr0J0Fq3A==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.0", - "@sinonjs/fake-timers": "^6.0.0", - "@sinonjs/text-encoding": "^0.7.1", - "just-extend": "^4.0.2", - "path-to-regexp": "^1.7.0" - } - }, - "node-fetch": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", - "integrity": "sha1-5jNFY4bUqlWGP2dqerDaqP3ssP0=" - }, - "node-forge": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.8.5.tgz", - "integrity": "sha512-vFMQIWt+J/7FLNyKouZ9TazT74PRV3wgv9UT4cRjC8BffxFbKXkgIWR42URCPSnHm/QDz6BOlb2Q0U4+VQT67Q==" - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "object-inspect": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", - "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", - "dev": true - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "p-limit": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", - "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha1-yyhoVA4xPWHeWPr741zpAE1VQOY=" - }, - "parse-duration": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/parse-duration/-/parse-duration-0.1.2.tgz", - "integrity": "sha512-0qfMZyjOUFBeEIvJ5EayfXJqaEXxQ+Oj2b7tWJM3hvEXvXsYCk05EDVI23oYnEw2NaFYUWdABEVPBvBMh8L/pA==" - }, - "parse-ms": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-2.1.0.tgz", - "integrity": "sha1-NIVlp1PUOR+lJAKZVrFyy3dTCX0=" - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha1-1i27VnlAXXLEc37FhgDp3c8G0kw=" - }, - "path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "dev": true, - "requires": { - "isarray": "0.0.1" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - } - } - }, - "pathval": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", - "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", - "dev": true - }, - "picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", - "dev": true - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha1-SyzSXFDVmHNcUCkiJP2MbfQeMjE=" - }, - "pretty-ms": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-4.0.0.tgz", - "integrity": "sha1-Mbr0G5T9AiJwmKqgO9YmCOsNbpI=", - "requires": { - "parse-ms": "^2.0.0" - } - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "prom-client": { - "version": "11.5.3", - "resolved": "https://registry.npmjs.org/prom-client/-/prom-client-11.5.3.tgz", - "integrity": "sha512-iz22FmTbtkyL2vt0MdDFY+kWof+S9UB/NACxSn2aJcewtw+EERsen0urSkZ2WrHseNdydsvcxCTAnPcSMZZv4Q==", - "requires": { - "tdigest": "^0.1.1" - } - }, - "promise.allsettled": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/promise.allsettled/-/promise.allsettled-1.0.2.tgz", - "integrity": "sha512-UpcYW5S1RaNKT6pd+s9jp9K9rlQge1UXKskec0j6Mmuq7UJCvlS2J2/s/yuPN8ehftf9HXMxWlKiPbGGUzpoRg==", - "dev": true, - "requires": { - "array.prototype.map": "^1.0.1", - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1", - "function-bind": "^1.1.1", - "iterate-value": "^1.0.0" - } - }, - "protobufjs": { - "version": "6.8.8", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.8.8.tgz", - "integrity": "sha1-yLTxKC/XqQ5vWxCe0RyEr4KQjnw=", - "requires": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/long": "^4.0.0", - "@types/node": "^10.1.0", - "long": "^4.0.0" - }, - "dependencies": { - "@types/node": { - "version": "10.17.17", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.17.tgz", - "integrity": "sha512-gpNnRnZP3VWzzj5k3qrpRC6Rk3H/uclhAVo1aIvwzK5p5cOrs9yEyQ8H/HBsBY0u5rrWxXEiVPQ0dEB6pkjE8Q==" - } - } - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "readdirp": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.3.0.tgz", - "integrity": "sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==", - "dev": true, - "requires": { - "picomatch": "^2.0.7" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "require-in-the-middle": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-4.0.1.tgz", - "integrity": "sha512-EfkM2zANyGkrfIExsECMeNn/uzjvHrE9h36yLXSavmrDiH4tgDNvltAmEKnt4PNLbqKPHZz+uszW2wTKrLUX0w==", - "requires": { - "debug": "^4.1.1", - "module-details-from-path": "^1.0.3", - "resolve": "^1.12.0" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E=", - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "require-like": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/require-like/-/require-like-0.1.2.tgz", - "integrity": "sha1-rW8wwTvs15cBDEaK+ndcDAprR/o=", - "dev": true - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "resolve": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", - "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", - "requires": { - "path-parse": "^1.0.6" - } - }, - "retry-axios": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/retry-axios/-/retry-axios-0.3.2.tgz", - "integrity": "sha1-V1fID1hbTMTEmGqi/9R6YMbTXhM=" - }, - "retry-request": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-4.1.1.tgz", - "integrity": "sha512-BINDzVtLI2BDukjWmjAIRZ0oglnCAkpP2vQjM3jdLhmT62h0xnQgciPwBRDAvHqpkPT2Wo1XuUyLyn6nbGrZQQ==", - "requires": { - "debug": "^4.1.1", - "through2": "^3.0.1" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "rimraf": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", - "integrity": "sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto=", - "dev": true, - "optional": true, - "requires": { - "glob": "^6.0.1" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=" - }, - "safe-json-stringify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz", - "integrity": "sha1-NW5EvJjx+TzkXfFLzXwBzahuCv0=", - "dev": true, - "optional": true - }, - "sandboxed-module": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/sandboxed-module/-/sandboxed-module-2.0.4.tgz", - "integrity": "sha512-AwEPOdO8mg/wJjr876yCHP2DHqVN0MaggEXhp6IIf3bcI5cYoQl9QrrCHSrvToHjvdEiS5x4TVZRgjD2bEmNTA==", - "dev": true, - "requires": { - "require-like": "0.1.2", - "stack-trace": "0.0.9" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - }, - "serialize-javascript": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-3.0.0.tgz", - "integrity": "sha512-skZcHYw2vEX4bw90nAr2iTTsz6x2SrHEnfxgKYmZlvJYBEZrvbKtobJWlQ20zczKb3bsHHXXTYt48zBA7ni9cw==", - "dev": true - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "shimmer": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", - "integrity": "sha1-YQhZ994ye1h+/r9QH7QxF/mv8zc=" - }, - "sinon": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.0.2.tgz", - "integrity": "sha512-0uF8Q/QHkizNUmbK3LRFqx5cpTttEVXudywY9Uwzy8bTfZUhljZ7ARzSxnRHWYWtVTeh4Cw+tTb3iU21FQVO9A==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.2", - "@sinonjs/fake-timers": "^6.0.1", - "@sinonjs/formatio": "^5.0.1", - "@sinonjs/samsam": "^5.0.3", - "diff": "^4.0.2", - "nise": "^4.0.1", - "supports-color": "^7.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=" - }, - "split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha1-YFvZvjA6pZ+zX5Ip++oN3snqB9k=", - "requires": { - "through": "2" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "stack-trace": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.9.tgz", - "integrity": "sha1-qPbq7KkGdMMz58Q5U/J1tFFRBpU=", - "dev": true - }, - "stream-shift": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "string.prototype.trimend": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", - "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "string.prototype.trimstart": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", - "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "strip-json-comments": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", - "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - } - } - }, - "tdigest": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.1.tgz", - "integrity": "sha1-Ljyyw56kSeVdHmzZEReszKRYgCE=", - "requires": { - "bintrees": "1.0.1" - } - }, - "teeny-request": { - "version": "3.11.3", - "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-3.11.3.tgz", - "integrity": "sha1-M1xin3ZF5dZZk2LfLzIwxMvCOlU=", - "requires": { - "https-proxy-agent": "^2.2.1", - "node-fetch": "^2.2.0", - "uuid": "^3.3.2" - } - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" - }, - "through2": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", - "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", - "requires": { - "readable-stream": "2 || 3" - } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha1-dkb7XxiHHPu3dJ5pvTmmOI63RQw=", - "dev": true - }, - "underscore": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", - "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=" - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "dev": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "workerpool": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.0.0.tgz", - "integrity": "sha512-fU2OcNA/GVAJLLyKUoHkAgIhKb0JoCpSjLC/G2vYKxUjVmQwGbRVeoPJ1a8U4pnVofz4AQV5Y/NEw8oKqxEBtA==", - "dev": true - }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", - "dev": true - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - }, - "yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", - "dev": true, - "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, - "yargs-unparser": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", - "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", - "dev": true, - "requires": { - "flat": "^4.1.0", - "lodash": "^4.17.15", - "yargs": "^13.3.0" - } - }, - "yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==" - } - } -} From 37fda043d450a9cff8f4a0973b98fd3ff1384939 Mon Sep 17 00:00:00 2001 From: Jakob Ackermann Date: Fri, 14 Aug 2020 00:51:44 +0200 Subject: [PATCH 152/182] [http] use public node api for getting the response content-length --- libraries/metrics/http.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/metrics/http.js b/libraries/metrics/http.js index 34fde3c247..295efbcab3 100644 --- a/libraries/metrics/http.js +++ b/libraries/metrics/http.js @@ -39,7 +39,7 @@ module.exports.monitor = logger => (function(req, res, next) { requestUrl: reqUrl, requestSize, status: res.statusCode, - responseSize: (res._headers != null ? res._headers["content-length"] : undefined), + responseSize: res.getHeader("content-length"), userAgent: req.headers["user-agent"], remoteIp, referer: referrer, @@ -61,7 +61,7 @@ module.exports.monitor = logger => (function(req, res, next) { "content-length": req.headers["content-length"] }, res: { - "content-length": (res._headers != null ? res._headers["content-length"] : undefined), + "content-length": res.getHeader("content-length"), statusCode: res.statusCode }, "response-time": responseTimeMs From 6f4829e817b421be1dc8eb10a24d44f768369f7e Mon Sep 17 00:00:00 2001 From: Jakob Ackermann Date: Fri, 14 Aug 2020 00:41:21 +0200 Subject: [PATCH 153/182] [misc] fix module importing --- libraries/metrics/event_loop.js | 2 +- libraries/metrics/http.js | 2 +- libraries/metrics/{metrics.js => index.js} | 0 libraries/metrics/memory.js | 4 ++-- libraries/metrics/mongodb.js | 2 +- libraries/metrics/open_sockets.js | 4 ++-- libraries/metrics/test/unit/js/event_loop.js | 2 +- libraries/metrics/test/unit/js/timeAsyncMethodTests.js | 2 +- libraries/metrics/timeAsyncMethod.js | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) rename libraries/metrics/{metrics.js => index.js} (100%) diff --git a/libraries/metrics/event_loop.js b/libraries/metrics/event_loop.js index 58b0c732d2..5c4159ecb4 100644 --- a/libraries/metrics/event_loop.js +++ b/libraries/metrics/event_loop.js @@ -9,7 +9,7 @@ module.exports = (EventLoopMonitor = { monitor(logger, interval, log_threshold) { if (interval == null) { interval = 1000; } if (log_threshold == null) { log_threshold = 100; } - const Metrics = require("./metrics"); + const Metrics = require("./index"); // check for logger on startup to avoid exceptions later if undefined if ((logger == null)) { throw new Error("logger is undefined"); } // monitor delay in setInterval to detect event loop blocking diff --git a/libraries/metrics/http.js b/libraries/metrics/http.js index 34fde3c247..26db4b5507 100644 --- a/libraries/metrics/http.js +++ b/libraries/metrics/http.js @@ -11,7 +11,7 @@ const yn = require("yn"); const STACKDRIVER_LOGGING = yn(process.env['STACKDRIVER_LOGGING']); module.exports.monitor = logger => (function(req, res, next) { - const Metrics = require("./metrics"); + const Metrics = require("./index"); const startTime = process.hrtime(); const { end diff --git a/libraries/metrics/metrics.js b/libraries/metrics/index.js similarity index 100% rename from libraries/metrics/metrics.js rename to libraries/metrics/index.js diff --git a/libraries/metrics/memory.js b/libraries/metrics/memory.js index a068cad71d..2bcb7917d0 100644 --- a/libraries/metrics/memory.js +++ b/libraries/metrics/memory.js @@ -73,13 +73,13 @@ module.exports = (MemoryMonitor = { monitor(logger) { const interval = setInterval(() => MemoryMonitor.Check(logger) , oneMinute); - const Metrics = require("./metrics"); + const Metrics = require("./index"); return Metrics.registerDestructor(() => clearInterval(interval)); }, Check(logger) { let mem; - const Metrics = require("./metrics"); + const Metrics = require("./index"); const memBeforeGc = (mem = inMegaBytes(process.memoryUsage())); Metrics.gauge("memory.rss", mem.rss); Metrics.gauge("memory.heaptotal", mem.heapTotal); diff --git a/libraries/metrics/mongodb.js b/libraries/metrics/mongodb.js index edec01e421..230a8a4628 100644 --- a/libraries/metrics/mongodb.js +++ b/libraries/metrics/mongodb.js @@ -21,7 +21,7 @@ module.exports = { mongodbCore = require(v2_path); } catch (error1) {} - const Metrics = require("./metrics"); + const Metrics = require("./index"); const monitorMethod = function(base, method, type) { let _method; diff --git a/libraries/metrics/open_sockets.js b/libraries/metrics/open_sockets.js index 3232a8a851..fc7a11ec45 100644 --- a/libraries/metrics/open_sockets.js +++ b/libraries/metrics/open_sockets.js @@ -19,13 +19,13 @@ module.exports = (OpenSocketsMonitor = { monitor(logger) { const interval = setInterval(() => OpenSocketsMonitor.gaugeOpenSockets() , 5 * seconds); - const Metrics = require("./metrics"); + const Metrics = require("./index"); return Metrics.registerDestructor(() => clearInterval(interval)); }, gaugeOpenSockets() { let agents, hostname, url; - const Metrics = require("./metrics"); + const Metrics = require("./index"); const object = require('http').globalAgent.sockets; for (url in object) { agents = object[url]; diff --git a/libraries/metrics/test/unit/js/event_loop.js b/libraries/metrics/test/unit/js/event_loop.js index 7135287486..1791c0e216 100644 --- a/libraries/metrics/test/unit/js/event_loop.js +++ b/libraries/metrics/test/unit/js/event_loop.js @@ -24,7 +24,7 @@ describe('event_loop', function() { warn: sinon.stub() }; return this.event_loop = SandboxedModule.require(modulePath, { requires: { - './metrics': this.metrics + './index': this.metrics } } ); diff --git a/libraries/metrics/test/unit/js/timeAsyncMethodTests.js b/libraries/metrics/test/unit/js/timeAsyncMethodTests.js index 36bdb02cfa..de252acae4 100644 --- a/libraries/metrics/test/unit/js/timeAsyncMethodTests.js +++ b/libraries/metrics/test/unit/js/timeAsyncMethodTests.js @@ -25,7 +25,7 @@ describe('timeAsyncMethod', function() { inc: sinon.stub() }; this.timeAsyncMethod = SandboxedModule.require(modulePath, { requires: { - './metrics': this.metrics + './index': this.metrics } } ); diff --git a/libraries/metrics/timeAsyncMethod.js b/libraries/metrics/timeAsyncMethod.js index ddb2149859..b096cc6851 100644 --- a/libraries/metrics/timeAsyncMethod.js +++ b/libraries/metrics/timeAsyncMethod.js @@ -9,7 +9,7 @@ module.exports = function(obj, methodName, prefix, logger) { let modifedMethodName; - const metrics = require('./metrics'); + const metrics = require('./index'); if (typeof obj[methodName] !== 'function') { throw new Error(`[Metrics] expected object property '${methodName}' to be a function`); From 71ba4150fe1b195ddd1fa90088baba88b917776e Mon Sep 17 00:00:00 2001 From: Jakob Ackermann Date: Wed, 1 Apr 2020 16:10:40 +0200 Subject: [PATCH 154/182] [misc] enable compression for the /metrics route --- libraries/metrics/index.js | 5 ++++- libraries/metrics/package.json | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/metrics/index.js b/libraries/metrics/index.js index 54950e0008..25a739d6f7 100644 --- a/libraries/metrics/index.js +++ b/libraries/metrics/index.js @@ -8,6 +8,7 @@ let Metrics; console.log("using prometheus"); +const ExpressCompression = require('compression'); const prom = require('./prom_wrapper'); const { @@ -75,7 +76,9 @@ module.exports = (Metrics = { }, injectMetricsRoute(app) { - return app.get('/metrics', function(req, res) { + return app.get('/metrics', ExpressCompression({ + level: parseInt(process.env.METRICS_COMPRESSION_LEVEL || '1', 10) + }), function (req, res) { res.set('Content-Type', prom.registry.contentType); return res.end(prom.registry.metrics()); }); diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index b22b6996cc..6ae76b9b4a 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -10,6 +10,7 @@ "@google-cloud/debug-agent": "^3.0.0", "@google-cloud/profiler": "^0.2.3", "@google-cloud/trace-agent": "^3.2.0", + "compression": "^1.7.4", "prom-client": "^11.1.3", "underscore": "~1.6.0", "yn": "^3.1.1" From c530422f1efb4b74433fba8dabbfb2c4db64a207 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Fri, 4 Sep 2020 15:52:05 +0100 Subject: [PATCH 155/182] update package version to 3.1.0 --- libraries/metrics/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 6ae76b9b4a..5e76416759 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "@overleaf/metrics", - "version": "3.0.0", + "version": "3.1.0", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From 971a768c4e167d8cf0030958eefd73ed939fe8a4 Mon Sep 17 00:00:00 2001 From: Eric Mc Sween Date: Fri, 11 Sep 2020 14:18:22 -0400 Subject: [PATCH 156/182] Install prettier and eslint --- libraries/metrics/.eslintrc | 55 +++ libraries/metrics/.prettierrc | 4 + libraries/metrics/event_loop.js | 52 +-- libraries/metrics/http.js | 146 ++++---- libraries/metrics/index.js | 354 ++++++++++-------- libraries/metrics/memory.js | 166 ++++---- libraries/metrics/mongodb.js | 282 ++++++++------ libraries/metrics/open_sockets.js | 76 ++-- libraries/metrics/package.json | 16 +- libraries/metrics/prom_wrapper.js | 248 ++++++------ libraries/metrics/test/unit/js/event_loop.js | 71 ++-- .../test/unit/js/timeAsyncMethodTests.js | 318 +++++++++------- libraries/metrics/timeAsyncMethod.js | 114 +++--- libraries/metrics/uv_threadpool_size.js | 4 +- 14 files changed, 1102 insertions(+), 804 deletions(-) create mode 100644 libraries/metrics/.eslintrc create mode 100644 libraries/metrics/.prettierrc diff --git a/libraries/metrics/.eslintrc b/libraries/metrics/.eslintrc new file mode 100644 index 0000000000..dec00724f4 --- /dev/null +++ b/libraries/metrics/.eslintrc @@ -0,0 +1,55 @@ +{ + "extends": [ + "standard", + "prettier", + "prettier/standard" + ], + "parserOptions": { + "ecmaVersion": 2018 + }, + "plugins": [ + "mocha", + "chai-expect", + "chai-friendly" + ], + "env": { + "node": true + }, + "rules": { + // Swap the no-unused-expressions rule with a more chai-friendly one + "no-unused-expressions": 0, + "chai-friendly/no-unused-expressions": "error" + }, + "overrides": [ + { + // Test specific rules + "files": ["test/**/*.js"], + "env": { + "mocha": true + }, + "globals": { + "expect": true + }, + "rules": { + // mocha-specific rules + "mocha/handle-done-callback": "error", + "mocha/no-exclusive-tests": "error", + "mocha/no-global-tests": "error", + "mocha/no-identical-title": "error", + "mocha/no-nested-tests": "error", + "mocha/no-pending-tests": "error", + "mocha/no-skipped-tests": "error", + "mocha/no-mocha-arrows": "error", + + // chai-specific rules + "chai-expect/missing-assertion": "error", + "chai-expect/terminating-properties": "error", + + // prefer-arrow-callback applies to all callbacks, not just ones in mocha tests. + // we don't enforce this at the top-level - just in tests to manage `this` scope + // based on mocha's context mechanism + "mocha/prefer-arrow-callback": "error" + } + } + ] +} diff --git a/libraries/metrics/.prettierrc b/libraries/metrics/.prettierrc new file mode 100644 index 0000000000..b2095be81e --- /dev/null +++ b/libraries/metrics/.prettierrc @@ -0,0 +1,4 @@ +{ + "semi": false, + "singleQuote": true +} diff --git a/libraries/metrics/event_loop.js b/libraries/metrics/event_loop.js index 5c4159ecb4..37271321b4 100644 --- a/libraries/metrics/event_loop.js +++ b/libraries/metrics/event_loop.js @@ -4,27 +4,31 @@ * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -let EventLoopMonitor; -module.exports = (EventLoopMonitor = { - monitor(logger, interval, log_threshold) { - if (interval == null) { interval = 1000; } - if (log_threshold == null) { log_threshold = 100; } - const Metrics = require("./index"); - // check for logger on startup to avoid exceptions later if undefined - if ((logger == null)) { throw new Error("logger is undefined"); } - // monitor delay in setInterval to detect event loop blocking - let previous = Date.now(); - const intervalId = setInterval(function() { - const now = Date.now(); - const offset = now - previous - interval; - if (offset > log_threshold) { - logger.warn({offset}, "slow event loop"); - } - previous = now; - return Metrics.timing("event-loop-millsec", offset); - } - , interval); - - return Metrics.registerDestructor(() => clearInterval(intervalId)); - } -}); +module.exports = { + monitor(logger, interval, logThreshold) { + if (interval == null) { + interval = 1000 + } + if (logThreshold == null) { + logThreshold = 100 + } + const Metrics = require('./index') + // check for logger on startup to avoid exceptions later if undefined + if (logger == null) { + throw new Error('logger is undefined') + } + // monitor delay in setInterval to detect event loop blocking + let previous = Date.now() + const intervalId = setInterval(function() { + const now = Date.now() + const offset = now - previous - interval + if (offset > logThreshold) { + logger.warn({ offset }, 'slow event loop') + } + previous = now + return Metrics.timing('event-loop-millsec', offset) + }, interval) + + return Metrics.registerDestructor(() => clearInterval(intervalId)) + } +} diff --git a/libraries/metrics/http.js b/libraries/metrics/http.js index 4c9497c6d3..8d0f9caab1 100644 --- a/libraries/metrics/http.js +++ b/libraries/metrics/http.js @@ -5,73 +5,93 @@ * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -const os = require("os"); -const yn = require("yn"); +const yn = require('yn') -const STACKDRIVER_LOGGING = yn(process.env['STACKDRIVER_LOGGING']); +const STACKDRIVER_LOGGING = yn(process.env.STACKDRIVER_LOGGING) -module.exports.monitor = logger => (function(req, res, next) { - const Metrics = require("./index"); - const startTime = process.hrtime(); - const { - end - } = res; +module.exports.monitor = logger => + function(req, res, next) { + const Metrics = require('./index') + const startTime = process.hrtime() + const { end } = res res.end = function() { - let info; - end.apply(this, arguments); - const responseTime = process.hrtime(startTime); - const responseTimeMs = Math.round((responseTime[0] * 1000) + (responseTime[1] / 1000000)); - const requestSize = parseInt(req.headers["content-length"], 10); - if ((req.route != null ? req.route.path : undefined) != null) { - const routePath = req.route.path.toString().replace(/\//g, '_').replace(/\:/g, '').slice(1); - Metrics.timing("http_request", responseTimeMs, null, {method:req.method, status_code: res.statusCode, path:routePath}); - if (requestSize) { - Metrics.summary("http_request_size_bytes", requestSize, {method:req.method, status_code: res.statusCode, path:routePath}); - } + let info + end.apply(this, arguments) + const responseTime = process.hrtime(startTime) + const responseTimeMs = Math.round( + responseTime[0] * 1000 + responseTime[1] / 1000000 + ) + const requestSize = parseInt(req.headers['content-length'], 10) + if ((req.route != null ? req.route.path : undefined) != null) { + const routePath = req.route.path + .toString() + .replace(/\//g, '_') + .replace(/:/g, '') + .slice(1) + Metrics.timing('http_request', responseTimeMs, null, { + method: req.method, + status_code: res.statusCode, + path: routePath + }) + if (requestSize) { + Metrics.summary('http_request_size_bytes', requestSize, { + method: req.method, + status_code: res.statusCode, + path: routePath + }) } - const remoteIp = req.ip || __guard__(req.socket != null ? req.socket.socket : undefined, x => x.remoteAddress) || (req.socket != null ? req.socket.remoteAddress : undefined); - const reqUrl = req.originalUrl || req.url; - const referrer = req.headers['referer'] || req.headers['referrer']; - if (STACKDRIVER_LOGGING) { - info = { - httpRequest: { - requestMethod: req.method, - requestUrl: reqUrl, - requestSize, - status: res.statusCode, - responseSize: res.getHeader("content-length"), - userAgent: req.headers["user-agent"], - remoteIp, - referer: referrer, - latency: { - seconds: responseTime[0], - nanos: responseTime[1] - }, - protocol: req.protocol - } - }; - } else { - info = { - req: { - url: reqUrl, - method: req.method, - referrer, - "remote-addr": remoteIp, - "user-agent": req.headers["user-agent"], - "content-length": req.headers["content-length"] - }, - res: { - "content-length": res.getHeader("content-length"), - statusCode: res.statusCode - }, - "response-time": responseTimeMs - }; + } + const remoteIp = + req.ip || + __guard__( + req.socket != null ? req.socket.socket : undefined, + x => x.remoteAddress + ) || + (req.socket != null ? req.socket.remoteAddress : undefined) + const reqUrl = req.originalUrl || req.url + const referrer = req.headers.referer || req.headers.referrer + if (STACKDRIVER_LOGGING) { + info = { + httpRequest: { + requestMethod: req.method, + requestUrl: reqUrl, + requestSize, + status: res.statusCode, + responseSize: res.getHeader('content-length'), + userAgent: req.headers['user-agent'], + remoteIp, + referer: referrer, + latency: { + seconds: responseTime[0], + nanos: responseTime[1] + }, + protocol: req.protocol + } } - return logger.info(info, "%s %s", req.method, reqUrl); - }; - return next(); -}); + } else { + info = { + req: { + url: reqUrl, + method: req.method, + referrer, + 'remote-addr': remoteIp, + 'user-agent': req.headers['user-agent'], + 'content-length': req.headers['content-length'] + }, + res: { + 'content-length': res.getHeader('content-length'), + statusCode: res.statusCode + }, + 'response-time': responseTimeMs + } + } + return logger.info(info, '%s %s', req.method, reqUrl) + } + return next() + } function __guard__(value, transform) { - return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined; -} \ No newline at end of file + return typeof value !== 'undefined' && value !== null + ? transform(value) + : undefined +} diff --git a/libraries/metrics/index.js b/libraries/metrics/index.js index 25a739d6f7..178eb01868 100644 --- a/libraries/metrics/index.js +++ b/libraries/metrics/index.js @@ -5,187 +5,229 @@ * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -let Metrics; -console.log("using prometheus"); +let Metrics +console.log('using prometheus') -const ExpressCompression = require('compression'); -const prom = require('./prom_wrapper'); +const ExpressCompression = require('compression') +const prom = require('./prom_wrapper') -const { - collectDefaultMetrics -} = prom; +const { collectDefaultMetrics } = prom -let appname = "unknown"; -const hostname = require('os').hostname(); +let appname = 'unknown' +const hostname = require('os').hostname() -const destructors = []; +const destructors = [] -require("./uv_threadpool_size"); +require('./uv_threadpool_size') -module.exports = (Metrics = { - register: prom.registry, +module.exports = Metrics = { + register: prom.registry, - initialize(_name, opts) { - if (opts == null) { opts = {}; } - appname = _name; - collectDefaultMetrics({ timeout: 5000, prefix: Metrics.buildPromKey()}); - if (opts.ttlInMinutes) { - prom.ttlInMinutes = opts.ttlInMinutes; - } + initialize(_name, opts) { + if (opts == null) { + opts = {} + } + appname = _name + collectDefaultMetrics({ timeout: 5000, prefix: Metrics.buildPromKey() }) + if (opts.ttlInMinutes) { + prom.ttlInMinutes = opts.ttlInMinutes + } - console.log(`ENABLE_TRACE_AGENT set to ${process.env['ENABLE_TRACE_AGENT']}`); - if (process.env['ENABLE_TRACE_AGENT'] === "true") { - console.log("starting google trace agent"); - const traceAgent = require('@google-cloud/trace-agent'); + console.log( + `ENABLE_TRACE_AGENT set to ${process.env.ENABLE_TRACE_AGENT}` + ) + if (process.env.ENABLE_TRACE_AGENT === 'true') { + console.log('starting google trace agent') + const traceAgent = require('@google-cloud/trace-agent') - const traceOpts = - {ignoreUrls: [/^\/status/, /^\/health_check/]}; - traceAgent.start(traceOpts); - } + const traceOpts = { ignoreUrls: [/^\/status/, /^\/health_check/] } + traceAgent.start(traceOpts) + } - console.log(`ENABLE_DEBUG_AGENT set to ${process.env['ENABLE_DEBUG_AGENT']}`); - if (process.env['ENABLE_DEBUG_AGENT'] === "true") { - console.log("starting google debug agent"); - const debugAgent = require('@google-cloud/debug-agent'); - debugAgent.start({ - allowExpressions: true, - serviceContext: { - service: appname, - version: process.env['BUILD_VERSION'] - } - }); - } + console.log( + `ENABLE_DEBUG_AGENT set to ${process.env.ENABLE_DEBUG_AGENT}` + ) + if (process.env.ENABLE_DEBUG_AGENT === 'true') { + console.log('starting google debug agent') + const debugAgent = require('@google-cloud/debug-agent') + debugAgent.start({ + allowExpressions: true, + serviceContext: { + service: appname, + version: process.env.BUILD_VERSION + } + }) + } - console.log(`ENABLE_PROFILE_AGENT set to ${process.env['ENABLE_PROFILE_AGENT']}`); - if (process.env['ENABLE_PROFILE_AGENT'] === "true") { - console.log("starting google profile agent"); - const profiler = require('@google-cloud/profiler'); - profiler.start({ - serviceContext: { - service: appname, - version: process.env['BUILD_VERSION'] - } - }); - } + console.log( + `ENABLE_PROFILE_AGENT set to ${process.env.ENABLE_PROFILE_AGENT}` + ) + if (process.env.ENABLE_PROFILE_AGENT === 'true') { + console.log('starting google profile agent') + const profiler = require('@google-cloud/profiler') + profiler.start({ + serviceContext: { + service: appname, + version: process.env.BUILD_VERSION + } + }) + } - return Metrics.inc("process_startup"); - }, + return Metrics.inc('process_startup') + }, - registerDestructor(func) { - return destructors.push(func); - }, + registerDestructor(func) { + return destructors.push(func) + }, - injectMetricsRoute(app) { - return app.get('/metrics', ExpressCompression({ - level: parseInt(process.env.METRICS_COMPRESSION_LEVEL || '1', 10) - }), function (req, res) { - res.set('Content-Type', prom.registry.contentType); - return res.end(prom.registry.metrics()); - }); - }, + injectMetricsRoute(app) { + return app.get( + '/metrics', + ExpressCompression({ + level: parseInt(process.env.METRICS_COMPRESSION_LEVEL || '1', 10) + }), + function(req, res) { + res.set('Content-Type', prom.registry.contentType) + return res.end(prom.registry.metrics()) + } + ) + }, - buildPromKey(key){ - if (key == null) { key = ""; } - return key.replace(/[^a-zA-Z0-9]/g, "_"); - }, + buildPromKey(key) { + if (key == null) { + key = '' + } + return key.replace(/[^a-zA-Z0-9]/g, '_') + }, - sanitizeValue(value) { - return parseFloat(value); - }, + sanitizeValue(value) { + return parseFloat(value) + }, - set(key, value, sampleRate){ - if (sampleRate == null) { sampleRate = 1; } - return console.log("counts are not currently supported"); - }, + set(key, value, sampleRate) { + if (sampleRate == null) { + sampleRate = 1 + } + return console.log('counts are not currently supported') + }, - inc(key, sampleRate, opts){ - if (sampleRate == null) { sampleRate = 1; } - if (opts == null) { opts = {}; } - key = Metrics.buildPromKey(key); - opts.app = appname; - opts.host = hostname; - prom.metric('counter', key).inc(opts); - if (process.env['DEBUG_METRICS']) { - return console.log("doing inc", key, opts); - } - }, + inc(key, sampleRate, opts) { + if (sampleRate == null) { + sampleRate = 1 + } + if (opts == null) { + opts = {} + } + key = Metrics.buildPromKey(key) + opts.app = appname + opts.host = hostname + prom.metric('counter', key).inc(opts) + if (process.env.DEBUG_METRICS) { + return console.log('doing inc', key, opts) + } + }, - count(key, count, sampleRate, opts){ - if (sampleRate == null) { sampleRate = 1; } - if (opts == null) { opts = {}; } - key = Metrics.buildPromKey(key); - opts.app = appname; - opts.host = hostname; - prom.metric('counter', key).inc(opts, count); - if (process.env['DEBUG_METRICS']) { - return console.log("doing count/inc", key, opts); - } - }, + count(key, count, sampleRate, opts) { + if (sampleRate == null) { + sampleRate = 1 + } + if (opts == null) { + opts = {} + } + key = Metrics.buildPromKey(key) + opts.app = appname + opts.host = hostname + prom.metric('counter', key).inc(opts, count) + if (process.env.DEBUG_METRICS) { + return console.log('doing count/inc', key, opts) + } + }, - summary(key, value, opts){ - if (opts == null) { opts = {}; } - key = Metrics.buildPromKey(key); - opts.app = appname; - opts.host = hostname; - prom.metric('summary', key).observe(opts, value); - if (process.env['DEBUG_METRICS']) { - return console.log("doing summary", key, value, opts); - } - }, + summary(key, value, opts) { + if (opts == null) { + opts = {} + } + key = Metrics.buildPromKey(key) + opts.app = appname + opts.host = hostname + prom.metric('summary', key).observe(opts, value) + if (process.env.DEBUG_METRICS) { + return console.log('doing summary', key, value, opts) + } + }, - timing(key, timeSpan, sampleRate, opts){ - if (opts == null) { opts = {}; } - key = Metrics.buildPromKey("timer_" + key); - opts.app = appname; - opts.host = hostname; - prom.metric('summary', key).observe(opts, timeSpan); - if (process.env['DEBUG_METRICS']) { - return console.log("doing timing", key, opts); - } - }, + timing(key, timeSpan, sampleRate, opts) { + if (opts == null) { + opts = {} + } + key = Metrics.buildPromKey('timer_' + key) + opts.app = appname + opts.host = hostname + prom.metric('summary', key).observe(opts, timeSpan) + if (process.env.DEBUG_METRICS) { + return console.log('doing timing', key, opts) + } + }, - Timer : class { - constructor(key, sampleRate, opts){ - if (sampleRate == null) { sampleRate = 1; } - this.start = new Date(); - key = Metrics.buildPromKey(key); - this.key = key; - this.sampleRate = sampleRate; - this.opts = opts; - } + Timer: class { + constructor(key, sampleRate, opts) { + if (sampleRate == null) { + sampleRate = 1 + } + this.start = new Date() + key = Metrics.buildPromKey(key) + this.key = key + this.sampleRate = sampleRate + this.opts = opts + } - done() { - const timeSpan = new Date - this.start; - Metrics.timing(this.key, timeSpan, this.sampleRate, this.opts); - return timeSpan; - } - }, + done() { + const timeSpan = new Date() - this.start + Metrics.timing(this.key, timeSpan, this.sampleRate, this.opts) + return timeSpan + } + }, - gauge(key, value, sampleRate, opts){ - if (sampleRate == null) { sampleRate = 1; } - key = Metrics.buildPromKey(key); - prom.metric('gauge', key).set({app: appname, host: hostname, status: (opts != null ? opts.status : undefined)}, this.sanitizeValue(value)); - if (process.env['DEBUG_METRICS']) { - return console.log("doing gauge", key, opts); - } - }, + gauge(key, value, sampleRate, opts) { + if (sampleRate == null) { + sampleRate = 1 + } + key = Metrics.buildPromKey(key) + prom.metric('gauge', key).set( + { + app: appname, + host: hostname, + status: opts != null ? opts.status : undefined + }, + this.sanitizeValue(value) + ) + if (process.env.DEBUG_METRICS) { + return console.log('doing gauge', key, opts) + } + }, - globalGauge(key, value, sampleRate, opts){ - if (sampleRate == null) { sampleRate = 1; } - key = Metrics.buildPromKey(key); - return prom.metric('gauge', key).set({app: appname, status: (opts != null ? opts.status : undefined)},this.sanitizeValue(value)); - }, + globalGauge(key, value, sampleRate, opts) { + if (sampleRate == null) { + sampleRate = 1 + } + key = Metrics.buildPromKey(key) + return prom + .metric('gauge', key) + .set( + { app: appname, status: opts != null ? opts.status : undefined }, + this.sanitizeValue(value) + ) + }, - mongodb: require("./mongodb"), - http: require("./http"), - open_sockets: require("./open_sockets"), - event_loop: require("./event_loop"), - memory: require("./memory"), + mongodb: require('./mongodb'), + http: require('./http'), + open_sockets: require('./open_sockets'), + event_loop: require('./event_loop'), + memory: require('./memory'), - timeAsyncMethod: require('./timeAsyncMethod'), + timeAsyncMethod: require('./timeAsyncMethod'), - close() { - return Array.from(destructors).map((func) => - func()); - } -}); + close() { + return Array.from(destructors).map(func => func()) + } +} diff --git a/libraries/metrics/memory.js b/libraries/metrics/memory.js index 2bcb7917d0..b4fa7210a4 100644 --- a/libraries/metrics/memory.js +++ b/libraries/metrics/memory.js @@ -9,95 +9,105 @@ // adjust the period between gc()'s to reach a target of the gc saving // 4 megabytes each time. -let MemoryMonitor; -const oneMinute = 60 * 1000; -const oneMegaByte = 1024 * 1024; +let MemoryMonitor +const oneMinute = 60 * 1000 +const oneMegaByte = 1024 * 1024 -let CpuTimeBucket = 100; // current cpu time allowance in milliseconds -const CpuTimeBucketMax = 100; // maximum amount of cpu time allowed in bucket -const CpuTimeBucketRate = 10; // add this many milliseconds per minute +let CpuTimeBucket = 100 // current cpu time allowance in milliseconds +const CpuTimeBucketMax = 100 // maximum amount of cpu time allowed in bucket +const CpuTimeBucketRate = 10 // add this many milliseconds per minute -let gcInterval = 1; // how many minutes between gc (parameter is dynamically adjusted) -let countSinceLastGc = 0; // how many minutes since last gc -const MemoryChunkSize = 4; // how many megabytes we need to free to consider gc worth doing +let gcInterval = 1 // how many minutes between gc (parameter is dynamically adjusted) +let countSinceLastGc = 0 // how many minutes since last gc +const MemoryChunkSize = 4 // how many megabytes we need to free to consider gc worth doing const readyToGc = function() { - // update allowed cpu time - CpuTimeBucket = CpuTimeBucket + CpuTimeBucketRate; - CpuTimeBucket = CpuTimeBucket < CpuTimeBucketMax ? CpuTimeBucket : CpuTimeBucketMax; - // update counts since last gc - countSinceLastGc = countSinceLastGc + 1; - // check there is enough time since last gc and we have enough cpu - return (countSinceLastGc > gcInterval) && (CpuTimeBucket > 0); -}; + // update allowed cpu time + CpuTimeBucket = CpuTimeBucket + CpuTimeBucketRate + CpuTimeBucket = + CpuTimeBucket < CpuTimeBucketMax ? CpuTimeBucket : CpuTimeBucketMax + // update counts since last gc + countSinceLastGc = countSinceLastGc + 1 + // check there is enough time since last gc and we have enough cpu + return countSinceLastGc > gcInterval && CpuTimeBucket > 0 +} const executeAndTime = function(fn) { - // time the execution of fn() and subtract from cpu allowance - const t0 = process.hrtime(); - fn(); - const dt = process.hrtime(t0); - const timeTaken = (dt[0] + (dt[1]*1e-9)) * 1e3; // in milliseconds - CpuTimeBucket -= Math.ceil(timeTaken); - return timeTaken; -}; + // time the execution of fn() and subtract from cpu allowance + const t0 = process.hrtime() + fn() + const dt = process.hrtime(t0) + const timeTaken = (dt[0] + dt[1] * 1e-9) * 1e3 // in milliseconds + CpuTimeBucket -= Math.ceil(timeTaken) + return timeTaken +} const inMegaBytes = function(obj) { - // convert process.memoryUsage hash {rss,heapTotal,heapFreed} into megabytes - const result = {}; - for (let k in obj) { - const v = obj[k]; - result[k] = (v / oneMegaByte).toFixed(2); - } - return result; -}; + // convert process.memoryUsage hash {rss,heapTotal,heapFreed} into megabytes + const result = {} + for (const k in obj) { + const v = obj[k] + result[k] = (v / oneMegaByte).toFixed(2) + } + return result +} const updateMemoryStats = function(oldMem, newMem) { - countSinceLastGc = 0; - const delta = {}; - for (let k in newMem) { - delta[k] = (newMem[k] - oldMem[k]).toFixed(2); - } - // take the max of all memory measures - const savedMemory = Math.max(-delta.rss, -delta.heapTotal, -delta.heapUsed); - delta.megabytesFreed = savedMemory; - // did it do any good? - if (savedMemory < MemoryChunkSize) { - gcInterval = gcInterval + 1; // no, so wait longer next time - } else { - gcInterval = Math.max(gcInterval - 1, 1); // yes, wait less time - } - return delta; -}; + countSinceLastGc = 0 + const delta = {} + for (const k in newMem) { + delta[k] = (newMem[k] - oldMem[k]).toFixed(2) + } + // take the max of all memory measures + const savedMemory = Math.max(-delta.rss, -delta.heapTotal, -delta.heapUsed) + delta.megabytesFreed = savedMemory + // did it do any good? + if (savedMemory < MemoryChunkSize) { + gcInterval = gcInterval + 1 // no, so wait longer next time + } else { + gcInterval = Math.max(gcInterval - 1, 1) // yes, wait less time + } + return delta +} -module.exports = (MemoryMonitor = { - monitor(logger) { - const interval = setInterval(() => MemoryMonitor.Check(logger) - , oneMinute); - const Metrics = require("./index"); - return Metrics.registerDestructor(() => clearInterval(interval)); - }, +module.exports = MemoryMonitor = { + monitor(logger) { + const interval = setInterval(() => MemoryMonitor.Check(logger), oneMinute) + const Metrics = require('./index') + return Metrics.registerDestructor(() => clearInterval(interval)) + }, - Check(logger) { - let mem; - const Metrics = require("./index"); - const memBeforeGc = (mem = inMegaBytes(process.memoryUsage())); - Metrics.gauge("memory.rss", mem.rss); - Metrics.gauge("memory.heaptotal", mem.heapTotal); - Metrics.gauge("memory.heapused", mem.heapUsed); - Metrics.gauge("memory.gc-interval", gcInterval); - //Metrics.gauge("memory.cpu-time-bucket", CpuTimeBucket) + Check(logger) { + let mem + const Metrics = require('./index') + const memBeforeGc = (mem = inMegaBytes(process.memoryUsage())) + Metrics.gauge('memory.rss', mem.rss) + Metrics.gauge('memory.heaptotal', mem.heapTotal) + Metrics.gauge('memory.heapused', mem.heapUsed) + Metrics.gauge('memory.gc-interval', gcInterval) + // Metrics.gauge("memory.cpu-time-bucket", CpuTimeBucket) - logger.log(mem, "process.memoryUsage()"); + logger.log(mem, 'process.memoryUsage()') - if ((global.gc != null) && readyToGc()) { - const gcTime = (executeAndTime(global.gc)).toFixed(2); - const memAfterGc = inMegaBytes(process.memoryUsage()); - const deltaMem = updateMemoryStats(memBeforeGc, memAfterGc); - logger.log({gcTime, memBeforeGc, memAfterGc, deltaMem, gcInterval, CpuTimeBucket}, "global.gc() forced"); - //Metrics.timing("memory.gc-time", gcTime) - Metrics.gauge("memory.gc-rss-freed", -deltaMem.rss); - Metrics.gauge("memory.gc-heaptotal-freed", -deltaMem.heapTotal); - return Metrics.gauge("memory.gc-heapused-freed", -deltaMem.heapUsed); - } - } -}); + if (global.gc != null && readyToGc()) { + const gcTime = executeAndTime(global.gc).toFixed(2) + const memAfterGc = inMegaBytes(process.memoryUsage()) + const deltaMem = updateMemoryStats(memBeforeGc, memAfterGc) + logger.log( + { + gcTime, + memBeforeGc, + memAfterGc, + deltaMem, + gcInterval, + CpuTimeBucket + }, + 'global.gc() forced' + ) + // Metrics.timing("memory.gc-time", gcTime) + Metrics.gauge('memory.gc-rss-freed', -deltaMem.rss) + Metrics.gauge('memory.gc-heaptotal-freed', -deltaMem.heapTotal) + return Metrics.gauge('memory.gc-heapused-freed', -deltaMem.heapUsed) + } + } +} diff --git a/libraries/metrics/mongodb.js b/libraries/metrics/mongodb.js index 230a8a4628..89f1d0155f 100644 --- a/libraries/metrics/mongodb.js +++ b/libraries/metrics/mongodb.js @@ -5,124 +5,196 @@ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ module.exports = { - monitor(mongodb_require_path, logger) { + monitor(mongodbRequirePath, logger) { + let mongodb, mongodbCore + try { + // for the v1 driver the methods to wrap are in the mongodb + // module in lib/mongodb/db.js + mongodb = require(mongodbRequirePath) + } catch (error) {} - let mongodb, mongodbCore; - try { - // for the v1 driver the methods to wrap are in the mongodb - // module in lib/mongodb/db.js - mongodb = require(`${mongodb_require_path}`); - } catch (error) {} + try { + // for the v2 driver the relevant methods are in the mongodb-core + // module in lib/topologies/{server,replset,mongos}.js + const v2Path = mongodbRequirePath.replace(/\/mongodb$/, '/mongodb-core') + mongodbCore = require(v2Path) + } catch (error1) {} - try { - // for the v2 driver the relevant methods are in the mongodb-core - // module in lib/topologies/{server,replset,mongos}.js - const v2_path = mongodb_require_path.replace(/\/mongodb$/, '/mongodb-core'); - mongodbCore = require(v2_path); - } catch (error1) {} + const Metrics = require('./index') - const Metrics = require("./index"); + const monitorMethod = function(base, method, type) { + let _method + if (base == null) { + return + } + if ((_method = base[method]) == null) { + return + } + const arglen = _method.length - const monitorMethod = function(base, method, type) { - let _method; - if (base == null) { return; } - if ((_method = base[method]) == null) { return; } - const arglen = _method.length; + const mongoDriverV1Wrapper = function(dbCommand, options, callback) { + let query + if (typeof callback === 'undefined') { + callback = options + options = {} + } - const mongo_driver_v1_wrapper = function(db_command, options, callback) { - let query; - if (typeof callback === 'undefined') { - callback = options; - options = {}; - } + const collection = dbCommand.collectionName + if (collection.match(/\$cmd$/)) { + // Ignore noisy command methods like authenticating, ismaster and ping + return _method.call(this, dbCommand, options, callback) + } - const collection = db_command.collectionName; - if (collection.match(/\$cmd$/)) { - // Ignore noisy command methods like authenticating, ismaster and ping - return _method.call(this, db_command, options, callback); - } + if (dbCommand.query != null) { + query = Object.keys(dbCommand.query) + .sort() + .join('_') + } - let key = `mongo-requests.${collection}.${type}`; - if (db_command.query != null) { - query = Object.keys(db_command.query).sort().join("_"); - key += "." + query; - } + const timer = new Metrics.Timer('mongo', { collection, query }) + const start = new Date() + return _method.call(this, dbCommand, options, function() { + timer.done() + logger.log( + { + query: dbCommand.query, + query_type: type, + collection, + 'response-time': new Date() - start + }, + 'mongo request' + ) + return callback.apply(this, arguments) + }) + } - const timer = new Metrics.Timer("mongo", {collection, query}); - const start = new Date(); - return _method.call(this, db_command, options, function() { - timer.done(); - const time = new Date() - start; - logger.log({ - query: db_command.query, - query_type: type, - collection, - "response-time": new Date() - start - }, - "mongo request"); - return callback.apply(this, arguments); - }); - }; + const mongoDriverV2Wrapper = function(ns, ops, options, callback) { + let query + if (typeof callback === 'undefined') { + callback = options + options = {} + } - const mongo_driver_v2_wrapper = function(ns, ops, options, callback) { - let query; - if (typeof callback === 'undefined') { - callback = options; - options = {}; - } + if (ns.match(/\$cmd$/)) { + // Ignore noisy command methods like authenticating, ismaster and ping + return _method.call(this, ns, ops, options, callback) + } - if (ns.match(/\$cmd$/)) { - // Ignore noisy command methods like authenticating, ismaster and ping - return _method.call(this, ns, ops, options, callback); - } + let key = `mongo-requests.${ns}.${type}` + if (ops[0].q != null) { + // ops[0].q + query = Object.keys(ops[0].q) + .sort() + .join('_') + key += '.' + query + } - let key = `mongo-requests.${ns}.${type}`; - if (ops[0].q != null) { // ops[0].q - query = Object.keys(ops[0].q).sort().join("_"); - key += "." + query; - } + const timer = new Metrics.Timer(key) + const start = new Date() + return _method.call(this, ns, ops, options, function() { + timer.done() + logger.log( + { + query: ops[0].q, + query_type: type, + collection: ns, + 'response-time': new Date() - start + }, + 'mongo request' + ) + return callback.apply(this, arguments) + }) + } - const timer = new Metrics.Timer(key); - const start = new Date(); - return _method.call(this, ns, ops, options, function() { - timer.done(); - const time = new Date() - start; - logger.log({ - query: ops[0].q, - query_type: type, - collection: ns, - "response-time": new Date() - start - }, - "mongo request"); - return callback.apply(this, arguments); - }); - }; + if (arglen === 3) { + return (base[method] = mongoDriverV1Wrapper) + } else if (arglen === 4) { + return (base[method] = mongoDriverV2Wrapper) + } + } - if (arglen === 3) { - return base[method] = mongo_driver_v1_wrapper; - } else if (arglen === 4) { - return base[method] = mongo_driver_v2_wrapper; - } - }; + monitorMethod( + mongodb != null ? mongodb.Db.prototype : undefined, + '_executeQueryCommand', + 'query' + ) + monitorMethod( + mongodb != null ? mongodb.Db.prototype : undefined, + '_executeRemoveCommand', + 'remove' + ) + monitorMethod( + mongodb != null ? mongodb.Db.prototype : undefined, + '_executeInsertCommand', + 'insert' + ) + monitorMethod( + mongodb != null ? mongodb.Db.prototype : undefined, + '_executeUpdateCommand', + 'update' + ) - monitorMethod(mongodb != null ? mongodb.Db.prototype : undefined, "_executeQueryCommand", "query"); - monitorMethod(mongodb != null ? mongodb.Db.prototype : undefined, "_executeRemoveCommand", "remove"); - monitorMethod(mongodb != null ? mongodb.Db.prototype : undefined, "_executeInsertCommand", "insert"); - monitorMethod(mongodb != null ? mongodb.Db.prototype : undefined, "_executeUpdateCommand", "update"); + monitorMethod( + mongodbCore != null ? mongodbCore.Server.prototype : undefined, + 'command', + 'command' + ) + monitorMethod( + mongodbCore != null ? mongodbCore.Server.prototype : undefined, + 'remove', + 'remove' + ) + monitorMethod( + mongodbCore != null ? mongodbCore.Server.prototype : undefined, + 'insert', + 'insert' + ) + monitorMethod( + mongodbCore != null ? mongodbCore.Server.prototype : undefined, + 'update', + 'update' + ) - monitorMethod(mongodbCore != null ? mongodbCore.Server.prototype : undefined, "command", "command"); - monitorMethod(mongodbCore != null ? mongodbCore.Server.prototype : undefined, "remove", "remove"); - monitorMethod(mongodbCore != null ? mongodbCore.Server.prototype : undefined, "insert", "insert"); - monitorMethod(mongodbCore != null ? mongodbCore.Server.prototype : undefined, "update", "update"); + monitorMethod( + mongodbCore != null ? mongodbCore.ReplSet.prototype : undefined, + 'command', + 'command' + ) + monitorMethod( + mongodbCore != null ? mongodbCore.ReplSet.prototype : undefined, + 'remove', + 'remove' + ) + monitorMethod( + mongodbCore != null ? mongodbCore.ReplSet.prototype : undefined, + 'insert', + 'insert' + ) + monitorMethod( + mongodbCore != null ? mongodbCore.ReplSet.prototype : undefined, + 'update', + 'update' + ) - monitorMethod(mongodbCore != null ? mongodbCore.ReplSet.prototype : undefined, "command", "command"); - monitorMethod(mongodbCore != null ? mongodbCore.ReplSet.prototype : undefined, "remove", "remove"); - monitorMethod(mongodbCore != null ? mongodbCore.ReplSet.prototype : undefined, "insert", "insert"); - monitorMethod(mongodbCore != null ? mongodbCore.ReplSet.prototype : undefined, "update", "update"); - - monitorMethod(mongodbCore != null ? mongodbCore.Mongos.prototype : undefined, "command", "command"); - monitorMethod(mongodbCore != null ? mongodbCore.Mongos.prototype : undefined, "remove", "remove"); - monitorMethod(mongodbCore != null ? mongodbCore.Mongos.prototype : undefined, "insert", "insert"); - return monitorMethod(mongodbCore != null ? mongodbCore.Mongos.prototype : undefined, "update", "update"); - } -}; + monitorMethod( + mongodbCore != null ? mongodbCore.Mongos.prototype : undefined, + 'command', + 'command' + ) + monitorMethod( + mongodbCore != null ? mongodbCore.Mongos.prototype : undefined, + 'remove', + 'remove' + ) + monitorMethod( + mongodbCore != null ? mongodbCore.Mongos.prototype : undefined, + 'insert', + 'insert' + ) + return monitorMethod( + mongodbCore != null ? mongodbCore.Mongos.prototype : undefined, + 'update', + 'update' + ) + } +} diff --git a/libraries/metrics/open_sockets.js b/libraries/metrics/open_sockets.js index fc7a11ec45..01b7e8f874 100644 --- a/libraries/metrics/open_sockets.js +++ b/libraries/metrics/open_sockets.js @@ -5,44 +5,50 @@ * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -let OpenSocketsMonitor; -const URL = require("url"); -const seconds = 1000; +let OpenSocketsMonitor +const { URL } = require('url') +const seconds = 1000 // In Node 0.10 the default is 5, which means only 5 open connections at one. // Node 0.12 has a default of Infinity. Make sure we have no limit set, // regardless of Node version. -require("http").globalAgent.maxSockets = Infinity; -require("https").globalAgent.maxSockets = Infinity; +require('http').globalAgent.maxSockets = Infinity +require('https').globalAgent.maxSockets = Infinity -module.exports = (OpenSocketsMonitor = { - monitor(logger) { - const interval = setInterval(() => OpenSocketsMonitor.gaugeOpenSockets() - , 5 * seconds); - const Metrics = require("./index"); - return Metrics.registerDestructor(() => clearInterval(interval)); - }, +module.exports = OpenSocketsMonitor = { + monitor(logger) { + const interval = setInterval( + () => OpenSocketsMonitor.gaugeOpenSockets(), + 5 * seconds + ) + const Metrics = require('./index') + return Metrics.registerDestructor(() => clearInterval(interval)) + }, - gaugeOpenSockets() { - let agents, hostname, url; - const Metrics = require("./index"); - const object = require('http').globalAgent.sockets; - for (url in object) { - agents = object[url]; - url = URL.parse(`http://${url}`); - hostname = url.hostname != null ? url.hostname.replace(/\./g, "_") : undefined; - Metrics.gauge(`open_connections.http.${hostname}`, agents.length); - } - return (() => { - const result = []; - const object1 = require('https').globalAgent.sockets; - for (url in object1) { - agents = object1[url]; - url = URL.parse(`https://${url}`); - hostname = url.hostname != null ? url.hostname.replace(/\./g, "_") : undefined; - result.push(Metrics.gauge(`open_connections.https.${hostname}`, agents.length)); - } - return result; - })(); - } -}); + gaugeOpenSockets() { + let agents, hostname, url + const Metrics = require('./index') + const object = require('http').globalAgent.sockets + for (url in object) { + agents = object[url] + url = new URL(`http://${url}`) + hostname = + url.hostname != null ? url.hostname.replace(/\./g, '_') : undefined + Metrics.gauge(`open_connections.http.${hostname}`, agents.length) + } + return (() => { + const result = [] + const object1 = require('https').globalAgent.sockets + for (url in object1) { + agents = object1[url] + url = new URL(`https://${url}`) + hostname = + url.hostname != null ? url.hostname.replace(/\./g, '_') : undefined + result.push( + Metrics.gauge(`open_connections.https.${hostname}`, agents.length) + ) + } + return result + })() + } +} diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 5e76416759..2d509e0776 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -18,11 +18,25 @@ "devDependencies": { "bunyan": "^1.0.0", "chai": "^4.2.0", + "eslint": "^7.8.1", + "eslint-config-prettier": "^6.11.0", + "eslint-config-standard": "^14.1.1", + "eslint-plugin-chai-expect": "^2.2.0", + "eslint-plugin-chai-friendly": "^0.6.0", + "eslint-plugin-import": "^2.22.0", + "eslint-plugin-mocha": "^8.0.0", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-promise": "^4.2.1", + "eslint-plugin-standard": "^4.0.1", "mocha": "^8.0.1", + "prettier-eslint-cli": "^5.0.0", "sandboxed-module": "^2.0.4", "sinon": "^9.0.2" }, "scripts": { - "test": "mocha --reporter spec --recursive --exit --grep=$MOCHA_GREP test/unit" + "lint": "eslint --max-warnings 0 .", + "test": "mocha --reporter spec --recursive --exit --grep=$MOCHA_GREP test/unit", + "format": "prettier-eslint $PWD'/**/*.js' --list-different", + "format:fix": "prettier-eslint $PWD'/**/*.js' --write" } } diff --git a/libraries/metrics/prom_wrapper.js b/libraries/metrics/prom_wrapper.js index 64870ef746..64f267aedb 100644 --- a/libraries/metrics/prom_wrapper.js +++ b/libraries/metrics/prom_wrapper.js @@ -5,144 +5,162 @@ * DS205: Consider reworking code to avoid use of IIFEs * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -const prom = require('prom-client'); -const registry = require('prom-client').register; -const metrics = new Map(); - +const prom = require('prom-client') +const registry = require('prom-client').register +const metrics = new Map() const optsKey = function(opts) { - let keys = Object.keys(opts); - if (keys.length === 0) { return ''; } + let keys = Object.keys(opts) + if (keys.length === 0) { + return '' + } - keys = keys.sort(); + keys = keys.sort() - let hash = ''; - for (let key of Array.from(keys)) { - if (hash.length) { hash += ","; } - hash += `${key}:${opts[key]}`; - } + let hash = '' + for (const key of Array.from(keys)) { + if (hash.length) { + hash += ',' + } + hash += `${key}:${opts[key]}` + } - return hash; -}; + return hash +} const extendOpts = function(opts, labelNames) { - for (let label of Array.from(labelNames)) { - if (!opts[label]) { opts[label] = ''; } - } - return opts; -}; + for (const label of Array.from(labelNames)) { + if (!opts[label]) { + opts[label] = '' + } + } + return opts +} const optsAsArgs = function(opts, labelNames) { - const args = []; - for (let label of Array.from(labelNames)) { - args.push(opts[label] || ''); - } - return args; -}; - + const args = [] + for (const label of Array.from(labelNames)) { + args.push(opts[label] || '') + } + return args +} const PromWrapper = { - ttlInMinutes: 0, - registry, + ttlInMinutes: 0, + registry, - metric(type, name) { - return metrics.get(name) || new MetricWrapper(type, name); - }, - - collectDefaultMetrics: prom.collectDefaultMetrics -}; + metric(type, name) { + return metrics.get(name) || new MetricWrapper(type, name) + }, + collectDefaultMetrics: prom.collectDefaultMetrics +} class MetricWrapper { - constructor(type, name) { - metrics.set(name, this); - this.name = name; - this.instances = new Map(); - this.lastAccess = new Date(); - this.metric = (() => { switch (type) { - case "counter": - return new prom.Counter({ - name, - help: name, - labelNames: ['app','host','status','method', 'path'] - }); - case "summary": - return new prom.Summary({ - name, - help: name, - maxAgeSeconds: 60, - ageBuckets: 10, - labelNames: ['app', 'host', 'path', 'status_code', 'method', 'collection', 'query'] - }); - case "gauge": - return new prom.Gauge({ - name, - help: name, - labelNames: ['app','host', 'status'] - }); - } })(); - } + constructor(type, name) { + metrics.set(name, this) + this.name = name + this.instances = new Map() + this.lastAccess = new Date() + this.metric = (() => { + switch (type) { + case 'counter': + return new prom.Counter({ + name, + help: name, + labelNames: ['app', 'host', 'status', 'method', 'path'] + }) + case 'summary': + return new prom.Summary({ + name, + help: name, + maxAgeSeconds: 60, + ageBuckets: 10, + labelNames: [ + 'app', + 'host', + 'path', + 'status_code', + 'method', + 'collection', + 'query' + ] + }) + case 'gauge': + return new prom.Gauge({ + name, + help: name, + labelNames: ['app', 'host', 'status'] + }) + } + })() + } - inc(opts, value) { - return this._execMethod('inc', opts, value); - } + inc(opts, value) { + return this._execMethod('inc', opts, value) + } - observe(opts, value) { - return this._execMethod('observe', opts, value); - } + observe(opts, value) { + return this._execMethod('observe', opts, value) + } - set(opts, value) { - return this._execMethod('set', opts, value); - } + set(opts, value) { + return this._execMethod('set', opts, value) + } - sweep() { - const thresh = new Date(Date.now() - (1000 * 60 * PromWrapper.ttlInMinutes)); - this.instances.forEach((instance, key) => { - if (thresh > instance.time) { - if (process.env['DEBUG_METRICS']) { - console.log("Sweeping stale metric instance", this.name, {opts: instance.opts}, key); - } - return this.metric.remove(...Array.from(optsAsArgs(instance.opts, this.metric.labelNames) || [])); - } - }); + sweep() { + const thresh = new Date(Date.now() - 1000 * 60 * PromWrapper.ttlInMinutes) + this.instances.forEach((instance, key) => { + if (thresh > instance.time) { + if (process.env.DEBUG_METRICS) { + console.log( + 'Sweeping stale metric instance', + this.name, + { opts: instance.opts }, + key + ) + } + return this.metric.remove( + ...Array.from(optsAsArgs(instance.opts, this.metric.labelNames) || []) + ) + } + }) - if (thresh > this.lastAccess) { - if (process.env['DEBUG_METRICS']) { - console.log("Sweeping stale metric", this.name, thresh, this.lastAccess); - } - metrics.delete(this.name); - return registry.removeSingleMetric(this.name); - } - } + if (thresh > this.lastAccess) { + if (process.env.DEBUG_METRICS) { + console.log('Sweeping stale metric', this.name, thresh, this.lastAccess) + } + metrics.delete(this.name) + return registry.removeSingleMetric(this.name) + } + } - _execMethod(method, opts, value) { - opts = extendOpts(opts, this.metric.labelNames); - const key = optsKey(opts); - if (key !== '') { this.instances.set(key, { time: new Date(), opts }); } - this.lastAccess = new Date(); - return this.metric[method](opts, value); - } + _execMethod(method, opts, value) { + opts = extendOpts(opts, this.metric.labelNames) + const key = optsKey(opts) + if (key !== '') { + this.instances.set(key, { time: new Date(), opts }) + } + this.lastAccess = new Date() + return this.metric[method](opts, value) + } } - if (!PromWrapper.sweepRegistered) { - if (process.env['DEBUG_METRICS']) { - console.log("Registering sweep method"); - } - PromWrapper.sweepRegistered = true; - setInterval( - function() { - if (PromWrapper.ttlInMinutes) { - if (process.env['DEBUG_METRICS']) { - console.log("Sweeping metrics"); - } - return metrics.forEach((metric, key) => { - return metric.sweep(); - }); - } - }, - 60000); + if (process.env.DEBUG_METRICS) { + console.log('Registering sweep method') + } + PromWrapper.sweepRegistered = true + setInterval(function() { + if (PromWrapper.ttlInMinutes) { + if (process.env.DEBUG_METRICS) { + console.log('Sweeping metrics') + } + return metrics.forEach((metric, key) => { + return metric.sweep() + }) + } + }, 60000) } - -module.exports = PromWrapper; +module.exports = PromWrapper diff --git a/libraries/metrics/test/unit/js/event_loop.js b/libraries/metrics/test/unit/js/event_loop.js index 1791c0e216..5af886df99 100644 --- a/libraries/metrics/test/unit/js/event_loop.js +++ b/libraries/metrics/test/unit/js/event_loop.js @@ -3,45 +3,42 @@ * DS102: Remove unnecessary code created because of implicit returns * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -const chai = require('chai'); -const should = chai.should(); -const { - expect -} = chai; -const path = require('path'); -const modulePath = path.join(__dirname, '../../../event_loop.js'); -const SandboxedModule = require('sandboxed-module'); -const sinon = require("sinon"); +const chai = require('chai') +const { expect } = chai +const path = require('path') +const modulePath = path.join(__dirname, '../../../event_loop.js') +const SandboxedModule = require('sandboxed-module') +const sinon = require('sinon') describe('event_loop', function() { + before(function() { + this.metrics = { + timing: sinon.stub(), + registerDestructor: sinon.stub() + } + this.logger = { + warn: sinon.stub() + } + return (this.event_loop = SandboxedModule.require(modulePath, { + requires: { + './index': this.metrics + } + })) + }) - before(function() { - this.metrics = { - timing: sinon.stub(), - registerDestructor: sinon.stub() - }; - this.logger = { - warn: sinon.stub() - }; - return this.event_loop = SandboxedModule.require(modulePath, { requires: { - './index': this.metrics - } - } - ); - }); + describe('with a logger provided', function() { + before(function() { + return this.event_loop.monitor(this.logger) + }) - describe('with a logger provided', function() { - before(function() { - return this.event_loop.monitor(this.logger); - }); - - return it('should register a destructor with metrics', function() { - return this.metrics.registerDestructor.called.should.equal(true); - }); - }); - - return describe('without a logger provided', () => it('should throw an exception', function() { - return expect(this.event_loop.monitor).to.throw('logger is undefined'); - })); -}); + return it('should register a destructor with metrics', function() { + return expect(this.metrics.registerDestructor.called).to.equal(true) + }) + }) + return describe('without a logger provided', function() { + return it('should throw an exception', function() { + return expect(this.event_loop.monitor).to.throw('logger is undefined') + }) + }) +}) diff --git a/libraries/metrics/test/unit/js/timeAsyncMethodTests.js b/libraries/metrics/test/unit/js/timeAsyncMethodTests.js index de252acae4..5023d5a87f 100644 --- a/libraries/metrics/test/unit/js/timeAsyncMethodTests.js +++ b/libraries/metrics/test/unit/js/timeAsyncMethodTests.js @@ -4,160 +4,198 @@ * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -const chai = require('chai'); -const should = chai.should(); -const { - expect -} = chai; -const path = require('path'); -const modulePath = path.join(__dirname, '../../../timeAsyncMethod.js'); -const SandboxedModule = require('sandboxed-module'); -const sinon = require("sinon"); - +const chai = require('chai') +const { expect } = chai +const path = require('path') +const modulePath = path.join(__dirname, '../../../timeAsyncMethod.js') +const SandboxedModule = require('sandboxed-module') +const sinon = require('sinon') describe('timeAsyncMethod', function() { + beforeEach(function() { + this.Timer = { done: sinon.stub() } + this.TimerConstructor = sinon.stub().returns(this.Timer) + this.metrics = { + Timer: this.TimerConstructor, + inc: sinon.stub() + } + this.timeAsyncMethod = SandboxedModule.require(modulePath, { + requires: { + './index': this.metrics + } + }) - beforeEach(function() { - this.Timer = {done: sinon.stub()}; - this.TimerConstructor = sinon.stub().returns(this.Timer); - this.metrics = { - Timer: this.TimerConstructor, - inc: sinon.stub() - }; - this.timeAsyncMethod = SandboxedModule.require(modulePath, { requires: { - './index': this.metrics - } - } - ); + return (this.testObject = { + nextNumber(n, callback) { + return setTimeout(() => callback(null, n + 1), 100) + } + }) + }) - return this.testObject = { - nextNumber(n, callback) { - if (callback == null) { callback = function(err, result){}; } - return setTimeout( - () => callback(null, n+1) - , 100 - ); - } - };}); + it('should have the testObject behave correctly before wrapping', function(done) { + return this.testObject.nextNumber(2, (err, result) => { + expect(err).to.not.exist + expect(result).to.equal(3) + return done() + }) + }) - it('should have the testObject behave correctly before wrapping', function(done) { - return this.testObject.nextNumber(2, function(err, result) { - expect(err).to.not.exist; - expect(result).to.equal(3); - return done(); - }); - }); + it('should wrap method without error', function(done) { + this.timeAsyncMethod( + this.testObject, + 'nextNumber', + 'someContext.TestObject' + ) + return done() + }) - it('should wrap method without error', function(done) { - this.timeAsyncMethod(this.testObject, 'nextNumber', 'someContext.TestObject'); - return done(); - }); + it('should transparently wrap method invocation in timer', function(done) { + this.timeAsyncMethod( + this.testObject, + 'nextNumber', + 'someContext.TestObject' + ) + return this.testObject.nextNumber(2, (err, result) => { + expect(err).to.not.exist + expect(result).to.equal(3) + expect(this.TimerConstructor.callCount).to.equal(1) + expect(this.Timer.done.callCount).to.equal(1) + return done() + }) + }) - it('should transparently wrap method invocation in timer', function(done) { - this.timeAsyncMethod(this.testObject, 'nextNumber', 'someContext.TestObject'); - return this.testObject.nextNumber(2, (err, result) => { - expect(err).to.not.exist; - expect(result).to.equal(3); - expect(this.TimerConstructor.callCount).to.equal(1); - expect(this.Timer.done.callCount).to.equal(1); - return done(); - }); - }); + it('should increment success count', function(done) { + this.metrics.inc = sinon.stub() + this.timeAsyncMethod( + this.testObject, + 'nextNumber', + 'someContext.TestObject' + ) + return this.testObject.nextNumber(2, (err, result) => { + if (err) { + return done(err) + } + expect(this.metrics.inc.callCount).to.equal(1) + expect( + this.metrics.inc.calledWith('someContext_result', 1, { + method: 'TestObject_nextNumber', + status: 'success' + }) + ).to.equal(true) + return done() + }) + }) - it('should increment success count', function(done) { - this.metrics.inc = sinon.stub(); - this.timeAsyncMethod(this.testObject, 'nextNumber', 'someContext.TestObject'); - return this.testObject.nextNumber(2, (err, result) => { - expect(this.metrics.inc.callCount).to.equal(1); - expect(this.metrics.inc.calledWith('someContext_result', 1, { method: 'TestObject_nextNumber', status: 'success'})).to.equal(true); - return done(); - }); - }); + describe('when base method produces an error', function() { + beforeEach(function() { + this.metrics.inc = sinon.stub() + return (this.testObject.nextNumber = function(n, callback) { + return setTimeout(() => callback(new Error('woops')), 100) + }) + }) - describe('when base method produces an error', function() { - beforeEach(function() { - this.metrics.inc = sinon.stub(); - return this.testObject.nextNumber = function(n, callback) { - if (callback == null) { callback = function(err, result){}; } - return setTimeout( - () => callback(new Error('woops')) - , 100 - ); - }; - }); + it('should propagate the error transparently', function(done) { + this.timeAsyncMethod( + this.testObject, + 'nextNumber', + 'someContext.TestObject' + ) + return this.testObject.nextNumber(2, (err, result) => { + expect(err).to.exist + expect(err).to.be.instanceof(Error) + expect(result).to.not.exist + return done() + }) + }) - it('should propagate the error transparently', function(done) { - this.timeAsyncMethod(this.testObject, 'nextNumber', 'someContext.TestObject'); - return this.testObject.nextNumber(2, (err, result) => { - expect(err).to.exist; - expect(err).to.be.instanceof(Error); - expect(result).to.not.exist; - return done(); - }); - }); + return it('should increment failure count', function(done) { + this.timeAsyncMethod( + this.testObject, + 'nextNumber', + 'someContext.TestObject' + ) + return this.testObject.nextNumber(2, (err, result) => { + expect(err).to.exist + expect(this.metrics.inc.callCount).to.equal(1) + expect( + this.metrics.inc.calledWith('someContext_result', 1, { + method: 'TestObject_nextNumber', + status: 'failed' + }) + ).to.equal(true) + return done() + }) + }) + }) - return it('should increment failure count', function(done) { - this.timeAsyncMethod(this.testObject, 'nextNumber', 'someContext.TestObject'); - return this.testObject.nextNumber(2, (err, result) => { - expect(this.metrics.inc.callCount).to.equal(1); - expect(this.metrics.inc.calledWith('someContext_result', 1, { method: 'TestObject_nextNumber', status: 'failed'})).to.equal(true); - return done(); - }); - }); - }); + describe('when a logger is supplied', function() { + beforeEach(function() { + return (this.logger = { log: sinon.stub() }) + }) - describe('when a logger is supplied', function() { - beforeEach(function() { - return this.logger = {log: sinon.stub()};}); + return it('should also call logger.log', function(done) { + this.timeAsyncMethod( + this.testObject, + 'nextNumber', + 'someContext.TestObject', + this.logger + ) + return this.testObject.nextNumber(2, (err, result) => { + expect(err).to.not.exist + expect(result).to.equal(3) + expect(this.TimerConstructor.callCount).to.equal(1) + expect(this.Timer.done.callCount).to.equal(1) + expect(this.logger.log.callCount).to.equal(1) + return done() + }) + }) + }) - return it('should also call logger.log', function(done) { - this.timeAsyncMethod(this.testObject, 'nextNumber', 'someContext.TestObject', this.logger); - return this.testObject.nextNumber(2, (err, result) => { - expect(err).to.not.exist; - expect(result).to.equal(3); - expect(this.TimerConstructor.callCount).to.equal(1); - expect(this.Timer.done.callCount).to.equal(1); - expect(this.logger.log.callCount).to.equal(1); - return done(); - }); - }); - }); + describe('when the wrapper cannot be applied', function() { + beforeEach(function() {}) - describe('when the wrapper cannot be applied', function() { - beforeEach(function() {}); + return it('should raise an error', function() { + const badWrap = () => { + return this.timeAsyncMethod( + this.testObject, + 'DEFINITELY_NOT_A_REAL_METHOD', + 'someContext.TestObject' + ) + } + return expect(badWrap).to.throw( + /^.*expected object property 'DEFINITELY_NOT_A_REAL_METHOD' to be a function.*$/ + ) + }) + }) - return it('should raise an error', function() { - const badWrap = () => { - return this.timeAsyncMethod(this.testObject, 'DEFINITELY_NOT_A_REAL_METHOD', 'someContext.TestObject'); - }; - return expect(badWrap).to.throw( - /^.*expected object property 'DEFINITELY_NOT_A_REAL_METHOD' to be a function.*$/ - ); - }); - }); - - return describe('when the wrapped function is not using a callback', function() { - beforeEach(function() { - this.realMethod = sinon.stub().returns(42); - return this.testObject.nextNumber = this.realMethod; - }); - - it('should not throw an error', function() { - this.timeAsyncMethod(this.testObject, 'nextNumber', 'someContext.TestObject'); - const badCall = () => { - return this.testObject.nextNumber(2); - }; - return expect(badCall).to.not.throw(Error); - }); - - return it('should call the underlying method', function() { - this.timeAsyncMethod(this.testObject, 'nextNumber', 'someContext.TestObject'); - const result = this.testObject.nextNumber(12); - expect(this.realMethod.callCount).to.equal(1); - expect(this.realMethod.calledWith(12)).to.equal(true); - return expect(result).to.equal(42); - }); - }); -}); + return describe('when the wrapped function is not using a callback', function() { + beforeEach(function() { + this.realMethod = sinon.stub().returns(42) + return (this.testObject.nextNumber = this.realMethod) + }) + it('should not throw an error', function() { + this.timeAsyncMethod( + this.testObject, + 'nextNumber', + 'someContext.TestObject' + ) + const badCall = () => { + return this.testObject.nextNumber(2) + } + return expect(badCall).to.not.throw(Error) + }) + return it('should call the underlying method', function() { + this.timeAsyncMethod( + this.testObject, + 'nextNumber', + 'someContext.TestObject' + ) + const result = this.testObject.nextNumber(12) + expect(this.realMethod.callCount).to.equal(1) + expect(this.realMethod.calledWith(12)).to.equal(true) + return expect(result).to.equal(42) + }) + }) +}) diff --git a/libraries/metrics/timeAsyncMethod.js b/libraries/metrics/timeAsyncMethod.js index b096cc6851..65553922c8 100644 --- a/libraries/metrics/timeAsyncMethod.js +++ b/libraries/metrics/timeAsyncMethod.js @@ -8,59 +8,77 @@ */ module.exports = function(obj, methodName, prefix, logger) { - let modifedMethodName; - const metrics = require('./index'); + let modifedMethodName + const metrics = require('./index') - if (typeof obj[methodName] !== 'function') { - throw new Error(`[Metrics] expected object property '${methodName}' to be a function`); - } + if (typeof obj[methodName] !== 'function') { + throw new Error( + `[Metrics] expected object property '${methodName}' to be a function` + ) + } - const key = `${prefix}.${methodName}`; + const key = `${prefix}.${methodName}` - const realMethod = obj[methodName]; + const realMethod = obj[methodName] - const splitPrefix = prefix.split("."); - const startPrefix = splitPrefix[0]; + const splitPrefix = prefix.split('.') + const startPrefix = splitPrefix[0] - if (splitPrefix[1] != null) { - modifedMethodName = `${splitPrefix[1]}_${methodName}`; - } else { - modifedMethodName = methodName; - } - return obj[methodName] = function(...originalArgs) { + if (splitPrefix[1] != null) { + modifedMethodName = `${splitPrefix[1]}_${methodName}` + } else { + modifedMethodName = methodName + } + return (obj[methodName] = function(...originalArgs) { + const adjustedLength = Math.max(originalArgs.length, 1) + const firstArgs = originalArgs.slice(0, adjustedLength - 1) + const callback = originalArgs[adjustedLength - 1] - const adjustedLength = Math.max(originalArgs.length, 1), firstArgs = originalArgs.slice(0, adjustedLength - 1), callback = originalArgs[adjustedLength - 1]; + if (callback == null || typeof callback !== 'function') { + if (logger != null) { + logger.log( + `[Metrics] expected wrapped method '${methodName}' to be invoked with a callback` + ) + } + return realMethod.apply(this, originalArgs) + } - if ((callback == null) || (typeof callback !== 'function')) { - if (logger != null) { - logger.log(`[Metrics] expected wrapped method '${methodName}' to be invoked with a callback`); - } - return realMethod.apply(this, originalArgs); - } + const timer = new metrics.Timer(startPrefix, 1, { + method: modifedMethodName + }) - const timer = new metrics.Timer(startPrefix, 1, {method: modifedMethodName}); - - return realMethod.call(this, ...Array.from(firstArgs), function(...callbackArgs) { - const elapsedTime = timer.done(); - const possibleError = callbackArgs[0]; - if (possibleError != null) { - metrics.inc(`${startPrefix}_result`, 1, {status:"failed", method: modifedMethodName}); - } else { - metrics.inc(`${startPrefix}_result`, 1, {status:"success", method: modifedMethodName}); - } - if (logger != null) { - const loggableArgs = {}; - try { - for (let idx = 0; idx < firstArgs.length; idx++) { - const arg = firstArgs[idx]; - if (arg.toString().match(/^[0-9a-f]{24}$/)) { - loggableArgs[`${idx}`] = arg; - } - } - } catch (error) {} - logger.log({key, args: loggableArgs, elapsedTime}, "[Metrics] timed async method call"); - } - return callback.apply(this, callbackArgs); - }); - }; -}; + return realMethod.call(this, ...Array.from(firstArgs), function( + ...callbackArgs + ) { + const elapsedTime = timer.done() + const possibleError = callbackArgs[0] + if (possibleError != null) { + metrics.inc(`${startPrefix}_result`, 1, { + status: 'failed', + method: modifedMethodName + }) + } else { + metrics.inc(`${startPrefix}_result`, 1, { + status: 'success', + method: modifedMethodName + }) + } + if (logger != null) { + const loggableArgs = {} + try { + for (let idx = 0; idx < firstArgs.length; idx++) { + const arg = firstArgs[idx] + if (arg.toString().match(/^[0-9a-f]{24}$/)) { + loggableArgs[`${idx}`] = arg + } + } + } catch (error) {} + logger.log( + { key, args: loggableArgs, elapsedTime }, + '[Metrics] timed async method call' + ) + } + return callback.apply(this, callbackArgs) + }) + }) +} diff --git a/libraries/metrics/uv_threadpool_size.js b/libraries/metrics/uv_threadpool_size.js index bc8204e0b1..b2a8425281 100644 --- a/libraries/metrics/uv_threadpool_size.js +++ b/libraries/metrics/uv_threadpool_size.js @@ -1,4 +1,4 @@ if (!process.env.UV_THREADPOOL_SIZE) { - process.env.UV_THREADPOOL_SIZE=16; - console.log(`Set UV_THREADPOOL_SIZE=${process.env.UV_THREADPOOL_SIZE}`); + process.env.UV_THREADPOOL_SIZE = 16 + console.log(`Set UV_THREADPOOL_SIZE=${process.env.UV_THREADPOOL_SIZE}`) } From 6c020f6e5453560acfa0e1bf1227a6e050a1544a Mon Sep 17 00:00:00 2001 From: Eric Mc Sween Date: Fri, 11 Sep 2020 14:40:01 -0400 Subject: [PATCH 157/182] Decaf cleanup: remove Array.from() --- libraries/metrics/index.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/metrics/index.js b/libraries/metrics/index.js index 178eb01868..cac34b5021 100644 --- a/libraries/metrics/index.js +++ b/libraries/metrics/index.js @@ -1,6 +1,5 @@ /* * decaffeinate suggestions: - * DS101: Remove unnecessary use of Array.from * DS102: Remove unnecessary code created because of implicit returns * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md @@ -228,6 +227,8 @@ module.exports = Metrics = { timeAsyncMethod: require('./timeAsyncMethod'), close() { - return Array.from(destructors).map(func => func()) + for (const func of destructors) { + func() + } } } From d7e4b3fe33a17aee4ac1420f8c7de493860edce1 Mon Sep 17 00:00:00 2001 From: Eric Mc Sween Date: Fri, 11 Sep 2020 14:42:13 -0400 Subject: [PATCH 158/182] Decaf cleanup: unnecessary returns --- libraries/metrics/index.js | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/libraries/metrics/index.js b/libraries/metrics/index.js index cac34b5021..b884092796 100644 --- a/libraries/metrics/index.js +++ b/libraries/metrics/index.js @@ -1,6 +1,5 @@ /* * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns * DS207: Consider shorter variations of null checks * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ @@ -32,9 +31,7 @@ module.exports = Metrics = { prom.ttlInMinutes = opts.ttlInMinutes } - console.log( - `ENABLE_TRACE_AGENT set to ${process.env.ENABLE_TRACE_AGENT}` - ) + console.log(`ENABLE_TRACE_AGENT set to ${process.env.ENABLE_TRACE_AGENT}`) if (process.env.ENABLE_TRACE_AGENT === 'true') { console.log('starting google trace agent') const traceAgent = require('@google-cloud/trace-agent') @@ -43,9 +40,7 @@ module.exports = Metrics = { traceAgent.start(traceOpts) } - console.log( - `ENABLE_DEBUG_AGENT set to ${process.env.ENABLE_DEBUG_AGENT}` - ) + console.log(`ENABLE_DEBUG_AGENT set to ${process.env.ENABLE_DEBUG_AGENT}`) if (process.env.ENABLE_DEBUG_AGENT === 'true') { console.log('starting google debug agent') const debugAgent = require('@google-cloud/debug-agent') @@ -72,22 +67,22 @@ module.exports = Metrics = { }) } - return Metrics.inc('process_startup') + Metrics.inc('process_startup') }, registerDestructor(func) { - return destructors.push(func) + destructors.push(func) }, injectMetricsRoute(app) { - return app.get( + app.get( '/metrics', ExpressCompression({ level: parseInt(process.env.METRICS_COMPRESSION_LEVEL || '1', 10) }), function(req, res) { res.set('Content-Type', prom.registry.contentType) - return res.end(prom.registry.metrics()) + res.end(prom.registry.metrics()) } ) }, @@ -107,7 +102,7 @@ module.exports = Metrics = { if (sampleRate == null) { sampleRate = 1 } - return console.log('counts are not currently supported') + console.log('counts are not currently supported') }, inc(key, sampleRate, opts) { @@ -122,7 +117,7 @@ module.exports = Metrics = { opts.host = hostname prom.metric('counter', key).inc(opts) if (process.env.DEBUG_METRICS) { - return console.log('doing inc', key, opts) + console.log('doing inc', key, opts) } }, @@ -138,7 +133,7 @@ module.exports = Metrics = { opts.host = hostname prom.metric('counter', key).inc(opts, count) if (process.env.DEBUG_METRICS) { - return console.log('doing count/inc', key, opts) + console.log('doing count/inc', key, opts) } }, @@ -151,7 +146,7 @@ module.exports = Metrics = { opts.host = hostname prom.metric('summary', key).observe(opts, value) if (process.env.DEBUG_METRICS) { - return console.log('doing summary', key, value, opts) + console.log('doing summary', key, value, opts) } }, @@ -164,7 +159,7 @@ module.exports = Metrics = { opts.host = hostname prom.metric('summary', key).observe(opts, timeSpan) if (process.env.DEBUG_METRICS) { - return console.log('doing timing', key, opts) + console.log('doing timing', key, opts) } }, @@ -201,7 +196,7 @@ module.exports = Metrics = { this.sanitizeValue(value) ) if (process.env.DEBUG_METRICS) { - return console.log('doing gauge', key, opts) + console.log('doing gauge', key, opts) } }, @@ -210,7 +205,7 @@ module.exports = Metrics = { sampleRate = 1 } key = Metrics.buildPromKey(key) - return prom + prom .metric('gauge', key) .set( { app: appname, status: opts != null ? opts.status : undefined }, From afecfd52120100e6d6d366824018f088fea58c26 Mon Sep 17 00:00:00 2001 From: Eric Mc Sween Date: Fri, 11 Sep 2020 14:52:09 -0400 Subject: [PATCH 159/182] Decaf cleanup: use default parameters --- libraries/metrics/index.js | 68 +++++++------------------------------- 1 file changed, 12 insertions(+), 56 deletions(-) diff --git a/libraries/metrics/index.js b/libraries/metrics/index.js index b884092796..11ea2ddd32 100644 --- a/libraries/metrics/index.js +++ b/libraries/metrics/index.js @@ -1,8 +1,3 @@ -/* - * decaffeinate suggestions: - * DS207: Consider shorter variations of null checks - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ let Metrics console.log('using prometheus') @@ -21,10 +16,7 @@ require('./uv_threadpool_size') module.exports = Metrics = { register: prom.registry, - initialize(_name, opts) { - if (opts == null) { - opts = {} - } + initialize(_name, opts = {}) { appname = _name collectDefaultMetrics({ timeout: 5000, prefix: Metrics.buildPromKey() }) if (opts.ttlInMinutes) { @@ -87,10 +79,7 @@ module.exports = Metrics = { ) }, - buildPromKey(key) { - if (key == null) { - key = '' - } + buildPromKey(key = '') { return key.replace(/[^a-zA-Z0-9]/g, '_') }, @@ -98,20 +87,11 @@ module.exports = Metrics = { return parseFloat(value) }, - set(key, value, sampleRate) { - if (sampleRate == null) { - sampleRate = 1 - } + set(key, value, sampleRate = 1) { console.log('counts are not currently supported') }, - inc(key, sampleRate, opts) { - if (sampleRate == null) { - sampleRate = 1 - } - if (opts == null) { - opts = {} - } + inc(key, sampleRate = 1, opts = {}) { key = Metrics.buildPromKey(key) opts.app = appname opts.host = hostname @@ -121,13 +101,7 @@ module.exports = Metrics = { } }, - count(key, count, sampleRate, opts) { - if (sampleRate == null) { - sampleRate = 1 - } - if (opts == null) { - opts = {} - } + count(key, count, sampleRate = 1, opts = {}) { key = Metrics.buildPromKey(key) opts.app = appname opts.host = hostname @@ -137,10 +111,7 @@ module.exports = Metrics = { } }, - summary(key, value, opts) { - if (opts == null) { - opts = {} - } + summary(key, value, opts = {}) { key = Metrics.buildPromKey(key) opts.app = appname opts.host = hostname @@ -150,10 +121,7 @@ module.exports = Metrics = { } }, - timing(key, timeSpan, sampleRate, opts) { - if (opts == null) { - opts = {} - } + timing(key, timeSpan, sampleRate, opts = {}) { key = Metrics.buildPromKey('timer_' + key) opts.app = appname opts.host = hostname @@ -164,10 +132,7 @@ module.exports = Metrics = { }, Timer: class { - constructor(key, sampleRate, opts) { - if (sampleRate == null) { - sampleRate = 1 - } + constructor(key, sampleRate = 1, opts = {}) { this.start = new Date() key = Metrics.buildPromKey(key) this.key = key @@ -182,16 +147,13 @@ module.exports = Metrics = { } }, - gauge(key, value, sampleRate, opts) { - if (sampleRate == null) { - sampleRate = 1 - } + gauge(key, value, sampleRate = 1, opts = {}) { key = Metrics.buildPromKey(key) prom.metric('gauge', key).set( { app: appname, host: hostname, - status: opts != null ? opts.status : undefined + status: opts.status }, this.sanitizeValue(value) ) @@ -200,17 +162,11 @@ module.exports = Metrics = { } }, - globalGauge(key, value, sampleRate, opts) { - if (sampleRate == null) { - sampleRate = 1 - } + globalGauge(key, value, sampleRate = 1, opts = {}) { key = Metrics.buildPromKey(key) prom .metric('gauge', key) - .set( - { app: appname, status: opts != null ? opts.status : undefined }, - this.sanitizeValue(value) - ) + .set({ app: appname, status: opts.status }, this.sanitizeValue(value)) }, mongodb: require('./mongodb'), From 6f69fb4869d001918fe063584658f4b415c60c79 Mon Sep 17 00:00:00 2001 From: Eric Mc Sween Date: Fri, 11 Sep 2020 15:43:08 -0400 Subject: [PATCH 160/182] Decaf cleanup: move functions to top level --- libraries/metrics/index.js | 307 +++++++++++++++++++------------------ 1 file changed, 159 insertions(+), 148 deletions(-) diff --git a/libraries/metrics/index.js b/libraries/metrics/index.js index 11ea2ddd32..4a8ee39195 100644 --- a/libraries/metrics/index.js +++ b/libraries/metrics/index.js @@ -1,4 +1,3 @@ -let Metrics console.log('using prometheus') const ExpressCompression = require('compression') @@ -13,173 +12,185 @@ const destructors = [] require('./uv_threadpool_size') -module.exports = Metrics = { - register: prom.registry, +function initialize(_name, opts = {}) { + appname = _name + collectDefaultMetrics({ timeout: 5000, prefix: buildPromKey() }) + if (opts.ttlInMinutes) { + prom.ttlInMinutes = opts.ttlInMinutes + } - initialize(_name, opts = {}) { - appname = _name - collectDefaultMetrics({ timeout: 5000, prefix: Metrics.buildPromKey() }) - if (opts.ttlInMinutes) { - prom.ttlInMinutes = opts.ttlInMinutes - } + console.log(`ENABLE_TRACE_AGENT set to ${process.env.ENABLE_TRACE_AGENT}`) + if (process.env.ENABLE_TRACE_AGENT === 'true') { + console.log('starting google trace agent') + const traceAgent = require('@google-cloud/trace-agent') - console.log(`ENABLE_TRACE_AGENT set to ${process.env.ENABLE_TRACE_AGENT}`) - if (process.env.ENABLE_TRACE_AGENT === 'true') { - console.log('starting google trace agent') - const traceAgent = require('@google-cloud/trace-agent') + const traceOpts = { ignoreUrls: [/^\/status/, /^\/health_check/] } + traceAgent.start(traceOpts) + } - const traceOpts = { ignoreUrls: [/^\/status/, /^\/health_check/] } - traceAgent.start(traceOpts) - } - - console.log(`ENABLE_DEBUG_AGENT set to ${process.env.ENABLE_DEBUG_AGENT}`) - if (process.env.ENABLE_DEBUG_AGENT === 'true') { - console.log('starting google debug agent') - const debugAgent = require('@google-cloud/debug-agent') - debugAgent.start({ - allowExpressions: true, - serviceContext: { - service: appname, - version: process.env.BUILD_VERSION - } - }) - } - - console.log( - `ENABLE_PROFILE_AGENT set to ${process.env.ENABLE_PROFILE_AGENT}` - ) - if (process.env.ENABLE_PROFILE_AGENT === 'true') { - console.log('starting google profile agent') - const profiler = require('@google-cloud/profiler') - profiler.start({ - serviceContext: { - service: appname, - version: process.env.BUILD_VERSION - } - }) - } - - Metrics.inc('process_startup') - }, - - registerDestructor(func) { - destructors.push(func) - }, - - injectMetricsRoute(app) { - app.get( - '/metrics', - ExpressCompression({ - level: parseInt(process.env.METRICS_COMPRESSION_LEVEL || '1', 10) - }), - function(req, res) { - res.set('Content-Type', prom.registry.contentType) - res.end(prom.registry.metrics()) + console.log(`ENABLE_DEBUG_AGENT set to ${process.env.ENABLE_DEBUG_AGENT}`) + if (process.env.ENABLE_DEBUG_AGENT === 'true') { + console.log('starting google debug agent') + const debugAgent = require('@google-cloud/debug-agent') + debugAgent.start({ + allowExpressions: true, + serviceContext: { + service: appname, + version: process.env.BUILD_VERSION } - ) - }, + }) + } - buildPromKey(key = '') { - return key.replace(/[^a-zA-Z0-9]/g, '_') - }, + console.log(`ENABLE_PROFILE_AGENT set to ${process.env.ENABLE_PROFILE_AGENT}`) + if (process.env.ENABLE_PROFILE_AGENT === 'true') { + console.log('starting google profile agent') + const profiler = require('@google-cloud/profiler') + profiler.start({ + serviceContext: { + service: appname, + version: process.env.BUILD_VERSION + } + }) + } - sanitizeValue(value) { - return parseFloat(value) - }, + inc('process_startup') +} - set(key, value, sampleRate = 1) { - console.log('counts are not currently supported') - }, +function registerDestructor(func) { + destructors.push(func) +} - inc(key, sampleRate = 1, opts = {}) { - key = Metrics.buildPromKey(key) - opts.app = appname - opts.host = hostname - prom.metric('counter', key).inc(opts) - if (process.env.DEBUG_METRICS) { - console.log('doing inc', key, opts) +function injectMetricsRoute(app) { + app.get( + '/metrics', + ExpressCompression({ + level: parseInt(process.env.METRICS_COMPRESSION_LEVEL || '1', 10) + }), + function(req, res) { + res.set('Content-Type', prom.registry.contentType) + res.end(prom.registry.metrics()) } - }, + ) +} - count(key, count, sampleRate = 1, opts = {}) { - key = Metrics.buildPromKey(key) - opts.app = appname - opts.host = hostname - prom.metric('counter', key).inc(opts, count) - if (process.env.DEBUG_METRICS) { - console.log('doing count/inc', key, opts) - } - }, +function buildPromKey(key = '') { + return key.replace(/[^a-zA-Z0-9]/g, '_') +} - summary(key, value, opts = {}) { - key = Metrics.buildPromKey(key) - opts.app = appname - opts.host = hostname - prom.metric('summary', key).observe(opts, value) - if (process.env.DEBUG_METRICS) { - console.log('doing summary', key, value, opts) - } - }, +function sanitizeValue(value) { + return parseFloat(value) +} - timing(key, timeSpan, sampleRate, opts = {}) { - key = Metrics.buildPromKey('timer_' + key) - opts.app = appname - opts.host = hostname - prom.metric('summary', key).observe(opts, timeSpan) - if (process.env.DEBUG_METRICS) { - console.log('doing timing', key, opts) - } - }, +function set(key, value, sampleRate = 1) { + console.log('counts are not currently supported') +} - Timer: class { - constructor(key, sampleRate = 1, opts = {}) { - this.start = new Date() - key = Metrics.buildPromKey(key) - this.key = key - this.sampleRate = sampleRate - this.opts = opts - } +function inc(key, sampleRate = 1, opts = {}) { + key = buildPromKey(key) + opts.app = appname + opts.host = hostname + prom.metric('counter', key).inc(opts) + if (process.env.DEBUG_METRICS) { + console.log('doing inc', key, opts) + } +} - done() { - const timeSpan = new Date() - this.start - Metrics.timing(this.key, timeSpan, this.sampleRate, this.opts) - return timeSpan - } - }, +function count(key, count, sampleRate = 1, opts = {}) { + key = buildPromKey(key) + opts.app = appname + opts.host = hostname + prom.metric('counter', key).inc(opts, count) + if (process.env.DEBUG_METRICS) { + console.log('doing count/inc', key, opts) + } +} - gauge(key, value, sampleRate = 1, opts = {}) { - key = Metrics.buildPromKey(key) - prom.metric('gauge', key).set( - { - app: appname, - host: hostname, - status: opts.status - }, - this.sanitizeValue(value) - ) - if (process.env.DEBUG_METRICS) { - console.log('doing gauge', key, opts) - } - }, +function summary(key, value, opts = {}) { + key = buildPromKey(key) + opts.app = appname + opts.host = hostname + prom.metric('summary', key).observe(opts, value) + if (process.env.DEBUG_METRICS) { + console.log('doing summary', key, value, opts) + } +} - globalGauge(key, value, sampleRate = 1, opts = {}) { - key = Metrics.buildPromKey(key) - prom - .metric('gauge', key) - .set({ app: appname, status: opts.status }, this.sanitizeValue(value)) - }, +function timing(key, timeSpan, sampleRate, opts = {}) { + key = buildPromKey('timer_' + key) + opts.app = appname + opts.host = hostname + prom.metric('summary', key).observe(opts, timeSpan) + if (process.env.DEBUG_METRICS) { + console.log('doing timing', key, opts) + } +} + +class Timer { + constructor(key, sampleRate = 1, opts = {}) { + this.start = new Date() + key = buildPromKey(key) + this.key = key + this.sampleRate = sampleRate + this.opts = opts + } + + done() { + const timeSpan = new Date() - this.start + timing(this.key, timeSpan, this.sampleRate, this.opts) + return timeSpan + } +} + +function gauge(key, value, sampleRate = 1, opts = {}) { + key = buildPromKey(key) + prom.metric('gauge', key).set( + { + app: appname, + host: hostname, + status: opts.status + }, + this.sanitizeValue(value) + ) + if (process.env.DEBUG_METRICS) { + console.log('doing gauge', key, opts) + } +} + +function globalGauge(key, value, sampleRate = 1, opts = {}) { + key = buildPromKey(key) + prom + .metric('gauge', key) + .set({ app: appname, status: opts.status }, this.sanitizeValue(value)) +} + +function close() { + for (const func of destructors) { + func() + } +} + +module.exports = { + initialize, + registerDestructor, + injectMetricsRoute, + buildPromKey, + sanitizeValue, + set, + inc, + count, + summary, + timing, + Timer, + gauge, + globalGauge, + close, + + register: prom.registry, mongodb: require('./mongodb'), http: require('./http'), open_sockets: require('./open_sockets'), event_loop: require('./event_loop'), memory: require('./memory'), - - timeAsyncMethod: require('./timeAsyncMethod'), - - close() { - for (const func of destructors) { - func() - } - } + timeAsyncMethod: require('./timeAsyncMethod') } From 3c9c17c22f0e6c0e1477fc455c8eb3c93312c030 Mon Sep 17 00:00:00 2001 From: Eric Mc Sween Date: Fri, 11 Sep 2020 15:44:16 -0400 Subject: [PATCH 161/182] Remove "using prometheus" log We now always use prometheus --- libraries/metrics/index.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/metrics/index.js b/libraries/metrics/index.js index 4a8ee39195..ce5af6eb0a 100644 --- a/libraries/metrics/index.js +++ b/libraries/metrics/index.js @@ -1,5 +1,3 @@ -console.log('using prometheus') - const ExpressCompression = require('compression') const prom = require('./prom_wrapper') From c05bd83e240ae847c588bc8c882a40806e43b718 Mon Sep 17 00:00:00 2001 From: Eric Mc Sween Date: Fri, 11 Sep 2020 15:54:58 -0400 Subject: [PATCH 162/182] Add a separate configure() method configure() sets options in the metrics module, but does not start the default metrics collectors and the profiling agents. --- libraries/metrics/index.js | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/libraries/metrics/index.js b/libraries/metrics/index.js index ce5af6eb0a..7ebd876c37 100644 --- a/libraries/metrics/index.js +++ b/libraries/metrics/index.js @@ -10,12 +10,25 @@ const destructors = [] require('./uv_threadpool_size') -function initialize(_name, opts = {}) { - appname = _name - collectDefaultMetrics({ timeout: 5000, prefix: buildPromKey() }) +/** + * Configure the metrics module + */ +function configure(opts = {}) { + if (opts.appName) { + appname = opts.appName + } if (opts.ttlInMinutes) { prom.ttlInMinutes = opts.ttlInMinutes } +} + +/** + * Configure the metrics module and start the default metrics collectors and + * profiling agents. + */ +function initialize(_name, opts = {}) { + configure({ ...opts, appName: _name }) + collectDefaultMetrics({ timeout: 5000, prefix: buildPromKey() }) console.log(`ENABLE_TRACE_AGENT set to ${process.env.ENABLE_TRACE_AGENT}`) if (process.env.ENABLE_TRACE_AGENT === 'true') { @@ -71,7 +84,7 @@ function injectMetricsRoute(app) { ) } -function buildPromKey(key = '') { +function buildPromKey(key) { return key.replace(/[^a-zA-Z0-9]/g, '_') } @@ -113,7 +126,7 @@ function summary(key, value, opts = {}) { } } -function timing(key, timeSpan, sampleRate, opts = {}) { +function timing(key, timeSpan, sampleRate = 1, opts = {}) { key = buildPromKey('timer_' + key) opts.app = appname opts.host = hostname @@ -168,6 +181,7 @@ function close() { } module.exports = { + configure, initialize, registerDestructor, injectMetricsRoute, From ec0441bc89b7f7eea8e4cc790a59f0bf3b09b04e Mon Sep 17 00:00:00 2001 From: Eric Mc Sween Date: Tue, 15 Sep 2020 08:37:05 -0400 Subject: [PATCH 163/182] 3.2.0 --- libraries/metrics/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 2d509e0776..b73f17358e 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "@overleaf/metrics", - "version": "3.1.0", + "version": "3.2.0", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From 2f35db4087bb0e4dcf6d6c0556896a01cdd763de Mon Sep 17 00:00:00 2001 From: Eric Mc Sween Date: Wed, 16 Sep 2020 16:45:56 -0400 Subject: [PATCH 164/182] Fix startup crash Version 3.2.0 crashes on startup because it calls buildPromKey() without arguments. To avoid this kind of obvious bug to happen again, I added some basic acceptance tests. --- libraries/metrics/.circleci/config.yml | 11 ++ libraries/metrics/index.js | 2 +- libraries/metrics/package.json | 4 +- .../metrics/test/acceptance/metrics_tests.js | 115 ++++++++++++++++++ 4 files changed, 130 insertions(+), 2 deletions(-) create mode 100644 libraries/metrics/.circleci/config.yml create mode 100644 libraries/metrics/test/acceptance/metrics_tests.js diff --git a/libraries/metrics/.circleci/config.yml b/libraries/metrics/.circleci/config.yml new file mode 100644 index 0000000000..d8eed2a65a --- /dev/null +++ b/libraries/metrics/.circleci/config.yml @@ -0,0 +1,11 @@ +version: 2.1 + +orbs: + node: circleci/node@3.0.0 + +workflows: + test: + jobs: + - node/test: + version: "10.22" + override-ci-command: npm install diff --git a/libraries/metrics/index.js b/libraries/metrics/index.js index 7ebd876c37..c76ab35c3c 100644 --- a/libraries/metrics/index.js +++ b/libraries/metrics/index.js @@ -28,7 +28,7 @@ function configure(opts = {}) { */ function initialize(_name, opts = {}) { configure({ ...opts, appName: _name }) - collectDefaultMetrics({ timeout: 5000, prefix: buildPromKey() }) + collectDefaultMetrics({ timeout: 5000, prefix: '' }) console.log(`ENABLE_TRACE_AGENT set to ${process.env.ENABLE_TRACE_AGENT}`) if (process.env.ENABLE_TRACE_AGENT === 'true') { diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index b73f17358e..b79b74b320 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -35,7 +35,9 @@ }, "scripts": { "lint": "eslint --max-warnings 0 .", - "test": "mocha --reporter spec --recursive --exit --grep=$MOCHA_GREP test/unit", + "test:unit": "mocha --reporter spec --recursive --exit --grep=$MOCHA_GREP test/unit", + "test:acceptance": "mocha --reporter spec --recursive --exit --grep=$MOCHA_GREP test/acceptance", + "test": "npm run test:unit && npm run test:acceptance", "format": "prettier-eslint $PWD'/**/*.js' --list-different", "format:fix": "prettier-eslint $PWD'/**/*.js' --write" } diff --git a/libraries/metrics/test/acceptance/metrics_tests.js b/libraries/metrics/test/acceptance/metrics_tests.js new file mode 100644 index 0000000000..e7f6cdd6cc --- /dev/null +++ b/libraries/metrics/test/acceptance/metrics_tests.js @@ -0,0 +1,115 @@ +const os = require('os') +const { expect } = require('chai') +const Metrics = require('../..') + +const HOSTNAME = os.hostname() +const APP_NAME = 'test-app' + +describe('Metrics module', function() { + before(function() { + Metrics.initialize(APP_NAME) + }) + + describe('at startup', function() { + it('increments the process_startup counter', async function() { + await expectMetricValue('process_startup', 1) + }) + + it('collects default metrics', async function() { + const metric = await getMetric('process_cpu_user_seconds_total') + expect(metric).to.exist + }) + }) + + describe('inc()', function() { + it('increments counts by 1', async function() { + Metrics.inc('duck_count') + await expectMetricValue('duck_count', 1) + Metrics.inc('duck_count') + Metrics.inc('duck_count') + await expectMetricValue('duck_count', 3) + }) + + it('escapes special characters in the key', async function() { + Metrics.inc('show.me the $!!') + await expectMetricValue('show_me_the____', 1) + }) + }) + + describe('count()', function() { + it('increments counts by the given count', async function() { + Metrics.count('rabbit_count', 5) + await expectMetricValue('rabbit_count', 5) + Metrics.count('rabbit_count', 6) + Metrics.count('rabbit_count', 7) + await expectMetricValue('rabbit_count', 18) + }) + }) + + describe('summary()', function() { + it('collects observations', async function() { + Metrics.summary('oven_temp', 200) + Metrics.summary('oven_temp', 300) + Metrics.summary('oven_temp', 450) + const sum = await getSummarySum('oven_temp') + expect(sum).to.equal(950) + }) + }) + + describe('timing()', function() { + it('collects timings', async function() { + Metrics.timing('sprint_100m', 10) + Metrics.timing('sprint_100m', 20) + Metrics.timing('sprint_100m', 30) + const sum = await getSummarySum('timer_sprint_100m') + expect(sum).to.equal(60) + }) + }) + + describe('gauge()', function() { + it('records values', async function() { + Metrics.gauge('water_level', 1.5) + await expectMetricValue('water_level', 1.5) + Metrics.gauge('water_level', 4.2) + await expectMetricValue('water_level', 4.2) + }) + }) + + describe('globalGauge()', function() { + it('records values without a host label', async function() { + Metrics.globalGauge('tire_pressure', 99.99) + const { value, labels } = await getMetricValue('tire_pressure') + expect(value).to.equal(99.99) + expect(labels.host).to.equal('') + expect(labels.app).to.equal(APP_NAME) + }) + }) +}) + +function getMetric(key) { + return Metrics.register.getSingleMetric(key) +} + +async function getSummarySum(key) { + const metric = getMetric(key) + const item = await metric.get() + for (const value of item.values) { + if (value.metricName === `${key}_sum`) { + return value.value + } + } + return null +} + +async function getMetricValue(key) { + const metric = getMetric(key) + const item = await metric.get() + return item.values[0] +} + +async function expectMetricValue(key, expectedValue) { + const value = await getMetricValue(key) + expect(value.value).to.equal(expectedValue) + expect(value.labels.host).to.equal(HOSTNAME) + expect(value.labels.app).to.equal(APP_NAME) +} From bd1a1dbabfafb281136392e29e79bbde3c8df85d Mon Sep 17 00:00:00 2001 From: Eric Mc Sween Date: Thu, 17 Sep 2020 10:40:34 -0400 Subject: [PATCH 165/182] 3.2.1 --- libraries/metrics/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index b79b74b320..cb265922af 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "@overleaf/metrics", - "version": "3.2.0", + "version": "3.2.1", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From 0fdbb2dcc032d16f5115b9445b20a61b6cdec528 Mon Sep 17 00:00:00 2001 From: Eric Mc Sween Date: Thu, 17 Sep 2020 10:44:24 -0400 Subject: [PATCH 166/182] Add .npmignore to avoid publishing config files --- libraries/metrics/.npmignore | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 libraries/metrics/.npmignore diff --git a/libraries/metrics/.npmignore b/libraries/metrics/.npmignore new file mode 100644 index 0000000000..879872f6ad --- /dev/null +++ b/libraries/metrics/.npmignore @@ -0,0 +1,4 @@ +/.circleci +/.eslintrc +/.nvmrc +/.prettierrc From fedc3191b800d994923ae625fa6ae81ca3a042a9 Mon Sep 17 00:00:00 2001 From: Christopher Hoskin Date: Mon, 26 Oct 2020 17:33:24 +0000 Subject: [PATCH 167/182] Bump node to 10.19 --- libraries/metrics/.nvmrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/.nvmrc b/libraries/metrics/.nvmrc index 12e4141293..295bfdbe57 100644 --- a/libraries/metrics/.nvmrc +++ b/libraries/metrics/.nvmrc @@ -1 +1 @@ -6.9 +10.19 From d4a649353f698dc5dee56178ebdef427585578d2 Mon Sep 17 00:00:00 2001 From: Christopher Hoskin Date: Mon, 26 Oct 2020 17:33:43 +0000 Subject: [PATCH 168/182] Commit package-lock.json --- libraries/metrics/package-lock.json | 4872 +++++++++++++++++++++++++++ 1 file changed, 4872 insertions(+) create mode 100644 libraries/metrics/package-lock.json diff --git a/libraries/metrics/package-lock.json b/libraries/metrics/package-lock.json new file mode 100644 index 0000000000..0e63f00aba --- /dev/null +++ b/libraries/metrics/package-lock.json @@ -0,0 +1,4872 @@ +{ + "name": "@overleaf/metrics", + "version": "3.2.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@eslint/eslintrc": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.0.tgz", + "integrity": "sha512-+cIGPCBdLCzqxdtwppswP+zTsH9BOIGzAeKfBIbtb4gW/giMlfMwP0HUSFfhzh20f9u8uZ8hOp62+4GPquTbwQ==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "dev": true + } + } + }, + "@google-cloud/common": { + "version": "0.32.1", + "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-0.32.1.tgz", + "integrity": "sha512-bLdPzFvvBMtVkwsoBtygE9oUm3yrNmPa71gvOgucYI/GqvNP2tb6RYsDHPq98kvignhcgHGDI5wyNgxaCo8bKQ==", + "requires": { + "@google-cloud/projectify": "^0.3.3", + "@google-cloud/promisify": "^0.4.0", + "@types/request": "^2.48.1", + "arrify": "^2.0.0", + "duplexify": "^3.6.0", + "ent": "^2.2.0", + "extend": "^3.0.2", + "google-auth-library": "^3.1.1", + "pify": "^4.0.1", + "retry-request": "^4.0.0", + "teeny-request": "^3.11.3" + } + }, + "@google-cloud/debug-agent": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@google-cloud/debug-agent/-/debug-agent-3.2.0.tgz", + "integrity": "sha512-fP87kYbS6aeDna08BivwQ1J260mwJGchRi99XdWCgqbRwuFac8ul0OT5i2wEeDSc5QaDX8ZuWQQ0igZvh1rTyQ==", + "requires": { + "@google-cloud/common": "^0.32.0", + "@sindresorhus/is": "^0.15.0", + "acorn": "^6.0.0", + "coffeescript": "^2.0.0", + "console-log-level": "^1.4.0", + "extend": "^3.0.1", + "findit2": "^2.2.3", + "gcp-metadata": "^1.0.0", + "lodash.pickby": "^4.6.0", + "p-limit": "^2.2.0", + "pify": "^4.0.1", + "semver": "^6.0.0", + "source-map": "^0.6.1", + "split": "^1.0.0" + }, + "dependencies": { + "coffeescript": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-2.5.1.tgz", + "integrity": "sha512-J2jRPX0eeFh5VKyVnoLrfVFgLZtnnmp96WQSLAS8OrLm2wtQLcnikYKe1gViJKDH7vucjuhHvBKKBP3rKcD1tQ==" + } + } + }, + "@google-cloud/profiler": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@google-cloud/profiler/-/profiler-0.2.3.tgz", + "integrity": "sha512-rNvtrFtIebIxZEJ/O0t8n7HciZGIXBo8DvHxWqAmsCaeLvkTtsaL6HmPkwxrNQ1IhbYWAxF+E/DwCiHyhKmgTg==", + "requires": { + "@google-cloud/common": "^0.26.0", + "@types/console-log-level": "^1.4.0", + "@types/semver": "^5.5.0", + "bindings": "^1.2.1", + "console-log-level": "^1.4.0", + "delay": "^4.0.1", + "extend": "^3.0.1", + "gcp-metadata": "^0.9.0", + "nan": "^2.11.1", + "parse-duration": "^0.1.1", + "pify": "^4.0.0", + "pretty-ms": "^4.0.0", + "protobufjs": "~6.8.6", + "semver": "^5.5.0", + "teeny-request": "^3.3.0" + }, + "dependencies": { + "@google-cloud/common": { + "version": "0.26.2", + "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-0.26.2.tgz", + "integrity": "sha512-xJ2M/q3MrUbnYZuFlpF01caAlEhAUoRn0NXp93Hn3pkFpfSOG8YfbKbpBAHvcKVbBOAKVIwPsleNtuyuabUwLQ==", + "requires": { + "@google-cloud/projectify": "^0.3.2", + "@google-cloud/promisify": "^0.3.0", + "@types/duplexify": "^3.5.0", + "@types/request": "^2.47.0", + "arrify": "^1.0.1", + "duplexify": "^3.6.0", + "ent": "^2.2.0", + "extend": "^3.0.1", + "google-auth-library": "^2.0.0", + "pify": "^4.0.0", + "retry-request": "^4.0.0", + "through2": "^3.0.0" + } + }, + "@google-cloud/promisify": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-0.3.1.tgz", + "integrity": "sha512-QzB0/IMvB0eFxFK7Eqh+bfC8NLv3E9ScjWQrPOk6GgfNroxcVITdTlT8NRsRrcp5+QQJVPLkRqKG0PUdaWXmHw==" + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" + }, + "gcp-metadata": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-0.9.3.tgz", + "integrity": "sha512-caV4S84xAjENtpezLCT/GILEAF5h/bC4cNqZFmt/tjTn8t+JBtTkQrgBrJu3857YdsnlM8rxX/PMcKGtE8hUlw==", + "requires": { + "gaxios": "^1.0.2", + "json-bigint": "^0.3.0" + } + }, + "google-auth-library": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-2.0.2.tgz", + "integrity": "sha512-FURxmo1hBVmcfLauuMRKOPYAPKht3dGuI2wjeJFalDUThO0HoYVjr4yxt5cgYSFm1dgUpmN9G/poa7ceTFAIiA==", + "requires": { + "axios": "^0.18.0", + "gcp-metadata": "^0.7.0", + "gtoken": "^2.3.0", + "https-proxy-agent": "^2.2.1", + "jws": "^3.1.5", + "lru-cache": "^5.0.0", + "semver": "^5.5.0" + }, + "dependencies": { + "gcp-metadata": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-0.7.0.tgz", + "integrity": "sha512-ffjC09amcDWjh3VZdkDngIo7WoluyC5Ag9PAYxZbmQLOLNI8lvPtoKTSCyU54j2gwy5roZh6sSMTfkY2ct7K3g==", + "requires": { + "axios": "^0.18.0", + "extend": "^3.0.1", + "retry-axios": "0.3.2" + } + } + } + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "@google-cloud/projectify": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-0.3.3.tgz", + "integrity": "sha512-7522YHQ4IhaafgSunsFF15nG0TGVmxgXidy9cITMe+256RgqfcrfWphiMufW+Ou4kqagW/u3yxwbzVEW3dk2Uw==" + }, + "@google-cloud/promisify": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-0.4.0.tgz", + "integrity": "sha512-4yAHDC52TEMCNcMzVC8WlqnKKKq+Ssi2lXoUg9zWWkZ6U6tq9ZBRYLHHCRdfU+EU9YJsVmivwGcKYCjRGjnf4Q==" + }, + "@google-cloud/trace-agent": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@google-cloud/trace-agent/-/trace-agent-3.6.1.tgz", + "integrity": "sha512-KDo85aPN4gSxJ7oEIOlKd7aGENZFXAM1kbIn1Ds+61gh/K1CQWSyepgJo3nUpAwH6D1ezDWV7Iaf8ueoITc8Uw==", + "requires": { + "@google-cloud/common": "^0.32.1", + "builtin-modules": "^3.0.0", + "console-log-level": "^1.4.0", + "continuation-local-storage": "^3.2.1", + "extend": "^3.0.0", + "gcp-metadata": "^1.0.0", + "hex2dec": "^1.0.1", + "is": "^3.2.0", + "methods": "^1.1.1", + "require-in-the-middle": "^4.0.0", + "semver": "^6.0.0", + "shimmer": "^1.2.0", + "uuid": "^3.0.1" + } + }, + "@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" + }, + "@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" + }, + "@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", + "requires": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" + }, + "@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" + }, + "@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" + }, + "@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" + }, + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" + }, + "@sindresorhus/is": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.15.0.tgz", + "integrity": "sha512-lu8BpxjAtRCAo5ifytTpCPCj99LF7o/2Myn+NXyNCBqvPYn7Pjd76AMmUB5l7XF1U6t0hcWrlEM5ESufW7wAeA==" + }, + "@sinonjs/commons": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz", + "integrity": "sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", + "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@sinonjs/formatio": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-5.0.1.tgz", + "integrity": "sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1", + "@sinonjs/samsam": "^5.0.2" + } + }, + "@sinonjs/samsam": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.2.0.tgz", + "integrity": "sha512-CaIcyX5cDsjcW/ab7HposFWzV1kC++4HNsfnEdFJa7cP1QIuILAKV+BgfeqRXhcnSAc76r/Rh/O5C+300BwUIw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.6.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "@sinonjs/text-encoding": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", + "dev": true + }, + "@types/caseless": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", + "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==" + }, + "@types/console-log-level": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@types/console-log-level/-/console-log-level-1.4.0.tgz", + "integrity": "sha512-x+OscEQwcx5Biair4enH7ov9W+clcqUWaZRaxn5IkT4yNWWjRr2oiYDkY/x1uXSTVZOQ2xlbFQySaQGB+VdXGQ==" + }, + "@types/duplexify": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@types/duplexify/-/duplexify-3.6.0.tgz", + "integrity": "sha512-5zOA53RUlzN74bvrSGwjudssD9F3a797sDZQkiYpUOxW+WHaXTCPz4/d5Dgi6FKnOqZ2CpaTo0DhgIfsXAOE/A==", + "requires": { + "@types/node": "*" + } + }, + "@types/eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==", + "dev": true + }, + "@types/json-schema": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", + "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==", + "dev": true + }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, + "@types/long": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" + }, + "@types/node": { + "version": "14.14.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.3.tgz", + "integrity": "sha512-33/L34xS7HVUx23e0wOT2V1qPF1IrHgQccdJVm9uXGTB9vFBrrzBtkQymT8VskeKOxjz55MSqMv0xuLq+u98WQ==" + }, + "@types/request": { + "version": "2.48.5", + "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.5.tgz", + "integrity": "sha512-/LO7xRVnL3DxJ1WkPGDQrp4VTV1reX9RkC85mJ+Qzykj2Bdw+mG15aAfDahc76HtknjzE16SX/Yddn6MxVbmGQ==", + "requires": { + "@types/caseless": "*", + "@types/node": "*", + "@types/tough-cookie": "*", + "form-data": "^2.5.0" + } + }, + "@types/semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-41qEJgBH/TWgo5NFSvBCJ1qkoi3Q6ONSF2avrHq1LVEZfYpdHmj0y9SuTK+u9ZhG1sYQKBL1AWXKyLWP4RaUoQ==" + }, + "@types/tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==" + }, + "@typescript-eslint/experimental-utils": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-1.13.0.tgz", + "integrity": "sha512-zmpS6SyqG4ZF64ffaJ6uah6tWWWgZ8m+c54XXgwFtUv0jNz8aJAVx8chMCvnk7yl6xwn8d+d96+tWp7fXzTuDg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/typescript-estree": "1.13.0", + "eslint-scope": "^4.0.0" + }, + "dependencies": { + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + } + } + }, + "@typescript-eslint/parser": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-1.13.0.tgz", + "integrity": "sha512-ITMBs52PCPgLb2nGPoeT4iU3HdQZHcPaZVw+7CsFagRJHUhyeTgorEwHXhFf3e7Evzi8oujKNpHc8TONth8AdQ==", + "dev": true, + "requires": { + "@types/eslint-visitor-keys": "^1.0.0", + "@typescript-eslint/experimental-utils": "1.13.0", + "@typescript-eslint/typescript-estree": "1.13.0", + "eslint-visitor-keys": "^1.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "@typescript-eslint/typescript-estree": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-1.13.0.tgz", + "integrity": "sha512-b5rCmd2e6DCC6tCTN9GSUAuxdYwCM/k/2wdjHGrIRGPSJotWMCe/dGpi66u42bhuh8q3QBzqM4TMA1GUUCJvdw==", + "dev": true, + "requires": { + "lodash.unescape": "4.0.1", + "semver": "5.5.0" + }, + "dependencies": { + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "dev": true + } + } + }, + "@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true + }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "requires": { + "event-target-shim": "^5.0.0" + } + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==" + }, + "acorn-jsx": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "dev": true + }, + "agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "requires": { + "es6-promisify": "^5.0.0" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "array-includes": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", + "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0", + "is-string": "^1.0.5" + } + }, + "array.prototype.flat": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz", + "integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "async-listener": { + "version": "0.6.10", + "resolved": "https://registry.npmjs.org/async-listener/-/async-listener-0.6.10.tgz", + "integrity": "sha512-gpuo6xOyF4D5DE5WvyqZdPA3NGhiT6Qf07l7DCB0wwDEsLvDIbCr6j9S5aj5Ch96dLace5tXVzWBZkxU/c5ohw==", + "requires": { + "semver": "^5.3.0", + "shimmer": "^1.1.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "axios": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.1.tgz", + "integrity": "sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==", + "requires": { + "follow-redirects": "1.5.10", + "is-buffer": "^2.0.2" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" + }, + "bignumber.js": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", + "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==" + }, + "binary-extensions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", + "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", + "dev": true + }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "bintrees": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.1.tgz", + "integrity": "sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ=" + }, + "boolify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/boolify/-/boolify-1.0.1.tgz", + "integrity": "sha1-tcCeF8rNET0Rt7s+04TMASmU2Gs=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, + "builtin-modules": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz", + "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==" + }, + "bunyan": { + "version": "1.8.12", + "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.12.tgz", + "integrity": "sha1-8VDw9nSKvdcq6uhPBEA74u8RN5c=", + "dev": true, + "requires": { + "dtrace-provider": "~0.8", + "moment": "^2.10.6", + "mv": "~2", + "safe-json-stringify": "~1" + } + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + } + }, + "chai": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", + "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.0", + "type-detect": "^4.0.5" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, + "chokidar": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz", + "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" + } + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "cli-width": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", + "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", + "dev": true + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "common-tags": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz", + "integrity": "sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw==", + "dev": true + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "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" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "console-log-level": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/console-log-level/-/console-log-level-1.4.1.tgz", + "integrity": "sha512-VZzbIORbP+PPcN/gg3DXClTLPLg5Slwd5fL2MIc+o1qZ4BXBvWyc6QxPk6T/Mkr6IVjRpoAGf32XxP3ZWMVRcQ==" + }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, + "continuation-local-storage": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/continuation-local-storage/-/continuation-local-storage-3.2.1.tgz", + "integrity": "sha512-jx44cconVqkCEEyLSKWwkvUXwO561jXMa3LPjTPsm5QR22PA0/mhe33FT4Xb5y74JDvt/Cq+5lm8S8rskLv9ZA==", + "requires": { + "async-listener": "^0.6.0", + "emitter-listener": "^1.1.1" + } + }, + "core-js": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz", + "integrity": "sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "delay": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/delay/-/delay-4.4.0.tgz", + "integrity": "sha512-txgOrJu3OdtOfTiEOT2e76dJVfG/1dz2NZ4F0Pyt4UGZJryssMRp5vdM5wQoLwSOBNdrJv3F9PAhp/heqd7vrA==" + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dtrace-provider": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.8.tgz", + "integrity": "sha512-b7Z7cNtHPhH9EJhNNbbeqTcXB8LGFFZhq1PGgEvpeHlzd36bhbdTWoE/Ba/YguqpBSlAPKnARWhVlhunCMwfxg==", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.14.0" + } + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "emitter-listener": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/emitter-listener/-/emitter-listener-1.1.2.tgz", + "integrity": "sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ==", + "requires": { + "shimmer": "^1.2.0" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=" + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", + "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "requires": { + "es6-promise": "^4.0.3" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "eslint": { + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.12.0.tgz", + "integrity": "sha512-n5pEU27DRxCSlOhJ2rO57GDLcNsxO0LPpAbpFdh7xmcDmjmlGUfoyrsB3I7yYdQXO5N3gkSTiDrPSPNFiiirXA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@eslint/eslintrc": "^0.2.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.0", + "esquery": "^1.2.0", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash": "^4.17.19", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "dev": true + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "eslint-config-prettier": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.14.0.tgz", + "integrity": "sha512-DbVwh0qZhAC7CNDWcq8cBdK6FcVHiMTKmCypOPWeZkp9hJ8xYwTaWSa6bb6cjfi8KOeJy0e9a8Izxyx+O4+gCQ==", + "dev": true, + "requires": { + "get-stdin": "^6.0.0" + } + }, + "eslint-config-standard": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-14.1.1.tgz", + "integrity": "sha512-Z9B+VR+JIXRxz21udPTL9HpFMyoMUEeX1G251EQ6e05WD9aPVtVBn09XUmZ259wCMlCDmYDSZG62Hhm+ZTJcUg==", + "dev": true + }, + "eslint-import-resolver-node": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", + "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "resolve": "^1.13.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-module-utils": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", + "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "pkg-dir": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-plugin-chai-expect": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-chai-expect/-/eslint-plugin-chai-expect-2.2.0.tgz", + "integrity": "sha512-ExTJKhgeYMfY8wDj3UiZmgpMKJOUHGNHmWMlxT49JUDB1vTnw0sSNfXJSxnX+LcebyBD/gudXzjzD136WqPJrQ==", + "dev": true + }, + "eslint-plugin-chai-friendly": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-chai-friendly/-/eslint-plugin-chai-friendly-0.6.0.tgz", + "integrity": "sha512-Uvvv1gkbRGp/qfN15B0kQyQWg+oFA8buDSqrwmW3egNSk/FpqH2MjQqKOuKwmEL6w4QIQrIjDp+gg6kGGmD3oQ==", + "dev": true + }, + "eslint-plugin-es": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", + "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", + "dev": true, + "requires": { + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" + } + }, + "eslint-plugin-import": { + "version": "2.22.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz", + "integrity": "sha512-8K7JjINHOpH64ozkAhpT3sd+FswIZTfMZTjdx052pnWrgRCVfp8op9tbjpAk3DdUeI/Ba4C8OjdC0r90erHEOw==", + "dev": true, + "requires": { + "array-includes": "^3.1.1", + "array.prototype.flat": "^1.2.3", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.4", + "eslint-module-utils": "^2.6.0", + "has": "^1.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.1", + "read-pkg-up": "^2.0.0", + "resolve": "^1.17.0", + "tsconfig-paths": "^3.9.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-plugin-mocha": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-8.0.0.tgz", + "integrity": "sha512-n67etbWDz6NQM+HnTwZHyBwz/bLlYPOxUbw7bPuCyFujv7ZpaT/Vn6KTAbT02gf7nRljtYIjWcTxK/n8a57rQQ==", + "dev": true, + "requires": { + "eslint-utils": "^2.1.0", + "ramda": "^0.27.1" + } + }, + "eslint-plugin-node": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", + "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", + "dev": true, + "requires": { + "eslint-plugin-es": "^3.0.0", + "eslint-utils": "^2.0.0", + "ignore": "^5.1.1", + "minimatch": "^3.0.4", + "resolve": "^1.10.1", + "semver": "^6.1.0" + }, + "dependencies": { + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true + } + } + }, + "eslint-plugin-promise": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz", + "integrity": "sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw==", + "dev": true + }, + "eslint-plugin-standard": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-4.0.2.tgz", + "integrity": "sha512-nKptN8l7jksXkwFk++PhJB3cCDTcXOEyhISIN86Ue2feJ1LFyY3PrY3/xT2keXlJSY5bpmbiTG0f885/YKAvTA==", + "dev": true + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", + "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", + "dev": true + }, + "espree": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.0.tgz", + "integrity": "sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "esquery": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", + "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + } + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fast-text-encoding": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz", + "integrity": "sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig==" + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "findit2": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/findit2/-/findit2-2.2.3.tgz", + "integrity": "sha1-WKRmaX34piBc39vzlVNri9d3pfY=" + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + }, + "dependencies": { + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "requires": { + "debug": "=3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "form-data": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "gaxios": { + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-1.8.4.tgz", + "integrity": "sha512-BoENMnu1Gav18HcpV9IleMPZ9exM+AvUjrAOV4Mzs/vfz2Lu/ABv451iEXByKiMPn2M140uul1txXCg83sAENw==", + "requires": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^2.2.1", + "node-fetch": "^2.3.0" + } + }, + "gcp-metadata": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-1.0.0.tgz", + "integrity": "sha512-Q6HrgfrCQeEircnNP3rCcEgiDv7eF9+1B+1MMgpE190+/+0mjQR8PxeOaRgxZWmdDAF9EIryHB9g1moPiw1SbQ==", + "requires": { + "gaxios": "^1.0.2", + "json-bigint": "^0.3.0" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true + }, + "get-stdin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "dev": true + }, + "glob": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", + "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "dev": true, + "optional": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "google-auth-library": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-3.1.2.tgz", + "integrity": "sha512-cDQMzTotwyWMrg5jRO7q0A4TL/3GWBgO7I7q5xGKNiiFf9SmGY/OJ1YsLMgI2MVHHsEGyrqYnbnmV1AE+Z6DnQ==", + "requires": { + "base64-js": "^1.3.0", + "fast-text-encoding": "^1.0.0", + "gaxios": "^1.2.1", + "gcp-metadata": "^1.0.0", + "gtoken": "^2.3.2", + "https-proxy-agent": "^2.2.1", + "jws": "^3.1.5", + "lru-cache": "^5.0.0", + "semver": "^5.5.0" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "google-p12-pem": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-1.0.4.tgz", + "integrity": "sha512-SwLAUJqUfTB2iS+wFfSS/G9p7bt4eWcc2LyfvmUXe7cWp6p3mpxDo6LLI29MXdU6wvPcQ/up298X7GMC5ylAlA==", + "requires": { + "node-forge": "^0.8.0", + "pify": "^4.0.0" + } + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "gtoken": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-2.3.3.tgz", + "integrity": "sha512-EaB49bu/TCoNeQjhCYKI/CurooBKkGxIqFHsWABW0b25fobBYVTMe84A8EBVVZhl8emiUdNypil9huMOTmyAnw==", + "requires": { + "gaxios": "^1.0.4", + "google-p12-pem": "^1.0.0", + "jws": "^3.1.5", + "mime": "^2.2.0", + "pify": "^4.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "hex2dec": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/hex2dec/-/hex2dec-1.1.2.tgz", + "integrity": "sha512-Yu+q/XWr2fFQ11tHxPq4p4EiNkb2y+lAacJNhAdRXVfRIcDH6gi7htWFnnlIzvqHMHoWeIsfXlNAjZInpAOJDA==" + }, + "hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "dev": true + }, + "https-proxy-agent": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "requires": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "inquirer": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", + "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", + "dev": true, + "requires": { + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^2.0.0", + "lodash": "^4.17.12", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^2.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + } + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "is": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/is/-/is-3.3.0.tgz", + "integrity": "sha512-nW24QBoPcFGGHJGUwnfpI7Yc5CdqWNdsyHQszVE/z2pKHXzh7FZ5GWhJqSyaQ9wMkQnsTx+kAI8bHlCX4tKdbg==" + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-buffer": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==" + }, + "is-callable": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", + "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==", + "dev": true + }, + "is-core-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.0.0.tgz", + "integrity": "sha512-jq1AH6C8MuteOoBPwkxHafmByhL9j5q4OaPGdbuD+ZtQJVzH+i6E3BJDQcBA09k57i2Hh2yQbEG8yObZ0jdlWw==", + "requires": { + "has": "^1.0.3" + } + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-negative-zero": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz", + "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + }, + "is-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "json-bigint": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-0.3.1.tgz", + "integrity": "sha512-DGWnSzmusIreWlEupsUelHrhwmPPE+FiQvg+drKfk2p+bdEYa5mp4PJ8JsCWqae0M2jQNb0HPvnwvf1qOTThzQ==", + "requires": { + "bignumber.js": "^9.0.0" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + } + } + }, + "just-extend": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.1.tgz", + "integrity": "sha512-aWgeGFW67BP3e5181Ep1Fv2v8z//iBJfrvyTnq8wG86vEESwmonn1zPBJ0VfmT9CJq2FIT0VsETtrNFm2a+SHA==", + "dev": true + }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "dev": true + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lodash.pickby": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz", + "integrity": "sha1-feoh2MGNdwOifHBMFdO4SmfjOv8=" + }, + "lodash.unescape": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz", + "integrity": "sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw=", + "dev": true + }, + "log-symbols": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", + "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", + "dev": true, + "requires": { + "chalk": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "loglevel": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.0.tgz", + "integrity": "sha512-i2sY04nal5jDcagM3FMfG++T69GEEM8CYuOfeOIvmXzOIcwE9a/CJPR0MFM97pYMj/u10lzz7/zd7+qwhrBTqQ==", + "dev": true + }, + "loglevel-colored-level-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/loglevel-colored-level-prefix/-/loglevel-colored-level-prefix-1.0.0.tgz", + "integrity": "sha1-akAhj9x64V/HbD0PPmdsRlOIYD4=", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "loglevel": "^1.4.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "make-plural": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/make-plural/-/make-plural-4.3.0.tgz", + "integrity": "sha512-xTYd4JVHpSCW+aqDof6w/MebaMVNTVYBZhbB/vi513xXdiPT92JMVCo0Jq8W2UZnzYRFeVbQiQ+I25l13JuKvA==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true, + "optional": true + } + } + }, + "map-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.1.0.tgz", + "integrity": "sha512-glc9y00wgtwcDmp7GaE/0b0OnxpNJsVf3ael/An6Fe2Q51LLwN1er6sdomLRzz5h0+yMpiYLhWYF5R7HeqVd4g==", + "dev": true + }, + "messageformat": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/messageformat/-/messageformat-2.3.0.tgz", + "integrity": "sha512-uTzvsv0lTeQxYI2y1NPa1lItL5VRI8Gb93Y2K2ue5gBPyrbJxfDi/EYWxh2PKv5yO42AJeeqblS9MJSh/IEk4w==", + "dev": true, + "requires": { + "make-plural": "^4.3.0", + "messageformat-formatters": "^2.0.1", + "messageformat-parser": "^4.1.2" + } + }, + "messageformat-formatters": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/messageformat-formatters/-/messageformat-formatters-2.0.1.tgz", + "integrity": "sha512-E/lQRXhtHwGuiQjI7qxkLp8AHbMD5r2217XNe/SREbBlSawe0lOqsFb7rflZJmlQFSULNLIqlcjjsCPlB3m3Mg==", + "dev": true + }, + "messageformat-parser": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/messageformat-parser/-/messageformat-parser-4.1.3.tgz", + "integrity": "sha512-2fU3XDCanRqeOCkn7R5zW5VQHWf+T3hH65SzuqRvjatBK7r4uyFa5mEX+k6F9Bd04LVM5G4/BHBTUJsOdW7uyg==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", + "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==" + }, + "mime-db": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" + }, + "mime-types": { + "version": "2.1.27", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "requires": { + "mime-db": "1.44.0" + } + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.2.0.tgz", + "integrity": "sha512-lEWEMq2LMfNJMKeuEwb5UELi+OgFDollXaytR5ggQcHpzG3NP/R7rvixAvF+9/lLsTWhWG+4yD2M70GsM06nxw==", + "dev": true, + "requires": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.4.3", + "debug": "4.2.0", + "diff": "4.0.2", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.1.6", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.14.0", + "log-symbols": "4.0.0", + "minimatch": "3.0.4", + "ms": "2.1.2", + "nanoid": "3.1.12", + "serialize-javascript": "5.0.1", + "strip-json-comments": "3.1.1", + "supports-color": "7.2.0", + "which": "2.0.2", + "wide-align": "1.1.3", + "workerpool": "6.0.2", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "2.0.0" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "p-limit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.0.2.tgz", + "integrity": "sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "module-details-from-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.3.tgz", + "integrity": "sha1-EUyUlnPiqKNenTV4hSeqN7Z52is=" + }, + "moment": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", + "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==", + "dev": true, + "optional": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, + "mv": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", + "integrity": "sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI=", + "dev": true, + "optional": true, + "requires": { + "mkdirp": "~0.5.1", + "ncp": "~2.0.0", + "rimraf": "~2.4.0" + } + }, + "nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" + }, + "nanoid": { + "version": "3.1.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.12.tgz", + "integrity": "sha512-1qstj9z5+x491jfiC4Nelk+f8XBad7LN20PmyWINJEMRSf3wcAjAWysw1qaA8z6NSKe2sjq1hRSDpBH5paCb6A==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "ncp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", + "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=", + "dev": true, + "optional": true + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "nise": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/nise/-/nise-4.0.4.tgz", + "integrity": "sha512-bTTRUNlemx6deJa+ZyoCUTRvH3liK5+N6VQZ4NIw90AgDXY6iPnsqplNFf6STcj+ePk0H/xqxnP75Lr0J0Fq3A==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0", + "@sinonjs/fake-timers": "^6.0.0", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + } + }, + "node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" + }, + "node-forge": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.8.5.tgz", + "integrity": "sha512-vFMQIWt+J/7FLNyKouZ9TazT74PRV3wgv9UT4cRjC8BffxFbKXkgIWR42URCPSnHm/QDz6BOlb2Q0U4+VQT67Q==" + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "object-inspect": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", + "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.1.tgz", + "integrity": "sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.0", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.18.0-next.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", + "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-negative-zero": "^2.0.0", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } + } + }, + "object.values": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", + "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + }, + "dependencies": { + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + } + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-duration": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/parse-duration/-/parse-duration-0.1.3.tgz", + "integrity": "sha512-hMOZHfUmjxO5hMKn7Eft+ckP2M4nV4yzauLXiw3PndpkASnx5r8pDAMcOAiqxoemqWjMWmz4fOHQM6n6WwETXw==" + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "parse-ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-2.1.0.tgz", + "integrity": "sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==" + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, + "requires": { + "isarray": "0.0.1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + } + } + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "dev": true + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "prettier": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", + "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", + "dev": true + }, + "prettier-eslint": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/prettier-eslint/-/prettier-eslint-9.0.2.tgz", + "integrity": "sha512-u6EQqxUhaGfra9gy9shcR7MT7r/2twwEfRGy1tfzyaJvLQwSg34M9IU5HuF7FsLW2QUgr5VIUc56EPWibw1pdw==", + "dev": true, + "requires": { + "@typescript-eslint/parser": "^1.10.2", + "common-tags": "^1.4.0", + "core-js": "^3.1.4", + "dlv": "^1.1.0", + "eslint": "^5.0.0", + "indent-string": "^4.0.0", + "lodash.merge": "^4.6.0", + "loglevel-colored-level-prefix": "^1.0.0", + "prettier": "^1.7.0", + "pretty-format": "^23.0.1", + "require-relative": "^0.8.7", + "typescript": "^3.2.1", + "vue-eslint-parser": "^2.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "eslint": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz", + "integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.9.1", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^4.0.3", + "eslint-utils": "^1.3.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^5.0.1", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.7.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^6.2.2", + "js-yaml": "^3.13.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.11", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^5.5.1", + "strip-ansi": "^4.0.0", + "strip-json-comments": "^2.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0" + } + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, + "espree": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", + "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", + "dev": true, + "requires": { + "acorn": "^6.0.7", + "acorn-jsx": "^5.0.0", + "eslint-visitor-keys": "^1.0.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "dev": true + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "prettier-eslint-cli": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/prettier-eslint-cli/-/prettier-eslint-cli-5.0.0.tgz", + "integrity": "sha512-cei9UbN1aTrz3sQs88CWpvY/10PYTevzd76zoG1tdJ164OhmNTFRKPTOZrutVvscoQWzbnLKkviS3gu5JXwvZg==", + "dev": true, + "requires": { + "arrify": "^2.0.1", + "boolify": "^1.0.0", + "camelcase-keys": "^6.0.0", + "chalk": "^2.4.2", + "common-tags": "^1.8.0", + "core-js": "^3.1.4", + "eslint": "^5.0.0", + "find-up": "^4.1.0", + "get-stdin": "^7.0.0", + "glob": "^7.1.4", + "ignore": "^5.1.2", + "lodash.memoize": "^4.1.2", + "loglevel-colored-level-prefix": "^1.0.0", + "messageformat": "^2.2.1", + "prettier-eslint": "^9.0.0", + "rxjs": "^6.5.2", + "yargs": "^13.2.4" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "eslint": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz", + "integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.9.1", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^4.0.3", + "eslint-utils": "^1.3.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^5.0.1", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.7.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^6.2.2", + "js-yaml": "^3.13.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.11", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^5.5.1", + "strip-ansi": "^4.0.0", + "strip-json-comments": "^2.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0" + }, + "dependencies": { + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + } + } + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, + "espree": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", + "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", + "dev": true, + "requires": { + "acorn": "^6.0.7", + "acorn-jsx": "^5.0.0", + "eslint-visitor-keys": "^1.0.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "get-stdin": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz", + "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "dev": true + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "pretty-format": { + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz", + "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0", + "ansi-styles": "^3.2.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + } + } + }, + "pretty-ms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-4.0.0.tgz", + "integrity": "sha512-qG66ahoLCwpLXD09ZPHSCbUWYTqdosB7SMP4OffgTgL2PBKXMuUsrk5Bwg8q4qPkjTXsKBMr+YK3Ltd/6F9s/Q==", + "requires": { + "parse-ms": "^2.0.0" + } + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "prom-client": { + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/prom-client/-/prom-client-11.5.3.tgz", + "integrity": "sha512-iz22FmTbtkyL2vt0MdDFY+kWof+S9UB/NACxSn2aJcewtw+EERsen0urSkZ2WrHseNdydsvcxCTAnPcSMZZv4Q==", + "requires": { + "tdigest": "^0.1.1" + } + }, + "protobufjs": { + "version": "6.8.9", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.8.9.tgz", + "integrity": "sha512-j2JlRdUeL/f4Z6x4aU4gj9I2LECglC+5qR2TrWb193Tla1qfdaNQTZ8I27Pt7K0Ajmvjjpft7O3KWTGciz4gpw==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.0", + "@types/node": "^10.1.0", + "long": "^4.0.0" + }, + "dependencies": { + "@types/node": { + "version": "10.17.42", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.42.tgz", + "integrity": "sha512-HElxYF7C/MSkuvlaHB2c+82zhXiuO49Cq056Dol8AQuTph7oJtduo2n6J8rFa+YhJyNgQ/Lm20ZaxqD0vxU0+Q==" + } + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "dev": true + }, + "ramda": { + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.1.tgz", + "integrity": "sha512-PgIdVpn5y5Yns8vqb8FzBUEYn98V3xcPgawAkkgj0YJ0qDsnHCiNmZYfOGMgOvoB0eWFLpYbhxUR3mxfDIMvpw==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + } + } + }, + "readdirp": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-in-the-middle": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-4.0.1.tgz", + "integrity": "sha512-EfkM2zANyGkrfIExsECMeNn/uzjvHrE9h36yLXSavmrDiH4tgDNvltAmEKnt4PNLbqKPHZz+uszW2wTKrLUX0w==", + "requires": { + "debug": "^4.1.1", + "module-details-from-path": "^1.0.3", + "resolve": "^1.12.0" + } + }, + "require-like": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/require-like/-/require-like-0.1.2.tgz", + "integrity": "sha1-rW8wwTvs15cBDEaK+ndcDAprR/o=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "require-relative": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz", + "integrity": "sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4=", + "dev": true + }, + "resolve": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.18.1.tgz", + "integrity": "sha512-lDfCPaMKfOJXjy0dPayzPdF1phampNWr3qFCjAu+rw/qbQmr5jWH5xN2hwh9QKfw9E5v4hwV7A+jrCmL8yjjqA==", + "requires": { + "is-core-module": "^2.0.0", + "path-parse": "^1.0.6" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, + "retry-axios": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/retry-axios/-/retry-axios-0.3.2.tgz", + "integrity": "sha512-jp4YlI0qyDFfXiXGhkCOliBN1G7fRH03Nqy8YdShzGqbY5/9S2x/IR6C88ls2DFkbWuL3ASkP7QD3pVrNpPgwQ==" + }, + "retry-request": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-4.1.3.tgz", + "integrity": "sha512-QnRZUpuPNgX0+D1xVxul6DbJ9slvo4Rm6iV/dn63e048MvGbUZiKySVt6Tenp04JqmchxjiLltGerOJys7kJYQ==", + "requires": { + "debug": "^4.1.1" + } + }, + "rimraf": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", + "integrity": "sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto=", + "dev": true, + "optional": true, + "requires": { + "glob": "^6.0.1" + } + }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true + }, + "rxjs": { + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz", + "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safe-json-stringify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz", + "integrity": "sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==", + "dev": true, + "optional": true + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "sandboxed-module": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/sandboxed-module/-/sandboxed-module-2.0.4.tgz", + "integrity": "sha512-AwEPOdO8mg/wJjr876yCHP2DHqVN0MaggEXhp6IIf3bcI5cYoQl9QrrCHSrvToHjvdEiS5x4TVZRgjD2bEmNTA==", + "dev": true, + "requires": { + "require-like": "0.1.2", + "stack-trace": "0.0.9" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "serialize-javascript": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", + "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "shimmer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", + "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, + "sinon": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.2.0.tgz", + "integrity": "sha512-eSNXz1XMcGEMHw08NJXSyTHIu6qTCOiN8x9ODACmZpNQpr0aXTBXBnI4xTzQzR+TEpOmLiKowGf9flCuKIzsbw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.8.1", + "@sinonjs/fake-timers": "^6.0.1", + "@sinonjs/formatio": "^5.0.1", + "@sinonjs/samsam": "^5.2.0", + "diff": "^4.0.2", + "nise": "^4.0.4", + "supports-color": "^7.1.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + } + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz", + "integrity": "sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw==", + "dev": true + }, + "split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "requires": { + "through": "2" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "stack-trace": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.9.tgz", + "integrity": "sha1-qPbq7KkGdMMz58Q5U/J1tFFRBpU=", + "dev": true + }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "string.prototype.trimend": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.2.tgz", + "integrity": "sha512-8oAG/hi14Z4nOVP0z6mdiVZ/wqjDtWSLygMigTzAb+7aPEDTleeFf+WrF+alzecxIRkckkJVn+dTlwzJXORATw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.18.0-next.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", + "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-negative-zero": "^2.0.0", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } + } + }, + "string.prototype.trimstart": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.2.tgz", + "integrity": "sha512-7F6CdBTl5zyu30BJFdzSTlSlLPwODC23Od+iLoVH8X6+3fvDPPuBVVj9iaB1GOsSTSIgVfsfm27R2FGrAPznWg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.18.0-next.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", + "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-negative-zero": "^2.0.0", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "dev": true + } + } + }, + "tdigest": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.1.tgz", + "integrity": "sha1-Ljyyw56kSeVdHmzZEReszKRYgCE=", + "requires": { + "bintrees": "1.0.1" + } + }, + "teeny-request": { + "version": "3.11.3", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-3.11.3.tgz", + "integrity": "sha512-CKncqSF7sH6p4rzCgkb/z/Pcos5efl0DmolzvlqRQUNcpRIruOhY9+T1FsIlyEbfWd7MsFpodROOwHYh2BaXzw==", + "requires": { + "https-proxy-agent": "^2.2.1", + "node-fetch": "^2.2.0", + "uuid": "^3.3.2" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "through2": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", + "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", + "requires": { + "inherits": "^2.0.4", + "readable-stream": "2 || 3" + } + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "tsconfig-paths": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", + "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + } + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "typescript": { + "version": "3.9.7", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz", + "integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==", + "dev": true + }, + "underscore": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=" + }, + "uri-js": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", + "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + }, + "v8-compile-cache": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz", + "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "vue-eslint-parser": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-2.0.3.tgz", + "integrity": "sha512-ZezcU71Owm84xVF6gfurBQUGg8WQ+WZGxgDEQu1IHFBZNx7BFZg3L1yHxrCBNNwbwFtE1GuvfJKMtb6Xuwc/Bw==", + "dev": true, + "requires": { + "debug": "^3.1.0", + "eslint-scope": "^3.7.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^3.5.2", + "esquery": "^1.0.0", + "lodash": "^4.17.4" + }, + "dependencies": { + "acorn": { + "version": "5.7.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", + "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", + "dev": true + }, + "acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "dev": true, + "requires": { + "acorn": "^3.0.4" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "dev": true + } + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "eslint-scope": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.3.tgz", + "integrity": "sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, + "espree": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "dev": true, + "requires": { + "acorn": "^5.5.0", + "acorn-jsx": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "dev": true + } + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "workerpool": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.0.2.tgz", + "integrity": "sha512-DSNyvOpFKrNusaaUwk+ej6cBj1bmhLcBfj80elGk+ZIo5JSkq+unB1dLKEOcNfJDZgjGICfhQ0Q5TbP0PvF4+Q==", + "dev": true + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + } + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "requires": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "dependencies": { + "camelcase": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.1.0.tgz", + "integrity": "sha512-WCMml9ivU60+8rEJgELlFp1gxFcEGxwYleE3bziHEDeqsqAWGHdimB7beBFGjLzVNgPGyDsfgXLQEYMpmIFnVQ==", + "dev": true + }, + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true + } + } + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==" + } + } +} From f874291998c1f3989c481293a9b0bcd3cc90cb58 Mon Sep 17 00:00:00 2001 From: Christopher Hoskin Date: Mon, 26 Oct 2020 17:40:18 +0000 Subject: [PATCH 169/182] Bump google-cloud trace-agent, debug-agent and profiler to latest --- libraries/metrics/package-lock.json | 1384 +++++++++++++++++++-------- libraries/metrics/package.json | 6 +- 2 files changed, 995 insertions(+), 395 deletions(-) diff --git a/libraries/metrics/package-lock.json b/libraries/metrics/package-lock.json index 0e63f00aba..efcd8828b1 100644 --- a/libraries/metrics/package-lock.json +++ b/libraries/metrics/package-lock.json @@ -113,180 +113,491 @@ } }, "@google-cloud/common": { - "version": "0.32.1", - "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-0.32.1.tgz", - "integrity": "sha512-bLdPzFvvBMtVkwsoBtygE9oUm3yrNmPa71gvOgucYI/GqvNP2tb6RYsDHPq98kvignhcgHGDI5wyNgxaCo8bKQ==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-3.4.1.tgz", + "integrity": "sha512-e5z0CwsM0RXky+PnyPtQ3QK46ksqm+kE7kX8pm8X+ddBwZJipHchKeazMM5fLlGCS+AALalzXb+uYmH72TRnpQ==", "requires": { - "@google-cloud/projectify": "^0.3.3", - "@google-cloud/promisify": "^0.4.0", - "@types/request": "^2.48.1", - "arrify": "^2.0.0", - "duplexify": "^3.6.0", + "@google-cloud/projectify": "^2.0.0", + "@google-cloud/promisify": "^2.0.0", + "arrify": "^2.0.1", + "duplexify": "^4.1.1", "ent": "^2.2.0", "extend": "^3.0.2", - "google-auth-library": "^3.1.1", - "pify": "^4.0.1", - "retry-request": "^4.0.0", - "teeny-request": "^3.11.3" + "google-auth-library": "^6.1.1", + "retry-request": "^4.1.1", + "teeny-request": "^7.0.0" } }, "@google-cloud/debug-agent": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@google-cloud/debug-agent/-/debug-agent-3.2.0.tgz", - "integrity": "sha512-fP87kYbS6aeDna08BivwQ1J260mwJGchRi99XdWCgqbRwuFac8ul0OT5i2wEeDSc5QaDX8ZuWQQ0igZvh1rTyQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@google-cloud/debug-agent/-/debug-agent-5.1.2.tgz", + "integrity": "sha512-fdsTF99abIOFNv8gMPTMaz6/UjW0t8Wk77jgaSnx3wMfBXoPP8mIemXaLYKiyMj9N/TuIDIJ3zdK1C9RoreIPQ==", "requires": { - "@google-cloud/common": "^0.32.0", - "@sindresorhus/is": "^0.15.0", - "acorn": "^6.0.0", + "@google-cloud/common": "^3.0.0", + "acorn": "^7.0.0", "coffeescript": "^2.0.0", "console-log-level": "^1.4.0", - "extend": "^3.0.1", + "extend": "^3.0.2", "findit2": "^2.2.3", - "gcp-metadata": "^1.0.0", - "lodash.pickby": "^4.6.0", - "p-limit": "^2.2.0", - "pify": "^4.0.1", - "semver": "^6.0.0", + "gcp-metadata": "^4.0.0", + "p-limit": "^3.0.1", + "semver": "^7.0.0", "source-map": "^0.6.1", "split": "^1.0.0" }, "dependencies": { - "coffeescript": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-2.5.1.tgz", - "integrity": "sha512-J2jRPX0eeFh5VKyVnoLrfVFgLZtnnmp96WQSLAS8OrLm2wtQLcnikYKe1gViJKDH7vucjuhHvBKKBP3rKcD1tQ==" + "@google-cloud/common": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-3.4.1.tgz", + "integrity": "sha512-e5z0CwsM0RXky+PnyPtQ3QK46ksqm+kE7kX8pm8X+ddBwZJipHchKeazMM5fLlGCS+AALalzXb+uYmH72TRnpQ==", + "requires": { + "@google-cloud/projectify": "^2.0.0", + "@google-cloud/promisify": "^2.0.0", + "arrify": "^2.0.1", + "duplexify": "^4.1.1", + "ent": "^2.2.0", + "extend": "^3.0.2", + "google-auth-library": "^6.1.1", + "retry-request": "^4.1.1", + "teeny-request": "^7.0.0" + } + }, + "@google-cloud/projectify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-2.0.1.tgz", + "integrity": "sha512-ZDG38U/Yy6Zr21LaR3BTiiLtpJl6RkPS/JwoRT453G+6Q1DhlV0waNf8Lfu+YVYGIIxgKnLayJRfYlFJfiI8iQ==" + }, + "@google-cloud/promisify": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-2.0.3.tgz", + "integrity": "sha512-d4VSA86eL/AFTe5xtyZX+ePUjE8dIFu2T8zmdeNBSa5/kNgXPCx/o/wbFNHAGLJdGnk1vddRuMESD9HbOC8irw==" + }, + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "requires": { + "debug": "4" + } + }, + "duplexify": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.1.tgz", + "integrity": "sha512-DY3xVEmVHTv1wSzKNbwoU6nVjzI369Y6sPoqfYr0/xlx3IdX2n94xIszTcjPO8W8ZIv0Wb0PXNcjuZyT4wiICA==", + "requires": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.0" + } + }, + "gaxios": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.2.0.tgz", + "integrity": "sha512-+6WPeVzPvOshftpxJwRi2Ozez80tn/hdtOUag7+gajDHRJvAblKxTFSSMPtr2hmnLy7p0mvYz0rMXLBl8pSO7Q==", + "requires": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.3.0" + } + }, + "gcp-metadata": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.2.0.tgz", + "integrity": "sha512-vQZD57cQkqIA6YPGXM/zc+PIZfNRFdukWGsGZ5+LcJzesi5xp6Gn7a02wRJi4eXPyArNMIYpPET4QMxGqtlk6Q==", + "requires": { + "gaxios": "^3.0.0", + "json-bigint": "^1.0.0" + } + }, + "google-auth-library": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.1.2.tgz", + "integrity": "sha512-X9EUX8R+kIpsf55KdSPhFWF0RNyBGuBc1zeYc/5Sjuk65eIYqq91rINJVBD22pp+w/PuM2fasHiA6H2xYjxTIQ==", + "requires": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^3.0.0", + "gcp-metadata": "^4.2.0", + "gtoken": "^5.0.4", + "jws": "^4.0.0", + "lru-cache": "^6.0.0" + } + }, + "google-p12-pem": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.0.3.tgz", + "integrity": "sha512-wS0ek4ZtFx/ACKYF3JhyGe5kzH7pgiQ7J5otlumqR9psmWMYc+U9cErKlCYVYHoUaidXHdZ2xbo34kB+S+24hA==", + "requires": { + "node-forge": "^0.10.0" + } + }, + "gtoken": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.4.tgz", + "integrity": "sha512-U9wnSp4GZ7ov6zRdPuRHG4TuqEWqRRgT1gfXGNArhzBUn9byrPeH8uTmBWU/ZiWJJvTEmkjhDIC3mqHWdVi3xQ==", + "requires": { + "gaxios": "^3.0.0", + "google-p12-pem": "^3.0.3", + "jws": "^4.0.0", + "mime": "^2.2.0" + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "requires": { + "bignumber.js": "^9.0.0" + } + }, + "jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "requires": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, + "node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" + }, + "p-limit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.0.2.tgz", + "integrity": "sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg==", + "requires": { + "p-try": "^2.0.0" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==" + }, + "teeny-request": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-7.0.1.tgz", + "integrity": "sha512-sasJmQ37klOlplL4Ia/786M5YlOcoLGQyq2TE4WHSRupbAuDaQW0PfVxV4MtdBtRJ4ngzS+1qim8zP6Zp35qCw==", + "requires": { + "http-proxy-agent": "^4.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.1", + "stream-events": "^1.0.5", + "uuid": "^8.0.0" + } + }, + "uuid": { + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz", + "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==" } } }, "@google-cloud/profiler": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@google-cloud/profiler/-/profiler-0.2.3.tgz", - "integrity": "sha512-rNvtrFtIebIxZEJ/O0t8n7HciZGIXBo8DvHxWqAmsCaeLvkTtsaL6HmPkwxrNQ1IhbYWAxF+E/DwCiHyhKmgTg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@google-cloud/profiler/-/profiler-4.0.3.tgz", + "integrity": "sha512-YFjoa37DpKY92fqQrY285yTACj3WB0Dby9RMRTsFFSgd+WK3PCsNJ18xrNgD/RJuLttw6eMXESNgj7QuwEkoog==", "requires": { - "@google-cloud/common": "^0.26.0", + "@google-cloud/common": "^3.0.0", "@types/console-log-level": "^1.4.0", - "@types/semver": "^5.5.0", - "bindings": "^1.2.1", + "@types/semver": "^7.0.0", "console-log-level": "^1.4.0", "delay": "^4.0.1", - "extend": "^3.0.1", - "gcp-metadata": "^0.9.0", - "nan": "^2.11.1", - "parse-duration": "^0.1.1", - "pify": "^4.0.0", - "pretty-ms": "^4.0.0", - "protobufjs": "~6.8.6", - "semver": "^5.5.0", - "teeny-request": "^3.3.0" + "extend": "^3.0.2", + "gcp-metadata": "^4.0.0", + "parse-duration": "^0.4.4", + "pprof": "2.0.0", + "pretty-ms": "^7.0.0", + "protobufjs": "~6.10.0", + "semver": "^7.0.0", + "teeny-request": "^7.0.0" }, "dependencies": { "@google-cloud/common": { - "version": "0.26.2", - "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-0.26.2.tgz", - "integrity": "sha512-xJ2M/q3MrUbnYZuFlpF01caAlEhAUoRn0NXp93Hn3pkFpfSOG8YfbKbpBAHvcKVbBOAKVIwPsleNtuyuabUwLQ==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-3.4.1.tgz", + "integrity": "sha512-e5z0CwsM0RXky+PnyPtQ3QK46ksqm+kE7kX8pm8X+ddBwZJipHchKeazMM5fLlGCS+AALalzXb+uYmH72TRnpQ==", "requires": { - "@google-cloud/projectify": "^0.3.2", - "@google-cloud/promisify": "^0.3.0", - "@types/duplexify": "^3.5.0", - "@types/request": "^2.47.0", - "arrify": "^1.0.1", - "duplexify": "^3.6.0", + "@google-cloud/projectify": "^2.0.0", + "@google-cloud/promisify": "^2.0.0", + "arrify": "^2.0.1", + "duplexify": "^4.1.1", "ent": "^2.2.0", - "extend": "^3.0.1", - "google-auth-library": "^2.0.0", - "pify": "^4.0.0", - "retry-request": "^4.0.0", - "through2": "^3.0.0" + "extend": "^3.0.2", + "google-auth-library": "^6.1.1", + "retry-request": "^4.1.1", + "teeny-request": "^7.0.0" } }, - "@google-cloud/promisify": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-0.3.1.tgz", - "integrity": "sha512-QzB0/IMvB0eFxFK7Eqh+bfC8NLv3E9ScjWQrPOk6GgfNroxcVITdTlT8NRsRrcp5+QQJVPLkRqKG0PUdaWXmHw==" + "@google-cloud/projectify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-2.0.1.tgz", + "integrity": "sha512-ZDG38U/Yy6Zr21LaR3BTiiLtpJl6RkPS/JwoRT453G+6Q1DhlV0waNf8Lfu+YVYGIIxgKnLayJRfYlFJfiI8iQ==" }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" + "@google-cloud/promisify": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-2.0.3.tgz", + "integrity": "sha512-d4VSA86eL/AFTe5xtyZX+ePUjE8dIFu2T8zmdeNBSa5/kNgXPCx/o/wbFNHAGLJdGnk1vddRuMESD9HbOC8irw==" + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "requires": { + "debug": "4" + } + }, + "duplexify": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.1.tgz", + "integrity": "sha512-DY3xVEmVHTv1wSzKNbwoU6nVjzI369Y6sPoqfYr0/xlx3IdX2n94xIszTcjPO8W8ZIv0Wb0PXNcjuZyT4wiICA==", + "requires": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.0" + } + }, + "gaxios": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.2.0.tgz", + "integrity": "sha512-+6WPeVzPvOshftpxJwRi2Ozez80tn/hdtOUag7+gajDHRJvAblKxTFSSMPtr2hmnLy7p0mvYz0rMXLBl8pSO7Q==", + "requires": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.3.0" + } }, "gcp-metadata": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-0.9.3.tgz", - "integrity": "sha512-caV4S84xAjENtpezLCT/GILEAF5h/bC4cNqZFmt/tjTn8t+JBtTkQrgBrJu3857YdsnlM8rxX/PMcKGtE8hUlw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.2.0.tgz", + "integrity": "sha512-vQZD57cQkqIA6YPGXM/zc+PIZfNRFdukWGsGZ5+LcJzesi5xp6Gn7a02wRJi4eXPyArNMIYpPET4QMxGqtlk6Q==", "requires": { - "gaxios": "^1.0.2", - "json-bigint": "^0.3.0" + "gaxios": "^3.0.0", + "json-bigint": "^1.0.0" } }, "google-auth-library": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-2.0.2.tgz", - "integrity": "sha512-FURxmo1hBVmcfLauuMRKOPYAPKht3dGuI2wjeJFalDUThO0HoYVjr4yxt5cgYSFm1dgUpmN9G/poa7ceTFAIiA==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.1.2.tgz", + "integrity": "sha512-X9EUX8R+kIpsf55KdSPhFWF0RNyBGuBc1zeYc/5Sjuk65eIYqq91rINJVBD22pp+w/PuM2fasHiA6H2xYjxTIQ==", "requires": { - "axios": "^0.18.0", - "gcp-metadata": "^0.7.0", - "gtoken": "^2.3.0", - "https-proxy-agent": "^2.2.1", - "jws": "^3.1.5", - "lru-cache": "^5.0.0", - "semver": "^5.5.0" - }, - "dependencies": { - "gcp-metadata": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-0.7.0.tgz", - "integrity": "sha512-ffjC09amcDWjh3VZdkDngIo7WoluyC5Ag9PAYxZbmQLOLNI8lvPtoKTSCyU54j2gwy5roZh6sSMTfkY2ct7K3g==", - "requires": { - "axios": "^0.18.0", - "extend": "^3.0.1", - "retry-axios": "0.3.2" - } - } + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^3.0.0", + "gcp-metadata": "^4.2.0", + "gtoken": "^5.0.4", + "jws": "^4.0.0", + "lru-cache": "^6.0.0" } }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "google-p12-pem": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.0.3.tgz", + "integrity": "sha512-wS0ek4ZtFx/ACKYF3JhyGe5kzH7pgiQ7J5otlumqR9psmWMYc+U9cErKlCYVYHoUaidXHdZ2xbo34kB+S+24hA==", "requires": { - "yallist": "^3.0.2" + "node-forge": "^0.10.0" + } + }, + "gtoken": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.4.tgz", + "integrity": "sha512-U9wnSp4GZ7ov6zRdPuRHG4TuqEWqRRgT1gfXGNArhzBUn9byrPeH8uTmBWU/ZiWJJvTEmkjhDIC3mqHWdVi3xQ==", + "requires": { + "gaxios": "^3.0.0", + "google-p12-pem": "^3.0.3", + "jws": "^4.0.0", + "mime": "^2.2.0" + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "requires": { + "bignumber.js": "^9.0.0" + } + }, + "jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "requires": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, + "node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" } }, "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==" + }, + "teeny-request": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-7.0.1.tgz", + "integrity": "sha512-sasJmQ37klOlplL4Ia/786M5YlOcoLGQyq2TE4WHSRupbAuDaQW0PfVxV4MtdBtRJ4ngzS+1qim8zP6Zp35qCw==", + "requires": { + "http-proxy-agent": "^4.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.1", + "stream-events": "^1.0.5", + "uuid": "^8.0.0" + } + }, + "uuid": { + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz", + "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==" } } }, "@google-cloud/projectify": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-0.3.3.tgz", - "integrity": "sha512-7522YHQ4IhaafgSunsFF15nG0TGVmxgXidy9cITMe+256RgqfcrfWphiMufW+Ou4kqagW/u3yxwbzVEW3dk2Uw==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-2.0.1.tgz", + "integrity": "sha512-ZDG38U/Yy6Zr21LaR3BTiiLtpJl6RkPS/JwoRT453G+6Q1DhlV0waNf8Lfu+YVYGIIxgKnLayJRfYlFJfiI8iQ==" }, "@google-cloud/promisify": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-0.4.0.tgz", - "integrity": "sha512-4yAHDC52TEMCNcMzVC8WlqnKKKq+Ssi2lXoUg9zWWkZ6U6tq9ZBRYLHHCRdfU+EU9YJsVmivwGcKYCjRGjnf4Q==" + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-2.0.3.tgz", + "integrity": "sha512-d4VSA86eL/AFTe5xtyZX+ePUjE8dIFu2T8zmdeNBSa5/kNgXPCx/o/wbFNHAGLJdGnk1vddRuMESD9HbOC8irw==" }, "@google-cloud/trace-agent": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@google-cloud/trace-agent/-/trace-agent-3.6.1.tgz", - "integrity": "sha512-KDo85aPN4gSxJ7oEIOlKd7aGENZFXAM1kbIn1Ds+61gh/K1CQWSyepgJo3nUpAwH6D1ezDWV7Iaf8ueoITc8Uw==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@google-cloud/trace-agent/-/trace-agent-5.1.1.tgz", + "integrity": "sha512-YTcK0RLN90pLCprg0XC8uV4oAVd79vsXhkcxmEVwiOOYjUDvSrAhb7y/0SY606zgfhJHmUTNb/fZSWEtZP/slQ==", "requires": { - "@google-cloud/common": "^0.32.1", + "@google-cloud/common": "^3.0.0", + "@opencensus/propagation-stackdriver": "0.0.22", "builtin-modules": "^3.0.0", "console-log-level": "^1.4.0", "continuation-local-storage": "^3.2.1", - "extend": "^3.0.0", - "gcp-metadata": "^1.0.0", + "extend": "^3.0.2", + "gcp-metadata": "^4.0.0", + "google-auth-library": "^6.0.0", "hex2dec": "^1.0.1", "is": "^3.2.0", "methods": "^1.1.1", - "require-in-the-middle": "^4.0.0", - "semver": "^6.0.0", + "require-in-the-middle": "^5.0.0", + "semver": "^7.0.0", "shimmer": "^1.2.0", - "uuid": "^3.0.1" + "source-map-support": "^0.5.16", + "uuid": "^8.0.0" + }, + "dependencies": { + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==" + } + } + }, + "@opencensus/core": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/@opencensus/core/-/core-0.0.22.tgz", + "integrity": "sha512-ErazJtivjceNoOZI1bG9giQ6cWS45J4i6iPUtlp7dLNu58OLs/v+CD0FsaPCh47XgPxAI12vbBE8Ec09ViwHNA==", + "requires": { + "continuation-local-storage": "^3.2.1", + "log-driver": "^1.2.7", + "semver": "^7.0.0", + "shimmer": "^1.2.0", + "uuid": "^8.0.0" + }, + "dependencies": { + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==" + } + } + }, + "@opencensus/propagation-stackdriver": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/@opencensus/propagation-stackdriver/-/propagation-stackdriver-0.0.22.tgz", + "integrity": "sha512-eBvf/ihb1mN8Yz/ASkz8nHzuMKqygu77+VNnUeR0yEh3Nj+ykB8VVR6lK+NAFXo1Rd1cOsTmgvuXAZgDAGleQQ==", + "requires": { + "@opencensus/core": "^0.0.22", + "hex2dec": "^1.0.1", + "uuid": "^8.0.0" } }, "@protobufjs/aspromise": { @@ -343,11 +654,6 @@ "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" }, - "@sindresorhus/is": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.15.0.tgz", - "integrity": "sha512-lu8BpxjAtRCAo5ifytTpCPCj99LF7o/2Myn+NXyNCBqvPYn7Pjd76AMmUB5l7XF1U6t0hcWrlEM5ESufW7wAeA==" - }, "@sinonjs/commons": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz", @@ -393,24 +699,16 @@ "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", "dev": true }, - "@types/caseless": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", - "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==" + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==" }, "@types/console-log-level": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@types/console-log-level/-/console-log-level-1.4.0.tgz", "integrity": "sha512-x+OscEQwcx5Biair4enH7ov9W+clcqUWaZRaxn5IkT4yNWWjRr2oiYDkY/x1uXSTVZOQ2xlbFQySaQGB+VdXGQ==" }, - "@types/duplexify": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@types/duplexify/-/duplexify-3.6.0.tgz", - "integrity": "sha512-5zOA53RUlzN74bvrSGwjudssD9F3a797sDZQkiYpUOxW+WHaXTCPz4/d5Dgi6FKnOqZ2CpaTo0DhgIfsXAOE/A==", - "requires": { - "@types/node": "*" - } - }, "@types/eslint-visitor-keys": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", @@ -434,31 +732,10 @@ "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" }, - "@types/node": { - "version": "14.14.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.3.tgz", - "integrity": "sha512-33/L34xS7HVUx23e0wOT2V1qPF1IrHgQccdJVm9uXGTB9vFBrrzBtkQymT8VskeKOxjz55MSqMv0xuLq+u98WQ==" - }, - "@types/request": { - "version": "2.48.5", - "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.5.tgz", - "integrity": "sha512-/LO7xRVnL3DxJ1WkPGDQrp4VTV1reX9RkC85mJ+Qzykj2Bdw+mG15aAfDahc76HtknjzE16SX/Yddn6MxVbmGQ==", - "requires": { - "@types/caseless": "*", - "@types/node": "*", - "@types/tough-cookie": "*", - "form-data": "^2.5.0" - } - }, "@types/semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-41qEJgBH/TWgo5NFSvBCJ1qkoi3Q6ONSF2avrHq1LVEZfYpdHmj0y9SuTK+u9ZhG1sYQKBL1AWXKyLWP4RaUoQ==" - }, - "@types/tough-cookie": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz", - "integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==" + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-+nVsLKlcUCeMzD2ufHEYuJ9a2ovstb6Dp52A5VsoKxDXgvE051XgHI/33I1EymwkRGQkwnA0LkhnUzituGs4EQ==" }, "@typescript-eslint/experimental-utils": { "version": "1.13.0", @@ -527,6 +804,11 @@ "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", "dev": true }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, "abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -547,7 +829,8 @@ "acorn": { "version": "6.4.2", "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==" + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "dev": true }, "acorn-jsx": { "version": "5.3.1", @@ -556,11 +839,11 @@ "dev": true }, "agent-base": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "requires": { - "es6-promisify": "^5.0.0" + "debug": "4" } }, "ajv": { @@ -587,6 +870,11 @@ "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", "dev": true }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, "anymatch": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", @@ -597,6 +885,20 @@ "picomatch": "^2.0.4" } }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, "array-includes": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", @@ -651,25 +953,10 @@ } } }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "axios": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.1.tgz", - "integrity": "sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==", - "requires": { - "follow-redirects": "1.5.10", - "is-buffer": "^2.0.2" - } - }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "base64-js": { "version": "1.3.1", @@ -710,7 +997,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -736,6 +1022,11 @@ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, "builtin-modules": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz", @@ -823,6 +1114,11 @@ "readdirp": "~3.5.0" } }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, "cli-cursor": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", @@ -866,6 +1162,16 @@ } } }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + }, + "coffeescript": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-2.5.1.tgz", + "integrity": "sha512-J2jRPX0eeFh5VKyVnoLrfVFgLZtnnmp96WQSLAS8OrLm2wtQLcnikYKe1gViJKDH7vucjuhHvBKKBP3rKcD1tQ==" + }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -881,14 +1187,6 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, "common-tags": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz", @@ -935,8 +1233,12 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" }, "console-log-level": { "version": "1.4.1", @@ -1014,6 +1316,11 @@ "type-detect": "^4.0.0" } }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", @@ -1034,10 +1341,15 @@ "resolved": "https://registry.npmjs.org/delay/-/delay-4.4.0.tgz", "integrity": "sha512-txgOrJu3OdtOfTiEOT2e76dJVfG/1dz2NZ4F0Pyt4UGZJryssMRp5vdM5wQoLwSOBNdrJv3F9PAhp/heqd7vrA==" }, - "delayed-stream": { + "delegates": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" }, "diff": { "version": "4.0.2", @@ -1071,14 +1383,26 @@ } }, "duplexify": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.1.tgz", + "integrity": "sha512-DY3xVEmVHTv1wSzKNbwoU6nVjzI369Y6sPoqfYr0/xlx3IdX2n94xIszTcjPO8W8ZIv0Wb0PXNcjuZyT4wiICA==", "requires": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", "stream-shift": "^1.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } } }, "ecdsa-sig-formatter": { @@ -1164,19 +1488,6 @@ "is-symbol": "^1.0.2" } }, - "es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" - }, - "es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", - "requires": { - "es6-promise": "^4.0.3" - } - }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -1767,44 +2078,18 @@ "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", "dev": true }, - "follow-redirects": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", - "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", "requires": { - "debug": "=3.1.0" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "form-data": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", - "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" + "minipass": "^2.6.0" } }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "fsevents": { "version": "2.1.3", @@ -1824,24 +2109,60 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, "gaxios": { - "version": "1.8.4", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-1.8.4.tgz", - "integrity": "sha512-BoENMnu1Gav18HcpV9IleMPZ9exM+AvUjrAOV4Mzs/vfz2Lu/ABv451iEXByKiMPn2M140uul1txXCg83sAENw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.2.0.tgz", + "integrity": "sha512-+6WPeVzPvOshftpxJwRi2Ozez80tn/hdtOUag7+gajDHRJvAblKxTFSSMPtr2hmnLy7p0mvYz0rMXLBl8pSO7Q==", "requires": { "abort-controller": "^3.0.0", "extend": "^3.0.2", - "https-proxy-agent": "^2.2.1", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", "node-fetch": "^2.3.0" } }, "gcp-metadata": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-1.0.0.tgz", - "integrity": "sha512-Q6HrgfrCQeEircnNP3rCcEgiDv7eF9+1B+1MMgpE190+/+0mjQR8PxeOaRgxZWmdDAF9EIryHB9g1moPiw1SbQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.2.0.tgz", + "integrity": "sha512-vQZD57cQkqIA6YPGXM/zc+PIZfNRFdukWGsGZ5+LcJzesi5xp6Gn7a02wRJi4eXPyArNMIYpPET4QMxGqtlk6Q==", "requires": { - "gaxios": "^1.0.2", - "json-bigint": "^0.3.0" + "gaxios": "^3.0.0", + "json-bigint": "^1.0.0" } }, "get-caller-file": { @@ -1895,43 +2216,27 @@ } }, "google-auth-library": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-3.1.2.tgz", - "integrity": "sha512-cDQMzTotwyWMrg5jRO7q0A4TL/3GWBgO7I7q5xGKNiiFf9SmGY/OJ1YsLMgI2MVHHsEGyrqYnbnmV1AE+Z6DnQ==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.1.2.tgz", + "integrity": "sha512-X9EUX8R+kIpsf55KdSPhFWF0RNyBGuBc1zeYc/5Sjuk65eIYqq91rINJVBD22pp+w/PuM2fasHiA6H2xYjxTIQ==", "requires": { + "arrify": "^2.0.0", "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", "fast-text-encoding": "^1.0.0", - "gaxios": "^1.2.1", - "gcp-metadata": "^1.0.0", - "gtoken": "^2.3.2", - "https-proxy-agent": "^2.2.1", - "jws": "^3.1.5", - "lru-cache": "^5.0.0", - "semver": "^5.5.0" - }, - "dependencies": { - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "requires": { - "yallist": "^3.0.2" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } + "gaxios": "^3.0.0", + "gcp-metadata": "^4.2.0", + "gtoken": "^5.0.4", + "jws": "^4.0.0", + "lru-cache": "^6.0.0" } }, "google-p12-pem": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-1.0.4.tgz", - "integrity": "sha512-SwLAUJqUfTB2iS+wFfSS/G9p7bt4eWcc2LyfvmUXe7cWp6p3mpxDo6LLI29MXdU6wvPcQ/up298X7GMC5ylAlA==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.0.3.tgz", + "integrity": "sha512-wS0ek4ZtFx/ACKYF3JhyGe5kzH7pgiQ7J5otlumqR9psmWMYc+U9cErKlCYVYHoUaidXHdZ2xbo34kB+S+24hA==", "requires": { - "node-forge": "^0.8.0", - "pify": "^4.0.0" + "node-forge": "^0.10.0" } }, "growl": { @@ -1941,15 +2246,14 @@ "dev": true }, "gtoken": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-2.3.3.tgz", - "integrity": "sha512-EaB49bu/TCoNeQjhCYKI/CurooBKkGxIqFHsWABW0b25fobBYVTMe84A8EBVVZhl8emiUdNypil9huMOTmyAnw==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.4.tgz", + "integrity": "sha512-U9wnSp4GZ7ov6zRdPuRHG4TuqEWqRRgT1gfXGNArhzBUn9byrPeH8uTmBWU/ZiWJJvTEmkjhDIC3mqHWdVi3xQ==", "requires": { - "gaxios": "^1.0.4", - "google-p12-pem": "^1.0.0", - "jws": "^3.1.5", - "mime": "^2.2.0", - "pify": "^4.0.0" + "gaxios": "^3.0.0", + "google-p12-pem": "^3.0.3", + "jws": "^4.0.0", + "mime": "^2.2.0" } }, "has": { @@ -1972,6 +2276,11 @@ "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", "dev": true }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -1989,31 +2298,57 @@ "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", "dev": true }, - "https-proxy-agent": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", - "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", "requires": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" }, "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "requires": { - "ms": "^2.1.1" + "debug": "4" } } } }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, + "ignore-walk": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", + "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", + "requires": { + "minimatch": "^3.0.4" + } + }, "import-fresh": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", @@ -2040,7 +2375,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -2051,6 +2385,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" + }, "inquirer": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", @@ -2173,11 +2512,6 @@ "binary-extensions": "^2.0.0" } }, - "is-buffer": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", - "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==" - }, "is-callable": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", @@ -2207,8 +2541,7 @@ "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" }, "is-glob": { "version": "4.0.1", @@ -2246,6 +2579,11 @@ "has-symbols": "^1.0.1" } }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" + }, "is-string": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", @@ -2280,9 +2618,9 @@ "dev": true }, "json-bigint": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-0.3.1.tgz", - "integrity": "sha512-DGWnSzmusIreWlEupsUelHrhwmPPE+FiQvg+drKfk2p+bdEYa5mp4PJ8JsCWqae0M2jQNb0HPvnwvf1qOTThzQ==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", "requires": { "bignumber.js": "^9.0.0" } @@ -2323,9 +2661,9 @@ "dev": true }, "jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", "requires": { "buffer-equal-constant-time": "1.0.1", "ecdsa-sig-formatter": "1.0.11", @@ -2333,11 +2671,11 @@ } }, "jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", "requires": { - "jwa": "^1.4.1", + "jwa": "^2.0.0", "safe-buffer": "^5.0.1" } }, @@ -2405,17 +2743,17 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "lodash.pickby": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz", - "integrity": "sha1-feoh2MGNdwOifHBMFdO4SmfjOv8=" - }, "lodash.unescape": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz", "integrity": "sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw=", "dev": true }, + "log-driver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", + "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==" + }, "log-symbols": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", @@ -2548,6 +2886,21 @@ "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + }, + "dependencies": { + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, "make-plural": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/make-plural/-/make-plural-4.3.0.tgz", @@ -2628,7 +2981,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -2636,14 +2988,29 @@ "minimist": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "requires": { + "minipass": "^2.9.0" + } }, "mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, "requires": { "minimist": "0.0.8" } @@ -2863,6 +3230,26 @@ "dev": true, "optional": true }, + "needle": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.5.2.tgz", + "integrity": "sha512-LbRIwS9BfkPvNwNHlsA41Q29kL2L/6VaOJ0qisM5lLWsTV3nP15abO5ITL6L81zqFhzjRKDAYjpcBcwM0AVvLQ==", + "requires": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, "negotiator": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", @@ -2893,9 +3280,63 @@ "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" }, "node-forge": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.8.5.tgz", - "integrity": "sha512-vFMQIWt+J/7FLNyKouZ9TazT74PRV3wgv9UT4cRjC8BffxFbKXkgIWR42URCPSnHm/QDz6BOlb2Q0U4+VQT67Q==" + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" + }, + "node-pre-gyp": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.14.0.tgz", + "integrity": "sha512-+CvDC7ZttU/sSt9rFjix/P05iS43qHCOOGzcr3Ry99bXG7VX953+vFyEuph/tfqoYu8dttBkE86JSKBO2OzcxA==", + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4.4.2" + }, + "dependencies": { + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "nopt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", + "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } }, "normalize-package-data": { "version": "2.5.0", @@ -2923,6 +3364,50 @@ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true }, + "npm-bundled": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", + "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==", + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==" + }, + "npm-packlist": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", + "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, "object-inspect": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", @@ -3017,11 +3502,24 @@ "word-wrap": "^1.2.3" } }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } }, "p-limit": { "version": "2.3.0", @@ -3072,9 +3570,9 @@ } }, "parse-duration": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/parse-duration/-/parse-duration-0.1.3.tgz", - "integrity": "sha512-hMOZHfUmjxO5hMKn7Eft+ckP2M4nV4yzauLXiw3PndpkASnx5r8pDAMcOAiqxoemqWjMWmz4fOHQM6n6WwETXw==" + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/parse-duration/-/parse-duration-0.4.4.tgz", + "integrity": "sha512-KbAJuYGUhZkB9gotDiKLnZ7Z3VTacK3fgwmDdB6ZVDtJbMBT6MfLga0WJaYpPDu0mzqT0NgHtHDt5PY4l0nidg==" }, "parse-json": { "version": "2.2.0", @@ -3099,8 +3597,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-is-inside": { "version": "1.0.2", @@ -3165,11 +3662,6 @@ "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", "dev": true }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" - }, "pkg-dir": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", @@ -3179,6 +3671,60 @@ "find-up": "^2.1.0" } }, + "pprof": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pprof/-/pprof-2.0.0.tgz", + "integrity": "sha512-a3ngxqmo6jw+SyPHoxkHUwPKSoYjZoSNFfIpwUhyorFMsON9vh7Y1/kG+o+mEjt6HMpbU9FczFiiRV68VFjUbg==", + "requires": { + "bindings": "^1.2.1", + "delay": "^4.0.1", + "findit2": "^2.2.3", + "nan": "^2.14.0", + "node-pre-gyp": "^0.14.0", + "p-limit": "^2.0.0", + "pify": "^5.0.0", + "protobufjs": "~6.8.6", + "source-map": "^0.7.3", + "split": "^1.0.1" + }, + "dependencies": { + "@types/node": { + "version": "10.17.42", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.42.tgz", + "integrity": "sha512-HElxYF7C/MSkuvlaHB2c+82zhXiuO49Cq056Dol8AQuTph7oJtduo2n6J8rFa+YhJyNgQ/Lm20ZaxqD0vxU0+Q==" + }, + "pify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz", + "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==" + }, + "protobufjs": { + "version": "6.8.9", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.8.9.tgz", + "integrity": "sha512-j2JlRdUeL/f4Z6x4aU4gj9I2LECglC+5qR2TrWb193Tla1qfdaNQTZ8I27Pt7K0Ajmvjjpft7O3KWTGciz4gpw==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.0", + "@types/node": "^10.1.0", + "long": "^4.0.0" + } + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" + } + } + }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -3873,11 +4419,11 @@ } }, "pretty-ms": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-4.0.0.tgz", - "integrity": "sha512-qG66ahoLCwpLXD09ZPHSCbUWYTqdosB7SMP4OffgTgL2PBKXMuUsrk5Bwg8q4qPkjTXsKBMr+YK3Ltd/6F9s/Q==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-7.0.1.tgz", + "integrity": "sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==", "requires": { - "parse-ms": "^2.0.0" + "parse-ms": "^2.1.0" } }, "process-nextick-args": { @@ -3900,9 +4446,9 @@ } }, "protobufjs": { - "version": "6.8.9", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.8.9.tgz", - "integrity": "sha512-j2JlRdUeL/f4Z6x4aU4gj9I2LECglC+5qR2TrWb193Tla1qfdaNQTZ8I27Pt7K0Ajmvjjpft7O3KWTGciz4gpw==", + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.10.1.tgz", + "integrity": "sha512-pb8kTchL+1Ceg4lFd5XUpK8PdWacbvV5SK2ULH2ebrYtl4GjJmS24m6CKME67jzV53tbJxHlnNOSqQHbTsR9JQ==", "requires": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", @@ -3914,15 +4460,15 @@ "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", - "@types/long": "^4.0.0", - "@types/node": "^10.1.0", + "@types/long": "^4.0.1", + "@types/node": "^13.7.0", "long": "^4.0.0" }, "dependencies": { "@types/node": { - "version": "10.17.42", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.42.tgz", - "integrity": "sha512-HElxYF7C/MSkuvlaHB2c+82zhXiuO49Cq056Dol8AQuTph7oJtduo2n6J8rFa+YhJyNgQ/Lm20ZaxqD0vxU0+Q==" + "version": "13.13.28", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.28.tgz", + "integrity": "sha512-EM/qFeRH8ZCD+TlsaIPULyyFm9vOhFIvgskY2JmHbEsWsOPgN+rtjSXrcHGgJpob4Nu17VfO95FKewr0XY7iOQ==" } } }, @@ -3953,6 +4499,29 @@ "safe-buffer": "^5.1.0" } }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + } + } + }, "read-pkg": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", @@ -4017,9 +4586,9 @@ "dev": true }, "require-in-the-middle": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-4.0.1.tgz", - "integrity": "sha512-EfkM2zANyGkrfIExsECMeNn/uzjvHrE9h36yLXSavmrDiH4tgDNvltAmEKnt4PNLbqKPHZz+uszW2wTKrLUX0w==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-5.0.3.tgz", + "integrity": "sha512-p/ICV8uMlqC4tjOYabLMxAWCIKa0YUQgZZ6KDM0xgXJNgdGQ1WmL2A07TwmrZw+wi6ITUFKzH5v3n+ENEyXVkA==", "requires": { "debug": "^4.1.1", "module-details-from-path": "^1.0.3", @@ -4069,11 +4638,6 @@ "signal-exit": "^3.0.2" } }, - "retry-axios": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/retry-axios/-/retry-axios-0.3.2.tgz", - "integrity": "sha512-jp4YlI0qyDFfXiXGhkCOliBN1G7fRH03Nqy8YdShzGqbY5/9S2x/IR6C88ls2DFkbWuL3ASkP7QD3pVrNpPgwQ==" - }, "retry-request": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-4.1.3.tgz", @@ -4122,8 +4686,7 @@ "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "sandboxed-module": { "version": "2.0.4", @@ -4135,10 +4698,16 @@ "stack-trace": "0.0.9" } }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true }, "serialize-javascript": { "version": "5.0.1", @@ -4152,8 +4721,7 @@ "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, "shebang-command": { "version": "2.0.0", @@ -4178,8 +4746,7 @@ "signal-exit": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", - "dev": true + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" }, "sinon": { "version": "9.2.0", @@ -4240,6 +4807,15 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "spdx-correct": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", @@ -4292,6 +4868,14 @@ "integrity": "sha1-qPbq7KkGdMMz58Q5U/J1tFFRBpU=", "dev": true }, + "stream-events": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", + "integrity": "sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==", + "requires": { + "stubs": "^3.0.0" + } + }, "stream-shift": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", @@ -4397,6 +4981,14 @@ "safe-buffer": "~5.1.0" } }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -4409,6 +5001,11 @@ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true }, + "stubs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", + "integrity": "sha1-6NK6H6nJBXAwPAMLaQD31fiavls=" + }, "table": { "version": "5.4.6", "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", @@ -4429,6 +5026,20 @@ } } }, + "tar": { + "version": "4.4.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", + "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + } + }, "tdigest": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.1.tgz", @@ -4438,13 +5049,15 @@ } }, "teeny-request": { - "version": "3.11.3", - "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-3.11.3.tgz", - "integrity": "sha512-CKncqSF7sH6p4rzCgkb/z/Pcos5efl0DmolzvlqRQUNcpRIruOhY9+T1FsIlyEbfWd7MsFpodROOwHYh2BaXzw==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-7.0.1.tgz", + "integrity": "sha512-sasJmQ37klOlplL4Ia/786M5YlOcoLGQyq2TE4WHSRupbAuDaQW0PfVxV4MtdBtRJ4ngzS+1qim8zP6Zp35qCw==", "requires": { - "https-proxy-agent": "^2.2.1", - "node-fetch": "^2.2.0", - "uuid": "^3.3.2" + "http-proxy-agent": "^4.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.1", + "stream-events": "^1.0.5", + "uuid": "^8.0.0" } }, "text-table": { @@ -4458,15 +5071,6 @@ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, - "through2": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", - "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", - "requires": { - "inherits": "^2.0.4", - "readable-stream": "2 || 3" - } - }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -4558,9 +5162,9 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz", + "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==" }, "v8-compile-cache": { "version": "2.1.1", @@ -4673,7 +5277,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "dev": true, "requires": { "string-width": "^1.0.2 || 2" }, @@ -4681,14 +5284,12 @@ "ansi-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, "requires": { "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^4.0.0" @@ -4698,7 +5299,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, "requires": { "ansi-regex": "^3.0.0" } diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index cb265922af..ffa79c305e 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -7,9 +7,9 @@ "url": "https://github.com/overleaf/metrics-module.git" }, "dependencies": { - "@google-cloud/debug-agent": "^3.0.0", - "@google-cloud/profiler": "^0.2.3", - "@google-cloud/trace-agent": "^3.2.0", + "@google-cloud/debug-agent": "^5.1.2", + "@google-cloud/profiler": "^4.0.3", + "@google-cloud/trace-agent": "^5.1.1", "compression": "^1.7.4", "prom-client": "^11.1.3", "underscore": "~1.6.0", From 725478d95f88928d90d2eaf6ae44567879566969 Mon Sep 17 00:00:00 2001 From: Christopher Hoskin Date: Tue, 27 Oct 2020 14:02:21 +0000 Subject: [PATCH 170/182] Release 3.3.0 --- libraries/metrics/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index ffa79c305e..2b5c9554b5 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "@overleaf/metrics", - "version": "3.2.1", + "version": "3.3.0", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From 20b3d5070c0fcfc8597d031ea878270224cd48dc Mon Sep 17 00:00:00 2001 From: Eric Mc Sween Date: Thu, 29 Oct 2020 09:49:55 -0400 Subject: [PATCH 171/182] Export a configured prom-client Metrics.initialize() and Metrics.configure() will configure the default Prometheus registry with default "app" and "host" labels. The configured prom-client module is available as Metrics.prom. --- libraries/metrics/index.js | 65 ++++++++----------- libraries/metrics/prom_wrapper.js | 14 +--- .../metrics/test/acceptance/metrics_tests.js | 8 +-- 3 files changed, 34 insertions(+), 53 deletions(-) diff --git a/libraries/metrics/index.js b/libraries/metrics/index.js index c76ab35c3c..03357da193 100644 --- a/libraries/metrics/index.js +++ b/libraries/metrics/index.js @@ -1,11 +1,11 @@ +const os = require('os') const ExpressCompression = require('compression') -const prom = require('./prom_wrapper') +const promClient = require('prom-client') +const promWrapper = require('./prom_wrapper') -const { collectDefaultMetrics } = prom - -let appname = 'unknown' -const hostname = require('os').hostname() +const DEFAULT_APP_NAME = 'unknown' +const { collectDefaultMetrics } = promWrapper const destructors = [] require('./uv_threadpool_size') @@ -14,11 +14,11 @@ require('./uv_threadpool_size') * Configure the metrics module */ function configure(opts = {}) { - if (opts.appName) { - appname = opts.appName - } + const appName = opts.appName || DEFAULT_APP_NAME + const hostname = os.hostname() + promClient.register.setDefaultLabels({ app: appName, host: hostname }) if (opts.ttlInMinutes) { - prom.ttlInMinutes = opts.ttlInMinutes + promWrapper.ttlInMinutes = opts.ttlInMinutes } } @@ -26,8 +26,9 @@ function configure(opts = {}) { * Configure the metrics module and start the default metrics collectors and * profiling agents. */ -function initialize(_name, opts = {}) { - configure({ ...opts, appName: _name }) +function initialize(appName, opts = {}) { + appName = appName || DEFAULT_APP_NAME + configure({ ...opts, appName }) collectDefaultMetrics({ timeout: 5000, prefix: '' }) console.log(`ENABLE_TRACE_AGENT set to ${process.env.ENABLE_TRACE_AGENT}`) @@ -46,7 +47,7 @@ function initialize(_name, opts = {}) { debugAgent.start({ allowExpressions: true, serviceContext: { - service: appname, + service: appName, version: process.env.BUILD_VERSION } }) @@ -58,7 +59,7 @@ function initialize(_name, opts = {}) { const profiler = require('@google-cloud/profiler') profiler.start({ serviceContext: { - service: appname, + service: appName, version: process.env.BUILD_VERSION } }) @@ -78,8 +79,8 @@ function injectMetricsRoute(app) { level: parseInt(process.env.METRICS_COMPRESSION_LEVEL || '1', 10) }), function(req, res) { - res.set('Content-Type', prom.registry.contentType) - res.end(prom.registry.metrics()) + res.set('Content-Type', promWrapper.registry.contentType) + res.end(promWrapper.registry.metrics()) } ) } @@ -98,9 +99,7 @@ function set(key, value, sampleRate = 1) { function inc(key, sampleRate = 1, opts = {}) { key = buildPromKey(key) - opts.app = appname - opts.host = hostname - prom.metric('counter', key).inc(opts) + promWrapper.metric('counter', key).inc(opts) if (process.env.DEBUG_METRICS) { console.log('doing inc', key, opts) } @@ -108,9 +107,7 @@ function inc(key, sampleRate = 1, opts = {}) { function count(key, count, sampleRate = 1, opts = {}) { key = buildPromKey(key) - opts.app = appname - opts.host = hostname - prom.metric('counter', key).inc(opts, count) + promWrapper.metric('counter', key).inc(opts, count) if (process.env.DEBUG_METRICS) { console.log('doing count/inc', key, opts) } @@ -118,9 +115,7 @@ function count(key, count, sampleRate = 1, opts = {}) { function summary(key, value, opts = {}) { key = buildPromKey(key) - opts.app = appname - opts.host = hostname - prom.metric('summary', key).observe(opts, value) + promWrapper.metric('summary', key).observe(opts, value) if (process.env.DEBUG_METRICS) { console.log('doing summary', key, value, opts) } @@ -128,9 +123,7 @@ function summary(key, value, opts = {}) { function timing(key, timeSpan, sampleRate = 1, opts = {}) { key = buildPromKey('timer_' + key) - opts.app = appname - opts.host = hostname - prom.metric('summary', key).observe(opts, timeSpan) + promWrapper.metric('summary', key).observe(opts, timeSpan) if (process.env.DEBUG_METRICS) { console.log('doing timing', key, opts) } @@ -154,14 +147,9 @@ class Timer { function gauge(key, value, sampleRate = 1, opts = {}) { key = buildPromKey(key) - prom.metric('gauge', key).set( - { - app: appname, - host: hostname, - status: opts.status - }, - this.sanitizeValue(value) - ) + promWrapper + .metric('gauge', key) + .set({ status: opts.status }, sanitizeValue(value)) if (process.env.DEBUG_METRICS) { console.log('doing gauge', key, opts) } @@ -169,9 +157,9 @@ function gauge(key, value, sampleRate = 1, opts = {}) { function globalGauge(key, value, sampleRate = 1, opts = {}) { key = buildPromKey(key) - prom + promWrapper .metric('gauge', key) - .set({ app: appname, status: opts.status }, this.sanitizeValue(value)) + .set({ host: 'global', status: opts.status }, sanitizeValue(value)) } function close() { @@ -196,8 +184,9 @@ module.exports = { gauge, globalGauge, close, + prom: promClient, - register: prom.registry, + register: promWrapper.registry, mongodb: require('./mongodb'), http: require('./http'), diff --git a/libraries/metrics/prom_wrapper.js b/libraries/metrics/prom_wrapper.js index 64f267aedb..57ddf0e2ac 100644 --- a/libraries/metrics/prom_wrapper.js +++ b/libraries/metrics/prom_wrapper.js @@ -68,7 +68,7 @@ class MetricWrapper { return new prom.Counter({ name, help: name, - labelNames: ['app', 'host', 'status', 'method', 'path'] + labelNames: ['status', 'method', 'path'] }) case 'summary': return new prom.Summary({ @@ -76,21 +76,13 @@ class MetricWrapper { help: name, maxAgeSeconds: 60, ageBuckets: 10, - labelNames: [ - 'app', - 'host', - 'path', - 'status_code', - 'method', - 'collection', - 'query' - ] + labelNames: ['path', 'status_code', 'method', 'collection', 'query'] }) case 'gauge': return new prom.Gauge({ name, help: name, - labelNames: ['app', 'host', 'status'] + labelNames: ['host', 'status'] }) } })() diff --git a/libraries/metrics/test/acceptance/metrics_tests.js b/libraries/metrics/test/acceptance/metrics_tests.js index e7f6cdd6cc..ff72348159 100644 --- a/libraries/metrics/test/acceptance/metrics_tests.js +++ b/libraries/metrics/test/acceptance/metrics_tests.js @@ -80,7 +80,7 @@ describe('Metrics module', function() { Metrics.globalGauge('tire_pressure', 99.99) const { value, labels } = await getMetricValue('tire_pressure') expect(value).to.equal(99.99) - expect(labels.host).to.equal('') + expect(labels.host).to.equal('global') expect(labels.app).to.equal(APP_NAME) }) }) @@ -102,9 +102,9 @@ async function getSummarySum(key) { } async function getMetricValue(key) { - const metric = getMetric(key) - const item = await metric.get() - return item.values[0] + const metrics = await Metrics.register.getMetricsAsJSON() + const metric = metrics.find(m => m.name === key) + return metric.values[0] } async function expectMetricValue(key, expectedValue) { From 142d9a57160f64c62e941aece19fa951714ad97b Mon Sep 17 00:00:00 2001 From: Eric Mc Sween Date: Fri, 30 Oct 2020 07:39:47 -0400 Subject: [PATCH 172/182] 3.4.0 --- libraries/metrics/package-lock.json | 2 +- libraries/metrics/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/metrics/package-lock.json b/libraries/metrics/package-lock.json index efcd8828b1..66c59042d8 100644 --- a/libraries/metrics/package-lock.json +++ b/libraries/metrics/package-lock.json @@ -1,6 +1,6 @@ { "name": "@overleaf/metrics", - "version": "3.2.1", + "version": "3.4.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 2b5c9554b5..5bedf80c5d 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "@overleaf/metrics", - "version": "3.3.0", + "version": "3.4.0", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From 2d1c84ea2e7ecced821387aa8d1564e911c6430a Mon Sep 17 00:00:00 2001 From: Jakob Ackermann Date: Sat, 3 Oct 2020 18:58:28 +0200 Subject: [PATCH 173/182] [misc] fix collection of open sockets ``` > require('http').globalAgent.sockets { 'HOST:PORT:': [{ ... }, { ... }] } ``` - `new URL('http://HOST:PORT:')` throws -> test suite `open_sockets` - gauges were not cleaned up after no agents were present for a given key. This lead to continuous emission of the previous connection count for a given hostname, following the completion of all requests. -> test suite `when all requests complete` --- libraries/metrics/open_sockets.js | 48 ++++--- .../metrics/test/acceptance/metrics_tests.js | 130 ++++++++++++++++++ 2 files changed, 153 insertions(+), 25 deletions(-) diff --git a/libraries/metrics/open_sockets.js b/libraries/metrics/open_sockets.js index 01b7e8f874..c650e203d9 100644 --- a/libraries/metrics/open_sockets.js +++ b/libraries/metrics/open_sockets.js @@ -6,7 +6,6 @@ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ let OpenSocketsMonitor -const { URL } = require('url') const seconds = 1000 // In Node 0.10 the default is 5, which means only 5 open connections at one. @@ -15,6 +14,27 @@ const seconds = 1000 require('http').globalAgent.maxSockets = Infinity require('https').globalAgent.maxSockets = Infinity +const SOCKETS_HTTP = require('http').globalAgent.sockets +const SOCKETS_HTTPS = require('https').globalAgent.sockets + +// keep track of set gauges and reset them in the next collection cycle +const SEEN_HOSTS_HTTP = new Set() +const SEEN_HOSTS_HTTPS = new Set() + +function collectOpenConnections(sockets, seenHosts, prefix) { + const Metrics = require('./index') + Object.keys(sockets).forEach(host => seenHosts.add(host)) + seenHosts.forEach(host => { + // host: 'HOST:PORT:' + const hostname = host.split(':')[0] + const openConnections = (sockets[host] || []).length + if (!openConnections) { + seenHosts.delete(host) + } + Metrics.gauge(`open_connections.${prefix}.${hostname}`, openConnections) + }) +} + module.exports = OpenSocketsMonitor = { monitor(logger) { const interval = setInterval( @@ -26,29 +46,7 @@ module.exports = OpenSocketsMonitor = { }, gaugeOpenSockets() { - let agents, hostname, url - const Metrics = require('./index') - const object = require('http').globalAgent.sockets - for (url in object) { - agents = object[url] - url = new URL(`http://${url}`) - hostname = - url.hostname != null ? url.hostname.replace(/\./g, '_') : undefined - Metrics.gauge(`open_connections.http.${hostname}`, agents.length) - } - return (() => { - const result = [] - const object1 = require('https').globalAgent.sockets - for (url in object1) { - agents = object1[url] - url = new URL(`https://${url}`) - hostname = - url.hostname != null ? url.hostname.replace(/\./g, '_') : undefined - result.push( - Metrics.gauge(`open_connections.https.${hostname}`, agents.length) - ) - } - return result - })() + collectOpenConnections(SOCKETS_HTTP, SEEN_HOSTS_HTTP, 'http') + collectOpenConnections(SOCKETS_HTTPS, SEEN_HOSTS_HTTPS, 'https') } } diff --git a/libraries/metrics/test/acceptance/metrics_tests.js b/libraries/metrics/test/acceptance/metrics_tests.js index ff72348159..01b00b73d7 100644 --- a/libraries/metrics/test/acceptance/metrics_tests.js +++ b/libraries/metrics/test/acceptance/metrics_tests.js @@ -1,4 +1,5 @@ const os = require('os') +const http = require('http') const { expect } = require('chai') const Metrics = require('../..') @@ -84,6 +85,129 @@ describe('Metrics module', function() { expect(labels.app).to.equal(APP_NAME) }) }) + + describe('open_sockets', function() { + const keyServer1 = 'open_connections_http_127_42_42_1' + const keyServer2 = 'open_connections_http_127_42_42_2' + + let finish1, finish2, emitResponse1, emitResponse2 + function resetEmitResponse1() { + emitResponse1 = new Promise(resolve => (finish1 = resolve)) + } + resetEmitResponse1() + function resetEmitResponse2() { + emitResponse2 = new Promise(resolve => (finish2 = resolve)) + } + resetEmitResponse2() + + let server1, server2 + before(function setupServer1(done) { + server1 = http.createServer((req, res) => { + res.write('...') + emitResponse1.then(() => res.end()) + }) + server1.listen(0, '127.42.42.1', done) + }) + before(function setupServer2(done) { + server2 = http.createServer((req, res) => { + res.write('...') + emitResponse2.then(() => res.end()) + }) + server2.listen(0, '127.42.42.2', done) + }) + after(function cleanupPendingRequests() { + finish1() + finish2() + }) + after(function shutdownServer1(done) { + if (server1) server1.close(done) + }) + after(function shutdownServer2(done) { + if (server2) server2.close(done) + }) + + let urlServer1, urlServer2 + before(function setUrls() { + urlServer1 = `http://127.42.42.1:${server1.address().port}/` + urlServer2 = `http://127.42.42.2:${server2.address().port}/` + }) + describe('gaugeOpenSockets()', function() { + beforeEach(function runGaugeOpenSockets() { + Metrics.open_sockets.gaugeOpenSockets() + }) + + describe('without pending connections', function() { + it('emits no open_connections', async function() { + await expectNoMetricValue(keyServer1) + await expectNoMetricValue(keyServer2) + }) + }) + + describe('with pending connections for server1', function() { + before(function(done) { + http.get(urlServer1) + http.get(urlServer1) + setTimeout(done, 10) + }) + + it('emits 2 open_connections for server1', async function() { + await expectMetricValue(keyServer1, 2) + }) + + it('emits no open_connections for server2', async function() { + await expectNoMetricValue(keyServer2) + }) + }) + + describe('with pending connections for server1 and server2', function() { + before(function(done) { + http.get(urlServer2) + http.get(urlServer2) + setTimeout(done, 10) + }) + + it('emits 2 open_connections for server1', async function() { + await expectMetricValue(keyServer1, 2) + }) + + it('emits 2 open_connections for server1', async function() { + await expectMetricValue(keyServer1, 2) + }) + }) + + describe('when requests finish for server1', function() { + before(function(done) { + finish1() + resetEmitResponse1() + http.get(urlServer1) + + setTimeout(done, 10) + }) + + it('emits 1 open_connections for server1', async function() { + await expectMetricValue(keyServer1, 1) + }) + + it('emits 2 open_connections for server2', async function() { + await expectMetricValue(keyServer2, 2) + }) + }) + + describe('when all requests complete', function() { + before(function(done) { + finish1() + finish2() + + setTimeout(done, 10) + }) + + it('emits no open_connections', async function() { + await expectNoMetricValue(keyServer1) + await expectNoMetricValue(keyServer2) + }) + }) + }) + }) }) function getMetric(key) { @@ -113,3 +237,9 @@ async function expectMetricValue(key, expectedValue) { expect(value.labels.host).to.equal(HOSTNAME) expect(value.labels.app).to.equal(APP_NAME) } + +async function expectNoMetricValue(key) { + const metric = getMetric(key) + if (!metric) return + await expectMetricValue(key, 0) +} From 8e76e79a83e2e79133f1869fc3fbc2346126d9e0 Mon Sep 17 00:00:00 2001 From: Jakob Ackermann Date: Wed, 25 Nov 2020 11:25:16 +0000 Subject: [PATCH 174/182] [misc] version bump to 3.4.1 --- libraries/metrics/package-lock.json | 2 +- libraries/metrics/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/metrics/package-lock.json b/libraries/metrics/package-lock.json index 66c59042d8..b6406b3a61 100644 --- a/libraries/metrics/package-lock.json +++ b/libraries/metrics/package-lock.json @@ -1,6 +1,6 @@ { "name": "@overleaf/metrics", - "version": "3.4.0", + "version": "3.4.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 5bedf80c5d..7ef934f9fe 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "@overleaf/metrics", - "version": "3.4.0", + "version": "3.4.1", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From 7274217d799993813f9b6d726acadd6128a6862d Mon Sep 17 00:00:00 2001 From: Eric Mc Sween Date: Fri, 8 Jan 2021 14:41:50 -0500 Subject: [PATCH 175/182] Decaf cleanup --- libraries/metrics/http.js | 29 +++++++---------------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/libraries/metrics/http.js b/libraries/metrics/http.js index 8d0f9caab1..c0c387bfce 100644 --- a/libraries/metrics/http.js +++ b/libraries/metrics/http.js @@ -1,10 +1,3 @@ -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * DS103: Rewrite code to no longer use __guard__ - * DS207: Consider shorter variations of null checks - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ const yn = require('yn') const STACKDRIVER_LOGGING = yn(process.env.STACKDRIVER_LOGGING) @@ -15,14 +8,13 @@ module.exports.monitor = logger => const startTime = process.hrtime() const { end } = res res.end = function() { - let info end.apply(this, arguments) const responseTime = process.hrtime(startTime) const responseTimeMs = Math.round( responseTime[0] * 1000 + responseTime[1] / 1000000 ) const requestSize = parseInt(req.headers['content-length'], 10) - if ((req.route != null ? req.route.path : undefined) != null) { + if (req.route && req.route.path != null) { const routePath = req.route.path .toString() .replace(/\//g, '_') @@ -43,13 +35,12 @@ module.exports.monitor = logger => } const remoteIp = req.ip || - __guard__( - req.socket != null ? req.socket.socket : undefined, - x => x.remoteAddress - ) || - (req.socket != null ? req.socket.remoteAddress : undefined) + (req.socket && req.socket.socket && req.socket.socket.remoteAddress) || + (req.socket && req.socket.remoteAddress) const reqUrl = req.originalUrl || req.url const referrer = req.headers.referer || req.headers.referrer + + let info if (STACKDRIVER_LOGGING) { info = { httpRequest: { @@ -85,13 +76,7 @@ module.exports.monitor = logger => 'response-time': responseTimeMs } } - return logger.info(info, '%s %s', req.method, reqUrl) + logger.info(info, '%s %s', req.method, reqUrl) } - return next() + next() } - -function __guard__(value, transform) { - return typeof value !== 'undefined' && value !== null - ? transform(value) - : undefined -} From 8dcbd5aec0d68cad9caa693edcd1db921e962eb7 Mon Sep 17 00:00:00 2001 From: Eric Mc Sween Date: Fri, 8 Jan 2021 14:53:29 -0500 Subject: [PATCH 176/182] Add support for the swagger-tools router The swagger-tools router puts the request path in the req.swagger.apiPath property. --- libraries/metrics/http.js | 46 +++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/libraries/metrics/http.js b/libraries/metrics/http.js index c0c387bfce..bca75b30a2 100644 --- a/libraries/metrics/http.js +++ b/libraries/metrics/http.js @@ -14,12 +14,12 @@ module.exports.monitor = logger => responseTime[0] * 1000 + responseTime[1] / 1000000 ) const requestSize = parseInt(req.headers['content-length'], 10) - if (req.route && req.route.path != null) { - const routePath = req.route.path - .toString() - .replace(/\//g, '_') - .replace(/:/g, '') - .slice(1) + const routePath = getRoutePath(req) + const remoteIp = getRemoteIp(req) + const reqUrl = req.originalUrl || req.url + const referrer = req.headers.referer || req.headers.referrer + + if (routePath != null) { Metrics.timing('http_request', responseTimeMs, null, { method: req.method, status_code: res.statusCode, @@ -33,12 +33,6 @@ module.exports.monitor = logger => }) } } - const remoteIp = - req.ip || - (req.socket && req.socket.socket && req.socket.socket.remoteAddress) || - (req.socket && req.socket.remoteAddress) - const reqUrl = req.originalUrl || req.url - const referrer = req.headers.referer || req.headers.referrer let info if (STACKDRIVER_LOGGING) { @@ -80,3 +74,31 @@ module.exports.monitor = logger => } next() } + +function getRoutePath(req) { + if (req.route && req.route.path != null) { + return req.route.path + .toString() + .replace(/\//g, '_') + .replace(/:/g, '') + .slice(1) + } + if (req.swagger && req.swagger.apiPath != null) { + return req.swagger.apiPath + } + return null +} + +function getRemoteIp(req) { + if (req.ip) { + return req.ip + } + if (req.socket) { + if (req.socket.socket && req.socket.socket.remoteAddress) { + return req.socket.socket.remoteAddress + } else if (req.socket.remoteAddress) { + return req.socket.remoteAddress + } + } + return null +} From 3581d0ce87778bb0f638f1ff92b565ba4b87b400 Mon Sep 17 00:00:00 2001 From: Eric Mc Sween Date: Mon, 11 Jan 2021 08:03:49 -0500 Subject: [PATCH 177/182] 3.5.0 --- libraries/metrics/package-lock.json | 2 +- libraries/metrics/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/metrics/package-lock.json b/libraries/metrics/package-lock.json index b6406b3a61..bd63f72688 100644 --- a/libraries/metrics/package-lock.json +++ b/libraries/metrics/package-lock.json @@ -1,6 +1,6 @@ { "name": "@overleaf/metrics", - "version": "3.4.1", + "version": "3.5.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 7ef934f9fe..134bccfaba 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "@overleaf/metrics", - "version": "3.4.1", + "version": "3.5.0", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From 29742d6a87829b7736007282e344fd2aee27b4ed Mon Sep 17 00:00:00 2001 From: Jakob Ackermann Date: Sat, 3 Oct 2020 19:40:46 +0200 Subject: [PATCH 178/182] [misc] register the metrics sweeping interval handle for later cleanup --- libraries/metrics/index.js | 1 + libraries/metrics/prom_wrapper.js | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/libraries/metrics/index.js b/libraries/metrics/index.js index 03357da193..238cf5ab81 100644 --- a/libraries/metrics/index.js +++ b/libraries/metrics/index.js @@ -30,6 +30,7 @@ function initialize(appName, opts = {}) { appName = appName || DEFAULT_APP_NAME configure({ ...opts, appName }) collectDefaultMetrics({ timeout: 5000, prefix: '' }) + promWrapper.setupSweeping() console.log(`ENABLE_TRACE_AGENT set to ${process.env.ENABLE_TRACE_AGENT}`) if (process.env.ENABLE_TRACE_AGENT === 'true') { diff --git a/libraries/metrics/prom_wrapper.js b/libraries/metrics/prom_wrapper.js index 57ddf0e2ac..9fe3407346 100644 --- a/libraries/metrics/prom_wrapper.js +++ b/libraries/metrics/prom_wrapper.js @@ -138,12 +138,15 @@ class MetricWrapper { } } -if (!PromWrapper.sweepRegistered) { +let sweepingInterval +PromWrapper.setupSweeping = function() { + if (sweepingInterval) { + clearInterval(sweepingInterval) + } if (process.env.DEBUG_METRICS) { console.log('Registering sweep method') } - PromWrapper.sweepRegistered = true - setInterval(function() { + sweepingInterval = setInterval(function() { if (PromWrapper.ttlInMinutes) { if (process.env.DEBUG_METRICS) { console.log('Sweeping metrics') @@ -153,6 +156,9 @@ if (!PromWrapper.sweepRegistered) { }) } }, 60000) + + const Metrics = require('./index') + Metrics.registerDestructor(() => clearInterval(sweepingInterval)) } module.exports = PromWrapper From 20223d865f26a83a1b132ccfbfc7ab84a3d3446d Mon Sep 17 00:00:00 2001 From: Jakob Ackermann Date: Sat, 3 Oct 2020 19:42:24 +0200 Subject: [PATCH 179/182] [misc] do not register a noop sweeping interval --- libraries/metrics/prom_wrapper.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/libraries/metrics/prom_wrapper.js b/libraries/metrics/prom_wrapper.js index 9fe3407346..7ec65547c2 100644 --- a/libraries/metrics/prom_wrapper.js +++ b/libraries/metrics/prom_wrapper.js @@ -143,18 +143,22 @@ PromWrapper.setupSweeping = function() { if (sweepingInterval) { clearInterval(sweepingInterval) } + if (!PromWrapper.ttlInMinutes) { + if (process.env.DEBUG_METRICS) { + console.log('Not registering sweep method -- empty ttl') + } + return + } if (process.env.DEBUG_METRICS) { console.log('Registering sweep method') } sweepingInterval = setInterval(function() { - if (PromWrapper.ttlInMinutes) { - if (process.env.DEBUG_METRICS) { - console.log('Sweeping metrics') - } - return metrics.forEach((metric, key) => { - return metric.sweep() - }) + if (process.env.DEBUG_METRICS) { + console.log('Sweeping metrics') } + return metrics.forEach((metric, key) => { + return metric.sweep() + }) }, 60000) const Metrics = require('./index') From e1650616b853d73f6c7381e720ab30d9a1fd02a7 Mon Sep 17 00:00:00 2001 From: Jakob Ackermann Date: Sat, 3 Oct 2020 19:42:24 +0200 Subject: [PATCH 180/182] [misc] version bump to 3.5.1 --- libraries/metrics/package-lock.json | 2 +- libraries/metrics/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/metrics/package-lock.json b/libraries/metrics/package-lock.json index bd63f72688..56fc668bdb 100644 --- a/libraries/metrics/package-lock.json +++ b/libraries/metrics/package-lock.json @@ -1,6 +1,6 @@ { "name": "@overleaf/metrics", - "version": "3.5.0", + "version": "3.5.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/libraries/metrics/package.json b/libraries/metrics/package.json index 134bccfaba..be8ff08387 100644 --- a/libraries/metrics/package.json +++ b/libraries/metrics/package.json @@ -1,6 +1,6 @@ { "name": "@overleaf/metrics", - "version": "3.5.0", + "version": "3.5.1", "description": "A drop-in metrics and monitoring module for node.js apps", "repository": { "type": "git", From acef9e7d8d7f71cbff6912e210c4165acfc3eaa7 Mon Sep 17 00:00:00 2001 From: Christopher Hoskin Date: Tue, 16 Mar 2021 11:47:18 +0000 Subject: [PATCH 181/182] Add basic README --- libraries/metrics/README.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 libraries/metrics/README.md diff --git a/libraries/metrics/README.md b/libraries/metrics/README.md new file mode 100644 index 0000000000..6f01e85ff7 --- /dev/null +++ b/libraries/metrics/README.md @@ -0,0 +1,30 @@ +overleaf/metrics-module +======================= + +Wrappers the [prom-client](https://github.com/siimon/prom-client) npm module to provide [Prometheus](https://prometheus.io/) metrics at `/metrics`. + +Use: +``` +const metrics = require('@overleaf/metrics') +metrics.initialize('myapp') + +const express = require('express') +const app = express() +metrics.injectMetricsRoute(app) +``` +Request logging can be enabled: +``` +const logger = require('logger-sharelatex') +... +app.use(metrics.http.monitor(logger)) +``` + +The metrics module can be configured through the following environment variables: + +* `DEBUG_METRICS` - enables display of debugging messages to the console. +* `ENABLE_TRACE_AGENT` - enables @google-cloud/trace-agent on Google Cloud +* `ENABLE_DEBUG_AGENT` - enables @google-cloud/debug-agent on Google Cloud +* `ENABLE_PROFILE_AGENT` - enables @google-cloud/profiler on Google Cloud +* `METRICS_COMPRESSION_LEVEL` - sets the [compression level](https://www.npmjs.com/package/compression#level) for `/metrics` +* `STACKDRIVER_LOGGING` - toggles the request logging format +* `UV_THREADPOOL_SIZE` - sets the libuv [thread pool](http://docs.libuv.org/en/v1.x/threadpool.html) size \ No newline at end of file From 23efa1d977bb368d9526d4654832dee1414fd6eb Mon Sep 17 00:00:00 2001 From: Jakob Ackermann Date: Tue, 27 Jul 2021 16:33:33 +0100 Subject: [PATCH 182/182] [misc] prepare for monorepo - add git ignore entries - sync/create package-lock.json - delete .nvmrc --- libraries/metrics/.gitignore | 3 +++ libraries/metrics/.nvmrc | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) delete mode 100644 libraries/metrics/.nvmrc diff --git a/libraries/metrics/.gitignore b/libraries/metrics/.gitignore index 3c3629e647..cbf8548194 100644 --- a/libraries/metrics/.gitignore +++ b/libraries/metrics/.gitignore @@ -1 +1,4 @@ node_modules + +.npmrc +Dockerfile diff --git a/libraries/metrics/.nvmrc b/libraries/metrics/.nvmrc deleted file mode 100644 index 295bfdbe57..0000000000 --- a/libraries/metrics/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -10.19