diff --git a/config.apps.yaml b/config.apps.yaml index 20d816c1..9a3d9b63 100644 --- a/config.apps.yaml +++ b/config.apps.yaml @@ -86,6 +86,14 @@ services: user-agent: '{{user-agent}}' accept-language: '{{accept-language}}' body: '{{ default(request.query, {}) }}' + # the template used for contacting MW Rest API + mwrestapi_req: + method: '{{request.method}}' + uri: https://{{domain}}/w/rest.php/v1/{+path} + query: '{{ default(request.query, {}) }}' + headers: '{{request.headers}}' + body: '{{request.body}}' + timeout: 60000 # 60 * 1000 # the template used for requesting ResourceLoader module content from load.php mw_resource_loader_req: method: post diff --git a/config.dev.yaml b/config.dev.yaml index 6043846a..f5644aef 100644 --- a/config.dev.yaml +++ b/config.dev.yaml @@ -87,6 +87,14 @@ services: user-agent: '{{user-agent}}' accept-language: '{{accept-language}}' body: '{{ default(request.query, {}) }}' + # the template used for contacting MW Rest API + mwrestapi_req: + method: '{{request.method}}' + uri: https://{{domain}}/w/rest.php/v1/{+path} + query: '{{ default(request.query, {}) }}' + headers: '{{request.headers}}' + body: '{{request.body}}' + timeout: 60000 # 60 * 1000 # the template used for requesting ResourceLoader module content from load.php mw_resource_loader_req: method: post diff --git a/config.labs.yaml b/config.labs.yaml index 1d12195b..370da135 100644 --- a/config.labs.yaml +++ b/config.labs.yaml @@ -86,6 +86,14 @@ services: user-agent: '{{user-agent}}' accept-language: '{{accept-language}}' body: '{{ default(request.query, {}) }}' + # the template used for contacting MW Rest API + mwrestapi_req: + method: '{{request.method}}' + uri: https://{{domain}}/w/rest.php/v1/{+path} + query: '{{ default(request.query, {}) }}' + headers: '{{request.headers}}' + body: '{{request.body}}' + timeout: 60000 # 60 * 1000 # the template used for requesting ResourceLoader module content from load.php mw_resource_loader_req: method: post diff --git a/config.prod.yaml b/config.prod.yaml index 077187fb..b94424ad 100644 --- a/config.prod.yaml +++ b/config.prod.yaml @@ -99,6 +99,14 @@ services: user-agent: '{{user-agent}}' accept-language: '{{accept-language}}' body: '{{ default(request.query, {}) }}' + # the template used for contacting MW Rest API + mwrestapi_req: + method: '{{request.method}}' + uri: https://{{domain}}/w/rest.php/v1/{+path} + query: '{{ default(request.query, {}) }}' + headers: '{{request.headers}}' + body: '{{request.body}}' + timeout: 60000 # 60 * 1000 # the template used for requesting ResourceLoader module content from load.php mw_resource_loader_req: method: post diff --git a/dist/config.yaml b/dist/config.yaml index 9abb73df..1563046c 100644 --- a/dist/config.yaml +++ b/dist/config.yaml @@ -68,6 +68,13 @@ services: headers: user-agent: '{{user-agent}}' body: '{{ default(request.query, {}) }}' + # the template used for contacting MW Rest API + mwrestapi_req: + method: '{{request.method}}' + uri: https://{{domain}}/w/rest.php/v1/{+path} + query: '{{ default(request.query, {}) }}' + headers: '{{request.headers}}' + body: '{{request.body}}' # the template used for contacting RESTBase restbase_req: method: '{{request.method}}' diff --git a/lib/api-util.js b/lib/api-util.js index 5011ff49..b4a73389 100644 --- a/lib/api-util.js +++ b/lib/api-util.js @@ -14,6 +14,46 @@ function prettyMwApiReq(request) { return `${request.uri}?${querystring.stringify(request.body)}`; } +/** + * Calls the MW REST API with the supplied domain, path and request parameters + * @param {!Object} req the incoming request object + * @param {?string} path the REST API path to contact without the leading slash + * @param {?Object} [restReq={}] the object containing the REST request details + * @param {?string} [restReq.method=get] the request method + * @param {?Object} [restReq.query={}] the query string to send, if any + * @param {?Object} [restReq.headers={}] the request headers to send + * @param {?Object} [restReq.body=null] the body of the request, if any + * @return {!Promise} a promise resolving as the response object from the REST API + * + */ +function mwRestApiGet(req, path, restReq) { + + const app = req.app; + if (path.constructor === Object) { + restReq = path; + path = undefined; + } + restReq = restReq || {}; + restReq.method = restReq.method || 'get'; + restReq.query = restReq.query || {}; + restReq.headers = restReq.headers || {}; + restReq.params = restReq.params || {}; + restReq.params.path = path || restReq.params.path; + restReq.params.domain = restReq.params.domain || req.params.domain; + if (!restReq.params.path || !restReq.params.domain) { + return BBPromise.reject(new HTTPError({ + status: 500, + type: 'internal_error', + title: 'Invalid internal call', + detail: 'domain and path need to be defined for the REST API call' + })); + } + restReq.params.path = restReq.params.path[0] === '/' ? + restReq.params.path.slice(1) : restReq.params.path; + + return req.issueRequest(app.mwrestapi_tbl.expand({ request: restReq })); +} + /** * Make a request for ResourceLoader modules to MediaWiki's load.php entry point. * @@ -229,6 +269,7 @@ function setupApiTemplates(app) { }; } app.restbase_tpl = new Template(app.conf.restbase_req); + app.mwrestapi_tbl = new Template(app.conf.mwrestapi_req); // set up the MediaWiki page request template if (!app.conf.mw_resource_loader_req) { @@ -240,7 +281,6 @@ function setupApiTemplates(app) { }; } app.mw_resource_loader_tpl = new Template(app.conf.mw_resource_loader_req); - } /** @@ -277,6 +317,7 @@ function getCommonsDomain(domain) { module.exports = { // Shared with service-template-node mwApiGet, + mwRestApiGet, restApiGet, setupApiTemplates, diff --git a/lib/mobile-util.js b/lib/mobile-util.js index f2098e9e..877c328d 100644 --- a/lib/mobile-util.js +++ b/lib/mobile-util.js @@ -26,6 +26,7 @@ mUtil.CONTENT_TYPES = { type: 'application/json' }, talk: { name: 'Talk', version: '0.1.1', type: 'application/json' }, + significantChanges: { name: 'SignificantChanges', version: '0.0.1', type: 'application/json' }, mediaList: { name: 'MediaList', version: '1.1.0', type: 'application/json' }, i18n: { name: 'i18n', version: '0.0.1', type: 'application/json' } }; diff --git a/lib/mwapi.js b/lib/mwapi.js index 933699a7..3e5db17f 100644 --- a/lib/mwapi.js +++ b/lib/mwapi.js @@ -127,6 +127,53 @@ mwapi.getSiteInfo = function(req) { return siteInfoCache[rp.domain]; }; +mwapi.queryForRevisions = function(req, title, pageSize, rvStart, rvEnd) { + const query = apiParams({ + action: 'query', + prop: 'revisions', + titles: title || req.params.title, + rvslots: 'main', + rvprop: 'ids|timestamp|user|userid|size|parsedcomment|comment|tags|flags|size', + rvdir: 'older', + format: 'json', + rvlimit: pageSize || '20' + }); + + // to get around "parameters rvstartid & rvstart cannot be used together" error + if (rvStart && rvEnd) { + query.rvstart = rvStart; + query.rvend = rvEnd; + } else if (rvEnd) { + query.rvend = rvEnd; + } else { + query.rvstartid = req.query.rvstartid; + } + + return api.mwApiGet(req, query); +}; + +mwapi.queryForUsers = function(req, userids) { + + var useridstring = ''; + for (let i = 0; i < userids.length; i++) { + const userid = userids[i]; + if (i === 0) { + useridstring += userid; + } else { + useridstring += `|${userid}`; + } + } + + const query = apiParams({ + action: 'query', + list: 'users', + ususerids: useridstring, + usprop: 'groups|editcount', + }); + + return api.mwApiGet(req, query); +}; + /** * Given protection status for an article simplify it to allow easy reference * diff --git a/lib/mwrestapi.js b/lib/mwrestapi.js new file mode 100644 index 00000000..53765ccd --- /dev/null +++ b/lib/mwrestapi.js @@ -0,0 +1,10 @@ +const api = require('./api-util'); +const mwrestapi = {}; + +mwrestapi.queryForDiff = function(req, fromRevID, toRevID) { + const path = `revision/${fromRevID}/compare/${toRevID}`; + + return api.mwRestApiGet(req, path); +}; + +module.exports = mwrestapi; diff --git a/package-lock.json b/package-lock.json index ae5da377..715d0361 100644 --- a/package-lock.json +++ b/package-lock.json @@ -135,6 +135,11 @@ "to-fast-properties": "^2.0.0" } }, + "@root/encoding": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@root/encoding/-/encoding-1.0.1.tgz", + "integrity": "sha512-OaEub02ufoU038gy6bsNHQOjIn8nUjGiLcaRmJ40IUykneJkIW5fxDqKxQx48cszuNflYldsJLPPXCrGfHs8yQ==" + }, "@sindresorhus/is": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", @@ -239,6 +244,17 @@ "uri-js": "^4.2.2" } }, + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "optional": true, + "requires": { + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" + } + }, "ansi-align": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", @@ -708,6 +724,16 @@ "long": "^4.0.0" } }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "optional": true, + "requires": { + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" + } + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -1018,6 +1044,11 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, + "core-js": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", + "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==" + }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -3148,6 +3179,15 @@ "html-escaper": "^2.0.0" } }, + "jodid25519": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz", + "integrity": "sha1-BtSRIlUJNBlHfUJWM2BuDpB4KWc=", + "optional": true, + "requires": { + "jsbn": "~0.1.0" + } + }, "js-beautify": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.13.0.tgz", @@ -3415,6 +3455,23 @@ "json-buffer": "3.0.0" } }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "optional": true, + "requires": { + "is-buffer": "^1.1.5" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "optional": true + } + } + }, "latest-version": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", @@ -3424,6 +3481,12 @@ "package-json": "^6.3.0" } }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "optional": true + }, "less": { "version": "3.12.2", "resolved": "https://registry.npmjs.org/less/-/less-3.12.2.tgz", @@ -3607,6 +3670,12 @@ "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "optional": true + }, "lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", @@ -4533,215 +4602,3537 @@ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" - }, - "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-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", - "dev": true - }, - "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=" - }, - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "requires": { - "pify": "^3.0.0" - } - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" - }, - "picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", - "dev": true - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, - "pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "requires": { - "find-up": "^3.0.0" - } - }, - "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", - "requires": { - "chalk": "^2.4.2", - "source-map": "^0.6.1", - "supports-color": "^6.1.0" + "parsoid": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/parsoid/-/parsoid-0.7.1.tgz", + "integrity": "sha1-Eh3PWdC6zZJHQFmIUliI+aa6Iyg=", + "requires": { + "async": "^0.9.2", + "babybird": "^0.0.1", + "body-parser": "^1.16.0", + "compression": "^1.6.2", + "connect-busboy": "^0.0.2", + "content-type": "git+https://github.com/wikimedia/content-type.git#master", + "core-js": "^2.4.1", + "diff": "^1.0.7", + "domino": "^1.0.28", + "entities": "^1.1.1", + "express": "^4.14.0", + "express-handlebars": "^3.0.0", + "finalhandler": "^0.5.0", + "js-yaml": "^3.6.1", + "mediawiki-title": "^0.5.6", + "negotiator": "git+https://github.com/arlolra/negotiator.git#full-parse-access", + "node-uuid": "^1.4.7", + "pegjs": "git+https://github.com/tstarling/pegjs.git#fork", + "prfun": "^2.1.4", + "request": "^2.79.0", + "semver": "^5.3.0", + "serve-favicon": "^2.3.2", + "service-runner": "^2.1.13", + "simplediff": "^0.1.1", + "yargs": "^5.0.0" }, "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "JSV": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/JSV/-/JSV-4.0.2.tgz", + "integrity": "sha1-0Hf2glVx+CEy+d/67Vh7QCn+/1c=" + }, + "abbrev": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=" + }, + "accepts": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz", + "integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=", "requires": { - "has-flag": "^3.0.0" + "mime-types": "~2.1.11", + "negotiator": "0.6.1" } - } - } - }, - "pre-commit": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/pre-commit/-/pre-commit-1.2.2.tgz", - "integrity": "sha1-287g7p3nI15X95xW186UZBpp7sY=", - "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "spawn-sync": "^1.0.15", - "which": "1.2.x" - }, - "dependencies": { - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "dev": true, + }, + "alea": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/alea/-/alea-0.0.9.tgz", + "integrity": "sha1-9zjLRfg0MAafRc9pzL8xLdV6nho=" + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=" + }, + "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": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "argparse": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", + "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "sprintf-js": "~1.0.2" } }, - "which": { - "version": "1.2.14", - "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", - "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", - "dev": true, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "asap": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.5.tgz", + "integrity": "sha1-UidltQw1EEkOUtfc/ghe+bqWlY8=" + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" + }, + "assert-plus": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=" + }, + "assertion-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.2.tgz", + "integrity": "sha1-E8pRXYYgbaC6xm6DTdOX2HWBCUw=" + }, + "async": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "aws-sign2": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=" + }, + "aws4": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.5.0.tgz", + "integrity": "sha1-Cin/t5wxyecS7rCH6OemS0pW11U=" + }, + "babel-runtime": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.20.0.tgz", + "integrity": "sha1-hzAL3PTNdw8JvwBIxkIE4XgG0W8=", "requires": { - "isexe": "^2.0.0" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.10.0" } - } - } - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", - "dev": true - }, - "preq": { - "version": "0.5.14", - "resolved": "https://registry.npmjs.org/preq/-/preq-0.5.14.tgz", - "integrity": "sha512-kuJ5ndEgjs27kTTQ/P2ipPQoHeCJcAI4i97mU3xSjkjx6CsuQOsCe2l5twTGC0SCB5UkzRpmrpXmvN0Ip4ZCxA==", - "requires": { - "bluebird": "^3.5.5", - "request": "^2.88.0", - "requestretry": "4.0.2" - } - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, - "proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", - "dev": true - }, - "proxy-addr": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", - "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", - "requires": { - "forwarded": "~0.1.2", - "ipaddr.js": "1.9.1" - } - }, - "prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", - "dev": true, - "optional": true - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true - }, - "psl": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz", - "integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==" - }, - "pstree.remy": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", - "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", - "dev": true - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - }, - "pupa": { + }, + "babybird": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/babybird/-/babybird-0.0.1.tgz", + "integrity": "sha1-2oDHnG10Qc3+x8L/LcvXwT69vqI=", + "requires": { + "asap": "^2.0.3", + "is-arguments": "^1.0.2" + } + }, + "babylon": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.15.0.tgz", + "integrity": "sha1-umXPoagOF1mw6J+1YuJ9zK5wNI4=" + }, + "balanced-match": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=" + }, + "bl": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.0.tgz", + "integrity": "sha1-E5fn7ELF9dw4dHDFAONKn2vp6pg=", + "requires": { + "readable-stream": "^2.0.5" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.2.tgz", + "integrity": "sha1-qeb+w8fdqF+LsbO6cChgRVb8gl4=", + "requires": { + "buffer-shims": "^1.0.0", + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" + } + } + } + }, + "bluebird": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", + "integrity": "sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM=" + }, + "body-parser": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.16.0.tgz", + "integrity": "sha1-kkpeRyxiKfudabhaINXyUy3seIs=", + "requires": { + "bytes": "2.4.0", + "content-type": "~1.0.2", + "debug": "2.6.0", + "depd": "~1.1.0", + "http-errors": "~1.5.1", + "iconv-lite": "0.4.15", + "on-finished": "~2.3.0", + "qs": "6.2.1", + "raw-body": "~2.2.0", + "type-is": "~1.6.14" + }, + "dependencies": { + "content-type": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz", + "integrity": "sha1-t9ETrueo3Se9IRM8TcJSnfFyHu0=" + } + } + }, + "boom": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "requires": { + "hoek": "2.x.x" + } + }, + "brace-expansion": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.6.tgz", + "integrity": "sha1-cZfX6qm4fmSDkOph/GbIRCdCDfk=", + "requires": { + "balanced-match": "^0.4.1", + "concat-map": "0.0.1" + } + }, + "buffer-shims": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", + "integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E=" + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" + }, + "bunyan": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.5.tgz", + "integrity": "sha1-DWGegwBfuJBw9fR5gvwb8AYAh4o=", + "requires": { + "dtrace-provider": "~0.8", + "moment": "^2.10.6", + "mv": "~2", + "safe-json-stringify": "~1" + } + }, + "bunyan-syslog-udp": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/bunyan-syslog-udp/-/bunyan-syslog-udp-0.1.0.tgz", + "integrity": "sha1-+/ruA6gc0qlavBj5LJnyu4fiQpw=" + }, + "busboy": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", + "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=", + "requires": { + "dicer": "0.2.5", + "readable-stream": "1.1.x" + } + }, + "bytes": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz", + "integrity": "sha1-fZcZb51br39pNeJZhVSe3SpsIzk=" + }, + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" + }, + "caseless": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", + "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=" + }, + "chai": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz", + "integrity": "sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=", + "requires": { + "assertion-error": "^1.0.1", + "deep-eql": "^0.1.3", + "type-detect": "^1.0.0" + } + }, + "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" + } + }, + "clarinet": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/clarinet/-/clarinet-0.11.0.tgz", + "integrity": "sha1-bMkSuTE43IZ/wnPNNOqQ6D4FRxk=" + }, + "cli": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", + "integrity": "sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ=", + "requires": { + "exit": "0.1.2", + "glob": "^7.1.1" + }, + "dependencies": { + "glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", + "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" + } + } + } + }, + "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=" + } + } + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "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=" + }, + "colors": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=" + }, + "combined-stream": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "requires": { + "graceful-readlink": ">= 1.0.0" + } + }, + "comment-parser": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-0.3.1.tgz", + "integrity": "sha1-/WV6rIwUktMIyaYQD8m0nSQ1q6E=", + "requires": { + "readable-stream": "^2.0.4" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.2.tgz", + "integrity": "sha1-qeb+w8fdqF+LsbO6cChgRVb8gl4=", + "requires": { + "buffer-shims": "^1.0.0", + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" + } + } + } + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + }, + "compressible": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.9.tgz", + "integrity": "sha1-baq04rWZwncN2eIeeokbHFp1VCU=", + "requires": { + "mime-db": ">= 1.24.0 < 2" + } + }, + "compression": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.6.2.tgz", + "integrity": "sha1-zOsSHsydCcUtetDDNQ6pPd1AK8M=", + "requires": { + "accepts": "~1.3.3", + "bytes": "2.3.0", + "compressible": "~2.0.8", + "debug": "~2.2.0", + "on-headers": "~1.0.1", + "vary": "~1.1.0" + }, + "dependencies": { + "bytes": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.3.0.tgz", + "integrity": "sha1-1baAoWW2IBc5rLYRVCqrwtjOsHA=" + }, + "debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "requires": { + "ms": "0.7.1" + } + }, + "ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=" + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "connect-busboy": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/connect-busboy/-/connect-busboy-0.0.2.tgz", + "integrity": "sha1-rFyclmchcYheV2xmsr/ZXTuxEJc=", + "requires": { + "busboy": "*" + } + }, + "console-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", + "requires": { + "date-now": "^0.1.4" + } + }, + "content-disposition": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.1.tgz", + "integrity": "sha1-h0dsamfI2qh+Muh2Ft+IO6f7Bxs=" + }, + "content-type": { + "version": "git+https://github.com/wikimedia/content-type.git#47b2632d0a2ee79a7d67268e2f6621becd95d05b", + "from": "git+https://github.com/wikimedia/content-type.git#master" + }, + "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=" + }, + "cookiejar": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.0.6.tgz", + "integrity": "sha1-Cr81atANHFohnYjURRgEbdAmrP4=" + }, + "core-js": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz", + "integrity": "sha1-TekR5mew6ukSTjQlS1OupvxhjT4=" + }, + "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=" + }, + "coveralls": { + "version": "2.11.15", + "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-2.11.15.tgz", + "integrity": "sha1-N9NHQ2nWbBTzP6c6nSXO5uCZ/KA=", + "requires": { + "js-yaml": "3.6.1", + "lcov-parse": "0.0.10", + "log-driver": "1.2.5", + "minimist": "1.2.0", + "request": "2.75.0" + }, + "dependencies": { + "bl": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.1.2.tgz", + "integrity": "sha1-/cqHGplxOqANGeO7ukHER4emU5g=", + "requires": { + "readable-stream": "~2.0.5" + } + }, + "form-data": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.0.0.tgz", + "integrity": "sha1-bwrrrcxdoWwT4ezBETfYX5uIOyU=", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.5", + "mime-types": "^2.1.11" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "js-yaml": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.6.1.tgz", + "integrity": "sha1-bl/mfYsgXOTSL60Ft3geja3MSzA=", + "requires": { + "argparse": "^1.0.7", + "esprima": "^2.6.0" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + }, + "readable-stream": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" + } + }, + "request": { + "version": "2.75.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.75.0.tgz", + "integrity": "sha1-0rgmiihtoT6qXQGt9dGMyQ9lfZM=", + "requires": { + "aws-sign2": "~0.6.0", + "aws4": "^1.2.1", + "bl": "~1.1.2", + "caseless": "~0.11.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.0", + "forever-agent": "~0.6.1", + "form-data": "~2.0.0", + "har-validator": "~2.0.6", + "hawk": "~3.1.3", + "http-signature": "~1.1.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.7", + "node-uuid": "~1.4.7", + "oauth-sign": "~0.8.1", + "qs": "~6.2.0", + "stringstream": "~0.0.4", + "tough-cookie": "~2.3.0", + "tunnel-agent": "~0.4.1" + } + } + } + }, + "cryptiles": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "requires": { + "boom": "2.x.x" + } + }, + "cst": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/cst/-/cst-0.4.9.tgz", + "integrity": "sha1-Ua8UITv1+OjnFZZqxkXh4qVsaDQ=", + "requires": { + "babel-runtime": "^6.9.2", + "babylon": "^6.8.1", + "source-map-support": "^0.4.0" + } + }, + "cycle": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", + "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=" + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "^1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "date-now": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", + "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=" + }, + "debug": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.0.tgz", + "integrity": "sha1-vFlryr52F/Edn6FTYe3tVgi4SZs=", + "requires": { + "ms": "0.7.2" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "deep-eql": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", + "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=", + "requires": { + "type-detect": "0.1.1" + }, + "dependencies": { + "type-detect": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", + "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=" + } + } + }, + "deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=" + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" + }, + "define-properties": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", + "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", + "requires": { + "foreach": "^2.0.5", + "object-keys": "^1.0.8" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "depd": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz", + "integrity": "sha1-4b2Cxqq2ztlluXuIsX7T5SjKGMM=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "dicer": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", + "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=", + "requires": { + "readable-stream": "1.1.x", + "streamsearch": "0.1.2" + } + }, + "diff": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", + "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=" + }, + "dom-serializer": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", + "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", + "requires": { + "domelementtype": "~1.1.1", + "entities": "~1.1.1" + }, + "dependencies": { + "domelementtype": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", + "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=" + } + } + }, + "dom-storage": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dom-storage/-/dom-storage-2.0.2.tgz", + "integrity": "sha1-7RfL9oq9EOCu+BgnE+KXxeS1ALA=" + }, + "domelementtype": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", + "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=" + }, + "domhandler": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", + "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", + "requires": { + "domelementtype": "1" + } + }, + "domino": { + "version": "1.0.28", + "resolved": "https://registry.npmjs.org/domino/-/domino-1.0.28.tgz", + "integrity": "sha1-nOP2qSIaLDKImEsU6hkc0ns5L4c=" + }, + "domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz", + "integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA=" + }, + "entities": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", + "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=" + }, + "error-ex": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.0.tgz", + "integrity": "sha1-5ntD8+gsluo6WE/+4Ln8MyXYAtk=", + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "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=" + }, + "escodegen": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", + "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", + "requires": { + "esprima": "^2.7.1", + "estraverse": "^1.9.1", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.2.0" + } + }, + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=" + }, + "estraverse": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=" + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" + }, + "etag": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.7.0.tgz", + "integrity": "sha1-A9MLX2fdbmMtKUXTDWZScxo01dg=" + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=" + }, + "express": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/express/-/express-4.14.0.tgz", + "integrity": "sha1-we4/Qs3Ikfs9xlCoki1R7IR9DWY=", + "requires": { + "accepts": "~1.3.3", + "array-flatten": "1.1.1", + "content-disposition": "0.5.1", + "content-type": "~1.0.2", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "~2.2.0", + "depd": "~1.1.0", + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "etag": "~1.7.0", + "finalhandler": "0.5.0", + "fresh": "0.3.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.1", + "path-to-regexp": "0.1.7", + "proxy-addr": "~1.1.2", + "qs": "6.2.0", + "range-parser": "~1.2.0", + "send": "0.14.1", + "serve-static": "~1.11.1", + "type-is": "~1.6.13", + "utils-merge": "1.0.0", + "vary": "~1.1.0" + }, + "dependencies": { + "content-type": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz", + "integrity": "sha1-t9ETrueo3Se9IRM8TcJSnfFyHu0=" + }, + "debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "requires": { + "ms": "0.7.1" + } + }, + "finalhandler": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.5.0.tgz", + "integrity": "sha1-6VCKvs6bbbqHGmlCodeRG5GRGsc=", + "requires": { + "debug": "~2.2.0", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "statuses": "~1.3.0", + "unpipe": "~1.0.0" + } + }, + "ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=" + }, + "qs": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.0.tgz", + "integrity": "sha1-O3hIwDwt7OaalSKw+ujEEm10Xzs=" + } + } + }, + "express-handlebars": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/express-handlebars/-/express-handlebars-3.0.0.tgz", + "integrity": "sha1-gKBwu4GbCeSvLKbQeA91zgXnXC8=", + "requires": { + "glob": "^6.0.4", + "graceful-fs": "^4.1.2", + "handlebars": "^4.0.5", + "object.assign": "^4.0.3", + "promise": "^7.0.0" + } + }, + "extend": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz", + "integrity": "sha1-WkdDU7nzNT3dgXbf03uRyDpG8dQ=" + }, + "extsprintf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz", + "integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA=" + }, + "eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=" + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + }, + "finalhandler": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.5.1.tgz", + "integrity": "sha1-LEANjUUwk1vCMlScX6OF7Afeb80=", + "requires": { + "debug": "~2.2.0", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "statuses": "~1.3.1", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "requires": { + "ms": "0.7.1" + } + }, + "ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=" + } + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=" + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.2.tgz", + "integrity": "sha1-icNTQAi5fq2ky7FX1Y9vXfAl6uQ=", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.5", + "mime-types": "^2.1.12" + } + }, + "formidable": { + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.0.17.tgz", + "integrity": "sha1-71SRSQ+UM7cF+qdyScmQKa40hVk=" + }, + "forwarded": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.0.tgz", + "integrity": "sha1-Ge+YdMSuHCl7zweP3mOgm2aoQ2M=" + }, + "fresh": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.3.0.tgz", + "integrity": "sha1-ZR+DjiJCTnVm3hYdg1jKoZn4PU8=" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "function-bind": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.0.tgz", + "integrity": "sha1-FhdnFMgBeY5Ojyz391KUZ7tKV3E=" + }, + "gelf-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/gelf-stream/-/gelf-stream-1.1.1.tgz", + "integrity": "sha1-nOqbY4asMBx0GDjKPLkeZtv79mk=", + "requires": { + "gelfling": "^0.3.0" + } + }, + "gelfling": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/gelfling/-/gelfling-0.3.1.tgz", + "integrity": "sha1-M2qY+BUQ+a4K8qSU4XRooRap3AQ=" + }, + "generate-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", + "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=" + }, + "generate-object-property": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", + "requires": { + "is-property": "^1.0.0" + } + }, + "get-caller-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", + "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=" + }, + "getpass": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.6.tgz", + "integrity": "sha1-KD/9n8ElaECHUxHBtg6MQBhxEOY=", + "requires": { + "assert-plus": "^1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "glob": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", + "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.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=" + }, + "growl": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", + "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=" + }, + "handlebars": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.6.tgz", + "integrity": "sha1-LORISFBTf5yXqAJtU5m5NcTtTtc=", + "requires": { + "async": "^1.4.0", + "optimist": "^0.6.1", + "source-map": "^0.4.4", + "uglify-js": "^2.6" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" + } + } + }, + "har-validator": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", + "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", + "requires": { + "chalk": "^1.1.1", + "commander": "^2.9.0", + "is-my-json-valid": "^2.12.4", + "pinkie-promise": "^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-color": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz", + "integrity": "sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=" + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=" + }, + "hat": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/hat/-/hat-0.0.3.tgz", + "integrity": "sha1-uwFKnmSzeIrtgAWRdBPU/z1QLYo=" + }, + "hawk": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "requires": { + "boom": "2.x.x", + "cryptiles": "2.x.x", + "hoek": "2.x.x", + "sntp": "1.x.x" + } + }, + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" + }, + "hosted-git-info": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.1.5.tgz", + "integrity": "sha1-C6gdkNouJas0ozLm7HeTbhWYEYs=" + }, + "hot-shots": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/hot-shots/-/hot-shots-4.3.1.tgz", + "integrity": "sha1-WKbB/3F/JWc75NL3NtHJTV154jk=" + }, + "htmlparser2": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", + "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", + "requires": { + "domelementtype": "1", + "domhandler": "2.3", + "domutils": "1.5", + "entities": "1.0", + "readable-stream": "1.1" + }, + "dependencies": { + "entities": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", + "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=" + } + } + }, + "http-errors": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.5.1.tgz", + "integrity": "sha1-eIwNLB3iyBuebowBhDtrl+uSB1A=", + "requires": { + "inherits": "2.0.3", + "setprototypeof": "1.0.2", + "statuses": ">= 1.3.1 < 2" + } + }, + "http-signature": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "requires": { + "assert-plus": "^0.2.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "i": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/i/-/i-0.3.5.tgz", + "integrity": "sha1-HSuFQVjsgWkRPGy39raAHpniEdU=" + }, + "iconv-lite": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz", + "integrity": "sha1-/iZaIYrGpXz+hUkn6dBMGYJe3es=" + }, + "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" + } + }, + "inherit": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/inherit/-/inherit-2.2.6.tgz", + "integrity": "sha1-8WFLBshUToEo5CKchjR9tzrZeI0=" + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" + }, + "ipaddr.js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.2.0.tgz", + "integrity": "sha1-irpJyRknmVhb3WQ+DMtQ6K53e6Q=" + }, + "is-arguments": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.2.tgz", + "integrity": "sha1-B+MK15UxhEF5tkLS2DmUNRgshyc=" + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + }, + "is-builtin-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "requires": { + "builtin-modules": "^1.0.0" + } + }, + "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-my-json-valid": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz", + "integrity": "sha1-k27do8o8IR/ZjzstPgjaQ/eykVs=", + "requires": { + "generate-function": "^2.0.0", + "generate-object-property": "^1.1.0", + "jsonpointer": "^4.0.0", + "xtend": "^4.0.0" + } + }, + "is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "isexe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-1.1.2.tgz", + "integrity": "sha1-NvPiLmB1CSD15yQaR2qMakInWtA=" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "istanbul": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", + "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", + "requires": { + "abbrev": "1.0.x", + "async": "1.x", + "escodegen": "1.8.x", + "esprima": "2.7.x", + "glob": "^5.0.15", + "handlebars": "^4.0.1", + "js-yaml": "3.x", + "mkdirp": "0.5.x", + "nopt": "3.x", + "once": "1.x", + "resolve": "1.1.x", + "supports-color": "^3.1.0", + "which": "^1.1.1", + "wordwrap": "^1.0.0" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" + }, + "glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "requires": { + "has-flag": "^1.0.0" + } + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" + } + } + }, + "jade": { + "version": "0.26.3", + "resolved": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz", + "integrity": "sha1-jxDXl32NefL2/4YqgbBRPMslaGw=", + "requires": { + "commander": "0.6.1", + "mkdirp": "0.3.0" + }, + "dependencies": { + "commander": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", + "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=" + }, + "mkdirp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", + "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=" + } + } + }, + "js-yaml": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz", + "integrity": "sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A=", + "requires": { + "argparse": "^1.0.7", + "esprima": "^2.6.0" + } + }, + "jscs": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/jscs/-/jscs-3.0.7.tgz", + "integrity": "sha1-cUG03/W4bjLQ6Z12S4NnZ8MNIBo=", + "requires": { + "chalk": "~1.1.0", + "cli-table": "~0.3.1", + "commander": "~2.9.0", + "cst": "^0.4.3", + "estraverse": "^4.1.0", + "exit": "~0.1.2", + "glob": "^5.0.1", + "htmlparser2": "3.8.3", + "js-yaml": "~3.4.0", + "jscs-jsdoc": "^2.0.0", + "jscs-preset-wikimedia": "~1.0.0", + "jsonlint": "~1.6.2", + "lodash": "~3.10.0", + "minimatch": "~3.0.0", + "natural-compare": "~1.2.2", + "pathval": "~0.1.1", + "prompt": "~0.2.14", + "reserved-words": "^0.1.1", + "resolve": "^1.1.6", + "strip-bom": "^2.0.0", + "strip-json-comments": "~1.0.2", + "to-double-quotes": "^2.0.0", + "to-single-quotes": "^2.0.0", + "vow": "~0.4.8", + "vow-fs": "~0.3.4", + "xmlbuilder": "^3.1.0" + }, + "dependencies": { + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" + }, + "glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "js-yaml": { + "version": "3.4.6", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.4.6.tgz", + "integrity": "sha1-a+GyP2JJ9T0pM3D9TRqqY84bTrA=", + "requires": { + "argparse": "^1.0.2", + "esprima": "^2.6.0", + "inherit": "^2.2.2" + } + } + } + }, + "jscs-jsdoc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jscs-jsdoc/-/jscs-jsdoc-2.0.0.tgz", + "integrity": "sha1-9T684CmqMSW9iCkLpQ1k1FEKSHE=", + "requires": { + "comment-parser": "^0.3.1", + "jsdoctypeparser": "~1.2.0" + } + }, + "jscs-preset-wikimedia": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/jscs-preset-wikimedia/-/jscs-preset-wikimedia-1.0.0.tgz", + "integrity": "sha1-//VjNCA4/C6IJre7cwnDrjQG/H4=" + }, + "jsdoctypeparser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/jsdoctypeparser/-/jsdoctypeparser-1.2.0.tgz", + "integrity": "sha1-597cFToRhJ/8UUEUSuhqfvDCU5I=", + "requires": { + "lodash": "^3.7.0" + } + }, + "jshint": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.9.4.tgz", + "integrity": "sha1-XjupeEjVKQJz21FK7kf+JM9ZKTQ=", + "requires": { + "cli": "~1.0.0", + "console-browserify": "1.1.x", + "exit": "0.1.x", + "htmlparser2": "3.8.x", + "lodash": "3.7.x", + "minimatch": "~3.0.2", + "shelljs": "0.3.x", + "strip-json-comments": "1.0.x" + }, + "dependencies": { + "lodash": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.7.0.tgz", + "integrity": "sha1-Nni9irmVBXwHreg27S7wh9qBHUU=" + } + } + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "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=" + }, + "jsonlint": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/jsonlint/-/jsonlint-1.6.2.tgz", + "integrity": "sha1-VzcEUIX1XrRVxosf9OvAG9UOiDA=", + "requires": { + "JSV": ">= 4.0.x", + "nomnom": ">= 1.5.x" + } + }, + "jsonpointer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", + "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=" + }, + "jsprim": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.3.1.tgz", + "integrity": "sha1-KnJW9wQSop7jZwqspiWZTE3P8lI=", + "requires": { + "extsprintf": "1.0.2", + "json-schema": "0.2.3", + "verror": "1.3.6" + } + }, + "kad": { + "version": "git+https://github.com/gwicke/kad.git#f35971036f43814043245da82b12d035b7bbfd16", + "from": "git+https://github.com/gwicke/kad.git#master" + }, + "kad-fs": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/kad-fs/-/kad-fs-0.0.4.tgz", + "integrity": "sha1-Aupapc8iIlclV5YnzP1tJmNyKJo=", + "requires": { + "readable-stream": "^2.0.4" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.2.tgz", + "integrity": "sha1-qeb+w8fdqF+LsbO6cChgRVb8gl4=", + "requires": { + "buffer-shims": "^1.0.0", + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" + } + } + } + }, + "kad-localstorage": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/kad-localstorage/-/kad-localstorage-0.0.7.tgz", + "integrity": "sha1-96LngNpT+yi5Q8LFqJTCeaqBDxc=", + "requires": { + "dom-storage": "^2.0.1" + } + }, + "kad-memstore": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/kad-memstore/-/kad-memstore-0.0.1.tgz", + "integrity": "sha1-g8t0hJasSRxxNRBMvla4jKc5JHc=", + "requires": { + "readable-stream": "^2.0.5" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.2.tgz", + "integrity": "sha1-qeb+w8fdqF+LsbO6cChgRVb8gl4=", + "requires": { + "buffer-shims": "^1.0.0", + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" + } + } + } + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "requires": { + "invert-kv": "^1.0.0" + } + }, + "lcov-parse": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-0.0.10.tgz", + "integrity": "sha1-GwuP+ayceIklBYK3C3ExXZ2m2aM=" + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "limitation": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/limitation/-/limitation-0.1.9.tgz", + "integrity": "sha1-ugVf9906JnplzGvi3spOpr672wM=", + "requires": { + "bluebird": "^3.3.1", + "kad": "git+https://github.com/gwicke/kad.git#master", + "readable-stream": "^2.0.5" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.2.tgz", + "integrity": "sha1-qeb+w8fdqF+LsbO6cChgRVb8gl4=", + "requires": { + "buffer-shims": "^1.0.0", + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" + } + } + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + } + }, + "lodash": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=" + }, + "lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=" + }, + "log-driver": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.5.tgz", + "integrity": "sha1-euTsJXMC/XkNVXyxDJcQDYV7AFY=" + }, + "lru-cache": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", + "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "mediawiki-title": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mediawiki-title/-/mediawiki-title-0.5.6.tgz", + "integrity": "sha1-VJBpKU4ncoofE77T1wXWvuz06iQ=" + }, + "merge": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz", + "integrity": "sha1-dTHjnUlJwoGma4xabgJl6LBYlNo=" + }, + "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=" + }, + "mime": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz", + "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM=" + }, + "mime-db": { + "version": "1.26.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.26.0.tgz", + "integrity": "sha1-6v/NDk/Gk1z4E02iRuLmw1MFrf8=" + }, + "mime-types": { + "version": "2.1.14", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.14.tgz", + "integrity": "sha1-9+99l1g/yvO30oK2+LVnnaselO4=", + "requires": { + "mime-db": "~1.26.0" + } + }, + "minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha1-Kk5AkLlrLbBqnX3wEFWmKnfJt3Q=", + "requires": { + "brace-expansion": "^1.0.0" + } + }, + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" + }, + "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" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + } + } + }, + "mocha": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-2.5.3.tgz", + "integrity": "sha1-FhvlvetJZ3HrmzV0UFC2IrWu/Fg=", + "requires": { + "commander": "2.3.0", + "debug": "2.2.0", + "diff": "1.4.0", + "escape-string-regexp": "1.0.2", + "glob": "3.2.11", + "growl": "1.9.2", + "jade": "0.26.3", + "mkdirp": "0.5.1", + "supports-color": "1.2.0", + "to-iso-string": "0.0.2" + }, + "dependencies": { + "commander": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz", + "integrity": "sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM=" + }, + "debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "requires": { + "ms": "0.7.1" + } + }, + "escape-string-regexp": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", + "integrity": "sha1-Tbwv5nTnGUnK8/smlc5/LcHZqNE=" + }, + "glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", + "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", + "requires": { + "inherits": "2", + "minimatch": "0.3" + } + }, + "minimatch": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", + "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", + "requires": { + "lru-cache": "2", + "sigmund": "~1.0.0" + } + }, + "ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=" + }, + "supports-color": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz", + "integrity": "sha1-/x7R5hFp0Gs88tWI4YixjYhH4X4=" + } + } + }, + "ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=" + }, + "msgpack5": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/msgpack5/-/msgpack5-3.4.1.tgz", + "integrity": "sha1-NQ7zWJnGyHc3EP2E2IHd0zQKgRQ=", + "requires": { + "bl": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.2.tgz", + "integrity": "sha1-qeb+w8fdqF+LsbO6cChgRVb8gl4=", + "requires": { + "buffer-shims": "^1.0.0", + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" + } + } + } + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" + }, + "natural-compare": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.2.2.tgz", + "integrity": "sha1-H5bWDjFBysG20FZTzg2urHY69qo=" + }, + "ncp": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/ncp/-/ncp-0.4.2.tgz", + "integrity": "sha1-q8xsvT7C7Spyn/bnwfqPAXhKhXQ=" + }, + "negotiator": { + "version": "git+https://github.com/arlolra/negotiator.git#0418ab4e9a665772b7e233564a4525c9d9a8ec3a", + "from": "git+https://github.com/arlolra/negotiator.git#full-parse-access" + }, + "nock": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/nock/-/nock-8.2.1.tgz", + "integrity": "sha1-ZMxl4b3TiT9Yy6fhq/3Dj0DwNko=", + "requires": { + "chai": ">=1.9.2 <4.0.0", + "debug": "^2.2.0", + "deep-equal": "^1.0.0", + "json-stringify-safe": "^5.0.1", + "lodash": "~4.9.0", + "mkdirp": "^0.5.0", + "propagate": "0.4.0", + "qs": "^6.0.2" + }, + "dependencies": { + "lodash": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.9.0.tgz", + "integrity": "sha1-TCDXQvA86F3HAODderm8q4Xm/BQ=" + } + } + }, + "node-uuid": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz", + "integrity": "sha1-baWhdmjEs91ZYjvaEc9/pMH2Cm8=" + }, + "nomnom": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.8.1.tgz", + "integrity": "sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc=", + "requires": { + "chalk": "~0.4.0", + "underscore": "~1.6.0" + }, + "dependencies": { + "ansi-styles": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", + "integrity": "sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=" + }, + "chalk": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", + "integrity": "sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=", + "requires": { + "ansi-styles": "~1.0.0", + "has-color": "~0.1.0", + "strip-ansi": "~0.1.0" + } + }, + "strip-ansi": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", + "integrity": "sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=" + } + } + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "requires": { + "abbrev": "1" + } + }, + "normalize-package-data": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.5.tgz", + "integrity": "sha1-jZJPFClg4Xd+f/4XBUNjHMfLAt8=", + "requires": { + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "nsp": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/nsp/-/nsp-2.6.2.tgz", + "integrity": "sha1-k9+0xbKIXMNU2MoYtz8J5SucixY=", + "requires": { + "chalk": "^1.1.1", + "cli-table": "^0.3.1", + "https-proxy-agent": "^1.0.0", + "joi": "^6.9.1", + "nodesecurity-npm-utils": "^5.0.0", + "path-is-absolute": "^1.0.0", + "rc": "^1.1.2", + "semver": "^5.0.3", + "subcommand": "^2.0.3", + "wreck": "^6.3.0" + }, + "dependencies": { + "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" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "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=" + }, + "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" + }, + "dependencies": { + "ansi-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz", + "integrity": "sha1-xQYbbg74qBd15Q9dZhUb9r83EQc=" + } + } + }, + "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" + }, + "dependencies": { + "ansi-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz", + "integrity": "sha1-xQYbbg74qBd15Q9dZhUb9r83EQc=" + } + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + } + } + }, + "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=" + } + } + }, + "https-proxy-agent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz", + "integrity": "sha1-NffabEjOTdv6JkiRrFk+5f+GceY=", + "requires": { + "agent-base": "2", + "debug": "2", + "extend": "3" + }, + "dependencies": { + "agent-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.0.1.tgz", + "integrity": "sha1-vY+ehqjrIh//oHvRS+/VXfFCgV4=", + "requires": { + "extend": "~3.0.0", + "semver": "~5.0.1" + }, + "dependencies": { + "semver": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz", + "integrity": "sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no=" + } + } + }, + "debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "requires": { + "ms": "0.7.1" + }, + "dependencies": { + "ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=" + } + } + }, + "extend": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz", + "integrity": "sha1-WkdDU7nzNT3dgXbf03uRyDpG8dQ=" + } + } + }, + "joi": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/joi/-/joi-6.10.1.tgz", + "integrity": "sha1-TVDDGAeRIgAP5fFq8f+OGRe3fgY=", + "requires": { + "hoek": "2.x.x", + "isemail": "1.x.x", + "moment": "2.x.x", + "topo": "1.x.x" + }, + "dependencies": { + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" + }, + "isemail": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/isemail/-/isemail-1.2.0.tgz", + "integrity": "sha1-vgPfjMPineTSxd9lASY/H6RZXpo=" + }, + "moment": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.12.0.tgz", + "integrity": "sha1-3CVg0Zg41sBzGxpq+gRnUmTTYNY=" + }, + "topo": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/topo/-/topo-1.1.0.tgz", + "integrity": "sha1-6ddRYV0buH3IZdsYL6HKCl71NtU=", + "requires": { + "hoek": "2.x.x" + } + } + } + }, + "nodesecurity-npm-utils": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nodesecurity-npm-utils/-/nodesecurity-npm-utils-5.0.0.tgz", + "integrity": "sha1-Baow3jDKjIRcQEjpT9eOXgi1Xtk=" + }, + "path-is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz", + "integrity": "sha1-Jj2tpmqz8vsQv3+dJN2PPlcO+RI=" + }, + "rc": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.1.6.tgz", + "integrity": "sha1-Q2UbdrauU7XIAvEVH6P8OwWZack=", + "requires": { + "deep-extend": "~0.4.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~1.0.4" + }, + "dependencies": { + "deep-extend": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.1.tgz", + "integrity": "sha1-7+QRPQgIX05vlod1mBD4B0aeIlM=" + }, + "ini": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", + "integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=" + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + }, + "strip-json-comments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", + "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=" + } + } + }, + "semver": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.1.0.tgz", + "integrity": "sha1-hfLPhVBGXE3wAM99hvawVBBqueU=" + }, + "subcommand": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/subcommand/-/subcommand-2.0.3.tgz", + "integrity": "sha1-mz/Rp1PjxEHwBBDLRBMdhlX1LDI=", + "requires": { + "cliclopts": "^1.1.0", + "debug": "^2.1.3", + "minimist": "^1.2.0", + "xtend": "^4.0.0" + }, + "dependencies": { + "cliclopts": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cliclopts/-/cliclopts-1.1.1.tgz", + "integrity": "sha1-aUMcfLWvcjd0sNORG0w3USQxkQ8=" + }, + "debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "requires": { + "ms": "0.7.1" + }, + "dependencies": { + "ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=" + } + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" + } + } + }, + "wreck": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/wreck/-/wreck-6.3.0.tgz", + "integrity": "sha1-oTaXafB7u2LWo3gzanhx/Hc8dAs=", + "requires": { + "boom": "2.x.x", + "hoek": "2.x.x" + }, + "dependencies": { + "boom": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "requires": { + "hoek": "2.x.x" + } + }, + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" + } + } + } + } + }, + "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.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" + }, + "object-keys": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", + "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=" + }, + "object.assign": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.0.4.tgz", + "integrity": "sha1-scnMBE7xuf5jYG/BQau7MuFHMMw=", + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.0", + "object-keys": "^1.0.10" + } + }, + "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" + } + }, + "on-headers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz", + "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=" + }, + "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=", + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" + }, + "dependencies": { + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" + } + } + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "requires": { + "lcid": "^1.0.0" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "requires": { + "error-ex": "^1.2.0" + } + }, + "parseurl": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.1.tgz", + "integrity": "sha1-yKuMkiO6NIiKpkopeyiFO+wY2lY=" + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "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-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=" + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "pathval": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-0.1.1.tgz", + "integrity": "sha1-CPkRzcqczllCiA2ngXvAtyO2bYI=" + }, + "pegjs": { + "version": "git+https://github.com/tstarling/pegjs.git#36d584bd7bbc564c86c058c5dfe8053b1fe1d584", + "from": "git+https://github.com/tstarling/pegjs.git#fork" + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "requires": { + "pinkie": "^2.0.0" + } + }, + "pkginfo": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.4.0.tgz", + "integrity": "sha1-NJ27f/04CB/K3AhT32h/DHdEzWU=" + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" + }, + "prfun": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/prfun/-/prfun-2.1.4.tgz", + "integrity": "sha1-eHF9m3GM58q1XiC58kOI1fpR1cA=", + "requires": { + "core-js": "^2.3.0" + } + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" + }, + "promise": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.1.1.tgz", + "integrity": "sha1-SJZUxpJha4qlWwck+oCbt9tJxb8=", + "requires": { + "asap": "~2.0.3" + } + }, + "prompt": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/prompt/-/prompt-0.2.14.tgz", + "integrity": "sha1-V3VPZPVD/XsIRXB8gY7OYY8F/9w=", + "requires": { + "pkginfo": "0.x.x", + "read": "1.0.x", + "revalidator": "0.1.x", + "utile": "0.2.x", + "winston": "0.8.x" + } + }, + "propagate": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/propagate/-/propagate-0.4.0.tgz", + "integrity": "sha1-8/zKCm/gZzanulcpZgaWF8EwtIE=" + }, + "proxy-addr": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.3.tgz", + "integrity": "sha1-3JdQL1ci6IhGez+iKXp7H/R98HQ=", + "requires": { + "forwarded": "~0.1.0", + "ipaddr.js": "1.2.0" + } + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "qs": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.1.tgz", + "integrity": "sha1-zgPF/wk1vB2daanxTL0Y5WjWdiU=" + }, + "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.2.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.2.0.tgz", + "integrity": "sha1-mUl2z2pQlqQRYoQEkvC9xdbn+5Y=", + "requires": { + "bytes": "2.4.0", + "iconv-lite": "0.4.15", + "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" + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + } + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "reduce-component": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/reduce-component/-/reduce-component-1.0.1.tgz", + "integrity": "sha1-4Mk1QsV0UhvqE98PlIjtgqt3xdo=" + }, + "regenerator-runtime": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.1.tgz", + "integrity": "sha1-JX9BlhzkRVixj3gUr0jBdVn5+us=" + }, + "request": { + "version": "2.79.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.79.0.tgz", + "integrity": "sha1-Tf5b9r6LjNw3/Pk+BLZVd3InEN4=", + "requires": { + "aws-sign2": "~0.6.0", + "aws4": "^1.2.1", + "caseless": "~0.11.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.0", + "forever-agent": "~0.6.1", + "form-data": "~2.1.1", + "har-validator": "~2.0.6", + "hawk": "~3.1.3", + "http-signature": "~1.1.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.7", + "oauth-sign": "~0.8.1", + "qs": "~6.3.0", + "stringstream": "~0.0.4", + "tough-cookie": "~2.3.0", + "tunnel-agent": "~0.4.1", + "uuid": "^3.0.0" + }, + "dependencies": { + "qs": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.3.0.tgz", + "integrity": "sha1-9AOyZPI7wBIox0ExtAfxjV6l1EI=" + }, + "uuid": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz", + "integrity": "sha1-ZUS7ot/ajBzxfmKaOjBeK7H+5sE=" + } + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" + }, + "reserved-words": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/reserved-words/-/reserved-words-0.1.1.tgz", + "integrity": "sha1-b3wV5eVhTFDalhYw2kat3IfAzvI=" + }, + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=" + }, + "revalidator": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/revalidator/-/revalidator-0.1.8.tgz", + "integrity": "sha1-/s5hv6DBtSoga9axgZgYS91SOjs=" + }, + "rimraf": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz", + "integrity": "sha1-loAAk8vxoMhr2VtGJUZ1NcKd+gQ=", + "requires": { + "glob": "^7.0.5" + }, + "dependencies": { + "glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", + "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" + } + } + } + }, + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=" + }, + "send": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.14.1.tgz", + "integrity": "sha1-qVSYQyU5L1FTKndgdg5FlZjIn3o=", + "requires": { + "debug": "~2.2.0", + "depd": "~1.1.0", + "destroy": "~1.0.4", + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "etag": "~1.7.0", + "fresh": "0.3.0", + "http-errors": "~1.5.0", + "mime": "1.3.4", + "ms": "0.7.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.3.0" + }, + "dependencies": { + "debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "requires": { + "ms": "0.7.1" + } + }, + "ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=" + } + } + }, + "serve-favicon": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.3.2.tgz", + "integrity": "sha1-3UGeJo3gEqtysxnTN/IQUBP5OB8=", + "requires": { + "etag": "~1.7.0", + "fresh": "0.3.0", + "ms": "0.7.2", + "parseurl": "~1.3.1" + } + }, + "serve-static": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.11.1.tgz", + "integrity": "sha1-1sznaTUF9zPHWd5Xvvwa92wPCAU=", + "requires": { + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "parseurl": "~1.3.1", + "send": "0.14.1" + } + }, + "service-runner": { + "version": "2.1.13", + "resolved": "https://registry.npmjs.org/service-runner/-/service-runner-2.1.13.tgz", + "integrity": "sha1-6P94uTIw19gx6j7VWHqiKSuCnOs=", + "requires": { + "bluebird": "^3.4.6", + "bunyan": "^1.8.1", + "bunyan-syslog-udp": "^0.1.0", + "extend": "^3.0.0", + "gelf-stream": "^1.1.1", + "hot-shots": "^4.2.0", + "js-yaml": "^3.6.1", + "limitation": "^0.1.9", + "semver": "^5.3.0", + "yargs": "^5.0.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "setprototypeof": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.2.tgz", + "integrity": "sha1-gaVSFB7BBLiOic44MQOtXGZWTQg=" + }, + "shelljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", + "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=" + }, + "sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=" + }, + "simplediff": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/simplediff/-/simplediff-0.1.1.tgz", + "integrity": "sha1-sMrusJMiM3ADPGw6oRMNyGxqCHw=" + }, + "sntp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "requires": { + "hoek": "2.x.x" + } + }, + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "requires": { + "amdefine": ">=0.0.4" + } + }, + "source-map-support": { + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.10.tgz", + "integrity": "sha1-17GQOAQKFMCDehjmMKGWRTlSs3g=", + "requires": { + "source-map": "^0.5.3" + }, + "dependencies": { + "source-map": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=" + } + } + }, + "spdx-correct": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", + "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", + "requires": { + "spdx-license-ids": "^1.0.2" + } + }, + "spdx-expression-parse": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", + "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=" + }, + "spdx-license-ids": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", + "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=" + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "sshpk": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.10.2.tgz", + "integrity": "sha1-1agEziJpVRVjjnmNviMnPeBwpfo=", + "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", + "jodid25519": "^1.0.0", + "jsbn": "~0.1.0", + "tweetnacl": "~0.14.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "stack-trace": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.9.tgz", + "integrity": "sha1-qPbq7KkGdMMz58Q5U/J1tFFRBpU=" + }, + "statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" + }, + "streamsearch": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", + "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" + }, + "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": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + }, + "stringstream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "requires": { + "is-utf8": "^0.2.0" + } + }, + "strip-json-comments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", + "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=" + }, + "superagent": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-1.8.5.tgz", + "integrity": "sha1-HA3cOvMOgOuE68BcshItqP6UC1U=", + "requires": { + "component-emitter": "~1.2.0", + "cookiejar": "2.0.6", + "debug": "2", + "extend": "3.0.0", + "form-data": "1.0.0-rc3", + "formidable": "~1.0.14", + "methods": "~1.1.1", + "mime": "1.3.4", + "qs": "2.3.3", + "readable-stream": "1.0.27-1", + "reduce-component": "1.0.1" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" + }, + "form-data": { + "version": "1.0.0-rc3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.0-rc3.tgz", + "integrity": "sha1-01vGLn+8KTeuePlIqqDTjZBgdXc=", + "requires": { + "async": "^1.4.0", + "combined-stream": "^1.0.5", + "mime-types": "^2.1.3" + } + }, + "qs": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-2.3.3.tgz", + "integrity": "sha1-6eha2+ddoLvkyOBHaghikPhjtAQ=" + }, + "readable-stream": { + "version": "1.0.27-1", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.27-1.tgz", + "integrity": "sha1-a2eYPCA1fO/QfwFlABoW1xDZEHg=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + } + } + }, + "supertest": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-1.2.0.tgz", + "integrity": "sha1-hQp5X5Bo0vrxngF5n/CZYuDOQ74=", + "requires": { + "methods": "1.x", + "superagent": "^1.7.2" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + }, + "to-double-quotes": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-double-quotes/-/to-double-quotes-2.0.0.tgz", + "integrity": "sha1-qvIx1vqUiUn4GTAburRITYWI5Kc=" + }, + "to-iso-string": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/to-iso-string/-/to-iso-string-0.0.2.tgz", + "integrity": "sha1-TcGeZk38y+Jb2NtQiwDG2hWCVdE=" + }, + "to-single-quotes": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/to-single-quotes/-/to-single-quotes-2.0.1.tgz", + "integrity": "sha1-fMKRUfD18sQZRvEZ9ZMv5VQXASU=" + }, + "tough-cookie": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", + "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=", + "requires": { + "punycode": "^1.4.1" + } + }, + "tunnel-agent": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", + "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=" + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-detect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz", + "integrity": "sha1-diIXzAbbJY7EiQihKY6LlRIejqI=" + }, + "type-is": { + "version": "1.6.14", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.14.tgz", + "integrity": "sha1-4hljnBfe0coHiQkt1UoDgmuBfLI=", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.13" + } + }, + "underscore": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utile": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/utile/-/utile-0.2.1.tgz", + "integrity": "sha1-kwyI6ZCY1iIINMNWy9mncFItkNc=", + "requires": { + "async": "~0.2.9", + "deep-equal": "*", + "i": "0.3.x", + "mkdirp": "0.x.x", + "ncp": "0.4.x", + "rimraf": "2.x.x" + }, + "dependencies": { + "async": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=" + } + } + }, + "utils-merge": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz", + "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg=" + }, + "uuid": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", + "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=" + }, + "validate-npm-package-license": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", + "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", + "requires": { + "spdx-correct": "~1.0.0", + "spdx-expression-parse": "~1.0.0" + } + }, + "vary": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.0.tgz", + "integrity": "sha1-4eWv+70WrnaN0mdDlLmtMCJlMUA=" + }, + "verror": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz", + "integrity": "sha1-z/XfEpRtKX0rqu+qJoniW+AcAFw=", + "requires": { + "extsprintf": "1.0.2" + } + }, + "vow": { + "version": "0.4.13", + "resolved": "https://registry.npmjs.org/vow/-/vow-0.4.13.tgz", + "integrity": "sha1-58FPG9nIvg5zWaRZf+LR720afog=" + }, + "vow-fs": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/vow-fs/-/vow-fs-0.3.6.tgz", + "integrity": "sha1-LUxZviLivyYY3fWXq0uqkjvnIA0=", + "requires": { + "glob": "^7.0.5", + "uuid": "^2.0.2", + "vow": "^0.4.7", + "vow-queue": "^0.4.1" + }, + "dependencies": { + "glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", + "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" + } + } + } + }, + "vow-queue": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/vow-queue/-/vow-queue-0.4.2.tgz", + "integrity": "sha1-5/4XFg4Vx8QYTRtmapvGThjjAYQ=", + "requires": { + "vow": "~0.4.0" + } + }, + "which": { + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/which/-/which-1.2.12.tgz", + "integrity": "sha1-3me15FAmnxlJCe8j7OTr5Bb6EZI=", + "requires": { + "isexe": "^1.1.1" + } + }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=" + }, + "window-size": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", + "integrity": "sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU=" + }, + "winston": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/winston/-/winston-0.8.3.tgz", + "integrity": "sha1-ZLar9M0Brcrv1QCTk7HY6L7BnbA=", + "requires": { + "async": "0.2.x", + "colors": "0.6.x", + "cycle": "1.0.x", + "eyes": "0.1.x", + "isstream": "0.1.x", + "pkginfo": "0.3.x", + "stack-trace": "0.0.x" + }, + "dependencies": { + "async": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=" + }, + "colors": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", + "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=" + }, + "pkginfo": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.3.1.tgz", + "integrity": "sha1-Wyn2qB9wcXFC4J52W76rl7T4HiE=" + } + } + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "xmlbuilder": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-3.1.0.tgz", + "integrity": "sha1-LIaIjy1OrehQ+jjKf3Ij9yCVFuE=", + "requires": { + "lodash": "^3.5.0" + } + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" + }, + "yargs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-5.0.0.tgz", + "integrity": "sha1-M1UUSXfQV1fbuG1uOOwFYSOzpm4=", + "requires": { + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "lodash.assign": "^4.2.0", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.2", + "which-module": "^1.0.0", + "window-size": "^0.2.0", + "y18n": "^3.2.1", + "yargs-parser": "^3.2.0" + } + }, + "yargs-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-3.2.0.tgz", + "integrity": "sha1-UIE1XRnZ0MjF2BrakIy05tGGZk8=", + "requires": { + "camelcase": "^3.0.0", + "lodash.assign": "^4.1.0" + } + } + } + }, + "parsoid-jsapi": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/parsoid-jsapi/-/parsoid-jsapi-0.0.1.tgz", + "integrity": "sha1-AFiGuWCiP+0rcBogMH9rOr/6A7k=", + "requires": { + "domino": "^1.0.28", + "parsoid": "^0.7.1" + }, + "dependencies": { + "domino": { + "version": "1.0.30", + "resolved": "https://registry.npmjs.org/domino/-/domino-1.0.30.tgz", + "integrity": "sha512-ikq8WiDSkICdkElud317F2Sigc6A3EDpWsxWBwIZqOl95km4p/Vc9Rj98id7qKgsjDmExj0AVM7JOd4bb647Xg==" + } + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "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-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "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=" + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "postcss": { + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "dependencies": { + "JSV": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/JSV/-/JSV-4.0.2.tgz", + "integrity": "sha1-0Hf2glVx+CEy+d/67Vh7QCn+/1c=" + }, + "abbrev": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=" + }, + "accepts": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz", + "integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=", + "requires": { + "mime-types": "~2.1.11" + } + }, + "alea": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/alea/-/alea-0.0.9.tgz", + "integrity": "sha1-9zjLRfg0MAafRc9pzL8xLdV6nho=" + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=" + }, + "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": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "argparse": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", + "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "asap": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.5.tgz", + "integrity": "sha1-UidltQw1EEkOUtfc/ghe+bqWlY8=" + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" + }, + "assert-plus": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=" + }, + "assertion-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.2.tgz", + "integrity": "sha1-E8pRXYYgbaC6xm6DTdOX2HWBCUw=" + }, + "async": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "aws-sign2": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=" + }, + "aws4": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.5.0.tgz", + "integrity": "sha1-Cin/t5wxyecS7rCH6OemS0pW11U=" + }, + "babel-runtime": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.20.0.tgz", + "integrity": "sha1-hzAL3PTNdw8JvwBIxkIE4XgG0W8=", + "requires": { + "core-js": "^2.4.0" + } + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "pre-commit": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/pre-commit/-/pre-commit-1.2.2.tgz", + "integrity": "sha1-287g7p3nI15X95xW186UZBpp7sY=", + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "spawn-sync": "^1.0.15", + "which": "1.2.x" + }, + "dependencies": { + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "which": { + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", + "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "dev": true + }, + "preq": { + "version": "0.5.14", + "resolved": "https://registry.npmjs.org/preq/-/preq-0.5.14.tgz", + "integrity": "sha512-kuJ5ndEgjs27kTTQ/P2ipPQoHeCJcAI4i97mU3xSjkjx6CsuQOsCe2l5twTGC0SCB5UkzRpmrpXmvN0Ip4ZCxA==", + "requires": { + "bluebird": "^3.5.5", + "request": "^2.88.0", + "requestretry": "4.0.2" + } + }, + "prfun": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/prfun/-/prfun-2.1.5.tgz", + "integrity": "sha512-UCDQscAfQ1HArwvSUobJWbc3sTGLqGpYkRqXUpBZgf+zOWpOjz2dxnpRsOu+qxIj1K0n5UT1wgbCCgetsIwiug==", + "requires": { + "core-js": "^2.5.3" + } + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", + "dev": true + }, + "proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.1" + } + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true, + "optional": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "psl": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz", + "integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==" + }, + "pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "pupa": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.0.1.tgz", "integrity": "sha512-hEJH0s8PXLY/cdXh66tNEQGndDrIKNqNC5xmrysZy3i5C3oEoLna7YAOad+7u125+zH1HNXUmGEkrhb3c2VriA==", @@ -4862,6 +8253,12 @@ "es6-error": "^4.0.1" } }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "optional": true + }, "request": { "version": "2.88.2", "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", @@ -4950,6 +8347,15 @@ "signal-exit": "^3.0.2" } }, + "right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "optional": true, + "requires": { + "align-text": "^0.1.1" + } + }, "rimraf": { "version": "2.4.5", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", @@ -5678,6 +9084,60 @@ "is-typedarray": "^1.0.0" } }, + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "optional": true, + "requires": { + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" + }, + "dependencies": { + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "optional": true + }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "optional": true, + "requires": { + "center-align": "^0.1.1", + "right-align": "^0.1.1", + "wordwrap": "0.0.2" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "optional": true + }, + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "optional": true, + "requires": { + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", + "window-size": "0.1.0" + } + } + } + }, + "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=", + "optional": true + }, "undefsafe": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", @@ -5987,12 +9447,24 @@ } } }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", + "optional": true + }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true }, + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "optional": true + }, "wrap-ansi": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", diff --git a/package.json b/package.json index 87d8451b..b957acd9 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,9 @@ }, "homepage": "https://www.mediawiki.org/wiki/RESTBase_services_for_apps", "dependencies": { + "@root/encoding": "^1.0.1", + "parsoid-jsapi": "^0.0.1", + "prfun": "^2.1.4", "banana-i18n": "^1.3.1", "bluebird": "^3.7.2", "body-parser": "^1.19.0", diff --git a/routes/page/significant-events.js b/routes/page/significant-events.js new file mode 100644 index 00000000..1ec68e79 --- /dev/null +++ b/routes/page/significant-events.js @@ -0,0 +1,2234 @@ +const router = require('../../lib/util').router(); +const mUtil = require('../../lib/mobile-util'); +const mwapi = require('../../lib/mwapi'); +const mwrestapi = require('../../lib/mwrestapi'); +const BBPromise = require('bluebird'); +const api = require('../../lib/api-util'); +const express = require('express'); +const parsoidApi = require('../../lib/parsoid-access'); +const encoding = require('@root/encoding'); +const ParsoidJS = require('parsoid-jsapi'); +const PRFunPromise = require('prfun'); +const tUtil = require('../../lib/talk/TalkPageTopicUtilities'); +const NodeType = require('../../lib/nodeType'); +let app; + +const significantChangesCache = {}; +const maxAllowedCachedArticleSignificantEvents = 100; + +const tagReplacements = { + A: 'a', + B: 'b', + I: 'i', + SUP: 'sup', + SUB: 'sub', + DT: 'b', + CODE: 'b', + BIG: 'b', + LI: 'li', + OL: 'ol', + UL: 'ul', + DL: 'ul', + DD: 'li' +}; + +const tagsToRemoveEntirely = 'script,style'; +const tagsToRemoveButKeepContents = new Set(['P', 'DIV', 'SPAN']); +const escapeRegex = /[<>]/g; +const escapeMap = { + '<': '<', + '>': '>', + '&': '&' +}; +const attributesToRemoveMap = { + style: true, + id: true, + class: true, + rel: true, + about: true, + 'data-mw': true, + typeof: true +}; + +const escape = text => { + return text.replace(escapeRegex, (match) => { + return escapeMap[match] || ''; + }); +}; + +class CharacterChangeWithSections { + constructor(counts, addedSections, deletedSections) { + this.counts = counts; + this.addedSections = addedSections; + this.deletedSections = deletedSections; + } +} + +class CharacterChange { + constructor(addedCount, deletedCount) { + this.addedCount = addedCount; + this.deletedCount = deletedCount; + } + + totalCount() { + return this.addedCount + this.deletedCount; + } +} + +class SmallOutputExtended { + constructor(revid, parentid, timestamp, user, userid) { + this.revid = revid; + this.parentid = parentid; + this.timestamp = timestamp; + this.outputType = 'small-change'; + this.user = user; + this.userid = userid; + } +} + +class SmallOutput { + constructor(smallOutputExtended) { + this.revid = smallOutputExtended.revid; + this.parentid = smallOutputExtended.parentid; + this.timestamp = smallOutputExtended.timestamp; + this.outputType = 'small-change'; + } +} + +class VandalismOutput { + constructor(revid, parentid, timestamp, user, userid, sections) { + this.revid = revid; + this.parentid = parentid; + this.timestamp = timestamp; + this.outputType = 'vandalism-revert'; + this.user = user; + this.userid = userid; + this.sections = sections; + } +} + +class NewReferenceOutput { + constructor(sections, templates) { + this.outputType = 'new-template'; + this.sections = sections; + this.templates = templates; + } +} + +class AddedTextOutputExpanded { + constructor(characterChangeWithSections, snippet, snippetType, snippetHighlightRanges) { + this.outputType = 'added-text'; + this.snippet = snippet; + this.snippetType = snippetType; + this.snippetHighlightRanges = snippetHighlightRanges; + this.characterCount = characterChangeWithSections.counts.addedCount; + this.sections = characterChangeWithSections.addedSections; + } +} + +class AddedTextOutput { + constructor(addedTextOutputExpanded) { + this.outputType = addedTextOutputExpanded.outputType; + this.snippet = addedTextOutputExpanded.snippet; + this.snippetType = addedTextOutputExpanded.snippetType; + this.characterCount = addedTextOutputExpanded.characterCount; + this.sections = addedTextOutputExpanded.sections; + } +} + +class DeletedTextOutput { + constructor(characterChangeWithSections) { + this.outputType = 'deleted-text'; + this.characterCount = characterChangeWithSections.counts.deletedCount; + this.sections = characterChangeWithSections.deletedSections; + } +} + +class LargeOutput { + constructor(largeOutputExpanded) { + this.revid = largeOutputExpanded.revid; + this.parentid = largeOutputExpanded.parentid; + this.timestamp = largeOutputExpanded.timestamp; + this.outputType = 'large-change'; + this.user = largeOutputExpanded.user; + this.userid = largeOutputExpanded.userid; + this.significantChanges = largeOutputExpanded.significantChanges; + } +} + +class LargeOutputExpanded { + constructor(revid, parentid, timestamp, user, userid, significantChanges) { + this.revid = revid; + this.parentid = parentid; + this.timestamp = timestamp; + this.outputType = 'large-change'; + this.user = user; + this.userid = userid; + this.significantChanges = significantChanges; + } +} + +class NewTalkPageTopicExtended { + constructor(revid, parentid, timestamp, user, userid, snippet, type, highlightRanges, + characterChange, section) { + this.revid = revid; + this.parentid = parentid; + this.timestamp = timestamp; + this.outputType = 'new-talk-page-topic'; + this.snippet = snippet; + this.type = type; + this.highlightRanges = highlightRanges; + this.user = user; + this.userid = userid; + this.characterChange = characterChange; + this.section = section; + } +} + +class NewTalkPageTopic { + constructor(newTalkPageTopicExpanded) { + this.revid = newTalkPageTopicExpanded.revid; + this.parentid = newTalkPageTopicExpanded.parentid; + this.timestamp = newTalkPageTopicExpanded.timestamp; + this.outputType = 'new-talk-page-topic'; + this.snippet = newTalkPageTopicExpanded.snippet; + this.user = newTalkPageTopicExpanded.user; + this.userid = newTalkPageTopicExpanded.userid; + this.section = newTalkPageTopicExpanded.section; + } +} + +class PreformattedSnippet { + constructor(revid, outputType, snippet, snippetType, snippetHighlightRanges, + indexOfSignificantChanges) { + this.revid = revid; + this.outputType = outputType; + this.snippet = snippet; + this.snippetType = snippetType; + this.snippetHighlightRanges = snippetHighlightRanges; + this.indexOfSignificantChanges = indexOfSignificantChanges; + } +} + +function getThreshold(req) { + return 100; +} + +function insertSubstringInString(originalString, substring, index) { + if (index > 0) { + return originalString.substring(0, index) + substring + originalString.substring(index, + originalString.length); + } + + return substring + originalString; +} + +function stringByRemovingSubstring(originalString, beginningIndex, endIndex) { + const firstSubstring = originalString.substring(0,beginningIndex); + const secondSubstring = originalString.substring(endIndex); + return firstSubstring + secondSubstring; +} + +const diffAndRevisionPromise = (req, revision) => { + if (revision.parentid === null || revision.parentid === undefined || revision.parentid === 0) { + return Object.assign({ + revision: revision, + body: null + }); + } + return mwrestapi.queryForDiff(req, revision.parentid, revision.revid) + .then( (response) => { + return Object.assign({ + revision: revision, + body: response.body + }); + }) + .catch(e => { + return Object.assign({ + revision: revision, + body: null + }); + }); +}; + +function removeNodeButPreserveContents(node) { + while (node.childNodes.length > 0) { + const firstChild = node.firstChild; + if (firstChild) { + node.parentNode.insertBefore(firstChild, node); + } + } + node.parentNode.removeChild(node); +} + +function renameNodeAndClearOutAttributes(doc, node, newNodeName) { + + // first clear out attributes + for (var i = 0; i < node.attributes.length; i++) { + var attrib = node.attributes[i]; + if (attributesToRemoveMap[attrib] === true) { + node.removeAttribute(attrib); + } + } + + // then rename node if necessary + if (node.tagName.toLowerCase() === newNodeName.toLowerCase()) { + return; + } + + var newNode = doc.createElement(newNodeName); + newNode.innerHTML = node.innerHTML; + node.parentNode.replaceChild(newNode, node); +} + +function recursivelyEvaluateNode(doc, node) { + + if (node.nodeType === NodeType.ELEMENT_NODE) { + const sub = tagReplacements[node.tagName]; + + if (!sub) { + if (tagsToRemoveButKeepContents.has(node.tagName)) { + removeNodeButPreserveContents(node); + } else { + if (node.tagName !== 'BODY') { + node.parentNode.removeChild(node); + } + } + } else { + renameNodeAndClearOutAttributes(doc, node, sub); + } + } else if (node.nodeType === NodeType.TEXT_NODE) { + node.textContent = escape(node.textContent); + } + + if (node.childElementCount > 0) { + Array.from(node.children).forEach(child => { + recursivelyEvaluateNode(doc, child); + }); + } +} + +class UnexpectedSnippetFormatError extends Error { + constructor(message) { + super(message); + this.name = 'UnexpectedSnippetFormatError'; + } +} + +const formattedSnippetFromTextPromise = (req, text) => { + + const headers = Object.assign( { + accept: 'text/html', + profile: 'https://www.mediawiki.org/wiki/Specs/Mobile-HTML/1.0.0', + 'content-type': 'multipart/form-data', + 'output-mode': 'editPreview' + }); + + const formData = Object.assign({ + wikitext: text + }); + + const request = Object.assign({ + method: 'post', + uri: `https://en.wikipedia.org/api/rest_v1/transform/wikitext/to/mobile-html/${req.params.title}`, + query: {}, + headers: headers, + body: formData + }); + + return req.issueRequest(request) + .then( (response) => { + return mUtil.createDocument(response.body); + }).then( (response) => { + + // removing tags here + const elementsToRemove = response.querySelectorAll(tagsToRemoveEntirely); + const elementsToRemoveList = Array.prototype.slice.call(elementsToRemove); + const references = response.body.getElementsByClassName('mw-references-wrap'); + const referencesList = Array.prototype.slice.call(references); + const finalListToStrip = elementsToRemoveList.concat(referencesList); + finalListToStrip.forEach( (script) => { + script.parentNode.removeChild(script); + }); + + // mobile-html endpoint seems to return a wrapper pcs, section and paragraph element. + // strip these out as well. + + const pcsElement = response.getElementById('pcs'); + if (pcsElement) { + const section = pcsElement.firstChild; + if (section.tagName === 'SECTION') { + removeNodeButPreserveContents(section); + } + + const paragraph = pcsElement.firstChild; + if (paragraph && paragraph.tagName === 'P') { + removeNodeButPreserveContents(paragraph); + } + } else { + throw new UnexpectedSnippetFormatError(); + } + + removeNodeButPreserveContents(pcsElement); + + // now walk remaining doc elements and strip unsupported elements + + recursivelyEvaluateNode(response, response.body); + + return response; + }) + .then((response) => { + return response.body.innerHTML; + }) + .catch( (e) => { + return null; + }); +}; + +const snippetPromise = (req, preformattedSnippet) => { + + if (preformattedSnippet.snippet === null || + preformattedSnippet.snippet === undefined || + preformattedSnippet.snippetType === null || + preformattedSnippet.snippetType === undefined || + preformattedSnippet.snippetType === 2) { + // deleted complete line type. + // we shouldn't get here but gracefully return null for snippet without trying to + // format + preformattedSnippet.snippet = null; + return preformattedSnippet; + } + + var strippedSnippet; + const addHighlightStart = 'ioshighlightstart'; + const highlightEnd = 'ioshighlightend'; + + const addHighlightStartBin = encoding.strToBin(addHighlightStart); + const highlightEndBin = encoding.strToBin(highlightEnd); + + // strip deleted ranges from snippet + // add added delimiters to type 3 & 5 snippet (Added and deleted words in line) + // delimiters are later used for truncation starting point + if (preformattedSnippet.outputType === 'large-change') { + var snippetBinary = encoding.strToBin(preformattedSnippet.snippet); + switch (preformattedSnippet.snippetType) { + case 1: // Added complete line + break; + case 2: // Deleted complete line + // should be caught earlier + break; + case 5: + case 3: // Added and deleted words in line + + if (preformattedSnippet.snippetHighlightRanges === null || + preformattedSnippet.snippetHighlightRanges === undefined) { + break; + } + + // first strip deleted text + for (var d = preformattedSnippet.snippetHighlightRanges.length - 1; d >= 0; d-- ) { + const range = preformattedSnippet.snippetHighlightRanges[d]; + + switch (range.type) { + case 0: // Added + break; + case 1: // Deleted + snippetBinary = stringByRemovingSubstring(snippetBinary, range.start, + range.start + range.length); + + for (var i = d; i < preformattedSnippet.snippetHighlightRanges.length; + i++) { + const iRange = preformattedSnippet.snippetHighlightRanges[i]; + switch (iRange.type) { + case 0: // Added + iRange.start -= range.length; + preformattedSnippet.snippetHighlightRanges[i] = iRange; + break; + case 1: // Deleted + break; + default: + break; + } + } + break; + default: + break; + } + } + + // filter out deleted ranges + // eslint-disable-next-line no-case-declarations + const addedHighlightRanges = preformattedSnippet.snippetHighlightRanges + .filter(range => range.type !== null && range.type !== undefined && + range.type === 0); + + // then add added text delimiters + var addOffset = 0; + addedHighlightRanges.forEach(function (range) { + switch (range.type) { + case 0: // Added + if (range.start === null || range.start === undefined) { + break; + } + snippetBinary = insertSubstringInString(snippetBinary, + addHighlightStartBin, range.start + addOffset); + addOffset += addHighlightStartBin.length; + break; + case 1: // Deleted + break; + default: + break; + } + + snippetBinary = insertSubstringInString(snippetBinary, highlightEndBin, + range.start + addOffset + range.length); + addOffset += highlightEndBin.length; + }); + break; + default: + break; + } + + strippedSnippet = encoding.binToStr(snippetBinary); + } else { // new talk page topic + strippedSnippet = preformattedSnippet.snippet; + } + + // make request to format to mobile-html, reassign result back to snippet + return formattedSnippetFromTextPromise(req, strippedSnippet) + .then( (response) => { + // truncate snippet if needed + // note: there's an interesting case where the existence of the delimiters changes the + // output. In this case being next to + // a wikitext link caused Parsoid to think that this was a new wikitext article + // rather than an existing one. I'm forging ahead as I think the worst that could + // happen is a missing link + // but if other issues occur, we should remove delimiters. With that we would lose + // all possibility of stretch goal highlighting + // and truncation + + if (!response) { + preformattedSnippet.snippet = null; + return preformattedSnippet; + } + + var truncatedSnippet = response; + if (preformattedSnippet.snippetType !== undefined && + preformattedSnippet.snippetType !== null && + preformattedSnippet.snippetType === 5 || preformattedSnippet.snippetType === 3) { + // try to trim the areas before the first ioshighlightstart and after the last + // ioshighlight start so snippet is + // focused on area that changed + const firstStart = response.indexOf('ioshighlightstart'); + const lastStart = response.lastIndexOf('ioshighlightend'); + + // early exit here - some highlighting was inadvertantly pruned out, + // so don't attempt to truncate or preserve highlight delimiters + if (firstStart === -1 || lastStart === -1) { + if (firstStart === -1 && lastStart !== -1) { + truncatedSnippet = truncatedSnippet.replace(/ioshighlightend/g, ''); + } + + if (firstStart !== -1 && lastStart === -1) { + truncatedSnippet = truncatedSnippet.replace(/ioshighlightstart/g, ''); + } + + preformattedSnippet.snippet = truncatedSnippet; + return preformattedSnippet; + } + + // If highlighting starts at the beginning of the line, don't + // truncate or prepend ... + // Otherwise truncate and prepend ... + // all lines truncate at the last highlight end line and suffix with ... + // regardless if + // it's the last thing in the snippet. + var newTruncatedSnippet = truncatedSnippet.slice(0, lastStart + 'ioshighlightend'.length); + newTruncatedSnippet = newTruncatedSnippet.concat('...'); + if (firstStart > 0) { + newTruncatedSnippet = newTruncatedSnippet.slice(firstStart); + newTruncatedSnippet = '...'.concat(newTruncatedSnippet); + } + + const minLengthForTruncation = 'ioshighlightstart'.length + 'ioshighlightend'.length + '...'.length + '...'.length + 20; + if (newTruncatedSnippet.length > minLengthForTruncation) { + truncatedSnippet = newTruncatedSnippet; + } + + // UNCOMMENT THIS LINE IF HIGHLIGHTING IS NOT WORTH IT + // truncatedSnippet = truncatedSnippet.replace(/ioshighlightstart/g, '') + // .replace(/ioshighlightend/g, ''); + } + + truncatedSnippet = truncatedSnippet.replace(/ioshighlightstart/g, '').replace(/ioshighlightend/g, ''); + preformattedSnippet.snippet = truncatedSnippet; + return preformattedSnippet; + }); +}; + +const snippetPromises = (req, preformattedSnippets) => { + return BBPromise.map(preformattedSnippets, function(preformattedSnippet) { + return snippetPromise(req, preformattedSnippet); + }); +}; + +const diffAndRevisionPromises = (req, revisions) => { + return BBPromise.map(revisions, function(revision) { + return diffAndRevisionPromise(req, revision); + }); +}; + +function getTalkPageTitle(req) { + return `Talk:${req.params.title}`; +} + +const talkPageRevisionsPromise = (req, rvStart, rvEnd) => { + return mwapi.queryForRevisions(req, getTalkPageTitle(req), 100, rvStart, rvEnd ) + .catch(e => { + return null; + }); +}; + +function keyTitleForCache(req, title) { + var keyTitle = title || req.params.title; + const threshold = getThreshold(req); + keyTitle = `${threshold}-${keyTitle}`; + + return keyTitle; +} + +function getCachedAndUncachedItems(revisions, req, title) { + + // add cache to output and filter out of processing flow + const uncachedRevisions = []; + const cachedOutput = []; + + if (!revisions) { + return Object.assign({ + uncachedRevisions: [], + cachedOutput: [] + }); + } + + const keyTitle = keyTitleForCache(req, title); + for (var i = 0; i < revisions.length; i++) { + const revision = revisions[i]; + const domainDict = significantChangesCache[req.params.domain]; + if (domainDict) { + const titleDict = domainDict[keyTitle]; + if (titleDict) { + const cacheItem = titleDict[revision.revid]; + if (cacheItem) { + cachedOutput.push(cacheItem); + continue; + } + } + } + + uncachedRevisions.push(revision); + } + + return Object.assign({ + uncachedRevisions: uncachedRevisions, + cachedOutput: cachedOutput + }); +} + +function outputTypeCountsTowardsCache(outputType) { + return outputType === 'large-change' || outputType === 'vandalism-revert'; +} + +function calculateCacheForTitleIsMaxedOut(titleDict) { + // eslint-disable-next-line no-restricted-properties + var titleArray = Object.values(titleDict); + if (titleArray.length > 0) { + titleArray.pop(); // remove maxedOut element + const filteredObjects = titleArray.filter(outputObject => + outputTypeCountsTowardsCache(outputObject.outputType)); + return filteredObjects.length >= maxAllowedCachedArticleSignificantEvents; + } + + return false; +} + +function cacheForTitleIsMaxedOut(req, title) { + const keyTitle = keyTitleForCache(req, title); + var domainDict = significantChangesCache[req.params.domain]; + if (domainDict) { + var titleDict = domainDict[keyTitle]; + if (titleDict) { + if (titleDict.maxedOut) { + return true; + } + } + } + + return false; +} + +function latestAndEarliestCachedRevisionTimestamp(req, title) { + var domainDict = significantChangesCache[req.params.domain]; + const keyTitle = keyTitleForCache(req, title); + if (domainDict) { + var titleDict = domainDict[keyTitle]; + if (titleDict) { + // eslint-disable-next-line no-restricted-properties + var titleArray = Object.values(titleDict); + if (titleArray.length > 0) { + titleArray.pop(); // remove maxedOut element + const sortedTitleObjects = titleArray.sort(function (a, b) { + return new Date(b.timestamp) - new Date(a.timestamp); + }); + var latestTimestamp = null; + var earliestTimestamp = null; + if (sortedTitleObjects.length > 0) { + latestTimestamp = sortedTitleObjects[0].timestamp; + earliestTimestamp = sortedTitleObjects[sortedTitleObjects.length - 1].timestamp; + } + + return Object.assign( { + latestTimestamp: latestTimestamp, + earliestTimestamp: earliestTimestamp + }); + } + } + } + + return null; +} + +function setSignificantChangesCache(req, title, item) { + const keyTitle = keyTitleForCache(req, title); + var domainDict = significantChangesCache[req.params.domain] || {}; + var titleDict = domainDict[keyTitle] || {}; + titleDict[item.revid] = item; + titleDict.maxedOut = calculateCacheForTitleIsMaxedOut(titleDict); + domainDict[keyTitle] = titleDict; + significantChangesCache[req.params.domain] = domainDict; +} + +function cleanupCache(req) { + // cleanup article cache + var domainDict = significantChangesCache[req.params.domain]; + const articleTitle = keyTitleForCache(req, null); + if (domainDict) { + var titleDict = domainDict[articleTitle]; + if (titleDict) { + // eslint-disable-next-line no-restricted-properties + var titleArray = Object.values(titleDict); + if (titleArray.length > 0) { + titleArray.pop(); // remove maxedOut element + + const sortedTitleArray = titleArray.sort(function(a, b) { + if (a.timestamp && b.timestamp) { + return new Date(b.timestamp) - new Date(a.timestamp); + } + return 0; + }); + const significantCachedObjects = sortedTitleArray.filter(outputObject => { + if (outputObject.outputType) { + return outputTypeCountsTowardsCache(outputObject.outputType); + } + + return false; + }); + + const delta = significantCachedObjects.length - + maxAllowedCachedArticleSignificantEvents; + + var timestampCutoff = null; + if (delta > 0 && delta < significantCachedObjects.length && + significantCachedObjects.length > 0) { + const significantCachedObject = + significantCachedObjects[significantCachedObjects.length - delta - 1]; + timestampCutoff = significantCachedObject.timestamp; + } + + // clean out all cached article and cached talk page revisions + // after the 100th significant event + if (timestampCutoff) { + const cutoffDate = new Date(timestampCutoff); + + // clean out from article cache + for (var s = sortedTitleArray.length - 1; s >= 0; s--) { + const sortedObjectToConsider = sortedTitleArray[s]; + if (sortedObjectToConsider.timestamp !== null && + sortedObjectToConsider.timestamp !== undefined) { + const objectDate = new Date(sortedObjectToConsider.timestamp); + if (objectDate < cutoffDate) { + delete titleDict[sortedObjectToConsider.revid]; + } else { + break; + } + } + } + + // clean out from talk page cache + var talkPageTitle = getTalkPageTitle(req); + const keyTalkPageTitle = keyTitleForCache(req, talkPageTitle); + var talkPageTitleDict = domainDict[keyTalkPageTitle]; + if (talkPageTitleDict) { + // eslint-disable-next-line no-restricted-properties + var talkPageTitleArray = Object.values(talkPageTitleDict); + if (talkPageTitleArray.length > 0) { + talkPageTitleArray.pop(); // remove maxedOut element + const sortedTalkPageTitleArray = + talkPageTitleArray.sort(function(a, b) { + return new Date(b.timestamp) - new Date(a.timestamp); + }); + + for (var t = sortedTalkPageTitleArray.length - 1; t >= 0; t--) { + const sortedTalkObjectToConsider = sortedTalkPageTitleArray[t]; + const talkObjectDate = new + Date(sortedTalkObjectToConsider.timestamp); + if (talkObjectDate < cutoffDate) { + delete talkPageTitleDict[sortedTalkObjectToConsider.revid]; + } else { + break; + } + } + } + } + } + } + + } + } +} + +function getSummaryText(req) { + var domainDict = significantChangesCache[req.params.domain]; + const articleTitle = keyTitleForCache(req, null); + if (domainDict) { + var titleDict = domainDict[articleTitle]; + if (titleDict) { + // eslint-disable-next-line no-restricted-properties + var titleArray = Object.values(titleDict); + if (titleArray.length > 0) { + titleArray.pop(); // remove maxedOut element + const sortedTitleArray = titleArray.sort(function (a, b) { + return new Date(b.timestamp) - new Date(a.timestamp); + }); + const earliestItem = sortedTitleArray[sortedTitleArray.length - 1]; + if (earliestItem.timestamp !== undefined && earliestItem.timestamp !== null) { + const earliestTimestamp = earliestItem.timestamp; + var userids = []; + for (var i = 0; i <= titleArray.length - 1; i++) { + const object = titleArray[i]; + userids.push(object.userid); + } + var dedupedUserIds = new Set(userids); + const numUsers = dedupedUserIds.size; + + return Object.assign({ + earliestTimestamp: earliestTimestamp, + numChanges: titleArray.length, + numUsers: numUsers + }); + } + } + } + } + + return Object.assign( { + earliestTimestamp: null, + dedupedUserIds: null, + numUsers: null + }); +} + +function textWithHtmlCommentsStripped(text) { + + if (text === null || text === undefined) { + return null; + } + + return text.replace(/)/g, ''); +} + +function getSectionForDiffLine(diffBody, diffLine) { + + if (!diffBody || !diffLine) { + return null; + } + + var fromSection = null; + var toSection = null; + + // safety + if (!diffBody.from || + !diffBody.from.sections || + !diffBody.to || + !diffBody.to.sections || + !diffLine.offset) { + return null; + } + + // capture intro + if ((!diffBody.from.sections || + diffBody.from.sections.length === 0) && + (!diffBody.to.sections || + diffBody.to.sections.length === 0)) { + return null; + } + + // diffLine.offset.from = 0 is still valid if it's at the very beginning of the article. + // In this case javascript evaluates diffLine.offset.from to false, + // hence the need for the separate check. + if ((diffLine.offset.from || diffLine.offset.from === 0) && + diffBody.from.sections && diffBody.from.sections.length > 0 && + diffLine.offset.from < diffBody.from.sections[0].offset) { + fromSection = 'Intro'; + } + + if ((diffLine.offset.to || diffLine.offset.to === 0) && + diffBody.to.sections && diffBody.to.sections.length > 0 && + diffLine.offset.to < diffBody.to.sections[0].offset) { + toSection = 'Intro'; + } + + if (fromSection && toSection) { + if (diffLine.offset.to && diffLine.offset.to.length > 0) { + return textWithHtmlCommentsStripped(toSection); + } else { + return textWithHtmlCommentsStripped(fromSection); + } + } + + var prevSection = null; + if (!fromSection && diffLine.offset.from) { + for (let i = 0; i < diffBody.from.sections.length; i++) { + const section = diffBody.from.sections[i]; + + if (diffLine.offset.from < section.offset && prevSection) { + if (prevSection.heading) { + fromSection = prevSection.heading; + break; + } + } + + prevSection = section; + } + + if (!fromSection && diffLine.offset.from > 0 && diffBody.from.sections.length > 0) { + if (prevSection.heading) { + fromSection = prevSection.heading; + } + + } + } + + if (!toSection && diffLine.offset.to) { + prevSection = null; + for (let i = 0; i < diffBody.to.sections.length; i++) { + + const section = diffBody.to.sections[i]; + if (diffLine.offset.to < section.offset && prevSection) { + if (prevSection.heading) { + toSection = prevSection.heading; + break; + } + } + + prevSection = section; + } + + if (!toSection && diffLine.offset.to > 0 && diffBody.to.sections.length > 0) { + if (prevSection.heading) { + toSection = prevSection.heading; + } + } + } + + if (diffLine.offset.to || diffLine.offset.to === 0) { + // 0 is a valid value, but without explicit check JS sees it as invalid + return textWithHtmlCommentsStripped(toSection); + } else { + return textWithHtmlCommentsStripped(fromSection); + } +} + +function updateDiffAndRevisionsWithCharacterCount(diffAndRevisions) { + + if (!diffAndRevisions) { + return; + } + + // Loop through diffs, filter out type 0 (context type) and assign byte change properties + // to the remaining + + for (var i = 0; i < diffAndRevisions.length; i++) { + const diffAndRevision = diffAndRevisions[i]; + + if (!diffAndRevision.body || !diffAndRevision.body.diff) { + continue; + } + + var filteredDiffs = []; + + var aggregateAddedCount = 0; + var aggregateDeletedCount = 0; + var aggregateAddedSections = new Set(); + var aggregateDeletedSections = new Set(); + + for (var d = 0; d < diffAndRevision.body.diff.length; d++) { + const diff = diffAndRevision.body.diff[d]; + + if (diff.type === undefined || + diff.type === null || + diff.text === undefined || + diff.text === null) { + continue; + } + + var lineAddedCount = 0; + var lineDeletedCount = 0; + switch (diff.type) { + case 0: // Context line type + continue; + case 1: // Add complete line type + lineAddedCount = diff.text.length; + break; + case 2: // Delete complete line type + lineDeletedCount = diff.text.length; + break; + case 5: // Move paragraph destination type (also has added and deleted + // ranges in line) + // eslint-disable-next-line no-fallthrough + case 3: // Change line type (add and deleted ranges in line) + + if (diff.highlightRanges === undefined || + diff.highlightRanges === null) { + break; + } + + for (var h = 0; h < diff.highlightRanges.length; h++) { + const range = diff.highlightRanges[h]; + + if (range.start === null || + range.start === undefined || + range.length === null || + range.length === undefined) { + continue; + } + + const binaryText = encoding.strToBin(diff.text); + const binaryRangeText = binaryText.substring(range.start, + range.start + range.length); + const rangeText = encoding.binToStr(binaryRangeText); + const lengthToCalculate = rangeText.length; + + switch (range.type) { + case 0: // Add range type + lineAddedCount += lengthToCalculate; + break; + case 1: // Delete range type + lineDeletedCount += lengthToCalculate; + break; + default: + break; + } + } + break; + default: + break; + } + + aggregateAddedCount += lineAddedCount; + aggregateDeletedCount += lineDeletedCount; + + if (lineAddedCount > 0 ) { + const section = getSectionForDiffLine(diffAndRevision.body, diff); + if (section) { + aggregateAddedSections.add(section); + } + } + + if (lineDeletedCount > 0) { + const section = getSectionForDiffLine(diffAndRevision.body, diff); + if (section) { + aggregateDeletedSections.add(section); + } + } + + diff.characterChange = new CharacterChange(lineAddedCount, lineDeletedCount); + filteredDiffs.push(diff); + } + + const aggregateCounts = new CharacterChange(aggregateAddedCount, aggregateDeletedCount); + diffAndRevision.characterChangeWithSections = new CharacterChangeWithSections( + aggregateCounts, Array.from(aggregateAddedSections), + Array.from(aggregateDeletedSections)); + diffAndRevision.body.diff = filteredDiffs; + } +} + +function templateNamesToCallOut() { + return ['cite', 'citation', 'short description']; +} + +function needsToParseForAddedTemplates(text, includeOpeningBraces) { + + if (text === undefined || + text === null || + includeOpeningBraces === undefined || + includeOpeningBraces === null) { + return false; + } + + const names = templateNamesToCallOut(); + + for (var n = 0; n < names.length; n++) { + const name = names[n]; + + if ((text.includes(`{{${name}`) && includeOpeningBraces) || (text.includes(`${name}`) && + !includeOpeningBraces)) { + + if (!text.includes('citation needed')) { + return true; + } + } + } + + return false; +} + +// BUG: https://en.wikipedia.org/w/index.php?title=United_States&type=revision +// &diff=965295364&oldid=965071033 +// Should we be catching added tags? +// ANOTHER BUG: +// Sometimes new citations have spaces within deemed the same, so only part of it +// is sent in as text whereas we need all of cite. +// See here +// https://en.wikipedia.org/w/index.php?title=United_States&type=revision&diff=971349395&oldid=971332725 +// Also this one +// https://en.wikipedia.org/w/index.php?title=United_States&type=revision&diff=971260075&oldid=971259267 +// Definitely some mangled 'added-text' snippets going on here. +// https://en.wikipedia.org/w/index.php?title=United_States&type=revision&diff=970665187&oldid=970577931 +function structuredTemplatePromise(text, diffItem, revision) { + return new BBPromise((resolve) => { + var main = PRFunPromise.async(function*() { + var pdoc = yield ParsoidJS.parse(text, { pdoc: true }); + const splitTemplates = yield PRFunPromise.map(pdoc.filterTemplates(), + ParsoidJS.toWikitext); + var templateObjects = []; + + // Note: for now just grabbing the first split template + // (which includes only parent templates and not nested) + // to avoid duplicate template problem. If we need nested support we can loop through + // all split templates, then uniquely identify and dedupe templates later. + if (splitTemplates.length === 0) { + // bail early + const result = Object.assign( { + revision: revision, + diffItem: diffItem, + templates: templateObjects + }); + resolve(result); + return; + } + for (var s = 0; s < 1; s++) { + const splitTemplateText = splitTemplates[s]; + + const innerPdoc = yield ParsoidJS.parse(splitTemplateText, { pdoc: true }); + const individualTemplates = innerPdoc.filterTemplates(); + if (individualTemplates !== undefined && individualTemplates !== null) { + for (var i = 0; i < individualTemplates.length; i++) { + const template = individualTemplates[i]; + + if (!needsToParseForAddedTemplates(template.name, false)) { + continue; + } + + if (template.name === undefined || + template.name === null || + template.params === undefined || + template.params === null) { + continue; + } + + var dict = {}; + dict.name = template.name; + for (var p = 0; p < template.params.length; p++) { + const param = template.params[p].name; + if (param !== undefined && param !== null) { + const value = yield template.get(param).value.toWikitext(); + dict[param] = value; + } + } + templateObjects.push(dict); + } + } + } + const result = Object.assign( { + revision: revision, + diffItem: diffItem, + templates: templateObjects + }); + resolve(result); + }); + + main().done(); + }); +} + +function addStructuredTemplates(diffAndRevisions) { + + var promises = []; + + if (!diffAndRevisions) { + return Promise.all(promises) + .then( (response) => { + return diffAndRevisions; + }); + } + + for (var i = 0; i < diffAndRevisions.length; i++) { + const diffAndRevision = diffAndRevisions[i]; + + if (diffAndRevision.body === null || + diffAndRevision.body === undefined || + diffAndRevision.body.diff === null || + diffAndRevision.body.diff === undefined || + diffAndRevision.revision === null || + diffAndRevision.revision === undefined) { + continue; + } + + const addedLinesCount = diffAndRevision.body.diff.filter(diffItem => diffItem.type === 1) + .length; + if (addedLinesCount > 500) { + // This suggests some sort of mass change that would be too much work on the server + // to parse for templates. + // bypassing template detection in this case. + // this may be a good metric to tweak to boost performance + continue; + } + + for (var d = 0; d < diffAndRevision.body.diff.length; d++) { + const diffItem = diffAndRevision.body.diff[d]; + + if (diffItem.text === undefined || + diffItem.text === null) { + continue; + } + + switch (diffItem.type) { + case 1: // Add complete line type + if (needsToParseForAddedTemplates(diffItem.text, true)) { + promises.push(structuredTemplatePromise(diffItem.text, diffItem, + diffAndRevision.revision)); + } + break; + case 5: + case 3: { + + const binaryText = encoding.strToBin(diffItem.text); + var previousBinaryRangeText = null; + var previousRangeEndIndex = null; + for (var h = 0; h < diffItem.highlightRanges.length; h++) { + const range = diffItem.highlightRanges[h]; + + if (range.start === undefined || + range.start === null || + range.length === undefined || + range.length === null) { + continue; + } + + switch (range.type) { + case 0: { // Add range type + + const binaryRangeText = binaryText.substring(range.start, + range.start + range.length); + if (previousBinaryRangeText !== null && + previousRangeEndIndex !== null) { + + const inBetweenText = binaryText.substring( + previousRangeEndIndex, + range.start); + if (inBetweenText === ' ') { + previousBinaryRangeText += inBetweenText; + previousBinaryRangeText += binaryRangeText; + previousRangeEndIndex = range.start + range.length; + continue; + } else { + // before attempting to send off for template parsing, + // grab following '}}' to capture edge case templates + const nextTwoCharacters = binaryText + .substring(previousRangeEndIndex, + previousRangeEndIndex + 2); + if (nextTwoCharacters === '}}') { + previousBinaryRangeText += '}}'; + } + const rangeText = encoding + .binToStr(previousBinaryRangeText); + if (needsToParseForAddedTemplates(rangeText, + true)) { + promises.push(structuredTemplatePromise(rangeText, + diffItem, + diffAndRevision.revision)); + } + + previousBinaryRangeText = binaryRangeText; + previousRangeEndIndex = range.start + range.length; + } + + } else { + previousBinaryRangeText = binaryRangeText; + previousRangeEndIndex = range.start + range.length; + continue; + } + } + break; + case 1: // Deleted + previousRangeEndIndex = range.start + range.length; + + } + } + + // there's probably one last straggler range that we haven't checked + // due to how we're doing things + + if (previousBinaryRangeText !== null && previousRangeEndIndex !== null) { + + // before attempting to send off for template parsing, + // grab following '}}' to capture edge case templates + const nextTwoCharacters = binaryText.substring(previousRangeEndIndex, + previousRangeEndIndex + 2); + if (nextTwoCharacters === '}}') { + previousBinaryRangeText += '}}'; + } + + // also if first 2 characters start with '}}', it might throw things off + const firstTwoCharacters = previousBinaryRangeText.substring(0, + 2); + if (firstTwoCharacters === '}}') { + previousBinaryRangeText = previousBinaryRangeText.substring(2, + previousBinaryRangeText.length); + } + + const rangeText = encoding.binToStr(previousBinaryRangeText); + if (needsToParseForAddedTemplates(rangeText, true)) { + promises.push(structuredTemplatePromise(rangeText, diffItem, + diffAndRevision.revision)); + } + } + break; + } + default: + break; + } + } + } + + return Promise.all(promises) + .then( (response) => { + + // loop through responses, add to revision. + + diffAndRevisions.forEach( (diffAndRevision) => { + + var templatesAndDiffItems = []; + response.forEach( (item) => { + + if (item.revision !== null && + item.revision !== undefined && + diffAndRevision.revision !== null && + diffAndRevision.revision !== undefined && + item.templates !== null && + item.templates !== undefined && + item.templates.length > 0) { + if (item.revision.revid === diffAndRevision.revision.revid) { + const templateAndDiffItem = Object.assign({ + templates: item.templates, + diffItem: item.diffItem + }); + + templatesAndDiffItems.push(templateAndDiffItem); + } + } + }); + + diffAndRevision.templatesAndDiffItems = templatesAndDiffItems; + }); + + return diffAndRevisions; + }); +} + +function getNewTopicDiffAndRevisions(talkDiffAndRevisions) { + + if (talkDiffAndRevisions === null || + talkDiffAndRevisions === undefined) { + return null; + } + + const newSectionTalkPageDiffAndRevisions = []; + for (var index = 0; index < talkDiffAndRevisions.length; index++) { + const diffAndRevision = talkDiffAndRevisions[index]; + + if (diffAndRevision.revision === null || + diffAndRevision.revision === undefined || + diffAndRevision.revision.comment === null || + diffAndRevision.revision.comment === undefined || + diffAndRevision.revision.userid === null || + diffAndRevision.revision.userid === undefined || + diffAndRevision.revision.tags === null || + diffAndRevision.revision.tags === undefined) { + continue; + } + + if (diffAndRevision.revision.comment.toLowerCase().includes('new section') + && !diffAndRevision.revision.comment.toLowerCase() + .includes('semi-protected edit request') // don't show semi-protected edit requests + && diffAndRevision.revision.userid !== 4936590 // don't show signbot topics + && !diffAndRevision.revision.tags.includes('mw-reverted')) { // don't show mw-reverted posts + // see if this section was reverted in previous iterations + var wasUndoneOrRolledBackLater = false; + if (index - 1 > 0) { + var nextDiffAndRevision = talkDiffAndRevisions[index - 1]; + if (nextDiffAndRevision.revision.userid === 4936590) { // signbot, + // look for next revision + if (index - 2 > 0) { + nextDiffAndRevision = talkDiffAndRevisions[index - 2]; + } + } + if (nextDiffAndRevision.revision.tags.includes('mw-undo') || + nextDiffAndRevision.revision.tags.includes('mw-rollback')) { + wasUndoneOrRolledBackLater = true; + } + } + if (wasUndoneOrRolledBackLater === false) { + newSectionTalkPageDiffAndRevisions.push(diffAndRevision); + } + } + } + + return newSectionTalkPageDiffAndRevisions; +} + +function getAllChangedDiffLines(diffBody) { + const allChangedDiffLines = diffBody.diff.filter((item) => { + return item.type !== 0; + }); + return allChangedDiffLines; +} + +function getLargestDiffLine(diffBody) { + + if (diffBody === null || + diffBody === undefined || + diffBody.diff === null || + diffBody.diff === undefined) { + return null; + } + + diffBody.diff.sort(function(a, b) { + + if (b.characterChange === null || + b.characterChange === undefined || + a.characterChange === null || + a.characterChange === undefined) { + return 0; + } + + return b.characterChange.totalCount() - a.characterChange.totalCount(); + }); + + if (diffBody.diff.length > 0) { + const largestDiffLine = diffBody.diff[0]; + return largestDiffLine; + } + + return null; +} + +function getLargestDiffLineOfAdded(diffBody) { + + if (diffBody === null || + diffBody === undefined || + diffBody.diff === null || + diffBody.diff === undefined) { + return null; + } + + diffBody.diff.sort(function(a, b) { + + if (b.characterChange === null || + b.characterChange === undefined || + a.characterChange === null || + a.characterChange === undefined) { + return 0; + } + + return b.characterChange.addedCount - a.characterChange.addedCount; + }); + + if (diffBody.diff.length > 0) { + const largestDiffLine = diffBody.diff[0]; + return largestDiffLine; + } + + return null; +} + +function textContainsEmptyLineOrSection(text) { + if (text === null || + text === undefined) { + return false; + } + + const trimmedText = text.trim(); + return (trimmedText.length === 0 || text.includes('==')); +} + +function textContainsTemplate(text) { + + if (text === null || + text === undefined) { + return false; + } + + return text.includes('{{'); +} + +function getFirstDiffLineWithContent(diffBody) { + + if (diffBody === null || + diffBody === undefined || + diffBody.diff === null || + diffBody.diff === undefined) { + return null; + } + + const nonContextDiffLines = diffBody.diff.filter(diff => (diff.type !== null && + diff.type !== undefined && diff.text !== null && diff.text !== undefined + && diff.type > 0)); + const nonContextDiffLinesWithoutEmptyLineOrSectionsOrTemplates = + nonContextDiffLines.filter(diff => + !textContainsEmptyLineOrSection(diff.text) && !textContainsTemplate(diff.text)); + const nonContextDiffLinesWithoutEmptyLineOrSections = + nonContextDiffLines.filter(diff => !textContainsEmptyLineOrSection(diff.text)); + + if (nonContextDiffLines.length === 0) { + return null; + } + + // prefer to return a line without templates, otherwise try line with templates + if (nonContextDiffLinesWithoutEmptyLineOrSectionsOrTemplates.length > 0) { + return nonContextDiffLinesWithoutEmptyLineOrSectionsOrTemplates[0]; + } else if (nonContextDiffLinesWithoutEmptyLineOrSections.length > 0) { + return nonContextDiffLinesWithoutEmptyLineOrSections[0]; + } else { + return null; + } +} + +function sortOutput(output) { + + if (output === null || + output === undefined) { + return null; + } + + // sort by date + return output.sort(function(a, b) { + + if (b.timestamp === null || + b.timestamp === undefined || + a.timestamp === null || + a.timestamp === undefined) { + return 0; + } + + return new Date(b.timestamp) - new Date(a.timestamp); + }); +} + +function cleanOutput(output) { + + if (output === null || + output === undefined) { + return null; + } + + // convert large and small changes only to info needed + + const cleanedOutput = []; + for (var i = 0; i < output.length; i++) { + const item = output[i]; + + if (item.outputType === null || + item.outputType === undefined) { + continue; + } + + if (item.outputType === 'large-change') { + cleanedOutput.push(new LargeOutput(item)); + } else if (item.outputType === 'new-talk-page-topic') { + cleanedOutput.push(new NewTalkPageTopic(item)); + } else if (item.outputType === 'small-change') { + cleanedOutput.push(new SmallOutput(item)); + } else { + cleanedOutput.push(item); + } + } + + return cleanedOutput; +} + +function editCountsAndGroupsPromise(req, cleanedOutput) { + + if (cleanedOutput === undefined || + cleanedOutput === null) { + return null; + } + + // gather unique userids + var userids = []; + cleanedOutput.forEach( (outputItem) => { + if (outputItem.userid !== undefined && outputItem.userid !== null && + outputItem.userid !== 0) { + userids.push(outputItem.userid); + } + }); + var dedupedIdsSet = new Set(userids); + var dedupedIds = Array.from(dedupedIdsSet); + // fetch counts and groups + return mwapi.queryForUsers(req, dedupedIds) + .then( (response) => { + // distribute results back into cleanedOutput + + if (response.body === null || + response.body === undefined || + response.body.query === null || + response.body.query === undefined || + response.body.query.users === null || + response.body.query.users === undefined) { + cleanedOutput.forEach( (outputItem) => { + if (outputItem.outputType !== 'small-change') { + outputItem.userGroups = null; + outputItem.userEditCount = null; + } + }); + return cleanedOutput; + } + + const users = response.body.query.users; + users.forEach( (user) => { + cleanedOutput.forEach( (outputItem) => { + + if (outputItem.userid !== null && + outputItem.userid !== undefined && + user.userid !== null && + user.userid !== undefined) { + if (outputItem.userid === user.userid) { + outputItem.userGroups = user.groups; + outputItem.userEditCount = user.editcount; + } + } + }); + }); + + return cleanedOutput; + }) + .catch( (e) => { + return cleanedOutput; + }); +} + +function isRequestingFirstPage(req) { + return req.query.rvstartid === undefined || req.query.rvstartid === null; +} + +function shaFromSortedOutput(req, sortedOutput) { + + if (sortedOutput === null || + sortedOutput === undefined) { + return null; + } + + if (!isRequestingFirstPage(req)) { + return null; + } + + var shaTitle; + var shaRevID; + for (var i = 0; i < sortedOutput.length; i++) { + const output = sortedOutput[i]; + + if (output.outputType === undefined || + output.outputType === null || + output.revid === undefined || + output.revid === null) { + continue; + } + + if (output.outputType === 'large-change') { + shaTitle = req.params.title; + shaRevID = output.revid; + break; + } + + if (output.outputType === 'new-talk-page-topic') { + shaTitle = getTalkPageTitle(req); + shaRevID = output.revid; + break; + } + } + + if (shaTitle === undefined || shaTitle === null || shaRevID === undefined || + shaRevID === null) { + // grab first item, even if it's a small type + for (var s = 0; s < sortedOutput.length; s++) { + const output = sortedOutput[s]; + if (output.outputType === undefined || + output.outputType === null || + output.revid === undefined || + output.revid === null) { + continue; + } + + if (output.outputType === 'small-change') { + shaTitle = req.params.title; + shaRevID = output.revid; + break; + } + } + } + + if (shaTitle === undefined || shaTitle === null || shaRevID === undefined || + shaRevID === null) { + return null; + } + + return tUtil.createSha256(`${shaTitle}${shaRevID}`); +} + +class MalformedArticleRevisionResponse extends Error { + constructor(message) { + super(message); + this.name = 'MalformedArticleRevisionResponse'; + } +} + +class AllArticleDiffCallsFailed extends Error { + constructor(message) { + super(message); + this.name = 'AllArticleDiffCallsFailed'; + } +} + +function getSignificantEvents(req, res) { + + // STEP 1: Gather list of article revisions + return mwapi.queryForRevisions(req) + .then( (response) => { + + // STEP 2: All at once gather diffs for each uncached revision and list of + // talk page revisions + + if (response.body === undefined || + response.body === null || + response.body.query === undefined || + response.body.query === null || + response.body.query.pages === undefined || + response.body.query.pages === null || + response.body.query.pages[0] === undefined || + response.body.query.pages[0] === null || + response.body.query.pages[0].revisions === undefined || + response.body.query.pages[0].revisions === null) { + throw new MalformedArticleRevisionResponse(); + } + + const revisions = response.body.query.pages[0].revisions; + + // BEGIN: PAGE CUTOFF LOGIC + // page cutoff: if cache is maxed out, filter out any revisions + // that occur before the cutoff + const cutoff = latestAndEarliestCachedRevisionTimestamp(req); + var filteredRevisions; + const isMaxedOut = cacheForTitleIsMaxedOut(req); + if (isMaxedOut && cutoff && cutoff.earliestTimestamp) { + filteredRevisions = revisions.filter((revision) => { + if (revision.timestamp === undefined || revision.timestamp === null || + cutoff.earliestTimestamp === undefined || + cutoff.earliestTimestamp === null) { + return 0; + } + return new Date(revision.timestamp) > new Date(cutoff.earliestTimestamp); + }); + } else { + filteredRevisions = revisions; + } + + // if cache is maxed out and filteredRevisions contains + // revisions from after the latest cached revision, + // propagate flag for needing cleanup later + var needsCacheCleanup = false; + if (isMaxedOut) { + for (var i = 0; i < filteredRevisions.length; i++) { + + const revision = filteredRevisions[i]; + + if (revision.timestamp === undefined || revision.timestamp === null || + cutoff.earliestTimestamp === undefined || + cutoff.earliestTimestamp === null) { + continue; + } + + const timestamp = new Date(revision.timestamp); + const latestCacheTimestamp = new Date(cutoff.latestTimestamp); + if (timestamp > latestCacheTimestamp) { + needsCacheCleanup = true; + break; + } + } + } + // END: PAGE CUTOFF LOGIC + + var nextRvStartId = null; + var talkPageRvStartId = null; + var talkPageRvEndId = null; + if (filteredRevisions && filteredRevisions.length > 0) { + const earliestRevision = filteredRevisions[filteredRevisions.length - 1]; + const latestRevision = filteredRevisions[0]; + if (earliestRevision.parentid !== null && earliestRevision.parentid !== undefined + && latestRevision.timestamp !== null && + latestRevision.timestamp !== undefined) { + nextRvStartId = earliestRevision.parentid; + // if rvstartid is missing from query, they are fetching the first page + // if they are fetching the first page, we don't want to block of + // talk page revision fetching at the start, in case talk page topics came in + // after the latest article revision + talkPageRvStartId = isRequestingFirstPage(req) ? null : + latestRevision.timestamp; + talkPageRvEndId = earliestRevision.timestamp; + } + } + + const articleEvalResults = getCachedAndUncachedItems(filteredRevisions, req, null); + + // save cached article revisions to finalOutput + const finalOutput = articleEvalResults.cachedOutput; + + const talkPageRevisionPromise = (talkPageRvEndId !== null) ? + talkPageRevisionsPromise(req, talkPageRvStartId, talkPageRvEndId) + : null; + + return BBPromise.props({ + articleDiffAndRevisions: diffAndRevisionPromises(req, + articleEvalResults.uncachedRevisions), + talkPageRevisions: talkPageRevisionPromise, + nextRvStartId: nextRvStartId, + needsCacheCleanup: needsCacheCleanup, + finalOutput: finalOutput + }); + }) + .then( (response) => { + + // if all articleDiffAndRevisions fail, return error + if (response.articleDiffAndRevisions !== undefined && + response.articleDiffAndRevisions !== null) { + const articleDiffAndRevisionsNullDiff = + response.articleDiffAndRevisions.filter(diffAndRevision => { + return diffAndRevision.body === undefined || diffAndRevision.body === null; + }); + + if (articleDiffAndRevisionsNullDiff.length === + response.articleDiffAndRevisions.length && + articleDiffAndRevisionsNullDiff.length > 0 && + response.articleDiffAndRevisions.length > 0) { // all diff calls failed + throw new AllArticleDiffCallsFailed(); + } + } + + // STEP 3: All at once gather diffs for uncached talk page revisions + + const articleDiffAndRevisions = response.articleDiffAndRevisions + .filter(x => x !== null); + const nextRvStartId = response.nextRvStartId; + const needsCacheCleanup = response.needsCacheCleanup; + + if (response.talkPageRevisions !== undefined && response.talkPageRevisions !== null && + response.talkPageRevisions.body !== undefined && + response.talkPageRevisions.body !== null && + response.talkPageRevisions.body.query !== undefined && + response.talkPageRevisions.body.query !== null && + response.talkPageRevisions.body.query.pages[0] !== undefined && + response.talkPageRevisions.body.query.pages[0] !== null && + response.talkPageRevisions.body.query.pages[0].revisions !== undefined && + response.talkPageRevisions.body.query.pages[0].revisions !== null) { + const talkPageRevisions = response.talkPageRevisions.body.query.pages[0].revisions; + const talkPageEvalResults = getCachedAndUncachedItems(talkPageRevisions, + req, getTalkPageTitle(req)); + + // save cached talk page revisions to finalOutput + const finalOutput = response.finalOutput.concat(talkPageEvalResults.cachedOutput); + + // for each uncached talk page revision, gather diffs + return diffAndRevisionPromises(req, talkPageEvalResults.uncachedRevisions) + .then( (response) => { + return Object.assign({ + articleDiffAndRevisions: articleDiffAndRevisions, + talkDiffAndRevisions: response, + nextRvStartId: nextRvStartId, + needsCacheCleanup: needsCacheCleanup, + finalOutput: finalOutput + }); + }); + } else { + return Object.assign({ + articleDiffAndRevisions: articleDiffAndRevisions, + talkDiffAndRevisions: null, + nextRvStartId: nextRvStartId, + needsCacheCleanup: needsCacheCleanup, + finalOutput: response.finalOutput + }); + } + }) + .then( (response) => { + + // Determine character size of change for every diff line and aggregate + // for every revision + updateDiffAndRevisionsWithCharacterCount(response.articleDiffAndRevisions); + if (response.talkDiffAndRevisions) { + updateDiffAndRevisionsWithCharacterCount(response.talkDiffAndRevisions); + } + + // Flag added template types + return addStructuredTemplates(response.articleDiffAndRevisions, false) + .then( (articleDiffAndRevisions) => { + response.articleDiffAndRevisions = articleDiffAndRevisions; + return response; + }); + }) + .then( (response) => { + + const threshold = getThreshold(req); + + // segment off into types + var uncachedOutput = []; + + for (var i = 0; i < response.articleDiffAndRevisions.length; i++) { + const diffAndRevision = response.articleDiffAndRevisions[i]; + + if (diffAndRevision.revision === undefined || diffAndRevision.revision === null) { + continue; + } + + const revision = diffAndRevision.revision; + + // edge case in case one of the diff endpoints fail...fallback to small type + if (diffAndRevision.body === undefined || diffAndRevision.body === null) { + const smallOutputObject = new SmallOutputExtended(revision.revid, + revision.parentid, revision.timestamp, revision.user, revision.userid); + uncachedOutput.push(smallOutputObject); + continue; + } + + if (revision.tags !== undefined && revision.tags !== null && + revision.tags.includes('mw-rollback') && + (revision.comment !== undefined && revision.comment !== null) && + (revision.comment.toLowerCase().includes('revert') || + revision.comment.toLowerCase().includes('vandalism')) && + diffAndRevision.body !== null && diffAndRevision.body !== undefined) { + const sections = diffAndRevision.characterChangeWithSections.addedSections + .concat(diffAndRevision.characterChangeWithSections.deletedSections); + const dedupedSections = new Set(sections); + const vandalismRevertOutputObject = new VandalismOutput(revision.revid, + revision.parentid, revision.timestamp, revision.user, revision.userid, + Array.from(dedupedSections)); + uncachedOutput.push(vandalismRevertOutputObject); + } else { + + var significantChanges = []; + if (diffAndRevision.templatesAndDiffItems !== undefined && + diffAndRevision.templatesAndDiffItems !== null && + diffAndRevision.templatesAndDiffItems.length > 0) { + + var sections = []; + var combinedTemplates = []; + + for (var t = 0; t < diffAndRevision.templatesAndDiffItems.length; t++) { + const templatesAndDiffItem = diffAndRevision.templatesAndDiffItems[t]; + const templates = templatesAndDiffItem.templates; + const diffItem = templatesAndDiffItem.diffItem; + const section = getSectionForDiffLine(diffAndRevision.body, + diffItem); + if (section) { + sections.push(section); + } + if (templates) { + combinedTemplates = combinedTemplates.concat(templates); + } + } + + const dedupedSections = new Set(sections); + const newReferenceOutputObject = + new NewReferenceOutput(Array.from(dedupedSections), + combinedTemplates); + significantChanges.push(newReferenceOutputObject); + } + + if (diffAndRevision.characterChangeWithSections !== undefined && + diffAndRevision.characterChangeWithSections !== null && + diffAndRevision.characterChangeWithSections.counts !== undefined && + diffAndRevision.characterChangeWithSections.counts !== null && + diffAndRevision.characterChangeWithSections.counts.totalCount() > + threshold) { + + if (diffAndRevision.characterChangeWithSections.counts.addedCount > 0) { + const largestDiffLine = getLargestDiffLineOfAdded(diffAndRevision.body); + if (largestDiffLine !== undefined && largestDiffLine !== null) { + const addedTextOutputObject = new AddedTextOutputExpanded( + diffAndRevision.characterChangeWithSections, + largestDiffLine.text, + largestDiffLine.type, largestDiffLine.highlightRanges); + significantChanges.push(addedTextOutputObject); + } + } + + if (diffAndRevision.characterChangeWithSections.counts.deletedCount > 0) { + const deletedTextOutputObject = new DeletedTextOutput( + diffAndRevision.characterChangeWithSections); + significantChanges.push(deletedTextOutputObject); + } + } + + if (significantChanges.length > 0) { + const largeOutputObject = new LargeOutputExpanded(revision.revid, + revision.parentid, revision.timestamp, revision.user, + revision.userid, significantChanges); + uncachedOutput.push(largeOutputObject); + } else { + const smallOutputObject = new SmallOutputExtended(revision.revid, + revision.parentid, revision.timestamp, revision.user, + revision.userid); + uncachedOutput.push(smallOutputObject); + } + } + } + + // get new talk page revisions, add to uncachedOutput. it will be sorted later. + if (response.talkDiffAndRevisions !== undefined && + response.talkDiffAndRevisions !== null) { + const newTopicDiffAndRevisions = getNewTopicDiffAndRevisions( + response.talkDiffAndRevisions); + if (newTopicDiffAndRevisions !== undefined && newTopicDiffAndRevisions !== null) { + newTopicDiffAndRevisions.forEach(function (diffAndRevision) { + const revision = diffAndRevision.revision; + + const nullSnippetTalkPageObject = new NewTalkPageTopicExtended( + revision.revid, revision.parentid, revision.timestamp, + revision.user, revision.userid,null,null, + null, null, null); + if (diffAndRevision.body !== undefined && diffAndRevision.body !== null) { + const firstDiffLine = getFirstDiffLineWithContent(diffAndRevision.body); + if (firstDiffLine !== undefined && firstDiffLine !== null) { + const section = getSectionForDiffLine(diffAndRevision.body, + firstDiffLine); + const newTalkPageTopicOutputObject = new NewTalkPageTopicExtended( + revision.revid, revision.parentid, + revision.timestamp, revision.user, + revision.userid, + firstDiffLine.text,firstDiffLine.type, + firstDiffLine.highlightRanges, + diffAndRevision.characterChangeWithSections.counts, section); + uncachedOutput.push(newTalkPageTopicOutputObject); + } else { + uncachedOutput.push(nullSnippetTalkPageObject); + } + } else { + const newTalkPageTopicOutputObject = new NewTalkPageTopicExtended( + revision.revid, revision.parentid, + revision.timestamp, revision.user, revision.userid, + null,null, null, null); + uncachedOutput.push(nullSnippetTalkPageObject); + } + }); + } + } + + return Object.assign({ nextRvStartId: response.nextRvStartId, + needsCacheCleanup: response.needsCacheCleanup, + uncachedOutput: uncachedOutput, + finalOutput: response.finalOutput } ); + }) + .then( (response) => { + + var preformattedSnippets = []; + for (var o = 0; o < response.uncachedOutput.length; o++) { + const item = response.uncachedOutput[o]; + + if (item.outputType === undefined || item.outputType === null) { + continue; + } + + if (item.outputType === 'new-talk-page-topic' && item.snippet !== null) { + const snippet = new PreformattedSnippet(item.revid, item.outputType, + item.snippet,1, null, + null); + preformattedSnippets.push(snippet); + } else if (item.outputType === 'large-change') { + for (let i = 0; i < item.significantChanges.length; i++) { + const significantChange = item.significantChanges[i]; + + if (significantChange.outputType === undefined || + significantChange.outputType === null || + significantChange.snippet === undefined || + significantChange.snippet === null || + significantChange.snippetType === undefined || + significantChange.snippetType === null) { + continue; + } + + if (significantChange.outputType === 'added-text') { + const snippet = new PreformattedSnippet(item.revid, item.outputType, + significantChange.snippet, significantChange.snippetType, + significantChange.snippetHighlightRanges, i); + preformattedSnippets.push(snippet); + } + } + } + } + + // convert large snippets from wikitext to mobile-html + return snippetPromises(req, preformattedSnippets) + .then( (formattedSnippets) => { + + // reassign formattedSnippets to snippet output + for (var fs = 0; fs < formattedSnippets.length; fs++) { + const formattedSnippet = formattedSnippets[fs]; + + for (var i = 0; i < response.uncachedOutput.length; i++) { + const item = response.uncachedOutput[i]; + + if (item.revid === undefined || item.revid === null || + formattedSnippet.revid === undefined || + formattedSnippet.revid === null || + item.outputType === undefined || item.outputType === null || + formattedSnippet.outputType === undefined || + formattedSnippet.outputType === null) { + continue; + } + + if (item.revid === formattedSnippet.revid && + item.outputType === formattedSnippet.outputType) { + if (formattedSnippet.outputType === 'new-talk-page-topic') { + item.snippet = formattedSnippet.snippet; + } else if (formattedSnippet.outputType === 'large-change') { + + if (item.significantChanges === undefined || + item.significantChanges === null || + formattedSnippet.indexOfSignificantChanges === undefined || + formattedSnippet.indexOfSignificantChanges === null) { + continue; + } + + if (item.significantChanges.length > + formattedSnippet.indexOfSignificantChanges) { + var significantChange = + item.significantChanges[ + formattedSnippet.indexOfSignificantChanges + ]; + significantChange.snippet = formattedSnippet.snippet; + if (significantChange.outputType === 'added-text') { + item.significantChanges[ + formattedSnippet.indexOfSignificantChanges + ] = new AddedTextOutput(significantChange); + } + } + } + } + } + } + + // push to final output and cache + // note we are using original response list, not snippet response + // (snippet only contains large) + response.uncachedOutput.forEach((item) => { + response.finalOutput.push(item); + var cacheKey; + if (item.outputType === 'new-talk-page-topic') { + const title = getTalkPageTitle(req); + setSignificantChangesCache(req, title, item); + } else { + setSignificantChangesCache(req, null, item); + } + }); + + return Object.assign({ nextRvStartId: response.nextRvStartId, + needsCacheCleanup: response.needsCacheCleanup, + finalOutput: response.finalOutput } ); + }); + }) + .then( (response) => { + + const sortedOutput = sortOutput((response.finalOutput)); + const cleanedOutput = cleanOutput(sortedOutput); + const sha = shaFromSortedOutput(req, sortedOutput); + + return editCountsAndGroupsPromise(req, cleanedOutput) + .then( (editCountsAndGroupsResponse) => { + return Object.assign({ nextRvStartId: response.nextRvStartId, + needsCacheCleanup: response.needsCacheCleanup, + cleanedOutput: editCountsAndGroupsResponse, sha: sha }); + }); + }) + .then( (response) => { + + if (response.needsCacheCleanup) { + cleanupCache(req); + } + + const summary = getSummaryText(req); + + const result = Object.assign({ nextRvStartId: response.nextRvStartId, + sha: response.sha, + timeline: response.cleanedOutput, + summary: summary }); + return result; + }); +} + +router.get('/page/significant-events/:title', (req, res) => { + return getSignificantEvents(req, res).then( (response) => { + res.send(response).end(); + }); +}); + +var countCacheWarmupPages = 0; + +function recursiveGetSignificantEvents(req, res) { + countCacheWarmupPages++; + return getSignificantEvents(req, res).then( (response) => { + + if (!response.nextRvStartId) { + const finalWarmupCount = countCacheWarmupPages; + countCacheWarmupPages = 0; + return Object.assign({ warmedPages: finalWarmupCount, + significantChangesCache: significantChangesCache }); + } + + req.query.rvstartid = response.nextRvStartId; + return recursiveGetSignificantEvents(req, res); + }); +} + +router.get('/page/significant-events-warmup/:title', (req, res) => { + return recursiveGetSignificantEvents(req, res) + .then( (response) => { + res.send(response).end(); + }); +}); + +module.exports = function(appObj) { + app = appObj; + return { + path: '/', + api_version: 1, + router + }; +};