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/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/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/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/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/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); + }); + }); +}); + + 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}`); +}