From 1db95d942ba4c94f7b1561887d81bd1419413f38 Mon Sep 17 00:00:00 2001 From: chenyang Date: Thu, 19 Apr 2018 09:52:37 +0800 Subject: [PATCH 01/18] support coding.net --- web/app.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/web/app.js b/web/app.js index 82952f3..9d64c90 100644 --- a/web/app.js +++ b/web/app.js @@ -114,9 +114,8 @@ function verify(req, app, payload) { repoURL = repo.links.html.href } else { - console.log('\nreceived webhook request from: ' + repo.url) - - repoURL = repo.url + repoURL = repo.url || repo.https_url + console.log('\nreceived webhook request from: ' + repoURL) } if (!repoURL) return @@ -142,8 +141,9 @@ function verify(req, app, payload) { if (!commit) return // skip it with [pod skip] message - console.log('commit message: ' + commit.message) - if (/\[pod skip\]/.test(commit.message)) { + var message = commit.message || commit.short_message + console.log('commit message: ' + message) + if (/\[pod skip\]/.test(message)) { console.log('aborted.') return } From 63106bca04cfea25805147a825e3a6a46942f42f Mon Sep 17 00:00:00 2001 From: chenyang Date: Thu, 19 Apr 2018 11:27:33 +0800 Subject: [PATCH 02/18] process.env.NODE_ENV first --- lib/api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/api.js b/lib/api.js index d7cdce4..d834810 100644 --- a/lib/api.js +++ b/lib/api.js @@ -541,7 +541,7 @@ function prepareConfig(appInfo) { name: appInfo.name, script: appInfo.script, env: { - NODE_ENV: appInfo.config.node_env || globalConfig.node_env || 'development', + NODE_ENV: process.env.NODE_ENV || appInfo.config.node_env || globalConfig.node_env || 'development', PORT: appInfo.config.port } } From 6a1872a3010e7647a7a073ec1912f3483a3972d4 Mon Sep 17 00:00:00 2001 From: chenyang Date: Thu, 19 Apr 2018 16:34:45 +0800 Subject: [PATCH 03/18] merge global opts and app opts --- lib/api.js | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/lib/api.js b/lib/api.js index d834810..4026457 100644 --- a/lib/api.js +++ b/lib/api.js @@ -53,21 +53,16 @@ api.createApp = function (appname, options, callback) { options = null } - if (globalConfig.apps[appname] || appname === webInterfaceId) { + if (appname === webInterfaceId) { return abort(ERRORS.EXISTS, callback, { appname: appname }) } var paths = getAppPaths(appname) async.parallel([ function (done) { - // write config file - var opts = {} // merge options - if (options) { - for (var o in options) { - opts[o] = options[o] - } - } + var opts = Object.assign({}, globalConfig.apps[appname], options) + // write config file globalConfig.apps[appname] = opts var data = JSON.stringify(globalConfig, null, 4) fs.writeFile(globalConfigPath, data, function (err) { From 916a9cc19ebe5e3892fce70cee224275008bfc8e Mon Sep 17 00:00:00 2001 From: chenyang Date: Thu, 19 Apr 2018 17:13:12 +0800 Subject: [PATCH 04/18] log --- web/app.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/web/app.js b/web/app.js index 9d64c90..ed1a9ac 100644 --- a/web/app.js +++ b/web/app.js @@ -104,8 +104,10 @@ pod.once('ready', function () { function verify(req, app, payload) { // not even a remote app if (!app.remote) return - // check repo match + console.log('received webhook request: ', payload) + + // check repo match var repo = payload.repository var repoURL From f59b2653e7598ab0f48e4f7171c02f9f9759428a Mon Sep 17 00:00:00 2001 From: chenyang Date: Thu, 19 Apr 2018 17:17:47 +0800 Subject: [PATCH 05/18] log --- web/app.js | 1 + 1 file changed, 1 insertion(+) diff --git a/web/app.js b/web/app.js index ed1a9ac..391df1b 100644 --- a/web/app.js +++ b/web/app.js @@ -105,6 +105,7 @@ function verify(req, app, payload) { // not even a remote app if (!app.remote) return + console.log('app: ', app) console.log('received webhook request: ', payload) // check repo match From e4d9476bf526d78e8000aaf5dc9d072a128a57ec Mon Sep 17 00:00:00 2001 From: chenyang Date: Sun, 22 Apr 2018 21:52:39 +0800 Subject: [PATCH 06/18] support gogs webhook --- web/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/app.js b/web/app.js index 391df1b..0d9ed78 100644 --- a/web/app.js +++ b/web/app.js @@ -117,7 +117,7 @@ function verify(req, app, payload) { repoURL = repo.links.html.href } else { - repoURL = repo.url || repo.https_url + repoURL = repo.url || repo.https_url || repo.clone_url console.log('\nreceived webhook request from: ' + repoURL) } From a89b1ee1f6396771d99eb1c87413af9c3cf4c9ac Mon Sep 17 00:00:00 2001 From: chenyang Date: Sun, 22 Apr 2018 23:54:53 +0800 Subject: [PATCH 07/18] support not only js script --- lib/api.js | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/lib/api.js b/lib/api.js index 4026457..82550fc 100644 --- a/lib/api.js +++ b/lib/api.js @@ -132,26 +132,28 @@ api.startApp = function (appname, callback) { return abort(ERRORS.NOT_FOUND, callback, { appname: appname }) } - debug('checking if app main script exists...') - fs.exists(app.script, function (exists) { - if (!exists) { - return abort(ERRORS.NO_SCRIPT, callback, { appname: appname, script: app.script }) + // debug('checking if app main script exists...') + // fs.exists(app.script, function (exists) { + // if (!exists) { + // return abort(ERRORS.NO_SCRIPT, callback, { appname: appname, script: app.script }) + // } + // }) + + debug('checking if app is already running...') + Client.executeRemote('getMonitorData', {}, function (err, list) { + if (err) return callback(err) + var runningProcs = findInList(appname, list) + if (!runningProcs) { + debug('attempting to start app...') + pm2.start(prepareConfig(app), function (err) { + if (err) return callback(err) + return callback(null, appname.yellow + ' running on ' + (app.port || 'unknown port')) + }) + } else { + return abort(ERRORS.RUNNING, callback, { appname: appname }); } - debug('checking if app is already running...') - Client.executeRemote('getMonitorData', {}, function (err, list) { - if (err) return callback(err) - var runningProcs = findInList(appname, list) - if (!runningProcs) { - debug('attempting to start app...') - pm2.start(prepareConfig(app), function (err) { - if (err) return callback(err) - return callback(null, appname.yellow + ' running on ' + (app.port || 'unknown port')) - }) - } else { - return abort(ERRORS.RUNNING, callback, { appname: appname }); - } - }); - }) + }); + } api.startAllApps = function (callback) { From b8606a2a8055d04906b30e6b914c0037f17d5da5 Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 22 Aug 2018 17:11:11 +0100 Subject: [PATCH 08/18] Added passing environment variables to hook --- web/app.js | 145 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 98 insertions(+), 47 deletions(-) diff --git a/web/app.js b/web/app.js index 82952f3..2b23fb0 100644 --- a/web/app.js +++ b/web/app.js @@ -15,16 +15,19 @@ fs = require('fs'), var conf = pod.reloadConfig() // middlewares -var reloadConf = function (req, res, next) { +var reloadConf = function(req, res, next) +{ conf = pod.reloadConfig() next() } -var auth = function (req, res, next) { +var auth = function(req, res, next) +{ var user = basicAuth(req); const username = (conf.web.username || 'admin'); const password = (conf.web.password || 'admin'); console.log(JSON.stringify(user)) - if (!user || user.name !== username || user.pass !== password) { + if(!user || user.name !== username || user.pass !== password) + { res.setHeader('WWW-Authenticate', 'Basic realm=Authorization Required'); return res.sendStatus(401); } @@ -39,60 +42,77 @@ app.use(bodyParser.json()) app.use(statics(path.join(__dirname, 'static'))) -app.get('/', auth, function (req, res) { - pod.listApps(function (err, list) { - if (err) return res.end(err) +app.get('/', auth, function(req, res) +{ + pod.listApps(function(err, list) + { + if(err) return res.end(err) return res.render('index', { apps: list }) }) }) -app.get('/json', auth, function (req, res) { - pod.listApps(function (err, list) { - if (err) return res.end(err) +app.get('/json', auth, function(req, res) +{ + pod.listApps(function(err, list) + { + if(err) return res.end(err) res.json(list) res.end(); }) }) -app.post('/hooks/:appid', function (req, res) { +app.post('/hooks/:appid', function(req, res) +{ var appid = req.params.appid, payload = JSON.stringify(req.body), app = conf.apps[appid] - try { + try + { payload = JSON.parse(payload) - } catch (e) { + } catch(e) + { return res.end(e.toString()) } - if (req.get('X-GitHub-Event') === 'ping') { - if (ghURL(payload.repository.git_url).repopath === ghURL(app.remote).repopath) { + if(req.get('X-GitHub-Event') === 'ping') + { + if(ghURL(payload.repository.git_url).repopath === ghURL(app.remote).repopath) + { return res.status(200).end() - } else { + } else + { return res.status(500).end() } } - if (app && verify(req, app, payload)) { - executeHook(appid, app, payload, function () { + if(app && verify(req, app, payload)) + { + executeHook(appid, app, payload, function() + { res.end() }) - } else { + } else + { res.end() } }) // listen when API is ready -pod.once('ready', function () { +pod.once('ready', function() +{ // load config first conf = pod.getConfig() // conditional open up jsonp based on config - if (conf.web.jsonp === true) { - app.get('/jsonp', function (req, res) { - pod.listApps(function (err, list) { - if (err) return res.end(err) + if(conf.web.jsonp === true) + { + app.get('/jsonp', function(req, res) + { + pod.listApps(function(err, list) + { + if(err) return res.end(err) res.jsonp(list) }) }) @@ -101,27 +121,31 @@ pod.once('ready', function () { }) // Helpers -function verify(req, app, payload) { +function verify(req, app, payload) +{ // not even a remote app - if (!app.remote) return + if(!app.remote) return // check repo match var repo = payload.repository var repoURL - if (repo.links && /bitbucket\.org/.test(repo.links.html.href)) { + if(repo.links && /bitbucket\.org/.test(repo.links.html.href)) + { console.log('\nreceived webhook request from: ' + repo.links.html.href) repoURL = repo.links.html.href - } else { + } else + { console.log('\nreceived webhook request from: ' + repo.url) repoURL = repo.url } - if (!repoURL) return + if(!repoURL) return - if (ghURL(repoURL).repopath !== ghURL(app.remote).repopath) { + if(ghURL(repoURL).repopath !== ghURL(app.remote).repopath) + { console.log('aborted.') return } @@ -129,70 +153,97 @@ function verify(req, app, payload) { var commit // support bitbucket webhooks payload structure - if (/bitbucket\.org/.test(repoURL)) { + if(/bitbucket\.org/.test(repoURL)) + { commit = payload.push.changes[0].new commit.message = commit.target.message - } else { + } else + { // use gitlab's payload structure if detected commit = payload.head_commit ? payload.head_commit : payload.commits[payload.commits.length - 1]; } - if (!commit) return + if(!commit) return // skip it with [pod skip] message console.log('commit message: ' + commit.message) - if (/\[pod skip\]/.test(commit.message)) { + if(/\[pod skip\]/.test(commit.message)) + { console.log('aborted.') return } // check branch match var ref = commit.name ? commit.name : payload.ref - if (!ref) return + if(!ref) return var branch = ref.replace('refs/heads/', ''), expected = app.branch || 'master' console.log('expected branch: ' + expected + ', got branch: ' + branch) - if (branch !== expected) { + if(branch !== expected) + { console.log('aborted.') return } return true } -function executeHook(appid, app, payload, cb) { +function executeHook(appid, app, payload, cb) +{ // set a response timeout to avoid GitHub webhooks // hanging up due to long build times var responded = false - function respond(err) { - if (!responded) { + function respond(err) + { + if(!responded) + { responded = true cb(err) } } setTimeout(respond, 3000) - fs.readFile(path.resolve(__dirname, '../hooks/post-receive'), 'utf-8', function (err, template) { - if (err) return respond(err) + // add apps environment configuration to current environment + // run npm install / .podhook with the apps env configuration + var appEnv = process.env + var globalConfig = pod.getConfig() + appEnv.NODE_ENV = app.node_env || appEnv.NODE_ENV || 'development' + for(i in globalConfig.env) + { + appEnv[i] = globalConfig.env[i]; + } + + for(i in app.env) + { + appEnv[i] = app.env[i] + } + + fs.readFile(path.resolve(__dirname, '../hooks/post-receive'), 'utf-8', function(err, template) + { + if(err) return respond(err) var hookPath = conf.root + '/temphook.sh', hook = template .replace(/\{\{pod_dir\}\}/g, conf.root) .replace(/\{\{app\}\}/g, appid) - if (app.branch) { + if(app.branch) + { hook = hook.replace('origin/master', 'origin/' + app.branch) } - fs.writeFile(hookPath, hook, function (err) { - if (err) return respond(err) - fs.chmod(hookPath, '0777', function (err) { - if (err) return respond(err) + fs.writeFile(hookPath, hook, function(err) + { + if(err) return respond(err) + fs.chmod(hookPath, '0777', function(err) + { + if(err) return respond(err) console.log('excuting github webhook for ' + appid + '...') - var child = spawn('bash', [hookPath]) + var child = spawn('bash', [hookPath], {env: appEnv}) child.stdout.pipe(process.stdout) child.stderr.pipe(process.stderr) - child.on('exit', function (code) { + child.on('exit', function(code) + { fs.unlink(hookPath, respond) }) }) From 5d67bd320cbfe583f0506228eb3145e1c2b9056f Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 22 Aug 2018 17:19:39 +0100 Subject: [PATCH 09/18] Hopefully this will pass in the environment --- web/app.js | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/web/app.js b/web/app.js index 2b23fb0..9be2e36 100644 --- a/web/app.js +++ b/web/app.js @@ -209,17 +209,7 @@ function executeHook(appid, app, payload, cb) // add apps environment configuration to current environment // run npm install / .podhook with the apps env configuration var appEnv = process.env - var globalConfig = pod.getConfig() - appEnv.NODE_ENV = app.node_env || appEnv.NODE_ENV || 'development' - for(i in globalConfig.env) - { - appEnv[i] = globalConfig.env[i]; - } - - for(i in app.env) - { - appEnv[i] = app.env[i] - } + appEnv = app.node_env || appEnv.NODE_ENV || 'development' fs.readFile(path.resolve(__dirname, '../hooks/post-receive'), 'utf-8', function(err, template) { From 80140dba9e92dbf85c12420730cec98f018d7938 Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 22 Aug 2018 17:24:35 +0100 Subject: [PATCH 10/18] Reverted changes --- web/app.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/web/app.js b/web/app.js index 9be2e36..2b23fb0 100644 --- a/web/app.js +++ b/web/app.js @@ -209,7 +209,17 @@ function executeHook(appid, app, payload, cb) // add apps environment configuration to current environment // run npm install / .podhook with the apps env configuration var appEnv = process.env - appEnv = app.node_env || appEnv.NODE_ENV || 'development' + var globalConfig = pod.getConfig() + appEnv.NODE_ENV = app.node_env || appEnv.NODE_ENV || 'development' + for(i in globalConfig.env) + { + appEnv[i] = globalConfig.env[i]; + } + + for(i in app.env) + { + appEnv[i] = app.env[i] + } fs.readFile(path.resolve(__dirname, '../hooks/post-receive'), 'utf-8', function(err, template) { From d143c9fc8cacf32e6c853ec772f207ef8cb20919 Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 22 Aug 2018 17:46:33 +0100 Subject: [PATCH 11/18] Added .jshintrc and updated the code to work with my code style --- .jshintrc | 21 +++++ web/app.js | 244 ++++++++++++++++++++++++++++++++--------------------- 2 files changed, 168 insertions(+), 97 deletions(-) create mode 100644 .jshintrc diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 0000000..2339417 --- /dev/null +++ b/.jshintrc @@ -0,0 +1,21 @@ +{ + "globals" : { + "$" : true, + "alert" : true, + "angular" : true, + "app" : true, + "async" : true, + "moment" : true, + "window" : true, + "$rootScope" : true, + "Highcharts" : true, + "$filter" : true, + "DOMAINS" : true, + "renderPDF" : true + }, + "esversion" : 6, + "curly" : true, + "forin" : true, + "strict" : "implied", + "node" : true +} diff --git a/web/app.js b/web/app.js index 2b23fb0..75430a0 100644 --- a/web/app.js +++ b/web/app.js @@ -1,31 +1,31 @@ -const - bodyParser = require('body-parser'); -fs = require('fs'), - path = require('path'), - spawn = require('child_process').spawn, - express = require('express'), - pod = require('../lib/api'), - ghURL = require('parse-github-url'), - app = express(), - // favicon = require('serve-favicon'), - statics = require('serve-static'), - basicAuth = require('basic-auth'); +const bodyParser = require('body-parser'); +const fs = require('fs'); +const path = require('path'); +const spawn = require('child_process').spawn; +const express = require('express'); +const pod = require('../lib/api'); +const ghURL = require('parse-github-url'); +const app = express(); +// const favicon = require('serve-favicon'); +const statics = require('serve-static'); +const basicAuth = require('basic-auth'); // late def, wait until pod is ready -var conf = pod.reloadConfig() +var conf = pod.reloadConfig(); // middlewares var reloadConf = function(req, res, next) { - conf = pod.reloadConfig() - next() -} + conf = pod.reloadConfig(); + next(); +}; + var auth = function(req, res, next) { var user = basicAuth(req); const username = (conf.web.username || 'admin'); const password = (conf.web.password || 'admin'); - console.log(JSON.stringify(user)) + console.log(JSON.stringify(user)); if(!user || user.name !== username || user.pass !== password) { res.setHeader('WWW-Authenticate', 'Basic realm=Authorization Required'); @@ -34,57 +34,65 @@ var auth = function(req, res, next) next(); }; -app.set('views', __dirname + '/views') -app.set('view engine', 'ejs') +app.set('views', __dirname + '/views'); +app.set('view engine', 'ejs'); //app.use(favicon()) -app.use(reloadConf) -app.use(bodyParser.json()) -app.use(statics(path.join(__dirname, 'static'))) +app.use(reloadConf); +app.use(bodyParser.json()); +app.use(statics(path.join(__dirname, 'static'))); app.get('/', auth, function(req, res) { pod.listApps(function(err, list) { - if(err) return res.end(err) + if(err) + { + return res.end(err); + } + return res.render('index', { apps: list - }) - }) -}) + }); + }); +}); app.get('/json', auth, function(req, res) { pod.listApps(function(err, list) { - if(err) return res.end(err) - res.json(list) + if(err) + { + return res.end(err); + } + + res.json(list); res.end(); - }) -}) + }); +}); app.post('/hooks/:appid', function(req, res) { var appid = req.params.appid, payload = JSON.stringify(req.body), - app = conf.apps[appid] + app = conf.apps[appid]; try { - payload = JSON.parse(payload) + payload = JSON.parse(payload); } catch(e) { - return res.end(e.toString()) + return res.end(e.toString()); } if(req.get('X-GitHub-Event') === 'ping') { if(ghURL(payload.repository.git_url).repopath === ghURL(app.remote).repopath) { - return res.status(200).end() + return res.status(200).end(); } else { - return res.status(500).end() + return res.status(500).end(); } } @@ -92,19 +100,19 @@ app.post('/hooks/:appid', function(req, res) { executeHook(appid, app, payload, function() { - res.end() - }) + res.end(); + }); } else { - res.end() + res.end(); } -}) +}); // listen when API is ready pod.once('ready', function() { // load config first - conf = pod.getConfig() + conf = pod.getConfig(); // conditional open up jsonp based on config if(conf.web.jsonp === true) { @@ -112,52 +120,63 @@ pod.once('ready', function() { pod.listApps(function(err, list) { - if(err) return res.end(err) - res.jsonp(list) - }) - }) + if(err) + { + return res.end(err); + } + + res.jsonp(list); + }); + }); } - app.listen(process.env.PORT || 19999) -}) + + app.listen(process.env.PORT || 19999); +}); // Helpers function verify(req, app, payload) { // not even a remote app - if(!app.remote) return + if(!app.remote) + { + return; + } // check repo match - var repo = payload.repository - var repoURL + var repo = payload.repository; + var repoURL; if(repo.links && /bitbucket\.org/.test(repo.links.html.href)) { - console.log('\nreceived webhook request from: ' + repo.links.html.href) + console.log('\nreceived webhook request from: ' + repo.links.html.href); - repoURL = repo.links.html.href + repoURL = repo.links.html.href; } else { - console.log('\nreceived webhook request from: ' + repo.url) + console.log('\nreceived webhook request from: ' + repo.url); - repoURL = repo.url + repoURL = repo.url; } - if(!repoURL) return + if(!repoURL) + { + return; + } if(ghURL(repoURL).repopath !== ghURL(app.remote).repopath) { - console.log('aborted.') - return + console.log('aborted.'); + return; } - var commit + var commit; // support bitbucket webhooks payload structure if(/bitbucket\.org/.test(repoURL)) { - commit = payload.push.changes[0].new + commit = payload.push.changes[0].new; - commit.message = commit.target.message + commit.message = commit.target.message; } else { // use gitlab's payload structure if detected @@ -165,89 +184,120 @@ function verify(req, app, payload) payload.commits[payload.commits.length - 1]; } - if(!commit) return + if(!commit) + { + return; + } // skip it with [pod skip] message - console.log('commit message: ' + commit.message) + console.log('commit message: ' + commit.message); if(/\[pod skip\]/.test(commit.message)) { - console.log('aborted.') - return + console.log('aborted.'); + return; } + // check branch match - var ref = commit.name ? commit.name : payload.ref + var ref = commit.name ? commit.name : payload.ref; - if(!ref) return + if(!ref) + { + return; + } + + var branch = ref.replace('refs/heads/', ''); + var expected = app.branch || 'master'; + console.log('expected branch: ' + expected + ', got branch: ' + branch); - var branch = ref.replace('refs/heads/', ''), - expected = app.branch || 'master' - console.log('expected branch: ' + expected + ', got branch: ' + branch) if(branch !== expected) { - console.log('aborted.') - return + console.log('aborted.'); + return; } - return true + + return true; } function executeHook(appid, app, payload, cb) { - // set a response timeout to avoid GitHub webhooks // hanging up due to long build times - var responded = false + var responded = false; + function respond(err) { if(!responded) { - responded = true - cb(err) + responded = true; + cb(err); } } - setTimeout(respond, 3000) + + setTimeout(respond, 3000); // add apps environment configuration to current environment // run npm install / .podhook with the apps env configuration - var appEnv = process.env - var globalConfig = pod.getConfig() - appEnv.NODE_ENV = app.node_env || appEnv.NODE_ENV || 'development' - for(i in globalConfig.env) + var appEnv = process.env; + var globalConfig = pod.getConfig(); + appEnv.NODE_ENV = app.node_env || appEnv.NODE_ENV || 'development'; + + for(let i in globalConfig.env) { - appEnv[i] = globalConfig.env[i]; + if(globalConfig.env.hasOwnProperty(i)) + { + appEnv[i] = globalConfig.env[i]; + } } - for(i in app.env) + for(let i in app.env) { - appEnv[i] = app.env[i] + if(app.env.hasOwnProperty(i)) + { + appEnv[i] = app.env[i]; + } } fs.readFile(path.resolve(__dirname, '../hooks/post-receive'), 'utf-8', function(err, template) { - if(err) return respond(err) + if(err) + { + return respond(err); + } + var hookPath = conf.root + '/temphook.sh', hook = template .replace(/\{\{pod_dir\}\}/g, conf.root) - .replace(/\{\{app\}\}/g, appid) + .replace(/\{\{app\}\}/g, appid); + if(app.branch) { - hook = hook.replace('origin/master', 'origin/' + app.branch) + hook = hook.replace('origin/master', 'origin/' + app.branch); } + fs.writeFile(hookPath, hook, function(err) { - if(err) return respond(err) + if(err) + { + return respond(err); + } + fs.chmod(hookPath, '0777', function(err) { - if(err) return respond(err) - console.log('excuting github webhook for ' + appid + '...') - var child = spawn('bash', [hookPath], {env: appEnv}) - child.stdout.pipe(process.stdout) - child.stderr.pipe(process.stderr) + if(err) + { + return respond(err); + } + + console.log('excuting github webhook for ' + appid + '...'); + var child = spawn('bash', [hookPath], {env: appEnv}); + child.stdout.pipe(process.stdout); + child.stderr.pipe(process.stderr); child.on('exit', function(code) { - fs.unlink(hookPath, respond) - }) - }) - }) - }) + fs.unlink(hookPath, respond); + }); + }); + }); + }); } From c49e6816fe5c6df2010172143ede1a66ec01b103 Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 22 Aug 2018 17:46:55 +0100 Subject: [PATCH 12/18] Removed extra newline --- web/app.js | 1 - 1 file changed, 1 deletion(-) diff --git a/web/app.js b/web/app.js index 75430a0..8d6759e 100644 --- a/web/app.js +++ b/web/app.js @@ -300,4 +300,3 @@ function executeHook(appid, app, payload, cb) }); }); } - From aee5a90335f24e385a97efc2a028d3ee71cb3f5d Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 23 Aug 2018 15:45:03 +0100 Subject: [PATCH 13/18] Updated all the code to fit my code style --- .vscode/settings.json | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 20af2f6..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -// Place your settings in this file to overwrite default and user settings. -{ -} \ No newline at end of file From 3e925f45754149eb95fb24ae68c19816c8f7335c Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 23 Aug 2018 15:45:19 +0100 Subject: [PATCH 14/18] Actually committed all the files this time --- .gitignore | 3 +- .travis.yml | 13 - README.md | 6 + bin/pod | 2 +- hooks/post-receive | 18 +- lib/api.js | 1100 +++++++++++++++++++++++++++--------------- lib/cli.js | 604 +++++++++++++++-------- lib/conf.js | 3 +- lib/errors.js | 16 +- lib/formatter.js | 154 +++--- web/static/style.css | 75 +-- web/test.js | 4 +- web/views/index.ejs | 2 +- 13 files changed, 1272 insertions(+), 728 deletions(-) delete mode 100644 .travis.yml diff --git a/.gitignore b/.gitignore index 5e7166a..8cfd1b2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .DS_Store node_modules local -temp \ No newline at end of file +temp +.vscode/* diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 5f135b4..0000000 --- a/.travis.yml +++ /dev/null @@ -1,13 +0,0 @@ -language: node_js -branches: - only: - - master -node_js: - - "6.0" - - "7.0" - - "7.8" -before_install: - - git config --global user.email "yyx990803@gmail.com" - - git config --global user.name "Evan You" -before_script: - - npm link \ No newline at end of file diff --git a/README.md b/README.md index 7ed498e..fae2c3c 100644 --- a/README.md +++ b/README.md @@ -255,6 +255,12 @@ fi # restart is automatic so no need to include that here ``` +You can also access an apps environment variables directly in the podhook by accessing the variable with the environment variable name. For example: +```bash +# runs npm install with the node_env setting in .podrc, so it can ommit dev dependencies if on production +NODE_ENV=$NODE_ENV npm install +``` + You can also directly edit the post-receive script of an app found in `pod-root-dir/repos/my-app.git/hooks/post-receive` if you wish. ## Using the API diff --git a/bin/pod b/bin/pod index c1c3416..4ed1172 100755 --- a/bin/pod +++ b/bin/pod @@ -1,2 +1,2 @@ #!/usr/bin/env node -require('../lib/cli') \ No newline at end of file +require('../lib/cli'); diff --git a/hooks/post-receive b/hooks/post-receive index e7c3e22..8a9a399 100644 --- a/hooks/post-receive +++ b/hooks/post-receive @@ -12,16 +12,16 @@ git reset --hard origin/master # if has .podhook, execute that; otherwise default if [ -f .podhook ]; then - bash .podhook - rc=$? - if [[ $rc != 0 ]]; then - echo "`tput setaf 1`ERROR: .podhook exited with code $rc, working tree is reverted.`tput sgr0`" - git reset $LAST_COMMIT --hard - exit $rc - fi + bash .podhook + rc=$? + if [[ $rc != 0 ]]; then + echo "`tput setaf 1`ERROR: .podhook exited with code $rc, working tree is reverted.`tput sgr0`" + git reset $LAST_COMMIT --hard + exit $rc + fi elif [ -f package.json ]; then - npm install + npm install fi pod stop {{app}} -pod start {{app}} \ No newline at end of file +pod start {{app}} diff --git a/lib/api.js b/lib/api.js index d7cdce4..3912296 100644 --- a/lib/api.js +++ b/lib/api.js @@ -1,541 +1,811 @@ -let fs = require('fs'), - path = require('path'), - async = require('async'), - mkdirp = require('mkdirp'), - colors = require('colors'), - pm2 = require('pm2'), - pm2cst = require('pm2/constants.js'), - pm2prepare = require('pm2/lib/Common.js').prepareAppConf, - // Client is pm2's RPC daemon, we have to use it to get - // some custom behavior that is not exposed by pm2's CLI. - Client = pm2.Client, - exec = require('child_process').exec, - Emitter = require('events').EventEmitter, - debug = require('debug')('api') - -var conf = require('./conf'), - ERRORS = require('./errors'), - formatter = require('./formatter'), - hookTemplate = fs.readFileSync(__dirname + '/../hooks/post-receive', 'utf-8') +const fs = require('fs'); +const path = require('path'); +const async = require('async'); +const mkdirp = require('mkdirp'); +const pm2 = require('pm2'); +const exec = require('child_process').exec; +const Emitter = require('events').EventEmitter; +const debug = require('debug')('api'); +const conf = require('./conf'); +const ERRORS = require('./errors'); +const formatter = require('./formatter'); +const hookTemplate = fs.readFileSync(__dirname + '/../hooks/post-receive', 'utf-8'); // Load config data -var globalConfigPath = conf.path, - webInterfaceId = conf.webId, - globalConfig = readJSON(globalConfigPath) +const globalConfigPath = conf.path; +const webInterfaceId = conf.webId; +let globalConfig = readJSON(globalConfigPath); -upgradeConf() +let Client = pm2.Client; // Client is pm2's RPC daemon, we have to use it to get some custom behavior that is not exposed by pm2's CLI + +upgradeConf(); // If env var is present, overwrite root dir // mostly for testing. -if (process.env.POD_ROOT_DIR) globalConfig.root = process.env.POD_ROOT_DIR +if(process.env.POD_ROOT_DIR) +{ + globalConfig.root = process.env.POD_ROOT_DIR; +} // create default folders -if (!fs.existsSync(globalConfig.root)) mkdirp.sync(globalConfig.root) -if (!fs.existsSync(globalConfig.root + '/apps')) fs.mkdirSync(globalConfig.root + '/apps') -if (!fs.existsSync(globalConfig.root + '/repos')) fs.mkdirSync(globalConfig.root + '/repos') +if(!fs.existsSync(globalConfig.root)) +{ + mkdirp.sync(globalConfig.root); +} + +if(!fs.existsSync(globalConfig.root + '/apps')) +{ + fs.mkdirSync(globalConfig.root + '/apps'); +} + +if(!fs.existsSync(globalConfig.root + '/repos')) +{ + fs.mkdirSync(globalConfig.root + '/repos'); +} // The api is an emitter -var api = new Emitter() +const api = new Emitter(); // init and connect to pm2 //pm2.pm2Init() -pm2.connect(function () { +pm2.connect(function() +{ api.emit('ready'); Client = pm2.Client; -}) +}); -api.version = require('../package.json').version +api.version = require('../package.json').version; -api.createApp = function (appname, options, callback) { +api.createApp = function(appname, options, callback) +{ - if (typeof options === 'function') { - callback = options - options = null + if(typeof options === 'function') + { + callback = options; + options = null; } - if (globalConfig.apps[appname] || appname === webInterfaceId) { - return abort(ERRORS.EXISTS, callback, { appname: appname }) + if(globalConfig.apps[appname] || appname === webInterfaceId) + { + return abort(ERRORS.EXISTS, callback, {appname: appname}); } - var paths = getAppPaths(appname) + const paths = getAppPaths(appname); + async.parallel([ - function (done) { + function(done) + { // write config file - var opts = {} + let opts = {}; + // merge options - if (options) { - for (var o in options) { - opts[o] = options[o] + if(options) + { + for(var o in options) + { + if(options.hasOwnProperty(o)) + { + opts[o] = options[o]; + } } } - globalConfig.apps[appname] = opts - var data = JSON.stringify(globalConfig, null, 4) - fs.writeFile(globalConfigPath, data, function (err) { - done(err, 'updated config.') - }) + + globalConfig.apps[appname] = opts; + let data = JSON.stringify(globalConfig, null, 4); + + fs.writeFile(globalConfigPath, data, function(err) + { + done(err, 'updated config.'); + }); }, - function (done) { + function(done) + { // create repo - if (options && options.remote) { - createRemoteApp(paths, options.remote, done) - } else { - createAppRepo(paths, done) + if(options && options.remote) + { + createRemoteApp(paths, options.remote, done); + } else + { + createAppRepo(paths, done); } } ], - function (err, msgs) { - var repoMsgs = msgs.pop() - msgs = msgs.concat(repoMsgs) - return callback(err, msgs, api.getAppInfo(appname)) - }) -} + function(err, msgs) + { + let repoMsgs = msgs.pop(); -api.removeApp = function (appname, callback) { + msgs = msgs.concat(repoMsgs); + + return callback(err, msgs, api.getAppInfo(appname)); + } + ); +}; - if (appname === webInterfaceId) { - return abort(ERRORS.WEB, callback) +api.removeApp = function(appname, callback) +{ + + if(appname === webInterfaceId) + { + return abort(ERRORS.WEB, callback); } - var app = api.getAppInfo(appname) - if (!app) { - return abort(ERRORS.NOT_FOUND, callback, { appname: appname }) + const app = api.getAppInfo(appname); + + if(!app) + { + return abort(ERRORS.NOT_FOUND, callback, {appname: appname}); } - api.stopApp(appname, function (err) { - if (!err || /is not running/.test(err.toString())) { + api.stopApp(appname, function(err) + { + if(!err || /is not running/.test(err.toString())) + { async.parallel([ - function (done) { + function(done) + { // remove files exec('rm -rf ' + app.repoPath + ' ' + app.workPath, done - ) + ); }, - function (done) { + function(done) + { // rewrite config - delete globalConfig.apps[appname] - var data = JSON.stringify(globalConfig, null, 4) - fs.writeFile(globalConfigPath, data, done) + delete globalConfig.apps[appname]; + + let data = JSON.stringify(globalConfig, null, 4); + + fs.writeFile(globalConfigPath, data, done); } ], - function (err) { - if (err) return callback(err) - return callback(null, 'deleted app: ' + appname.yellow) - }) - } else { - return callback(err) + function(err) + { + if(err) + { + return callback(err); + } + + return callback(null, 'deleted app: ' + appname.yellow); + }); + } + else + { + return callback(err); } - }) + }); -} +}; -api.startApp = function (appname, callback) { +api.startApp = function(appname, callback) +{ + const app = api.getAppInfo(appname); - var app = api.getAppInfo(appname) - if (!app) { - return abort(ERRORS.NOT_FOUND, callback, { appname: appname }) + if(!app) + { + return abort(ERRORS.NOT_FOUND, callback, {appname: appname}); } - debug('checking if app main script exists...') - fs.exists(app.script, function (exists) { - if (!exists) { - return abort(ERRORS.NO_SCRIPT, callback, { appname: appname, script: app.script }) + debug('checking if app main script exists...'); + + fs.exists(app.script, function(exists) + { + if(!exists) + { + return abort(ERRORS.NO_SCRIPT, callback, {appname: appname, script: app.script}); } - debug('checking if app is already running...') - Client.executeRemote('getMonitorData', {}, function (err, list) { - if (err) return callback(err) - var runningProcs = findInList(appname, list) - if (!runningProcs) { - debug('attempting to start app...') - pm2.start(prepareConfig(app), function (err) { - if (err) return callback(err) - return callback(null, appname.yellow + ' running on ' + (app.port || 'unknown port')) - }) - } else { - return abort(ERRORS.RUNNING, callback, { appname: appname }); + + debug('checking if app is already running...'); + + Client.executeRemote('getMonitorData', {}, function(err, list) + { + if(err) + { + return callback(err); + } + + let runningProcs = findInList(appname, list); + + if(!runningProcs) + { + debug('attempting to start app...'); + + pm2.start(prepareConfig(app), function(err) + { + if(err) + { + return callback(err); + } + + return callback(null, appname.yellow + ' running on ' + (app.port || 'unknown port')); + }); + + } + else + { + return abort(ERRORS.RUNNING, callback, {appname: appname}); } }); - }) -} + }); +}; -api.startAllApps = function (callback) { +api.startAllApps = function(callback) +{ async.map( Object.keys(globalConfig.apps), api.startApp, callback - ) -} + ); +}; + +api.stopApp = function(appname, callback) +{ -api.stopApp = function (appname, callback) { + const app = api.getAppInfo(appname); - var app = api.getAppInfo(appname) - if (!app) { - return abort(ERRORS.NOT_FOUND, callback, { appname: appname }) + if(!app) + { + return abort(ERRORS.NOT_FOUND, callback, {appname: appname}); } - Client.executeRemote('getMonitorData', {}, function (err, list) { - if (err) return callback(err) - var runningProcs = findInList(appname, list) - if (!runningProcs) { - return callback(null, appname.yellow + ' is not running.') - } else { - async.map(runningProcs, function (proc, done) { - Client.executeRemote('stopProcessId', proc.pm_id, function (err) { - if (err) return done(err) - Client.executeRemote('deleteProcessId', proc.pm_id, done) - }) - }, function (err) { - if (err) return callback(err) - var l = runningProcs.length - return callback( - null, - appname.yellow + ' stopped.' + - (l > 1 ? (' (' + l + ' instances)').grey : '') - ) - }) + Client.executeRemote('getMonitorData', {}, function(err, list) + { + if(err) + { + return callback(err); } - }) -} -api.stopAllApps = function (callback) { + let runningProcs = findInList(appname, list); + + if(!runningProcs) + { + return callback(null, appname.yellow + ' is not running.'); + } + else + { + async.map(runningProcs, function(proc, done) + { + Client.executeRemote('stopProcessId', proc.pm_id, function(err) + { + if(err) + { + return done(err); + } + + Client.executeRemote('deleteProcessId', proc.pm_id, done); + }); + }, function(err) + { + if(err) + { + return callback(err); + } + + let l = runningProcs.length; + + return callback( + null, + appname.yellow + ' stopped.' + + (l > 1 ? (' (' + l + ' instances)').grey : '') + ); + } + ); + } + }); +}; + +api.stopAllApps = function(callback) +{ // only stop ones in the config async.map( Object.keys(globalConfig.apps), api.stopApp, callback - ) -} + ); +}; + +api.restartApp = function(appname, callback) +{ -api.restartApp = function (appname, callback) { + const app = api.getAppInfo(appname); - var app = api.getAppInfo(appname) - if (!app) { - return abort(ERRORS.NOT_FOUND, callback, { appname: appname }) + if(!app) + { + return abort(ERRORS.NOT_FOUND, callback, {appname: appname}); } - Client.executeRemote('getMonitorData', {}, function (err, list) { - if (err) return callback(err) - var runningProcs = findInList(appname, list) - if (!runningProcs) { - return abort(ERRORS.NOT_RUNNING, callback, { appname: appname }) - } else { - async.map(runningProcs, restart, function (err) { - if (err) return callback(err) - var l = runningProcs.length + Client.executeRemote('getMonitorData', {}, function(err, list) + { + if(err) + { + return callback(err); + } + + let runningProcs = findInList(appname, list); + + if(!runningProcs) + { + return abort(ERRORS.NOT_RUNNING, callback, {appname: appname}); + } + else + { + async.map(runningProcs, restart, function(err) + { + if(err) + { + return callback(err); + } + + let l = runningProcs.length; + return callback( null, appname.yellow + ' restarted.' + (l > 1 ? (' (' + l + ' instances)').grey : '') - ) - }) + ); + }); + } + }); +}; + +api.restartAllApps = function(callback) +{ + Client.executeRemote('getMonitorData', {}, function(err, list) + { + if(err) + { + return callback(err); } - }) -} -api.restartAllApps = function (callback) { - Client.executeRemote('getMonitorData', {}, function (err, list) { - if (err) return callback(err) - var runningProcs = [] - list.forEach(function (proc) { - if (proc.pm2_env.name in globalConfig.apps) { - runningProcs.push(proc) + let runningProcs = []; + + list.forEach(function(proc) + { + if(proc.pm2_env.name in globalConfig.apps) + { + runningProcs.push(proc); } - }) - async.map(runningProcs, restart, function (err, msgs) { - callback(err, msgs.map(function (msg) { - return 'instance of ' + msg - })) - }) - }) -} + }); -api.listApps = function (callback) { - var appList = Object.keys(globalConfig.apps) - if (!appList.length) { - return process.nextTick(function () { - return callback(null, []) - }) + async.map(runningProcs, restart, function(err, msgs) + { + callback(err, msgs.map(function(msg) + { + return 'instance of ' + msg; + })); + }); + }); +}; + +api.listApps = function(callback) +{ + let appList = Object.keys(globalConfig.apps); + + if(!appList.length) + { + return process.nextTick(function() + { + return callback(null, []); + }); } - Client.executeRemote('getMonitorData', {}, function (err, list) { - if (err) return callback(err) - return callback(null, appList.map(function (appname) { - var app = api.getAppInfo(appname) - app.instances = findInList(appname, list) - app.broken = isBroken(app) - return formatter.format(app) - })) - }) -} -api.prune = function (callback) { - var appList = Object.keys(globalConfig.apps), - pruned = [] + Client.executeRemote('getMonitorData', {}, function(err, list) + { + if(err) + { + return callback(err); + } + + return callback(null, appList.map(function(appname) + { + const app = api.getAppInfo(appname); + + app.instances = findInList(appname, list); + app.broken = isBroken(app); + + return formatter.format(app); + })); + }); +}; + +api.prune = function(callback) +{ + const appList = Object.keys(globalConfig.apps); + + let pruned = []; + async.parallel([ // clean root dir - function (done) { - fs.readdir(globalConfig.root, function (err, files) { - if (err) return callback(err) - async.map(files, function (f, next) { - if (f !== 'apps' && f !== 'repos') { - f = globalConfig.root + '/' + f - pruned.push(f) - removeFile(f, next) - } else { - next() + function(done) + { + fs.readdir(globalConfig.root, function(err, files) + { + if(err) + { + return callback(err); + } + + async.map(files, function(f, next) + { + if(f !== 'apps' && f !== 'repos') + { + f = globalConfig.root + '/' + f; + + pruned.push(f); + + removeFile(f, next); + } + else + { + next(); } - }, done) - }) + }, done); + }); }, // clean apps dir - function (done) { - fs.readdir(globalConfig.root + '/apps', function (err, files) { - if (err) return callback(err) - async.map(files, function (f, next) { - if (appList.indexOf(f) < 0) { - f = globalConfig.root + '/apps/' + f - pruned.push(f) - removeFile(f, next) - } else { - next() + function(done) + { + fs.readdir(globalConfig.root + '/apps', function(err, files) + { + if(err) + { + return callback(err); + } + + async.map(files, function(f, next) + { + if(appList.indexOf(f) < 0) + { + f = globalConfig.root + '/apps/' + f; + + pruned.push(f); + + removeFile(f, next); + } else + { + next(); } - }, done) - }) + }, done); + }); }, // clean repos dir - function (done) { - fs.readdir(globalConfig.root + '/repos', function (err, files) { - if (err) return callback(err) - async.map(files, function (f, next) { - var base = f.replace('.git', '') - if (appList.indexOf(base) < 0 || f.indexOf('.git') === -1) { - f = globalConfig.root + '/repos/' + f - pruned.push(f) - removeFile(f, next) - } else { - next() + function(done) + { + fs.readdir(globalConfig.root + '/repos', function(err, files) + { + if(err) + { + return callback(err); + } + + async.map(files, function(f, next) + { + const base = f.replace('.git', ''); + + if(appList.indexOf(base) < 0 || f.indexOf('.git') === -1) + { + f = globalConfig.root + '/repos/' + f; + + pruned.push(f); + + removeFile(f, next); + } else + { + next(); } - }, done) - }) + }, done); + }); } - ], function (err) { - var msg = pruned.length - ? 'pruned:\n' + pruned.join('\n').grey - : 'root directory is clean.' - return callback(err, msg) - }) -} + ], function(err) + { + let msg = pruned.length ? + 'pruned:\n' + pruned.join('\n').grey : + 'root directory is clean.'; -api.updateHooks = function (callback) { - var appList = Object.keys(globalConfig.apps), - updated = [] - async.map(appList, function (app, next) { - var info = getAppPaths(app) - createHook(info, function (err) { - if (!err) updated.push(info.name) - next(err) - }) - }, function (err) { - return callback(err, 'updated hooks for:\n' + updated.join('\n').yellow) - }) -} + return callback(err, msg); + } + ); +}; + +api.updateHooks = function(callback) +{ + const appList = Object.keys(globalConfig.apps); + let updated = []; + + async.map(appList, function(app, next) + { + const info = getAppPaths(app); + + createHook(info, function(err) + { + if(!err) + { + updated.push(info.name); + } -api.getAppInfo = function (appname) { - if (appname === webInterfaceId) { - return webConfig() + next(err); + }); + }, function(err) + { + return callback(err, 'updated hooks for:\n' + updated.join('\n').yellow); + } + ); +}; + +api.getAppInfo = function(appname) +{ + if(appname === webInterfaceId) + { + return webConfig(); } - var info = getAppPaths(appname) - info.config = globalConfig.apps[appname] - if (!info.config) return - info.script = path.resolve(info.workPath, getAppMainScript(info.workPath, appname) || globalConfig.default_script) - info.port = info.config.port || sniffPort(info.script) || null - return info -} -api.getConfig = function () { - return globalConfig -} + const info = getAppPaths(appname); -api.reloadConfig = function () { - globalConfig = readJSON(globalConfigPath) - return globalConfig -} + info.config = globalConfig.apps[appname]; -api.proxy = function () { - return Client.executeRemote.apply(Client, arguments) -} + if(!info.config) + { + return; + } + + info.script = path.resolve(info.workPath, getAppMainScript(info.workPath, appname) || globalConfig.default_script); + info.port = info.config.port || sniffPort(info.script) || null; + + return info; +}; + +api.getConfig = function() +{ + return globalConfig; +}; + +api.reloadConfig = function() +{ + globalConfig = readJSON(globalConfigPath); + + return globalConfig; +}; + +api.proxy = function() +{ + return Client.executeRemote.apply(Client, arguments); +}; // helpers -function restart(app, callback) { - Client.executeRemote('restartProcessId', { id: app.pm_id }, function (err) { - if (err) return callback(err) - return callback(null, app.pm2_env.name.yellow + ' restarted') - }) +function restart(app, callback) +{ + Client.executeRemote('restartProcessId', {id: app.pm_id}, function(err) + { + if(err) + { + return callback(err); + } + + return callback(null, app.pm2_env.name.yellow + ' restarted'); + }); } -function getAppPaths(app) { +function getAppPaths(app) +{ return { name: app, repoPath: globalConfig.root + '/repos/' + app + '.git', workPath: globalConfig.root + '/apps/' + app - } + }; } -function createAppRepo(info, done) { +function createAppRepo(info, done) +{ async.series([ - function (next) { + function(next) + { // create repo directory - fs.mkdir(info.repoPath, next) + fs.mkdir(info.repoPath, next); }, - function (next) { + function(next) + { // init bare repo - exec('git --git-dir ' + info.repoPath + ' --bare init', function (err) { - next(err, 'created bare repo at ' + info.repoPath.yellow) - }) + exec('git --git-dir ' + info.repoPath + ' --bare init', function(err) + { + next(err, 'created bare repo at ' + info.repoPath.yellow); + }); }, - function (next) { + function(next) + { // create post-receive hook - createHook(info, function (err) { - next(err, 'created post-receive hook.') - }) + createHook(info, function(err) + { + next(err, 'created post-receive hook.'); + }); }, - function (next) { + function(next) + { // clone an empty working copy - exec('git clone ' + info.repoPath + ' \"' + info.workPath+'\"', function (err) { - next(err, 'created empty working copy at ' + info.workPath.yellow) - }) + exec('git clone ' + info.repoPath + ' \"' + info.workPath + '\"', function(err) + { + next(err, 'created empty working copy at ' + info.workPath.yellow); + }); } - ], function (err, msgs) { - msgs.shift() - done(err, msgs) - }) + ], function(err, msgs) + { + msgs.shift(); + + done(err, msgs); + }); } -function createRemoteApp(info, remote, done) { - remote = expandRemote(remote) - exec('git clone ' + remote + ' \"' + info.workPath+'\"', function (err) { +function createRemoteApp(info, remote, done) +{ + remote = expandRemote(remote); + + exec('git clone ' + remote + ' \"' + info.workPath + '\"', function(err) + { done(err, [ 'created remote app at ' + info.workPath.yellow, 'tracking remote: ' + remote.cyan - ]) - }) + ]); + }); } -function expandRemote(remote) { - var m = remote.match(/^([\w-_]+)\/([\w-_]+)$/) - return m - ? 'https://github.com/' + m[1] + '/' + m[2] + '.git' - : remote +function expandRemote(remote) +{ + const m = remote.match(/^([\w-_]+)\/([\w-_]+)$/); + + return m ? + 'https://github.com/' + m[1] + '/' + m[2] + '.git' : + remote; } -function createHook(info, done) { - var hookPath = info.repoPath + '/hooks/post-receive' +function createHook(info, done) +{ + const hookPath = info.repoPath + '/hooks/post-receive'; + async.waterfall([ - function (next) { - var data = hookTemplate + function(next) + { + let data = hookTemplate .replace(/\{\{pod_dir\}\}/g, globalConfig.root) - .replace(/\{\{app\}\}/g, info.name) - fs.writeFile(hookPath, data, next) + .replace(/\{\{app\}\}/g, info.name); + + fs.writeFile(hookPath, data, next); }, - function (next) { - fs.chmod(hookPath, '0777', next) + function(next) + { + fs.chmod(hookPath, '0777', next); } - ], done) + ], done); } -function findInList(appname, list) { - if (!list || !list.length) return false - var ret = [], proc - for (var i = 0, j = list.length; i < j; i++) { - proc = list[i] - if ( +function findInList(appname, list) +{ + if(!list || !list.length) + { + return false; + } + + let ret = []; + let proc; + + for(var i = 0, j = list.length; i < j; i++) + { + proc = list[i]; + + if( proc.pm2_env.status !== 'stopped' && proc.pm2_env.name === appname - ) { - ret.push(list[i]) + ) + { + ret.push(list[i]); } } - return ret.length > 0 ? ret : null + + return ret.length > 0 ? ret : null; } -function getAppMainScript(workPath, appname) { - var pkg = readJSON(workPath + '/package.json') - var main +function getAppMainScript(workPath, appname) +{ + const pkg = readJSON(workPath + '/package.json'); + let main; - if (globalConfig.apps[appname].script) { - main = globalConfig.apps[appname].script - } else if (pkg && pkg.main) { - main = pkg.main + if(globalConfig.apps[appname].script) + { + main = globalConfig.apps[appname].script; + } + else if(pkg && pkg.main) + { + main = pkg.main; } - if (main) { - if (/\.js$/.test(main)) { - return main - } else { - var mainPath = path.resolve(workPath, main) - if (fs.existsSync(mainPath)) { - return fs.statSync(mainPath).isDirectory() - ? main + '/index.js' - : main - } else { - return main + '.js' + if(main) + { + if(/\.js$/.test(main)) + { + return main; + } + else + { + const mainPath = path.resolve(workPath, main); + + if(fs.existsSync(mainPath)) + { + return fs.statSync(mainPath).isDirectory() ? + main + '/index.js' : + main; + } + else + { + return main + '.js'; } } } } -function readJSON(file) { - if (!fs.existsSync(file)) { - return null - } else { - return JSON.parse(fs.readFileSync(file, 'utf-8')) +function readJSON(file) +{ + if(!fs.existsSync(file)) + { + return null; + } + else + { + return JSON.parse(fs.readFileSync(file, 'utf-8')); } } -function sniffPort(script) { - if (fs.existsSync(script)) { +function sniffPort(script) +{ + if(fs.existsSync(script)) + { // sniff port - var content = fs.readFileSync(script, 'utf-8'), - portMatch = content.match(/\.listen\(\D*(\d\d\d\d\d?)\D*\)/) + const content = fs.readFileSync(script, 'utf-8'); + let portMatch = content.match(/\.listen\(\D*(\d\d\d\d\d?)\D*\)/); - if (!portMatch) { - var portVariableMatch = content.match(/\.listen\(\s*([a-zA-Z_$]+)\s*/) + if(!portMatch) + { + var portVariableMatch = content.match(/\.listen\(\s*([a-zA-Z_$]+)\s*/); - if (portVariableMatch) { - portMatch = content.match(new RegExp(portVariableMatch[1] + '\\s*=\\D*(\\d\\d\\d\\d\\d?)\\D')) + if(portVariableMatch) + { + portMatch = content.match(new RegExp(portVariableMatch[1] + '\\s*=\\D*(\\d\\d\\d\\d\\d?)\\D')); } } - return portMatch ? portMatch[1] : null + return portMatch ? portMatch[1] : null; } } -function isBroken(app) { - return app.name !== webInterfaceId && - ( - (!app.config.remote && !fs.existsSync(app.repoPath)) || - !fs.existsSync(app.workPath) - ) +function isBroken(app) +{ + return app.name !== webInterfaceId && ( + (!app.config.remote && !fs.existsSync(app.repoPath)) || + !fs.existsSync(app.workPath) + ); } -function removeFile(f, cb) { - var isDir = fs.statSync(f).isDirectory() - fs[isDir ? 'rmdir' : 'unlink'](f, cb) +function removeFile(f, cb) +{ + const isDir = fs.statSync(f).isDirectory(); + + fs[isDir ? 'rmdir' : 'unlink'](f, cb); } -function webConfig() { - var p = path.resolve(__dirname, '../web') +function webConfig() +{ + const p = path.resolve(__dirname, '../web'); + return { name: webInterfaceId, workPath: p, config: globalConfig.web, script: p + '/app.js', port: globalConfig.web.port || 19999 - } + }; } -function prepareConfig(appInfo) { +function prepareConfig(appInfo) +{ var conf = { name: appInfo.name, @@ -544,55 +814,76 @@ function prepareConfig(appInfo) { NODE_ENV: appInfo.config.node_env || globalConfig.node_env || 'development', PORT: appInfo.config.port } - } + }; // copy other options and pass it to pm2 - for (var o in appInfo.config) { - if ( + for(var o in appInfo.config) + { + if( o !== 'port' && o !== 'node_env' && o !== 'remote' && o !== 'username' && o !== 'password' && o !== 'jsonp' - ) { - conf[o] = appInfo.config[o] + ) + { + conf[o] = appInfo.config[o]; } } - for (o in globalConfig.env) { - conf.env[o] = globalConfig.env[o] + for(o in globalConfig.env) + { + if(globalConfig.env.hasOwnProperty(o)) + { + conf.env[o] = globalConfig.env[o]; + } } // constraints, fallback to global config - conf.min_uptime = conf.min_uptime || globalConfig.min_uptime || undefined - conf.max_restarts = conf.max_restarts || globalConfig.max_restarts || undefined + conf.min_uptime = conf.min_uptime || globalConfig.min_uptime || undefined; + conf.max_restarts = conf.max_restarts || globalConfig.max_restarts || undefined; return conf; } -function abort(e, callback, data) { - var msg = e.msg - if (data) { - msg = msg.replace(/{{(.+?)}}/g, function (m, p1) { - return data[p1] || '' - }) +function abort(e, callback, data) +{ + let msg = e.msg; + + if(data) + { + msg = msg.replace(/{{(.+?)}}/g, function(m, p1) + { + return data[p1] || ''; + }); } - var err = new Error(msg) - err.code = e.code - return process.nextTick(function () { - return callback(err) - }) + + const err = new Error(msg); + err.code = e.code; + + return process.nextTick(function() + { + return callback(err); + }); } -function upgradeConf() { - if ( +function upgradeConf() +{ + if( globalConfig.web && globalConfig.node_env && globalConfig.default_script - ) return + ) + { + return; + } + + if(!globalConfig.web) + { + globalConfig.web = {}; + } - if (!globalConfig.web) globalConfig.web = {} var fieldsToConvert = { 'nodeEnv': 'node_env', 'defaultScript': 'default_script', @@ -601,21 +892,32 @@ function upgradeConf() { 'pidFile': 'pid_file', 'minUptime': 'min_uptime', 'maxRestarts': 'max_restarts' - } - convert(globalConfig) - fs.writeFile(globalConfigPath, JSON.stringify(globalConfig, null, 4)) - - function convert(conf) { - for (var key in conf) { - var converted = fieldsToConvert[key] - if (converted) { - conf[converted] = conf[key] - delete conf[key] - } else if (Object.prototype.toString.call(conf[key]) === '[object Object]') { - convert(conf[key]) + }; + + convert(globalConfig); + + fs.writeFile(globalConfigPath, JSON.stringify(globalConfig, null, 4)); + + function convert(conf) + { + for(var key in conf) + { + if(conf.hasOwnProperty(key)) + { + let converted = fieldsToConvert[key]; + + if(converted) + { + conf[converted] = conf[key]; + delete conf[key]; + } + else if(Object.prototype.toString.call(conf[key]) === '[object Object]') + { + convert(conf[key]); + } } } } } -module.exports = api +module.exports = api; diff --git a/lib/cli.js b/lib/cli.js index ac0fe4c..71ccc12 100644 --- a/lib/cli.js +++ b/lib/cli.js @@ -1,302 +1,482 @@ -var fs = require('fs'), - path = require('path'), - spawn = require('child_process').spawn, - colors = require('colors'), - mkdirp = require('mkdirp'), - Table = require('cli-table'), - format = require('./formatter').format, - api - -var rl = require('readline').createInterface({ +const fs = require('fs'); +const path = require('path'); +const spawn = require('child_process').spawn; +const colors = require('colors'); +const mkdirp = require('mkdirp'); +const Table = require('cli-table'); +const format = require('./formatter').format; + +let api; + +const rl = require('readline').createInterface({ input: process.stdin, output: process.stdout -}) - -var conf = require('./conf'), - globalConfigPath = conf.path, - webInterfaceId = conf.webId - -var tableOptions = { - style: { compact: true, 'padding-left': 4 }, - chars: { 'top': '' , 'top-mid': '' , 'top-left': '' , 'top-right': '' - , 'bottom': '' , 'bottom-mid': '' , 'bottom-left': '' , 'bottom-right': '' - , 'left': '' , 'left-mid': '' , 'mid': '' , 'mid-mid': '' - , 'right': '' , 'right-mid': '' , 'middle': ' ' }, - head: ['name', 'status', 'port', 'restarts', 'uptime', 'memory', 'CPU'].map(function (field) { - return field.grey +}); + +const conf = require('./conf'); +const globalConfigPath = conf.path; +const webInterfaceId = conf.webId; + +const tableOptions = { + style: {compact: true, 'padding-left': 4}, + chars: { + 'top': '', 'top-mid': '', 'top-left': '', 'top-right': '', + 'bottom': '', 'bottom-mid': '', 'bottom-left': '', 'bottom-right': '', + 'left': '', 'left-mid': '', 'mid': '', 'mid-mid': '', + 'right': '', 'right-mid': '', 'middle': ' ' + }, + head: ['name', 'status', 'port', 'restarts', 'uptime', 'memory', 'CPU'].map(function(field) + { + return field.grey; }) -} +}; -var cli = { +const cli = { + help: function() + { + console.log('\n POD '.green + 'v' + api.version); + console.log(fs.readFileSync(__dirname + '/../help/usage', 'utf-8')); - help: function () { - console.log('\n POD '.green + 'v' + api.version) - console.log(fs.readFileSync(__dirname + '/../help/usage', 'utf-8')) - process.exit(0) + process.exit(0); }, - create: function (appname) { - if (!appname) exit() + create: function(appname) + { + if(!appname) + { + exit(); + } - rl.close() - api.createApp(appname, output) + rl.close(); + api.createApp(appname, output); }, - remote: function (appname, repo, branch) { - if (!appname || !repo) exit() + remote: function(appname, repo, branch) + { + if(!appname || !repo) + { + exit(); + } + + rl.close(); - rl.close() api.createApp(appname, { remote: repo, branch: branch - }, output) + }, output); }, - rm: function (arg1, arg2) { - var force = false, - appname = arg1 - if (arg1 === '-f') { - force = true - appname = arg2 - } else if (arg2 === '-f') { - force = true + rm: function(arg1, arg2) + { + let force = false; + let appname = arg1; + + if(arg1 === '-f') + { + force = true; + appname = arg2; + } + else if(arg2 === '-f') + { + force = true; + } + + if(!appname) + { + exit(); } - if (!appname) exit() - if (force) { - rl.close() - return api.removeApp(appname, output) + + if(force) + { + rl.close(); + return api.removeApp(appname, output); } - rl.question('really delete ' + appname.yellow + '? (y/N)', function (reply) { - if (reply.toLowerCase() === 'y') { - rl.close() - api.removeApp(appname, output) - } else { - log('aborted.') - process.exit(0) + + rl.question('really delete ' + appname.yellow + '? (y/N)', function(reply) + { + if(reply.toLowerCase() === 'y') + { + rl.close(); + + api.removeApp(appname, output); + } + else + { + log('aborted.'); + process.exit(0); } - }) + }); }, - start: function (appname) { - if (!appname) exit() - api.startApp(appname, output) + start: function(appname) + { + if(!appname) + { + exit(); + } + + api.startApp(appname, output); }, - stop: function (appname) { - if (!appname) exit() - api.stopApp(appname, output) + stop: function(appname) + { + if(!appname) + { + exit(); + } + + api.stopApp(appname, output); }, - restart: function (appname) { - if (!appname) exit() - api.restartApp(appname, output) + restart: function(appname) + { + if(!appname) + { + exit(); + } + + api.restartApp(appname, output); }, - startall: function () { - api.startAllApps(output) + startall: function() + { + api.startAllApps(output); }, - stopall: function () { - api.stopAllApps(output) + stopall: function() + { + api.stopAllApps(output); }, - restartall: function () { - api.restartAllApps(output) + restartall: function() + { + api.restartAllApps(output); }, - list: function () { - api.listApps(function (err, apps) { - if (err) { - warn(err) - process.exit(1) + list: function() + { + api.listApps(function(err, apps) + { + if(err) + { + warn(err); + + process.exit(1); } - if (!apps || !apps.length) { - log('no apps found.') - } else { - var table = new Table(tableOptions) - table.push(new Array(7)) - apps.forEach(function (app) { - table.push(toArray(app)) - }) - console.log() - console.log(table.toString()) - console.log() + + if(!apps || !apps.length) + { + log('no apps found.'); } - process.exit(0) - }) + else + { + let table = new Table(tableOptions); + table.push(new Array(7)); + + apps.forEach(function(app) + { + table.push(toArray(app)); + }); + + console.log(); + console.log(table.toString()); + console.log(); + } + + process.exit(0); + }); }, - prune: function () { - api.prune(output) + prune: function() + { + api.prune(output); }, - hooks: function () { - api.updateHooks(output) + hooks: function() + { + api.updateHooks(output); }, - web: function (action) { - if (action === 'stop') { - api.stopApp(webInterfaceId, output) - } else if (action === 'restart') { - api.restartApp(webInterfaceId, output) - } else if (action === 'status') { - logStatus() - } else { - api.startApp(webInterfaceId, function (err, msg) { - if (msg && msg.indexOf('already') > 0) { // web interface already on - logStatus() - } else { - output(err, msg) + web: function(action) + { + if(action === 'stop') + { + api.stopApp(webInterfaceId, output); + } + else if(action === 'restart') + { + api.restartApp(webInterfaceId, output); + } + else if(action === 'status') + { + logStatus(); + } + else + { + api.startApp(webInterfaceId, function(err, msg) + { + if(msg && msg.indexOf('already') > 0) + { + // web interface already on + logStatus(); + } else + { + output(err, msg); } - }) + }); } - function logStatus () { - api.proxy('getMonitorData', {}, function (err, list) { - if (err) return output(err) - list.forEach(function (proc) { - if (proc.pm2_env.name === webInterfaceId) { - var app = api.getAppInfo(webInterfaceId) - app.instances = [proc] - var table = new Table(tableOptions) - table.push(toArray(format(app))) - console.log(table.toString()) - process.exit(0) + function logStatus() + { + api.proxy('getMonitorData', {}, function(err, list) + { + if(err) + { + return output(err); + } + + list.forEach(function(proc) + { + if(proc.pm2_env.name === webInterfaceId) + { + const app = api.getAppInfo(webInterfaceId); + app.instances = [proc]; + + let table = new Table(tableOptions); + table.push(toArray(format(app))); + + console.log(table.toString()); + + process.exit(0); } - }) - output(null, 'web interface is not running.') - }) + }); + + output(null, 'web interface is not running.'); + }); } } -} +}; // Init -if (!fs.existsSync(globalConfigPath)) { - if (process.env.POD_ROOT_DIR) return createRootDir(process.env.POD_ROOT_DIR) +if(!fs.existsSync(globalConfigPath)) +{ + if(process.env.POD_ROOT_DIR) + { + return createRootDir(process.env.POD_ROOT_DIR); + } + console.log( 'Hello! It seems it\'s your first time running pod on this machine.\n' + 'Please specify a directory for pod to put stuff in.\n' + '- Make sure your account has full access to that directory.\n' + '- You can use relative paths (resolved against your cwd).' - ) - rl.question('path: ', createRootDir) -} else { - loadAPI() + ); + + rl.question('path: ', createRootDir); +} +else +{ + loadAPI(); } -function createRootDir (dir) { - if (dir.charAt(0) === '~') { // home path - dir = process.env.HOME + dir.slice(1) - } else { - dir = path.resolve(process.cwd(), dir) +function createRootDir(dir) +{ + if(dir.charAt(0) === '~') + { + // home path + dir = process.env.HOME + dir.slice(1); } - if (fs.existsSync(dir)) { - if (!fs.statSync(dir).isDirectory()) { - warn('target path ' + dir.grey + ' is not a directory.') - process.exit(1) - } else { - initConfig(dir) - loadAPI() + else + { + dir = path.resolve(process.cwd(), dir); + } + + if(fs.existsSync(dir)) + { + if(!fs.statSync(dir).isDirectory()) + { + warn('target path ' + dir.grey + ' is not a directory.'); + + process.exit(1); + } + else + { + initConfig(dir); + + loadAPI(); } - } else { - if (process.env.TEST) return make() - rl.question('target path ' + dir.grey + ' doesn\'t exist. create it? (y/N)', function (reply) { - if (reply.toLowerCase() === 'y') { - make() - } else { - process.exit(0) + } + else + { + if(process.env.TEST) + { + return make(); + } + + rl.question('target path ' + dir.grey + ' doesn\'t exist. Create it? (y/N)', function(reply) + { + if(reply.toLowerCase() === 'y') + { + make(); } - }) + else + { + process.exit(0); + } + }); } - function make () { - console.log() - mkdirp.sync(dir) - log('created root directory: ' + dir.grey) - fs.mkdirSync(dir + '/repos') - log('created repos directory: ' + (dir + '/repos').grey) - fs.mkdirSync(dir + '/apps') - log('created apps directory: ' + (dir + '/apps').grey) - initConfig(dir) - log('created config file at: ' + globalConfigPath.grey) - loadAPI() + function make() + { + console.log(); + + mkdirp.sync(dir); + log('created root directory: ' + dir.grey); + + fs.mkdirSync(dir + '/repos'); + log('created repos directory: ' + (dir + '/repos').grey); + + fs.mkdirSync(dir + '/apps'); + log('created apps directory: ' + (dir + '/apps').grey); + + initConfig(dir); + log('created config file at: ' + globalConfigPath.grey); + + loadAPI(); } } -function initConfig (root) { +function initConfig(root) +{ var globalConfig = { root: root, node_env: 'development', default_script: 'app.js', apps: {}, web: {} - } - mkdirp.sync(globalConfigPath.slice(0, globalConfigPath.lastIndexOf('/'))) - fs.writeFileSync(globalConfigPath, JSON.stringify(globalConfig, null, 4)) + }; + + mkdirp.sync(globalConfigPath.slice(0, globalConfigPath.lastIndexOf('/'))); + fs.writeFileSync(globalConfigPath, JSON.stringify(globalConfig, null, 4)); } // env editor vars might contain args, which breaks edit() -function stripArgs (cmd) { - if (cmd) return cmd.split(' ')[0] +function stripArgs(cmd) +{ + if(cmd) + { + return cmd.split(' ')[0]; + } } -function loadAPI () { - api = require('./api') - api.once('ready', parseCommand) +function loadAPI() +{ + api = require('./api'); + api.once('ready', parseCommand); } -function parseCommand () { - var args = process.argv.slice(2), - command = args[0] || 'help' - if (cli[command]) { - cli[command].apply(null, args.slice(1)) - } else { - if (command) { - warn('unknown command ' + command.red) - process.exit(1) +function parseCommand() +{ + let args = process.argv.slice(2); + let command = args[0] || 'help'; + + if(cli[command]) + { + cli[command].apply(null, args.slice(1)); + } + else + { + if(command) + { + warn('unknown command ' + command.red); + + process.exit(1); } } } -function output (err, msg) { - if (err) { - warn(err) - process.exit(1) - } else { - log(msg) - process.exit(0) +function output(err, msg) +{ + if(err) + { + warn(err); + + process.exit(1); + } + else + { + log(msg); + + process.exit(0); } } -function log (msg) { - if (!Array.isArray(msg)) { - console.log('POD '.green + msg) - } else { - msg.forEach(function (m) { - console.log('POD '.green + m) - }) +function log(msg) +{ + if(!Array.isArray(msg)) + { + console.log('POD '.green + msg); + } + else + { + msg.forEach(function(m) + { + console.log('POD '.green + m); + }); } } -function warn (err) { - err = err.toString().replace('Error: ', '') - console.warn('POD '.green + 'ERR '.red + err) +function warn(err) +{ + err = err.toString().replace('Error: ', ''); + + console.warn('POD '.green + 'ERR '.red + err); } -function toArray (app) { +function toArray(app) +{ + // Restarts + let restarts = app.restarts; - var restarts = app.restarts - if (restarts === 0) restarts = restarts.toString().green - if (restarts > 0 && restarts < 10) restarts = restarts.toString().yellow - if (restarts > 10) restarts = restarts.toString().red + if(restarts === 0) + { + restarts = restarts.toString().green; + } - var status = app.status - if (status === 'ON') status = status.green - if (status === 'OFF') status = status.magenta - if (status === 'BROKEN' || status === 'ERROR') status = status.red + if(restarts > 0 && restarts < 10) + { + restarts = restarts.toString().yellow; + } - var uptime = app.uptime - if (uptime) uptime = uptime.cyan + if(restarts > 10) + { + restarts = restarts.toString().red; + } + + // Status + let status = app.status; + if(status === 'ON') + { + status = status.green; + } + + if(status === 'OFF') + { + status = status.magenta; + } + + if(status === 'BROKEN' || status === 'ERROR') + { + status = status.red; + } + + // Uptime + + let uptime = app.uptime; + if(uptime) + { + uptime = uptime.cyan; + } return [ app.name.yellow, @@ -306,10 +486,12 @@ function toArray (app) { uptime || '', app.memory || '', app.cpu || '' - ] + ]; } -function exit () { - warn('invalid command arguments') - process.exit(1) +function exit() +{ + warn('invalid command arguments'); + + process.exit(1); } diff --git a/lib/conf.js b/lib/conf.js index fa89539..bbbba71 100644 --- a/lib/conf.js +++ b/lib/conf.js @@ -1,5 +1,6 @@ const os = require('os'); + module.exports = { path: process.env.POD_CONF || ((process.env.HOME || os.homedir()) + '/.podrc'), webId: 'pod-web-service' -} \ No newline at end of file +}; diff --git a/lib/errors.js b/lib/errors.js index 303cb56..957afc8 100644 --- a/lib/errors.js +++ b/lib/errors.js @@ -5,11 +5,15 @@ var ERRORS = module.exports = { NOT_RUNNING: '{{appname}}'.yellow + ' is not running.', WEB: 'You cannot remove the web interface!', RUNNING: '{{appname}}'.yellow + 'is already running' -} +}; -for (var errKey in ERRORS) { - ERRORS[errKey] = { - msg: ERRORS[errKey], - code: errKey +for(var errKey in ERRORS) +{ + if(ERRORS.hasOwnProperty(errKey)) + { + ERRORS[errKey] = { + msg: ERRORS[errKey], + code: errKey + }; } -} \ No newline at end of file +} diff --git a/lib/formatter.js b/lib/formatter.js index f4c97ee..c558a84 100644 --- a/lib/formatter.js +++ b/lib/formatter.js @@ -1,25 +1,36 @@ -exports.format = formatAppInfo - -function formatAppInfo (app) { - app.uptime = null - var l = (app.instances && app.instances.length) || 0, - instances = l > 1 ? (' (' + l + ')') : '', - name = app.name + instances, - port = app.port || '????', - status = app.broken - ? 'BROKEN' - : app.instances - ? app.instances[0].pm2_env.status === 'errored' - ? 'ERROR' - : 'ON' - : 'OFF' - if (l) { - app.uptime = Date.now() - app.instances[0].pm2_env.pm_uptime - var restarts = countTotalRestarts(app.instances), - uptime = formatTime(app.uptime), - memory = formatMemory(app.instances), - cpu = formatCPU(app.instances) +exports.format = formatAppInfo; + +function formatAppInfo(app) +{ + app.uptime = null; + + const l = (app.instances && app.instances.length) || 0, + instances = l > 1 ? (' (' + l + ')') : '', + name = app.name + instances, + port = app.port || '????', + status = app.broken ? + 'BROKEN' : + app.instances ? + app.instances[0].pm2_env.status === 'errored' ? + 'ERROR' : + 'ON' : + 'OFF'; + + let restarts = countTotalRestarts(app.instances); + let uptime = formatTime(app.uptime); + let memory = formatMemory(app.instances); + let cpu = formatCPU(app.instances); + + if(l) + { + app.uptime = Date.now() - app.instances[0].pm2_env.pm_uptime; + + restarts = countTotalRestarts(app.instances); + uptime = formatTime(app.uptime); + memory = formatMemory(app.instances); + cpu = formatCPU(app.instances); } + return { name: name, port: port, @@ -31,48 +42,77 @@ function formatAppInfo (app) { cpu: cpu || null, instanceCount: l, raw: app - } + }; } -function countTotalRestarts (instances) { - var restarts = 0 - instances.forEach(function (ins) { - restarts += ins.pm2_env.restart_time - }) - return restarts +function countTotalRestarts(instances) +{ + let restarts = 0; + + instances.forEach(function(ins) + { + restarts += ins.pm2_env.restart_time; + }); + + return restarts; } -function formatTime (uptime) { - var sec_num = Math.floor(uptime / 1000), - days = Math.floor(sec_num / 86400), - hours = Math.floor(sec_num / 3600) % 24, - minutes = Math.floor(sec_num / 60) % 60, - seconds = sec_num % 60, - ret = [] - if (hours < 10) hours = "0" + hours - if (minutes < 10) minutes = "0" + minutes - if (seconds < 10) seconds = "0" + seconds - ret.push(hours, minutes, seconds) - return (days ? days + 'd ' : '') + ret.join(':') +function formatTime(uptime) +{ + let sec_num = Math.floor(uptime / 1000); + let days = Math.floor(sec_num / 86400); + let hours = Math.floor(sec_num / 3600) % 24; + let minutes = Math.floor(sec_num / 60) % 60; + let seconds = sec_num % 60; + let ret = []; + + if(hours < 10) + { + hours = '0' + hours; + } + + if(minutes < 10) + { + minutes = '0' + minutes; + } + + if(seconds < 10) + { + seconds = '0' + seconds; + } + + ret.push(hours, minutes, seconds); + + return (days ? days + 'd ' : '') + ret.join(':'); } -function formatMemory (instances) { - var mem = 0, - mb = 1048576 - instances.forEach(function (ins) { - mem += ins.monit.memory - }) - if (mem > mb) { - return (mem / mb).toFixed(2) + ' mb' - } else { - return (mem / 1024).toFixed(2) + ' kb' +function formatMemory(instances) +{ + let mem = 0; + let mb = 1048576; + + instances.forEach(function(ins) + { + mem += ins.monit.memory; + }); + + if(mem > mb) + { + return (mem / mb).toFixed(2) + ' mb'; + } + else + { + return (mem / 1024).toFixed(2) + ' kb'; } } -function formatCPU (instances) { - var total = 0 - instances.forEach(function (ins) { - total += ins.monit.cpu - }) - return total.toFixed(2) + '%' -} \ No newline at end of file +function formatCPU(instances) +{ + let total = 0; + instances.forEach(function(ins) + { + total += ins.monit.cpu; + }); + + return total.toFixed(2) + '%'; +} diff --git a/web/static/style.css b/web/static/style.css index 8b192a6..0c3f9ff 100644 --- a/web/static/style.css +++ b/web/static/style.css @@ -1,63 +1,75 @@ -body { - padding: 30px 50px; - font: 14px "Monaco", Helvetica, Arial, sans-serif; - font-weight: 300; - letter-spacing: 1px; - line-height: 1em; - color: #555; +body +{ + padding: 30px 50px; + font: 14px "Monaco", Helvetica, Arial, sans-serif; + font-weight: 300; + letter-spacing: 1px; + line-height: 1em; + color: #555; } -h1 { +h1 +{ font-weight: 300; font-size: 24px; margin-bottom: 30px; text-transform: uppercase; } -a { - color: #00B7FF; +a +{ + color: #00B7FF; } -.yes { +.yes +{ color: #6c0; } -.no { +.no +{ color: #f57; } -h2 { +h2 +{ color: #FF3333; } -.service { +.service +{ display: inline-block; width: 255px; } -#apps { +#apps +{ list-style-type: none; padding: 0; line-height: 2em; } -#apps li { +#apps li +{ padding: 12px 20px; border: 1px solid #ddd; border-top: none; } -#apps li:first-child { +#apps li:first-child +{ border-top: 1px solid #ddd; } -#apps span { +#apps span +{ display: inline-block; vertical-align: middle; margin-right: 10px; } -#apps .indicator { +#apps .indicator +{ width: 12px; height: 12px; border-radius: 100%; @@ -66,31 +78,40 @@ h2 { top: 1px; } -#apps .status { +#apps .status +{ width: 25px; } -#apps .indicator.ON { +#apps .indicator.ON +{ background-color: #6c6; } -#apps .indicator.BROKEN, #apps .indicator.ERROR { +#apps .indicator.BROKEN, #apps .indicator.ERROR +{ background-color: #f00; } -#apps .status.ON { +#apps .status.ON +{ color: #6c6; } -#apps .status.BROKEN, #apps .status.ERROR { + +#apps .status.BROKEN, +#apps .status.ERROR +{ color: #f00; } -#apps .port { +#apps .port +{ width: 100px; } -#apps .name { +#apps .name +{ color: #00B7FF; font-weight: bold; text-transform: uppercase; width: 120px; -} \ No newline at end of file +} diff --git a/web/test.js b/web/test.js index b773cd0..7638486 100644 --- a/web/test.js +++ b/web/test.js @@ -1,4 +1,4 @@ -var r = require('request') +var r = require('request'); r({ url: 'http://localhost:19999/hooks/test3', method: 'POST', @@ -16,4 +16,4 @@ r({ } }) } -}) \ No newline at end of file +}); diff --git a/web/views/index.ejs b/web/views/index.ejs index 85aebdd..7db21ee 100644 --- a/web/views/index.ejs +++ b/web/views/index.ejs @@ -26,4 +26,4 @@ <% }) %> - \ No newline at end of file + From 4cda4a383cfe7b6037493ffd1faece1f5ab13273 Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 23 Aug 2018 16:07:23 +0100 Subject: [PATCH 15/18] Updated package.json --- package.json | 106 +++++++++++++++++++++++++-------------------------- 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/package.json b/package.json index b65fba2..89f7887 100644 --- a/package.json +++ b/package.json @@ -1,55 +1,55 @@ { - "name": "pod", - "version": "0.9.1", - "preferGlobal": true, - "author": { - "name": "Evan You", - "email": "yyx990803@gmail.com" - }, - "dependencies": { - "pm2": "^2.4.5", - "parse-github-url": "^1.0.0", - "colors": "^1.1.2", - "async": "^2.3.0", - "serve-favicon":"^2.4.2", - "serve-static":"^1.12.1", - "mkdirp": "^0.5.1", - "body-parser": "^1.17.1", - "cli-table": "^0.3.1", - "basic-auth":"^1.1.0", - "express": "^4.15.2", - "ejs": "^2.5.6", - "debug": "^2.6.3" - }, - "devDependencies": { - "jscoverage": "^0.6.0", - "mocha": "^3.2.0", - "request": "^2.81.0" - }, - "keywords": [ - "cli", - "deployment", - "sysadmin", - "tools" - ], - "repository": { - "type": "git", - "url": "http://github.com/yyx990803/pod.git" - }, - "bin": { - "pod": "./bin/pod", - "pm2": "./node_modules/pm2/bin/pm2" - }, - "engines": { - "node": ">= 0.8.x" - }, - "main": "lib/api.js", - "description": "Super simple Node.js deployment tool", - "readme": "Pod simplifies the workflow of setting up, updating and managing multiple Node.js apps on a single Linux server.", - "readmeFilename": "README.md", - "scripts": { - "api": "mocha test/api.js --reporter spec --slow 1250", - "cli": "bash test/cli.sh", - "test": "mocha test/api.js -r jscoverage -R spec --slow 1250 --timeout 5000 && bash test/cli.sh" - } + "name": "puma-pod", + "version": "0.9.2", + "preferGlobal": true, + "author": { + "name": "Evan You", + "email": "yyx990803@gmail.com" + }, + "dependencies": { + "pm2": "^2.4.5", + "parse-github-url": "^1.0.0", + "colors": "^1.1.2", + "async": "^2.3.0", + "serve-favicon": "^2.4.2", + "serve-static": "^1.12.1", + "mkdirp": "^0.5.1", + "body-parser": "^1.17.1", + "cli-table": "^0.3.1", + "basic-auth": "^1.1.0", + "express": "^4.15.2", + "ejs": "^2.5.6", + "debug": "^2.6.3" + }, + "devDependencies": { + "jscoverage": "^0.6.0", + "mocha": "^3.2.0", + "request": "^2.81.0" + }, + "keywords": [ + "cli", + "deployment", + "sysadmin", + "tools" + ], + "repository": { + "type": "git", + "url": "http://github.com/Chifilly/pod.git" + }, + "bin": { + "pod": "./bin/pod", + "pm2": "./node_modules/pm2/bin/pm2" + }, + "engines": { + "node": ">= 0.8.x" + }, + "main": "lib/api.js", + "description": "Super simple Node.js deployment tool", + "readme": "Pod simplifies the workflow of setting up, updating and managing multiple Node.js apps on a single Linux server.", + "readmeFilename": "README.md", + "scripts": { + "api": "mocha test/api.js --reporter spec --slow 1250", + "cli": "bash test/cli.sh", + "test": "mocha test/api.js -r jscoverage -R spec --slow 1250 --timeout 5000 && bash test/cli.sh" + } } From 272ca62aa1bccdc6a813d87925e8054800af2937 Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 23 Aug 2018 16:28:53 +0100 Subject: [PATCH 16/18] Updated dependencies and removed unused dependencies --- lib/cli.js | 2 - package-lock.json | 3474 +++++++++++++++++++++++++++++++++++++++++++++ package.json | 19 +- web/app.js | 1 - 4 files changed, 3482 insertions(+), 14 deletions(-) create mode 100644 package-lock.json diff --git a/lib/cli.js b/lib/cli.js index 71ccc12..bc5d843 100644 --- a/lib/cli.js +++ b/lib/cli.js @@ -1,7 +1,5 @@ const fs = require('fs'); const path = require('path'); -const spawn = require('child_process').spawn; -const colors = require('colors'); const mkdirp = require('mkdirp'); const Table = require('cli-table'); const format = require('./formatter').format; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..f6f3fbc --- /dev/null +++ b/package-lock.json @@ -0,0 +1,3474 @@ +{ + "name": "puma-pod", + "version": "0.9.2", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@pm2/agent": { + "version": "0.5.14", + "resolved": "https://registry.npmjs.org/@pm2/agent/-/agent-0.5.14.tgz", + "integrity": "sha512-MSiK9+9wM5G8Bqd6g2WZQDfktj74opZebJUwc8Tjfb9wGsN66qcI1zi+Gt0PMTy1knBQ58ULGJz4qbFlXLttaA==", + "requires": { + "async": "^2.6.0", + "eventemitter2": "^5.0.1", + "fclone": "^1.0.11", + "moment": "^2.21.0", + "nssocket": "^0.6.0", + "pm2-axon": "^3.2.0", + "pm2-axon-rpc": "^0.5.0", + "semver": "^5.5.0", + "ws": "^5.1.0" + } + }, + "@pm2/io": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@pm2/io/-/io-2.1.3.tgz", + "integrity": "sha512-+uNBNvPyGg54qgg9ohcR3qeDc0JnnsfSNdeJoDBk7+/GZzgnMxoUyoi8TV88a+sgJAs3b6cj4GIdv8ClT+V3oA==", + "requires": { + "async": "2.6.1", + "debug": "3.1.0", + "deep-metrics": "0.0.2", + "deepmerge": "2.1.1", + "event-loop-inspector": "1.0.1", + "json-stringify-safe": "5.0.1", + "semver": "5.5.0", + "signal-exit": "3.0.2", + "tslib": "1.9.3", + "vxx": "1.2.2" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" + } + } + }, + "@pm2/js-api": { + "version": "0.5.24", + "resolved": "https://registry.npmjs.org/@pm2/js-api/-/js-api-0.5.24.tgz", + "integrity": "sha512-Cx/04MycR5CEDjf/PvItsKo0AGBHpHrKn0DqHBCAkOdjMcfvNThD6jUqA1NXDH7/JJE6OtJSpx3TFiV1rk+Jlg==", + "requires": { + "async": "^2.4.1", + "axios": "^0.16.2", + "debug": "^2.6.8", + "eventemitter2": "^4.1.0", + "ws": "^3.0.0" + }, + "dependencies": { + "eventemitter2": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-4.1.2.tgz", + "integrity": "sha1-DhqEd6+CGm7zmVsxG/dMI6UkfxU=" + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "accepts": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", + "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "requires": { + "mime-types": "~2.1.18", + "negotiator": "0.6.1" + } + }, + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true + }, + "amp": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/amp/-/amp-0.3.1.tgz", + "integrity": "sha1-at+NWKdPNh6CwfqNOJwHnhOfxH0=" + }, + "amp-message": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/amp-message/-/amp-message-0.1.2.tgz", + "integrity": "sha1-p48cmJlQh602GSpBKY5NtJ49/EU=", + "requires": { + "amp": "0.3.1" + } + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + }, + "dependencies": { + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + } + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" + }, + "async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", + "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", + "requires": { + "lodash": "^4.17.10" + } + }, + "async-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", + "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=" + }, + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + }, + "async-listener": { + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/async-listener/-/async-listener-0.6.9.tgz", + "integrity": "sha512-E7Z2/QMs0EPt/o9wpYO/J3hmMCDdr1aVDS3ttlur5D5JlZtxhfuOwi4e7S8zbYIxA5qOOYdxfqGj97XAfdNvkQ==", + "requires": { + "semver": "^5.3.0", + "shimmer": "^1.1.0" + } + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", + "dev": true + }, + "axios": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.16.2.tgz", + "integrity": "sha1-uk+S8XFn37q0CYN4VFS5rBScPG0=", + "requires": { + "follow-redirects": "^1.2.3", + "is-buffer": "^1.1.5" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "basic-auth": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", + "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=" + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "optional": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "binary-extensions": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz", + "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=" + }, + "blessed": { + "version": "0.1.81", + "resolved": "https://registry.npmjs.org/blessed/-/blessed-0.1.81.tgz", + "integrity": "sha1-+WLWh+wsNpVwrnGvhDJW5tDKESk=" + }, + "body-parser": { + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", + "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", + "requires": { + "bytes": "3.0.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "~1.6.3", + "iconv-lite": "0.4.23", + "on-finished": "~2.3.0", + "qs": "6.5.2", + "raw-body": "2.3.3", + "type-is": "~1.6.16" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "browser-stdout": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", + "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", + "dev": true + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "charm": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/charm/-/charm-0.1.2.tgz", + "integrity": "sha1-BsIe7RobBq62dVPNxT4jJ0usIpY=" + }, + "chokidar": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz", + "integrity": "sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==", + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.0", + "braces": "^2.3.0", + "fsevents": "^1.2.2", + "glob-parent": "^3.1.0", + "inherits": "^2.0.1", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "lodash.debounce": "^4.0.8", + "normalize-path": "^2.1.1", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.0.0", + "upath": "^1.0.5" + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "cli-table": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz", + "integrity": "sha1-9TsFJmqLGguTSz0IIebi3FkUriM=", + "requires": { + "colors": "1.0.3" + }, + "dependencies": { + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=" + } + } + }, + "cli-table-redemption": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cli-table-redemption/-/cli-table-redemption-1.0.1.tgz", + "integrity": "sha512-SjVCciRyx01I4azo2K2rcc0NP/wOceXGzG1ZpYkEulbbIxDA/5YWv0oxG2HtQ4v8zPC6bgbRI7SbNaTZCxMNkg==", + "requires": { + "chalk": "^1.1.3" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + } + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "coffee-script": { + "version": "1.12.7", + "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.12.7.tgz", + "integrity": "sha512-fLeEhqwymYat/MpTPUjSKHVYYl0ec2mOyALEMLmzr5i1isuG+6jfI2j2d5oBO3VIzgUXgBVIcOT9uH1TFxBckw==", + "dev": true + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color-convert": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz", + "integrity": "sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg==", + "requires": { + "color-name": "1.1.1" + } + }, + "color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=" + }, + "combined-stream": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", + "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz", + "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==", + "dev": true + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "continuation-local-storage": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/continuation-local-storage/-/continuation-local-storage-3.2.1.tgz", + "integrity": "sha512-jx44cconVqkCEEyLSKWwkvUXwO561jXMa3LPjTPsm5QR22PA0/mhe33FT4Xb5y74JDvt/Cq+5lm8S8rskLv9ZA==", + "requires": { + "async-listener": "^0.6.0", + "emitter-listener": "^1.1.1" + } + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cron": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cron/-/cron-1.4.0.tgz", + "integrity": "sha512-3xtjNiLRk/RLS11HivB8ZbMxdk8JzTmCuPzBYaXDEaNvkGrF67nFP4XWmhpo9e+NSpDx/vV7r+3g0UHLtXQaKQ==", + "requires": { + "moment-timezone": "^0.5.x" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" + }, + "deep-metrics": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/deep-metrics/-/deep-metrics-0.0.2.tgz", + "integrity": "sha512-2b4DO8YcPWSHrZ7XW9YjjJajmflw2EhKUMmeriZmGYsC8XvCWIyztsEjCQ3f5kIQO+ItzBK7BqVjSWlFZQtONQ==", + "requires": { + "semver": "^5.3.0" + } + }, + "deepmerge": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.1.1.tgz", + "integrity": "sha512-urQxA1smbLZ2cBbXbaYObM1dJ82aJ2H57A1C/Kklfh/ZN1bgH4G/n5KWhdNfOK11W98gqZfyYj7W4frJJRwA2w==" + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "diff": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", + "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "optional": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "ejs": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.6.1.tgz", + "integrity": "sha512-0xy4A/twfrRCnkhfk8ErDi5DqdAsAqeGxht4xkCUrsvhhbQNs7E+4jV0CN7+NKIY0aHE72+XvqtBIXzD31ZbXQ==" + }, + "emitter-listener": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/emitter-listener/-/emitter-listener-1.1.1.tgz", + "integrity": "sha1-6Lu+gkS8jg0LTvcc0UKUx/JBx+w=", + "requires": { + "shimmer": "^1.2.0" + } + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "escape-regexp": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/escape-regexp/-/escape-regexp-0.0.1.tgz", + "integrity": "sha1-9EvaEtRbvfnLf4Yu5+SCez3TIlQ=" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "event-loop-inspector": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/event-loop-inspector/-/event-loop-inspector-1.0.1.tgz", + "integrity": "sha512-kLntbbLeDp4qNGs4UflZiX9zk+1D4SmsLq3uHIXAZ/CePY46O0hTRl058mJW9orkn4XCSBMOX7zp9e1H79pVDA==" + }, + "eventemitter2": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-5.0.1.tgz", + "integrity": "sha1-YZegldX7a1folC9v1+qtY6CclFI=" + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "express": { + "version": "4.16.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.3.tgz", + "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", + "requires": { + "accepts": "~1.3.5", + "array-flatten": "1.1.1", + "body-parser": "1.18.2", + "content-disposition": "0.5.2", + "content-type": "~1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.1.1", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.3", + "qs": "6.5.1", + "range-parser": "~1.2.0", + "safe-buffer": "5.1.1", + "send": "0.16.2", + "serve-static": "1.13.2", + "setprototypeof": "1.1.0", + "statuses": "~1.4.0", + "type-is": "~1.6.16", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "body-parser": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", + "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", + "requires": { + "bytes": "3.0.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.1", + "http-errors": "~1.6.2", + "iconv-lite": "0.4.19", + "on-finished": "~2.3.0", + "qs": "6.5.1", + "raw-body": "2.3.2", + "type-is": "~1.6.15" + } + }, + "iconv-lite": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" + }, + "raw-body": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", + "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.2", + "iconv-lite": "0.4.19", + "unpipe": "1.0.0" + }, + "dependencies": { + "depd": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", + "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" + }, + "http-errors": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", + "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", + "requires": { + "depd": "1.1.1", + "inherits": "2.0.3", + "setprototypeof": "1.0.3", + "statuses": ">= 1.3.1 < 2" + } + }, + "setprototypeof": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", + "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" + } + } + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, + "fclone": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/fclone/-/fclone-1.0.11.tgz", + "integrity": "sha1-EOhdo4v+p/xZk0HClu4ddyZu5kA=" + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "finalhandler": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "unpipe": "~1.0.0" + }, + "dependencies": { + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" + } + } + }, + "follow-redirects": { + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.7.tgz", + "integrity": "sha512-NONJVIFiX7Z8k2WxfqBjtwqMifx7X42ORLFrOZ2LTKGj71G3C0kfdyTqGqr8fx5zSX6Foo/D95dgGWbPUiwnew==", + "requires": { + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", + "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "1.0.6", + "mime-types": "^2.1.12" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "requires": { + "map-cache": "^0.2.2" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz", + "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==", + "optional": true, + "requires": { + "nan": "^2.9.2", + "node-pre-gyp": "^0.10.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.4", + "bundled": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.0.1", + "bundled": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "debug": { + "version": "2.6.9", + "bundled": true, + "optional": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-extend": { + "version": "0.5.1", + "bundled": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "optional": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.21", + "bundled": true, + "optional": true, + "requires": { + "safer-buffer": "^2.1.0" + } + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true + }, + "minipass": { + "version": "2.2.4", + "bundled": true, + "requires": { + "safe-buffer": "^5.1.1", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.1.0", + "bundled": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "bundled": true, + "optional": true + }, + "needle": { + "version": "2.2.0", + "bundled": true, + "optional": true, + "requires": { + "debug": "^2.1.2", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.10.0", + "bundled": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.0", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.1.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.3", + "bundled": true, + "optional": true + }, + "npm-packlist": { + "version": "1.1.10", + "bundled": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true, + "optional": true + }, + "rc": { + "version": "1.2.7", + "bundled": true, + "optional": true, + "requires": { + "deep-extend": "^0.5.1", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "rimraf": { + "version": "2.6.2", + "bundled": true, + "optional": true, + "requires": { + "glob": "^7.0.5" + } + }, + "safe-buffer": { + "version": "5.1.1", + "bundled": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "optional": true + }, + "semver": { + "version": "5.5.0", + "bundled": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "optional": true + }, + "tar": { + "version": "4.4.1", + "bundled": true, + "optional": true, + "requires": { + "chownr": "^1.0.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.2.4", + "minizlib": "^1.1.0", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.1", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "optional": true + }, + "wide-align": { + "version": "1.1.2", + "bundled": true, + "optional": true, + "requires": { + "string-width": "^1.0.2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true + }, + "yallist": { + "version": "3.0.2", + "bundled": true + } + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "gkt": { + "version": "https://tgz.pm2.io/gkt-1.0.0.tgz", + "integrity": "sha512-zr6QQnzLt3Ja0t0XI8gws2kn7zV2p0l/D3kreNvS6hFZhVU5g+uY/30l42jbgt0XGcNBEmBDGJR71J692V92tA==", + "optional": true + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + }, + "graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", + "dev": true + }, + "growl": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", + "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", + "dev": true + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz", + "integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==", + "dev": true, + "requires": { + "ajv": "^5.3.0", + "har-schema": "^2.0.0" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "interpret": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", + "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=" + }, + "ipaddr.js": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", + "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=" + }, + "is": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is/-/is-3.2.1.tgz", + "integrity": "sha1-0Kwq1V63sL7JJqUmb2xmKqqD3KU=" + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-glob": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", + "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "requires": { + "isobject": "^3.0.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true, + "optional": true + }, + "jscoverage": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/jscoverage/-/jscoverage-0.6.0.tgz", + "integrity": "sha1-9eE6nhN3Yzh2jB7gLhrnHVFc2sk=", + "dev": true, + "requires": { + "coffee-script": "*", + "commander": "^2.6.0", + "debug": "~1.0.3", + "ejs": "1.0.0", + "optimist": "^0.6.1", + "uglify-js": "~2.4.15", + "xfs": "~0.1.8" + }, + "dependencies": { + "debug": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-1.0.5.tgz", + "integrity": "sha1-9yQSF0MPmd7EwrRz6rkiKOh0wqw=", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ejs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-1.0.0.tgz", + "integrity": "sha1-ycYKSKRu5FL7MqccMXuV5aofyz0=", + "dev": true + } + } + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "json3": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", + "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + }, + "lazy": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/lazy/-/lazy-1.0.11.tgz", + "integrity": "sha1-2qBoIGKCVCwIgojpdcKXwa53tpA=" + }, + "lodash": { + "version": "4.17.10", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", + "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" + }, + "lodash._baseassign": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", + "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", + "dev": true, + "requires": { + "lodash._basecopy": "^3.0.0", + "lodash.keys": "^3.0.0" + } + }, + "lodash._basecopy": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", + "dev": true + }, + "lodash._basecreate": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz", + "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=", + "dev": true + }, + "lodash._getnative": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", + "dev": true + }, + "lodash._isiterateecall": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", + "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", + "dev": true + }, + "lodash.create": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", + "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", + "dev": true, + "requires": { + "lodash._baseassign": "^3.0.0", + "lodash._basecreate": "^3.0.0", + "lodash._isiterateecall": "^3.0.0" + } + }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" + }, + "lodash.findindex": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.findindex/-/lodash.findindex-4.6.0.tgz", + "integrity": "sha1-oyRd7mH7m24GJLU1ElYku2nBEQY=" + }, + "lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", + "dev": true + }, + "lodash.isarray": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", + "dev": true + }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" + }, + "lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "dev": true, + "requires": { + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + } + }, + "lodash.merge": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz", + "integrity": "sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==" + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "requires": { + "object-visit": "^1.0.0" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" + }, + "mime-db": { + "version": "1.35.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz", + "integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg==" + }, + "mime-types": { + "version": "2.1.19", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz", + "integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==", + "requires": { + "mime-db": "~1.35.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mixin-deep": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", + "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-3.5.3.tgz", + "integrity": "sha512-/6na001MJWEtYxHOV1WLfsmR4YIynkUEhBwzsb+fk2qmQ3iqsi258l/Q2MWHJMImAcNpZ8DEdYAK72NHoIQ9Eg==", + "dev": true, + "requires": { + "browser-stdout": "1.3.0", + "commander": "2.9.0", + "debug": "2.6.8", + "diff": "3.2.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.1", + "growl": "1.9.2", + "he": "1.1.1", + "json3": "3.3.2", + "lodash.create": "3.1.1", + "mkdirp": "0.5.1", + "supports-color": "3.1.2" + }, + "dependencies": { + "commander": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "dev": true, + "requires": { + "graceful-readlink": ">= 1.0.0" + } + }, + "debug": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", + "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.2", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "supports-color": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", + "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "moment": { + "version": "2.22.2", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz", + "integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y=" + }, + "moment-timezone": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.21.tgz", + "integrity": "sha512-j96bAh4otsgj3lKydm3K7kdtA3iKf2m6MY2iSYCzCm5a1zmHo1g+aK3068dDEeocLZQIS9kU8bsdQHLqEvgW0A==", + "requires": { + "moment": ">= 2.9.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" + }, + "nan": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", + "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==", + "optional": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "needle": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.2.2.tgz", + "integrity": "sha512-mW7W8dKuVYefCpNzE3Z7xUmPI9wSrSL/1qH31YGMxmSOAnjatS3S9Zv3cmiHrhx3Jkp1SrWWBdOFXjfF48Uq3A==", + "requires": { + "debug": "^2.1.2", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, + "nssocket": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/nssocket/-/nssocket-0.6.0.tgz", + "integrity": "sha1-Wflvb/MhVm8zxw99vu7N/cBxVPo=", + "requires": { + "eventemitter2": "~0.4.14", + "lazy": "~1.0.11" + }, + "dependencies": { + "eventemitter2": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", + "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=" + } + } + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "requires": { + "isobject": "^3.0.0" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "requires": { + "isobject": "^3.0.1" + } + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + } + }, + "parse-github-url": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-github-url/-/parse-github-url-1.0.2.tgz", + "integrity": "sha512-kgBf6avCbO3Cn6+RnzRGLkUsv4ZVqv/VfAYkRsyBcgkshNvVBkRn1FEZcW0Jb+npXQWm2vHPnnOqFteZxRRGNw==" + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "pidusage": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/pidusage/-/pidusage-2.0.13.tgz", + "integrity": "sha512-YCe7ns8Val5L+GE84aE8lcl5iozuDvWf/rP4S9CXnsliK++EyJleAc6BmK4Fo8aFUjDQSe+lrkcFtap1mJimsg==" + }, + "pm2": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pm2/-/pm2-3.0.4.tgz", + "integrity": "sha512-E77QaThbZblI0azPwyqIcYY2+/xy25ouBvU5VEDc8zzG2+GEhVgm9Gcv9ek8uQn+DJ3v7b7zwr7wa4cn3ktEwQ==", + "requires": { + "@pm2/agent": "^0.5.11", + "@pm2/io": "~2.1.0", + "@pm2/js-api": "^0.5.15", + "async": "^2.6.1", + "blessed": "^0.1.81", + "chalk": "^2.4.1", + "chokidar": "^2.0.4", + "cli-table-redemption": "^1.0.0", + "commander": "2.15.1", + "cron": "^1.3", + "debug": "^3.1", + "eventemitter2": "5.0.1", + "fclone": "1.0.11", + "gkt": "https://tgz.pm2.io/gkt-1.0.0.tgz", + "mkdirp": "0.5.1", + "moment": "^2.22.2", + "needle": "^2.2.1", + "nssocket": "0.6.0", + "pidusage": "2.0.13", + "pm2-axon": "3.3.0", + "pm2-axon-rpc": "^0.5.1", + "pm2-deploy": "^0.3.9", + "pm2-multimeter": "^0.1.2", + "promptly": "^2", + "semver": "^5.5", + "shelljs": "~0.8.2", + "source-map-support": "^0.5.6", + "sprintf-js": "1.1.1", + "v8-compile-cache": "^2.0.0", + "vizion": "~0.2.0", + "yamljs": "^0.3.0" + }, + "dependencies": { + "commander": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==" + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "pm2-axon": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/pm2-axon/-/pm2-axon-3.3.0.tgz", + "integrity": "sha512-dAFlFYRuFbFjX7oAk41zT+dx86EuaFX/TgOp5QpUKRKwxb946IM6ydnoH5sSTkdI2pHSVZ+3Am8n/l0ocr7jdQ==", + "requires": { + "amp": "~0.3.1", + "amp-message": "~0.1.1", + "debug": "^3.0", + "escape-regexp": "0.0.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "pm2-axon-rpc": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/pm2-axon-rpc/-/pm2-axon-rpc-0.5.1.tgz", + "integrity": "sha512-hT8gN3/j05895QLXpwg+Ws8PjO4AVID6Uf9StWpud9HB2homjc1KKCcI0vg9BNOt56FmrqKDT1NQgheIz35+sA==", + "requires": { + "debug": "^3.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "pm2-deploy": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/pm2-deploy/-/pm2-deploy-0.3.10.tgz", + "integrity": "sha512-WagPKsX+LDCe8wLCL5nzu8RQvVUQ5GlFdJRVYCL0ogFnHfYRym91qNU4PkNSWSq11pdvG8la7DTjdW6FWXc8lw==", + "requires": { + "async": "^2.6", + "tv4": "^1.3" + } + }, + "pm2-multimeter": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/pm2-multimeter/-/pm2-multimeter-0.1.2.tgz", + "integrity": "sha1-Gh5VFT1BoFU0zqI8/oYKuqDrSs4=", + "requires": { + "charm": "~0.1.1" + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + }, + "promptly": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/promptly/-/promptly-2.2.0.tgz", + "integrity": "sha1-KhP6BjaIoqWYOxYf/wEIoH0m/HQ=", + "requires": { + "read": "^1.0.4" + } + }, + "proxy-addr": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", + "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.8.0" + } + }, + "psl": { + "version": "1.1.29", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", + "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==", + "dev": true + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" + }, + "raw-body": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", + "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", + "unpipe": "1.0.0" + } + }, + "read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", + "requires": { + "mute-stream": "~0.0.4" + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", + "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", + "requires": { + "graceful-fs": "^4.1.2", + "minimatch": "^3.0.2", + "readable-stream": "^2.0.2", + "set-immediate-shim": "^1.0.1" + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "requires": { + "resolve": "^1.1.6" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==" + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "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==", + "dev": true + } + } + }, + "resolve": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", + "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", + "requires": { + "path-parse": "^1.0.5" + } + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "semver": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", + "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==" + }, + "send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + }, + "dependencies": { + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" + } + } + }, + "serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + } + }, + "set-immediate-shim": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", + "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=" + }, + "set-value": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", + "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "shelljs": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.2.tgz", + "integrity": "sha512-pRXeNrCA2Wd9itwhvLp5LZQvPJ0wU6bcjaTMywHHGX5XWhVN2nzSu7WV0q+oUY7mGK3mgSkDDzP3MgjqdyIgbQ==", + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, + "shimmer": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.0.tgz", + "integrity": "sha512-xTCx2vohXC2EWWDqY/zb4+5Mu28D+HYNSOuFzsyRDRvI/e1ICb69afwaUwfjr+25ZXldbOLyp+iDUZHq8UnTag==" + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + }, + "source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "requires": { + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.9.tgz", + "integrity": "sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=" + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.1.tgz", + "integrity": "sha1-Nr54Mgr+WAH2zqPueLblqrlA6gw=" + }, + "sshpk": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", + "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + }, + "dependencies": { + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + } + } + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "dev": true, + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + } + }, + "tslib": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tv4": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/tv4/-/tv4-1.3.0.tgz", + "integrity": "sha1-0CDIRvrdUMhVq7JeuuzGj8EPeWM=" + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true, + "optional": true + }, + "type-is": { + "version": "1.6.16", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.18" + } + }, + "uglify-js": { + "version": "2.4.24", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.4.24.tgz", + "integrity": "sha1-+tV1XB4Vd2WLsG/5q25UjJW+vW4=", + "dev": true, + "requires": { + "async": "~0.2.6", + "source-map": "0.1.34", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.5.4" + }, + "dependencies": { + "async": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=", + "dev": true + }, + "source-map": { + "version": "0.1.34", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.34.tgz", + "integrity": "sha1-p8/omux7FoLDsZjQrPtH19CQVms=", + "dev": true, + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "dev": true + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" + }, + "union-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", + "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^0.4.3" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "set-value": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", + "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.1", + "to-object-path": "^0.3.0" + } + } + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" + } + } + }, + "upath": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz", + "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==" + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + }, + "v8-compile-cache": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.2.tgz", + "integrity": "sha512-1wFuMUIM16MDJRCrpbpuEPTUGmM5QMUg0cr3KFwra2XgOgFcPGDQHDh3CszSCD2Zewc/dh/pamNEW8CbfDebUw==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "vizion": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/vizion/-/vizion-0.2.13.tgz", + "integrity": "sha1-ExTN7is0EW+fWxJIU2+V2/zW718=", + "requires": { + "async": "1.5" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" + } + } + }, + "vxx": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/vxx/-/vxx-1.2.2.tgz", + "integrity": "sha1-dB+1HG8R0zg9pvm5IBil17qAdhE=", + "requires": { + "continuation-local-storage": "^3.1.4", + "debug": "^2.6.3", + "extend": "^3.0.0", + "is": "^3.2.0", + "lodash.findindex": "^4.4.0", + "lodash.isequal": "^4.0.0", + "lodash.merge": "^4.6.0", + "methods": "^1.1.1", + "semver": "^5.0.1", + "shimmer": "^1.0.0", + "uuid": "^3.0.1" + } + }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", + "dev": true + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "ws": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", + "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", + "requires": { + "async-limiter": "~1.0.0" + } + }, + "xfs": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/xfs/-/xfs-0.1.10.tgz", + "integrity": "sha1-TdL9uyraKifmxdRxy1fAleZStwM=", + "dev": true + }, + "yamljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/yamljs/-/yamljs-0.3.0.tgz", + "integrity": "sha512-C/FsVVhht4iPQYXOInoxUM/1ELSf9EsgKH34FofQOp6hwCPrW4vG4w5++TED3xRUo8gD7l0P1J1dLlDYzODsTQ==", + "requires": { + "argparse": "^1.0.7", + "glob": "^7.0.5" + } + }, + "yargs": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.5.4.tgz", + "integrity": "sha1-2K/49mXpTDS9JZvevRv68N3TU2E=", + "dev": true, + "requires": { + "camelcase": "^1.0.2", + "decamelize": "^1.0.0", + "window-size": "0.1.0", + "wordwrap": "0.0.2" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true + } + } + } + } +} diff --git a/package.json b/package.json index 89f7887..3546484 100644 --- a/package.json +++ b/package.json @@ -3,23 +3,20 @@ "version": "0.9.2", "preferGlobal": true, "author": { - "name": "Evan You", - "email": "yyx990803@gmail.com" + "name": "Adam Allsopp" }, "dependencies": { - "pm2": "^2.4.5", - "parse-github-url": "^1.0.0", - "colors": "^1.1.2", "async": "^2.3.0", - "serve-favicon": "^2.4.2", - "serve-static": "^1.12.1", - "mkdirp": "^0.5.1", + "basic-auth": "^1.1.0", "body-parser": "^1.17.1", "cli-table": "^0.3.1", - "basic-auth": "^1.1.0", - "express": "^4.15.2", + "debug": "^2.6.3", "ejs": "^2.5.6", - "debug": "^2.6.3" + "express": "^4.15.2", + "mkdirp": "^0.5.1", + "parse-github-url": "^1.0.0", + "pm2": "^3.0.4", + "serve-static": "^1.12.1" }, "devDependencies": { "jscoverage": "^0.6.0", diff --git a/web/app.js b/web/app.js index 8d6759e..b3b771a 100644 --- a/web/app.js +++ b/web/app.js @@ -6,7 +6,6 @@ const express = require('express'); const pod = require('../lib/api'); const ghURL = require('parse-github-url'); const app = express(); -// const favicon = require('serve-favicon'); const statics = require('serve-static'); const basicAuth = require('basic-auth'); From 849d8b4b29773aca212a5ae3c785e89c37f271d0 Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 23 Aug 2018 16:51:23 +0100 Subject: [PATCH 17/18] Fixed some goofs --- lib/cli.js | 2 ++ lib/formatter.js | 8 ++++---- package-lock.json | 5 +++++ package.json | 1 + 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/lib/cli.js b/lib/cli.js index bc5d843..b37fbea 100644 --- a/lib/cli.js +++ b/lib/cli.js @@ -4,6 +4,8 @@ const mkdirp = require('mkdirp'); const Table = require('cli-table'); const format = require('./formatter').format; +require('colors'); + let api; const rl = require('readline').createInterface({ diff --git a/lib/formatter.js b/lib/formatter.js index c558a84..beafda2 100644 --- a/lib/formatter.js +++ b/lib/formatter.js @@ -16,10 +16,10 @@ function formatAppInfo(app) 'ON' : 'OFF'; - let restarts = countTotalRestarts(app.instances); - let uptime = formatTime(app.uptime); - let memory = formatMemory(app.instances); - let cpu = formatCPU(app.instances); + let restarts; + let uptime; + let memory; + let cpu; if(l) { diff --git a/package-lock.json b/package-lock.json index f6f3fbc..e03e48c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -576,6 +576,11 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz", "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=" }, + "colors": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.2.tgz", + "integrity": "sha512-rhP0JSBGYvpcNQj4s5AdShMeE5ahMop96cTeDl/v9qQQm2fYClE2QXZRi8wLzc+GmXSxdIqqbOIAhyObEXDbfQ==" + }, "combined-stream": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", diff --git a/package.json b/package.json index 3546484..f036467 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "basic-auth": "^1.1.0", "body-parser": "^1.17.1", "cli-table": "^0.3.1", + "colors": "^1.3.2", "debug": "^2.6.3", "ejs": "^2.5.6", "express": "^4.15.2", From 023967247eb737e3e22c627899a465b2ac1642a0 Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 24 Aug 2018 10:56:50 +0100 Subject: [PATCH 18/18] Updated to cli-table2 and made the table prettier --- .gitignore | 1 + .vscode/tasks.json | 26 +++++++++++++ lib/api.js | 24 ++++++------ lib/cli.js | 95 ++++++++++++++++++++++------------------------ lib/errors.js | 12 +++--- lib/formatter.js | 26 ++++++------- package-lock.json | 60 +++++++++++++++++++++-------- package.json | 4 +- 8 files changed, 151 insertions(+), 97 deletions(-) create mode 100644 .vscode/tasks.json diff --git a/.gitignore b/.gitignore index 8cfd1b2..c2d6168 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ node_modules local temp .vscode/* +!.vscode/tasks.json diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..68a8e06 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,26 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "Install pod", + "type": "shell", + "command": "sudo npm i -g .", + "group": { + "kind": "build", + "isDefault": true + }, + "presentation": { + "echo": true, + "reveal": "always", + "focus": true, + "panel": "shared", + "showReuseMessage": true + }, + "options": { + "cwd": "${workspaceRoot}" + } + } + ] +} diff --git a/lib/api.js b/lib/api.js index 3912296..172e882 100644 --- a/lib/api.js +++ b/lib/api.js @@ -95,7 +95,7 @@ api.createApp = function(appname, options, callback) fs.writeFile(globalConfigPath, data, function(err) { - done(err, 'updated config.'); + done(err, 'updated config'); }); }, function(done) @@ -167,7 +167,7 @@ api.removeApp = function(appname, callback) return callback(err); } - return callback(null, 'deleted app: ' + appname.yellow); + return callback(null, 'deleted app: ' + appname.cyan); }); } else @@ -218,7 +218,7 @@ api.startApp = function(appname, callback) return callback(err); } - return callback(null, appname.yellow + ' running on ' + (app.port || 'unknown port')); + return callback(null, appname.cyan + ' running on ' + (app.port.yellow || 'unknown port')); }); } @@ -260,7 +260,7 @@ api.stopApp = function(appname, callback) if(!runningProcs) { - return callback(null, appname.yellow + ' is not running.'); + return callback(null, appname.cyan + ' is not running'); } else { @@ -286,7 +286,7 @@ api.stopApp = function(appname, callback) return callback( null, - appname.yellow + ' stopped.' + + appname.cyan + ' stopped' + (l > 1 ? (' (' + l + ' instances)').grey : '') ); } @@ -341,7 +341,7 @@ api.restartApp = function(appname, callback) return callback( null, - appname.yellow + ' restarted.' + + appname.cyan + ' restarted' + (l > 1 ? (' (' + l + ' instances)').grey : '') ); }); @@ -501,7 +501,7 @@ api.prune = function(callback) { let msg = pruned.length ? 'pruned:\n' + pruned.join('\n').grey : - 'root directory is clean.'; + 'root directory is clean'; return callback(err, msg); } @@ -528,7 +528,7 @@ api.updateHooks = function(callback) }); }, function(err) { - return callback(err, 'updated hooks for:\n' + updated.join('\n').yellow); + return callback(err, 'updated hooks for:\n' + updated.join('\n').cyan); } ); }; @@ -583,7 +583,7 @@ function restart(app, callback) return callback(err); } - return callback(null, app.pm2_env.name.yellow + ' restarted'); + return callback(null, app.pm2_env.name.cyan + ' restarted'); }); } @@ -609,7 +609,7 @@ function createAppRepo(info, done) // init bare repo exec('git --git-dir ' + info.repoPath + ' --bare init', function(err) { - next(err, 'created bare repo at ' + info.repoPath.yellow); + next(err, 'created bare repo at ' + info.repoPath.cyan); }); }, function(next) @@ -617,7 +617,7 @@ function createAppRepo(info, done) // create post-receive hook createHook(info, function(err) { - next(err, 'created post-receive hook.'); + next(err, 'created post-receive hook'); }); }, function(next) @@ -625,7 +625,7 @@ function createAppRepo(info, done) // clone an empty working copy exec('git clone ' + info.repoPath + ' \"' + info.workPath + '\"', function(err) { - next(err, 'created empty working copy at ' + info.workPath.yellow); + next(err, 'created empty working copy at ' + info.workPath.cyan); }); } ], function(err, msgs) diff --git a/lib/cli.js b/lib/cli.js index b37fbea..7abdc6f 100644 --- a/lib/cli.js +++ b/lib/cli.js @@ -1,8 +1,8 @@ const fs = require('fs'); const path = require('path'); const mkdirp = require('mkdirp'); -const Table = require('cli-table'); -const format = require('./formatter').format; +const Table = require('cli-table2'); +const format = require('./formatter'); require('colors'); @@ -18,23 +18,23 @@ const globalConfigPath = conf.path; const webInterfaceId = conf.webId; const tableOptions = { - style: {compact: true, 'padding-left': 4}, + style: {compact: true}, chars: { - 'top': '', 'top-mid': '', 'top-left': '', 'top-right': '', - 'bottom': '', 'bottom-mid': '', 'bottom-left': '', 'bottom-right': '', - 'left': '', 'left-mid': '', 'mid': '', 'mid-mid': '', - 'right': '', 'right-mid': '', 'middle': ' ' + 'top': '─', 'top-mid': '┬', 'top-left': '┌', 'top-right': '┐', + 'bottom': '─', 'bottom-mid': '┴', 'bottom-left': '└', 'bottom-right': '┘', + 'left': '│', 'left-mid': '├', 'mid': '─', 'mid-mid': '┼', + 'right': '│', 'right-mid': '┤', 'middle': '│' }, - head: ['name', 'status', 'port', 'restarts', 'uptime', 'memory', 'CPU'].map(function(field) + head: ['app name', 'status', 'port', 'restarts', 'uptime', 'memory', 'cpu%'].map(function(field) { - return field.grey; + return field.cyan; }) }; const cli = { help: function() { - console.log('\n POD '.green + 'v' + api.version); + console.log('\n POD'.green + ' | ' + 'v' + api.version); console.log(fs.readFileSync(__dirname + '/../help/usage', 'utf-8')); process.exit(0); @@ -92,7 +92,7 @@ const cli = { return api.removeApp(appname, output); } - rl.question('really delete ' + appname.yellow + '? (y/N)', function(reply) + rl.question('POD'.green + ' | really remove ' + appname.cyan + '? (y/N): ', function(reply) { if(reply.toLowerCase() === 'y') { @@ -102,7 +102,7 @@ const cli = { } else { - log('aborted.'); + log('cancelled deleting ' + appname.cyan); process.exit(0); } }); @@ -166,12 +166,11 @@ const cli = { if(!apps || !apps.length) { - log('no apps found.'); + log('no apps found'); } else { let table = new Table(tableOptions); - table.push(new Array(7)); apps.forEach(function(app) { @@ -251,7 +250,7 @@ const cli = { } }); - output(null, 'web interface is not running.'); + output(null, 'web interface is not running'); }); } } @@ -267,9 +266,9 @@ if(!fs.existsSync(globalConfigPath)) console.log( 'Hello! It seems it\'s your first time running pod on this machine.\n' + - 'Please specify a directory for pod to put stuff in.\n' + - '- Make sure your account has full access to that directory.\n' + - '- You can use relative paths (resolved against your cwd).' + 'Please specify a directory for pod to put files in.\n' + + ' - Make sure your account has full access to that directory.\n' + + ' - You can use relative paths (resolved against your cwd).' ); rl.question('path: ', createRootDir); @@ -295,7 +294,7 @@ function createRootDir(dir) { if(!fs.statSync(dir).isDirectory()) { - warn('target path ' + dir.grey + ' is not a directory.'); + warn('target path ' + dir.grey + ' is not a directory'); process.exit(1); } @@ -388,7 +387,7 @@ function parseCommand() { if(command) { - warn('unknown command ' + command.red); + warn('unknown command ' + command.cyan); process.exit(1); } @@ -415,13 +414,13 @@ function log(msg) { if(!Array.isArray(msg)) { - console.log('POD '.green + msg); + console.log('POD'.green + ' | ' + msg); } else { msg.forEach(function(m) { - console.log('POD '.green + m); + console.log('POD'.green + ' | ' + m); }); } } @@ -430,25 +429,22 @@ function warn(err) { err = err.toString().replace('Error: ', ''); - console.warn('POD '.green + 'ERR '.red + err); + console.warn('POD'.red + ' | ' + err); } function toArray(app) { // Restarts let restarts = app.restarts; - if(restarts === 0) { restarts = restarts.toString().green; } - - if(restarts > 0 && restarts < 10) + else if(restarts > 0 && restarts < 10) { restarts = restarts.toString().yellow; } - - if(restarts > 10) + else if(restarts > 10) { restarts = restarts.toString().red; } @@ -457,38 +453,39 @@ function toArray(app) let status = app.status; if(status === 'ON') { - status = status.green; + status = 'RUNNING'.green; } - - if(status === 'OFF') + else if(status === 'OFF') { - status = status.magenta; + status = 'STOPPED'.yellow; } - - if(status === 'BROKEN' || status === 'ERROR') + else if(status === 'BROKEN' || status === 'ERROR') { status = status.red; } - // Uptime - - let uptime = app.uptime; - if(uptime) - { - uptime = uptime.cyan; - } - return [ - app.name.yellow, - status, - app.port, - restarts || '', - uptime || '', - app.memory || '', - app.cpu || '' + toCLITableObject(app.name.cyan), + toCLITableObject(status), + toCLITableObject(app.port || '--'), + toCLITableObject(restarts || '--'), + toCLITableObject(app.uptime || '--'), + toCLITableObject(app.memory || '--'), + toCLITableObject(app.cpu || '--') ]; } +function toCLITableObject(text) +{ + const obj = { + hAlign: 'center', + }; + + obj.content = text; + + return obj; +} + function exit() { warn('invalid command arguments'); diff --git a/lib/errors.js b/lib/errors.js index 957afc8..6d14d67 100644 --- a/lib/errors.js +++ b/lib/errors.js @@ -1,10 +1,10 @@ var ERRORS = module.exports = { - EXISTS: 'an app with the name ' + '{{appname}}'.yellow + ' already exists.', - NOT_FOUND: 'app ' + '{{appname}}'.yellow + ' does not exist.', - NO_SCRIPT: 'cannot locate main script for ' + '{{appname}}'.yellow + ' ({{script}})'.grey, - NOT_RUNNING: '{{appname}}'.yellow + ' is not running.', - WEB: 'You cannot remove the web interface!', - RUNNING: '{{appname}}'.yellow + 'is already running' + EXISTS: 'an app with the name ' + '{{appname}}'.cyan + ' already exists', + NOT_FOUND: 'app ' + '{{appname}}'.cyan + ' does not exist', + NO_SCRIPT: 'cannot locate main script for ' + '{{appname}}'.cyan + ' ({{script}})'.grey, + NOT_RUNNING: '{{appname}}'.cyan + ' is not running', + WEB: 'You cannot remove the web interface', + RUNNING: '{{appname}}'.cyan + ' is already running' }; for(var errKey in ERRORS) diff --git a/lib/formatter.js b/lib/formatter.js index beafda2..4320ecc 100644 --- a/lib/formatter.js +++ b/lib/formatter.js @@ -4,24 +4,24 @@ function formatAppInfo(app) { app.uptime = null; - const l = (app.instances && app.instances.length) || 0, - instances = l > 1 ? (' (' + l + ')') : '', - name = app.name + instances, - port = app.port || '????', - status = app.broken ? - 'BROKEN' : - app.instances ? - app.instances[0].pm2_env.status === 'errored' ? - 'ERROR' : - 'ON' : - 'OFF'; + const processes = (app.instances && app.instances.length) || 0; + const instances = processes > 1 ? (' (' + processes + ')') : ''; + const name = app.name + instances; + const port = app.port; + const status = app.broken ? + 'BROKEN' : + app.instances ? + app.instances[0].pm2_env.status === 'errored' ? + 'ERROR' : + 'ON' : + 'OFF'; let restarts; let uptime; let memory; let cpu; - if(l) + if(processes) { app.uptime = Date.now() - app.instances[0].pm2_env.pm_uptime; @@ -40,7 +40,7 @@ function formatAppInfo(app) uptime: uptime || null, memory: memory || null, cpu: cpu || null, - instanceCount: l, + instanceCount: instances, raw: app }; } diff --git a/package-lock.json b/package-lock.json index e03e48c..5ac3dac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -495,21 +495,6 @@ } } }, - "cli-table": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz", - "integrity": "sha1-9TsFJmqLGguTSz0IIebi3FkUriM=", - "requires": { - "colors": "1.0.3" - }, - "dependencies": { - "colors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", - "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=" - } - } - }, "cli-table-redemption": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cli-table-redemption/-/cli-table-redemption-1.0.1.tgz", @@ -542,12 +527,34 @@ } } }, + "cli-table2": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/cli-table2/-/cli-table2-0.2.0.tgz", + "integrity": "sha1-LR738hig54biFFQFYtS9F3/jLZc=", + "requires": { + "colors": "^1.1.2", + "lodash": "^3.10.1", + "string-width": "^1.0.1" + }, + "dependencies": { + "lodash": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=" + } + } + }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", "dev": true }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + }, "coffee-script": { "version": "1.12.7", "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.12.7.tgz", @@ -1895,6 +1902,14 @@ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, "is-glob": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", @@ -2388,6 +2403,11 @@ } } }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, "oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", @@ -3104,6 +3124,16 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", diff --git a/package.json b/package.json index f036467..f9e725b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "puma-pod", - "version": "0.9.2", + "version": "0.9.3", "preferGlobal": true, "author": { "name": "Adam Allsopp" @@ -9,7 +9,7 @@ "async": "^2.3.0", "basic-auth": "^1.1.0", "body-parser": "^1.17.1", - "cli-table": "^0.3.1", + "cli-table2": "^0.2.0", "colors": "^1.3.2", "debug": "^2.6.3", "ejs": "^2.5.6",