From b982381c547aa25860f5f4075f9c0f18f43fcb9a Mon Sep 17 00:00:00 2001 From: "P.BARRY" Date: Wed, 31 Jul 2019 13:38:53 +0200 Subject: [PATCH] nubium added --- service/.gitignore | 78 + service/Dockerfile | 26 + service/README.md | 2 + service/VERSION | 1 + service/apidoc.js | 7 + service/config.js | 54 + service/index.js | 121 + service/mocha.entry.js | 23 + service/package-lock.json | 4305 +++++++++++++++++ service/package.json | 55 + service/services/core/config/router.js | 8 + service/services/core/config/router.spec.js | 24 + service/services/media/router.js | 201 + service/services/media/rsc/default/404.jpg | Bin 0 -> 11864 bytes .../restapi/collections/__template.js | 70 + .../restapi/collections/config/config.form.js | 36 + .../restapi/collections/config/config.js | 18 + .../landingpages/landingpages.form.js | 38 + .../collections/landingpages/landingpages.js | 32 + .../restapi/collections/media/media.js | 21 + .../users-filters/users-filters.js | 14 + .../restapi/collections/users/users.form.js | 58 + .../restapi/collections/users/users.js | 47 + .../restapi/collections/users/users.spec.js | 39 + service/services/restapi/router.js | 734 +++ service/services/restapi/router.spec.js | 25 + service/services/session/auth.js | 89 + service/services/session/router.js | 118 + service/services/session/router.spec.js | 171 + service/services/session/services.js | 107 + service/services/session/services.spec.js | 70 + service/tools/common.js | 43 + service/tools/middleware-done.js | 53 + service/tools/time-profiler.js | 22 + 34 files changed, 6710 insertions(+) create mode 100644 service/.gitignore create mode 100644 service/Dockerfile create mode 100644 service/README.md create mode 100644 service/VERSION create mode 100644 service/apidoc.js create mode 100644 service/config.js create mode 100644 service/index.js create mode 100644 service/mocha.entry.js create mode 100644 service/package-lock.json create mode 100644 service/package.json create mode 100644 service/services/core/config/router.js create mode 100644 service/services/core/config/router.spec.js create mode 100644 service/services/media/router.js create mode 100644 service/services/media/rsc/default/404.jpg create mode 100644 service/services/restapi/collections/__template.js create mode 100644 service/services/restapi/collections/config/config.form.js create mode 100644 service/services/restapi/collections/config/config.js create mode 100644 service/services/restapi/collections/landingpages/landingpages.form.js create mode 100644 service/services/restapi/collections/landingpages/landingpages.js create mode 100644 service/services/restapi/collections/media/media.js create mode 100644 service/services/restapi/collections/users-filters/users-filters.js create mode 100644 service/services/restapi/collections/users/users.form.js create mode 100644 service/services/restapi/collections/users/users.js create mode 100644 service/services/restapi/collections/users/users.spec.js create mode 100644 service/services/restapi/router.js create mode 100644 service/services/restapi/router.spec.js create mode 100644 service/services/session/auth.js create mode 100644 service/services/session/router.js create mode 100644 service/services/session/router.spec.js create mode 100644 service/services/session/services.js create mode 100644 service/services/session/services.spec.js create mode 100644 service/tools/common.js create mode 100644 service/tools/middleware-done.js create mode 100644 service/tools/time-profiler.js diff --git a/service/.gitignore b/service/.gitignore new file mode 100644 index 0000000..144585f --- /dev/null +++ b/service/.gitignore @@ -0,0 +1,78 @@ +# ---> Node +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# next.js build output +.next + +# nuxt.js build output +.nuxt + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless + +# FuseBox cache +.fusebox/ + diff --git a/service/Dockerfile b/service/Dockerfile new file mode 100644 index 0000000..bc126c6 --- /dev/null +++ b/service/Dockerfile @@ -0,0 +1,26 @@ +# build static files +FROM node:carbon-alpine as build-nubium-cloud +WORKDIR /app + +COPY package*.json ./ + +RUN npm install + +# final image +FROM node:carbon-alpine + +## install bash +#RUN apk add bash docker + +WORKDIR /app + +RUN mkdir -p /data/nubium-artifex + +# pkg not working in docker +COPY --from=build-nubium-cloud /app/ . +COPY . . + +ENV PORT 3009 +EXPOSE 3009 + +ENTRYPOINT ["node", "index.js"] \ No newline at end of file diff --git a/service/README.md b/service/README.md new file mode 100644 index 0000000..b7722c0 --- /dev/null +++ b/service/README.md @@ -0,0 +1,2 @@ +# nubium-artifex-service + diff --git a/service/VERSION b/service/VERSION new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/service/VERSION @@ -0,0 +1 @@ + diff --git a/service/apidoc.js b/service/apidoc.js new file mode 100644 index 0000000..60a8e2f --- /dev/null +++ b/service/apidoc.js @@ -0,0 +1,7 @@ +// //////////////////////////////////////////////////////////////////////////// +// Current Errors. +// //////////////////////////////////////////////////////////////////////////// + +// //////////////////////////////////////////////////////////////////////////// +// Current Params. +// //////////////////////////////////////////////////////////////////////////// diff --git a/service/config.js b/service/config.js new file mode 100644 index 0000000..df6534a --- /dev/null +++ b/service/config.js @@ -0,0 +1,54 @@ +const path = require('path') +const CFG = {} + +const CFG_DB_NAME = 'earth' + +CFG.media = { + cache: path.resolve('/data/nubium-artifex/cache'), + documents: path.resolve('/data/nubium-artifex/documents'), + '404': path.resolve(__dirname, './services/media/rsc/default/404.jpg') +} + +// console.log(CFG.media) + +CFG.server = { + port: process.env.PORT || 3009 +} + +CFG.mongo = { + url: `mongodb://localhost:27017/${CFG_DB_NAME}`, + db: CFG_DB_NAME +} + +CFG.jwt = { + enable: true, + jwtAuth: { + secret: '@@Earth@@Hello0WorlD!!!!', + passSalt: '@@Earth@@Hello0WorlDForP@55W0RD!!!!', + expiresIn: '15d' + }, + jwtAccess: { + secret: '@@Earth@@Hello0WorlD!!!!', + expiresIn: '24h' + }, + sid: 1 +} + +// //////////////////////////////////////////////////////////////////////////// +// UP FROM ENV +if (process.env.ENV === 'dev') { + CFG.mongo.url = 'mongodb://localhost:27017' + CFG.jwt.enable = false +} + +if (process.env.ENV === 'prod') { + CFG.mongo.url = 'mongodb://rw:pxcom@airpmp.aero:27017/admin' +} + +if (process.env.ENV === 'preprod') { + CFG.mongo.url = 'mongodb://localhost:27017' +} + +console.log(CFG.mongo.url) + +module.exports = CFG diff --git a/service/index.js b/service/index.js new file mode 100644 index 0000000..a64ddf1 --- /dev/null +++ b/service/index.js @@ -0,0 +1,121 @@ +const express = require('express') +const app = express() +const morgan = require('morgan') +const bodyParser = require('body-parser') +const mongoClient = require('mongodb').MongoClient +const fs = require('fs-extra') + +const session = require('./services/session/router') +const restapi = require('./services/restapi/router') +const media = require('./services/media/router') +const coreCfg = require('./services/core/config/router') + +const CFG = require('./config') +const PKG = require('./package') +const auth = require('./services/session/auth') + +const CTX = { + cfg: CFG, + logEnabled: true, + dbHandler: null, + db: null, + tools: require('./tools/common'), + models: {} +} + +let server = { + handler: null, + interval: null, + onReady: function () {} +} + +app.use(morgan('tiny', { + skip: function (req, res) { return !CTX.logEnabled } +})) +app.use(bodyParser.json()) +app.use(require('./tools/middleware-done')) + +mongoClient.connect(CFG.mongo.url, { useNewUrlParser: true }, function (pErr, pDbHandler) { + if (pErr) { + if (CTX.logEnabled) { + console.error(`[!] Failed to connect DB: ${CFG.mongo.url}`) + console.error(pErr) + } + process.exit(1) + } + // ////////////////////////////////////////////////////////////////////////// + // Init folder + fs.ensureDirSync(CFG.media.documents) + fs.ensureDirSync(CFG.media.cache) + + // ////////////////////////////////////////////////////////////////////////// + // DB HANDLING + if (CTX.logEnabled) console.log(`[-] Connected to mongoDB: ${CFG.mongo.url}`) + CTX.dbHandler = pDbHandler + CTX.db = CTX.dbHandler.db(CFG.mongo.db) + addUserIfRequired() + // ////////////////////////////////////////////////////////////////////////// + // ROUTING + + app.use('/session', session(CTX)) + app.use('/doc', express.static('../doc/api')) + app.get('/', (req, res) => { + res.send(`Hello World from Earth server - v${PKG.version} - build ${CTX.tools.git.currentRevision}`) + }) + // ALL API after auth call required authentification + app.use(auth(CTX)) + app.use('/api', restapi(CTX)) + app.use('/media', media(CTX)) + app.use('/core/config', coreCfg(CTX)) + + // ////////////////////////////////////////////////////////////////////////// + // LISTENING + server.handler = app.listen(CFG.server.port, () => { + if (CTX.logEnabled) console.log(`[-] Current build: ${CTX.tools.git.currentRevision}`) + if (CTX.logEnabled) console.log(`[-] Earth server listening on: ${CFG.server.port}`) + server.onReady() + }) +}) + +app.stop = function () { + server.interval = setTimeout(function () { + server.handler.close() + CTX.db.handler.close() + }, 500) +} + +app.setOnReady = function (done) { + clearTimeout(server.interval) + server.onReady = done + if (server.handler) { + server.onReady() + } +} + +app.setLog = function (pFlag) { + CTX.logEnabled = pFlag +} + +module.exports = app + +function addUserIfRequired () { + let dbUsers = CTX.db.collection('users') + dbUsers.find({}).count(function (pErr, pCount) { + if (!pCount) { + let user = { + username: 'admin', + email: 'admin@earth.com', + details: { + firstname: 'Admin', lastname: 'Admin', company: 'Earth', corporateTitle: 'BigBoss', language: 'en' + }, + rights: { + role: 'admin' + }, + multipass: { + hash: 'admin' + } + } + dbUsers.insert(user, function () {}) + } + }) +} diff --git a/service/mocha.entry.js b/service/mocha.entry.js new file mode 100644 index 0000000..de15455 --- /dev/null +++ b/service/mocha.entry.js @@ -0,0 +1,23 @@ +/* eslint-env mocha */ + +const server = require('./index') +server.setLog(false) + +global.login = {user: 'airpmp', pass: 'admin'} + +before(function (done) { + global.server = server + global.jwtAccess = '' + this.timeout(10000) + server.setOnReady(function () { + done() + }) +}) + +require('./services/session/router.spec') +require('./services/restapi/router.spec') +require('./services/core/config/router.spec') + +after(function () { + server.stop() +}) diff --git a/service/package-lock.json b/service/package-lock.json new file mode 100644 index 0000000..f011a31 --- /dev/null +++ b/service/package-lock.json @@ -0,0 +1,4305 @@ +{ + "name": "ground", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "JSONSelect": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/JSONSelect/-/JSONSelect-0.4.0.tgz", + "integrity": "sha1-oI7cxn6z/L6Z7WMIVTRKDPKCu40=" + }, + "accepts": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", + "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "requires": { + "mime-types": "2.1.19", + "negotiator": "0.6.1" + } + }, + "acorn": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.1.tgz", + "integrity": "sha512-d+nbxBUGKg7Arpsvbnlq61mc12ek3EY8EQldM3GPAhWJ1UVxC6TDGbIvUMNU6obBX3i1+ptCIzV4vq0gFPEGVQ==", + "dev": true + }, + "acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "dev": true, + "requires": { + "acorn": "3.3.0" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "dev": true + } + } + }, + "ajv": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.2.tgz", + "integrity": "sha512-hOs7GfvI6tUI1LfZddH82ky6mOMyTuY0mk7kE2pWpmhhUSkumzaTO5vbVwij39MdwPQWCV4Zv57Eo06NtL/GVA==", + "requires": { + "fast-deep-equal": "2.0.1", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.4.1", + "uri-js": "4.2.2" + } + }, + "ajv-keywords": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", + "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=", + "dev": true + }, + "ansi-escapes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", + "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==", + "dev": true + }, + "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": "1.0.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", + "integrity": "sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=", + "dev": true + }, + "apidoc": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/apidoc/-/apidoc-0.17.6.tgz", + "integrity": "sha1-TuisYQ3t3csQBsPij6fdY0tKXOY=", + "dev": true, + "requires": { + "apidoc-core": "0.8.3", + "fs-extra": "3.0.1", + "lodash": "4.17.10", + "markdown-it": "8.4.2", + "nomnom": "1.8.1", + "winston": "2.3.1" + }, + "dependencies": { + "fs-extra": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz", + "integrity": "sha1-N5TzeMWLNC6n27sjCVEJxLO2IpE=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "jsonfile": "3.0.1", + "universalify": "0.1.2" + } + }, + "jsonfile": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz", + "integrity": "sha1-pezG9l9T9mLEQVx2daAzHQmS7GY=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11" + } + } + } + }, + "apidoc-core": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/apidoc-core/-/apidoc-core-0.8.3.tgz", + "integrity": "sha1-2dY1RYKd8lDSzKBJaDqH53U2S5Y=", + "dev": true, + "requires": { + "fs-extra": "3.0.1", + "glob": "7.1.2", + "iconv-lite": "0.4.23", + "klaw-sync": "2.1.0", + "lodash": "4.17.10", + "semver": "5.3.0" + }, + "dependencies": { + "fs-extra": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz", + "integrity": "sha1-N5TzeMWLNC6n27sjCVEJxLO2IpE=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "jsonfile": "3.0.1", + "universalify": "0.1.2" + } + }, + "jsonfile": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz", + "integrity": "sha1-pezG9l9T9mLEQVx2daAzHQmS7GY=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11" + } + }, + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "dev": true + } + } + }, + "append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=" + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "archiver": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-1.3.0.tgz", + "integrity": "sha1-TyGU1tj5nfP1MeaIHxTxXVX6ryI=", + "requires": { + "archiver-utils": "1.3.0", + "async": "2.6.1", + "buffer-crc32": "0.2.13", + "glob": "7.1.2", + "lodash": "4.17.10", + "readable-stream": "2.3.6", + "tar-stream": "1.6.1", + "walkdir": "0.0.11", + "zip-stream": "1.2.0" + }, + "dependencies": { + "async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", + "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", + "requires": { + "lodash": "4.17.10" + } + } + } + }, + "archiver-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-1.3.0.tgz", + "integrity": "sha1-5QtMCccL89aA4y/xt5lOn52JUXQ=", + "requires": { + "glob": "7.1.2", + "graceful-fs": "4.1.11", + "lazystream": "1.0.0", + "lodash": "4.17.10", + "normalize-path": "2.1.1", + "readable-stream": "2.3.6" + } + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "requires": { + "delegates": "1.0.0", + "readable-stream": "2.3.6" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "1.0.3" + } + }, + "arguments-extended": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/arguments-extended/-/arguments-extended-0.0.3.tgz", + "integrity": "sha1-YQfkkX0OtvCk3WYyD8Fa/HLvSUY=", + "requires": { + "extended": "0.0.6", + "is-extended": "0.0.10" + } + }, + "array-extended": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/array-extended/-/array-extended-0.0.11.tgz", + "integrity": "sha1-1xRK50jek8pybxIQCdv/FibRZL0=", + "requires": { + "arguments-extended": "0.0.3", + "extended": "0.0.6", + "is-extended": "0.0.10" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "array-includes": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", + "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", + "dev": true, + "requires": { + "define-properties": "1.1.2", + "es-abstract": "1.12.0" + } + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "1.0.3" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", + "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", + "requires": { + "lodash": "4.17.10" + } + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "axios": { + "version": "0.18.0", + "resolved": "http://registry.npmjs.org/axios/-/axios-0.18.0.tgz", + "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", + "requires": { + "follow-redirects": "1.5.10", + "is-buffer": "1.1.6" + } + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base64-js": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", + "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==" + }, + "basic-auth": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.0.tgz", + "integrity": "sha1-AV2z81PgLlY3d1X5YnQuiYHnu7o=", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "binary": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", + "integrity": "sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=", + "requires": { + "buffers": "0.1.1", + "chainsaw": "0.1.0" + } + }, + "bl": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", + "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", + "requires": { + "readable-stream": "2.3.6", + "safe-buffer": "5.1.1" + } + }, + "body-parser": { + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", + "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", + "requires": { + "bytes": "3.0.0", + "content-type": "1.0.4", + "debug": "2.6.9", + "depd": "1.1.2", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", + "on-finished": "2.3.0", + "qs": "6.5.2", + "raw-body": "2.3.3", + "type-is": "1.6.16" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "bson": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/bson/-/bson-1.0.9.tgz", + "integrity": "sha512-IQX9/h7WdMBIW/q/++tGd+emQr0XMdeZ6icnT/74Xk9fnabWn+gZgpE+9V+gujL3hhJOoNrnDVY7tWdzc7NUTg==" + }, + "buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.0.tgz", + "integrity": "sha512-nUJyfChH7PMJy75eRDCCKtszSEFokUNXC1hNVSe+o+VdcgvDPLs20k3v8UXI8ruRYAJiYtyRea8mYyqPxoHWDw==", + "requires": { + "base64-js": "1.3.0", + "ieee754": "1.1.12" + } + }, + "buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "requires": { + "buffer-alloc-unsafe": "1.1.0", + "buffer-fill": "1.0.0" + } + }, + "buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==" + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" + }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, + "buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=" + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "buffers": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", + "integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s=" + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "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.14" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "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.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, + "call-me-maybe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=" + }, + "caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "dev": true, + "requires": { + "callsites": "0.2.0" + } + }, + "callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "dev": true + }, + "camelcase": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz", + "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==" + }, + "chai": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.1.2.tgz", + "integrity": "sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw=", + "dev": true, + "requires": { + "assertion-error": "1.1.0", + "check-error": "1.0.2", + "deep-eql": "3.0.1", + "get-func-name": "2.0.0", + "pathval": "1.1.0", + "type-detect": "4.0.8" + } + }, + "chai-http": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/chai-http/-/chai-http-4.0.0.tgz", + "integrity": "sha512-R30Lj3JHHPhknOyurh09ZEBgyO4iSSeTjbLmyLvTr88IFC+zwRjAmaxBwj9TbEAGi0IV2uW+RHaTxeah5rdSaQ==", + "dev": true, + "requires": { + "cookiejar": "2.1.2", + "is-ip": "2.0.0", + "methods": "1.1.2", + "qs": "6.5.2", + "superagent": "3.8.3" + } + }, + "chainsaw": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", + "integrity": "sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=", + "requires": { + "traverse": "0.3.9" + } + }, + "chalk": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", + "integrity": "sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=", + "dev": true, + "requires": { + "ansi-styles": "1.0.0", + "has-color": "0.1.7", + "strip-ansi": "0.1.1" + } + }, + "chardet": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", + "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", + "dev": true + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, + "chownr": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.2.tgz", + "integrity": "sha512-GkfeAQh+QNy3wquu9oIZr6SS5x7wGdSgNQvD10X3r+AZr1Oys22HW8kAmDMvNg2+Dm0TeGaEuO8gFwdBXxwO8A==" + }, + "circular-json": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", + "dev": true + }, + "cjson": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/cjson/-/cjson-0.2.1.tgz", + "integrity": "sha1-c82KrWXZ4VBfmvF0TTt5wVJ2gqU=" + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "2.0.0" + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + }, + "color": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/color/-/color-3.1.2.tgz", + "integrity": "sha512-vXTJhHebByxZn3lDvDJYw4lR5+uB3vuoHsuYA5AKuxRVn5wzzIfQKGLBmgdVRHKTJYeK5rvJcHnrd0Li49CFpg==", + "requires": { + "color-convert": "1.9.2", + "color-string": "1.5.3" + } + }, + "color-convert": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz", + "integrity": "sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg==", + "requires": { + "color-name": "1.1.1" + } + }, + "color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=" + }, + "color-string": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", + "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", + "requires": { + "color-name": "1.1.1", + "simple-swizzle": "0.2.2" + } + }, + "colors": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.2.tgz", + "integrity": "sha512-rhP0JSBGYvpcNQj4s5AdShMeE5ahMop96cTeDl/v9qQQm2fYClE2QXZRi8wLzc+GmXSxdIqqbOIAhyObEXDbfQ==" + }, + "combined-stream": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", + "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "dev": true, + "requires": { + "delayed-stream": "1.0.0" + } + }, + "commander": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "dev": true + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "compress-commons": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-1.2.2.tgz", + "integrity": "sha1-UkqfEJA/OoEzibAiXSfEi7dRiQ8=", + "requires": { + "buffer-crc32": "0.2.13", + "crc32-stream": "2.0.0", + "normalize-path": "2.1.1", + "readable-stream": "2.3.6" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "1.1.1", + "inherits": "2.0.3", + "readable-stream": "2.3.6", + "typedarray": "0.0.6" + } + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "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.1.2", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==", + "dev": true + }, + "core-js": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.3.0.tgz", + "integrity": "sha1-+rg/uwstjchfpjbEudNMdUIMbWU=" + }, + "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=" + }, + "crc": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", + "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", + "requires": { + "buffer": "5.2.0" + } + }, + "crc32-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-2.0.0.tgz", + "integrity": "sha1-483TtN8xaN10494/u8t7KX/pCPQ=", + "requires": { + "crc": "3.8.0", + "readable-stream": "2.3.6" + } + }, + "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.1.3", + "shebang-command": "1.2.0", + "which": "1.3.1" + } + }, + "cycle": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", + "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=", + "dev": true + }, + "date-extended": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/date-extended/-/date-extended-0.0.6.tgz", + "integrity": "sha1-I4AtV90b94GIE/4MMuhRqG2iZ8k=", + "requires": { + "array-extended": "0.0.11", + "extended": "0.0.6", + "is-extended": "0.0.10" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "debug-log": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/debug-log/-/debug-log-1.0.1.tgz", + "integrity": "sha1-IwdjLUwEOCuN+KMvcLiVBG1SdF8=", + "dev": true + }, + "declare.js": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/declare.js/-/declare.js-0.0.8.tgz", + "integrity": "sha1-BHit/5VkwAT1Hfc9i8E0AZ0o3N4=" + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "requires": { + "mimic-response": "1.0.1" + } + }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "deep-extend": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.5.1.tgz", + "integrity": "sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==" + }, + "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=", + "dev": true, + "requires": { + "foreach": "2.0.5", + "object-keys": "1.0.12" + } + }, + "deglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/deglob/-/deglob-2.1.1.tgz", + "integrity": "sha512-2kjwuGGonL7gWE1XU4Fv79+vVzpoQCl0V+boMwWtOQJV2AGDabCwez++nB1Nli/8BabAfZQ/UuHPlp6AymKdWw==", + "dev": true, + "requires": { + "find-root": "1.1.0", + "glob": "7.1.2", + "ignore": "3.3.10", + "pkg-config": "1.1.1", + "run-parallel": "1.1.9", + "uniq": "1.0.1" + } + }, + "del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "dev": true, + "requires": { + "globby": "5.0.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.1", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "rimraf": "2.6.2" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "deref": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/deref/-/deref-0.7.3.tgz", + "integrity": "sha512-9ROdWS8nWgz/uJxYWIDZyEAP+oANSl/pNQO27GFJWptVVocqBQ95iKmcboxjvjPQ0rn3IpJcA450hIJpznzVLg==", + "requires": { + "deep-extend": "0.5.1" + } + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" + }, + "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.14", + "streamsearch": "0.1.2" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "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.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "2.0.2" + } + }, + "drange": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/drange/-/drange-1.0.2.tgz", + "integrity": "sha512-bve7maXvfKW+vcsRpP8gzEDzkTg8O6AoCGvi/52pnllzhl/nmex8XLrHOUEQ42Z8GshcyftvG+E4s5vcd/qo0Q==" + }, + "ebnf-parser": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/ebnf-parser/-/ebnf-parser-0.1.10.tgz", + "integrity": "sha1-zR9rpHfFY4xAyX7ZtXLbW6tdgzE=" + }, + "ecdsa-sig-formatter": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.10.tgz", + "integrity": "sha1-HFlQAPBKiJffuFAAiSoPTDOvhsM=", + "requires": { + "safe-buffer": "5.1.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.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "end-of-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "requires": { + "once": "1.4.0" + } + }, + "entities": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", + "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=", + "dev": true + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "0.2.1" + } + }, + "es-abstract": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz", + "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==", + "dev": true, + "requires": { + "es-to-primitive": "1.1.1", + "function-bind": "1.1.1", + "has": "1.0.3", + "is-callable": "1.1.4", + "is-regex": "1.0.4" + } + }, + "es-to-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz", + "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", + "dev": true, + "requires": { + "is-callable": "1.1.4", + "is-date-object": "1.0.1", + "is-symbol": "1.0.1" + } + }, + "es6-promise": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.0.2.tgz", + "integrity": "sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y=" + }, + "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=", + "dev": true + }, + "escodegen": { + "version": "0.0.21", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-0.0.21.tgz", + "integrity": "sha1-U9ZSz6EDA4gnlFilJmxf/HCcY8M=", + "requires": { + "esprima": "1.0.4", + "estraverse": "0.0.4", + "source-map": "0.7.3" + }, + "dependencies": { + "esprima": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", + "integrity": "sha1-n1V+CPw7TSbs6d00+Pv0drYlha0=" + }, + "estraverse": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-0.0.4.tgz", + "integrity": "sha1-AaCTLf7ldGhKWYr1pnw7+bZCjbI=" + } + } + }, + "eslint": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.18.2.tgz", + "integrity": "sha512-qy4i3wODqKMYfz9LUI8N2qYDkHkoieTbiHpMrYUI/WbjhXJQr7lI4VngixTgaG+yHX+NBCv7nW4hA0ShbvaNKw==", + "dev": true, + "requires": { + "ajv": "5.5.2", + "babel-code-frame": "6.26.0", + "chalk": "2.4.1", + "concat-stream": "1.6.2", + "cross-spawn": "5.1.0", + "debug": "3.1.0", + "doctrine": "2.1.0", + "eslint-scope": "3.7.3", + "eslint-visitor-keys": "1.0.0", + "espree": "3.5.4", + "esquery": "1.0.1", + "esutils": "2.0.2", + "file-entry-cache": "2.0.0", + "functional-red-black-tree": "1.0.1", + "glob": "7.1.2", + "globals": "11.7.0", + "ignore": "3.3.10", + "imurmurhash": "0.1.4", + "inquirer": "3.3.0", + "is-resolvable": "1.1.0", + "js-yaml": "3.12.0", + "json-stable-stringify-without-jsonify": "1.0.1", + "levn": "0.3.0", + "lodash": "4.17.10", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "optionator": "0.8.2", + "path-is-inside": "1.0.2", + "pluralize": "7.0.0", + "progress": "2.0.0", + "require-uncached": "1.0.3", + "semver": "5.5.0", + "strip-ansi": "4.0.0", + "strip-json-comments": "2.0.1", + "table": "4.0.2", + "text-table": "0.2.0" + }, + "dependencies": { + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.1.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "1.9.2" + } + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.4.0" + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + } + } + }, + "eslint-config-standard": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-11.0.0.tgz", + "integrity": "sha512-oDdENzpViEe5fwuRCWla7AXQd++/oyIp8zP+iP9jiUPG6NBj3SHgdgtl/kTn00AjeN+1HNvavTKmYbMo+xMOlw==", + "dev": true + }, + "eslint-config-standard-jsx": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-5.0.0.tgz", + "integrity": "sha512-rLToPAEqLMPBfWnYTu6xRhm2OWziS2n40QFqJ8jAM8NSVzeVKTa3nclhsU4DpPJQRY60F34Oo1wi/71PN/eITg==", + "dev": true + }, + "eslint-import-resolver-node": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", + "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", + "dev": true, + "requires": { + "debug": "2.6.9", + "resolve": "1.8.1" + } + }, + "eslint-module-utils": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.2.0.tgz", + "integrity": "sha1-snA2LNiLGkitMIl2zn+lTphBF0Y=", + "dev": true, + "requires": { + "debug": "2.6.9", + "pkg-dir": "1.0.0" + } + }, + "eslint-plugin-import": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.9.0.tgz", + "integrity": "sha1-JgAu+/ylmJtyiKwEdQi9JPIXsWk=", + "dev": true, + "requires": { + "builtin-modules": "1.1.1", + "contains-path": "0.1.0", + "debug": "2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "0.3.2", + "eslint-module-utils": "2.2.0", + "has": "1.0.3", + "lodash": "4.17.10", + "minimatch": "3.0.4", + "read-pkg-up": "2.0.0" + }, + "dependencies": { + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "2.0.2", + "isarray": "1.0.0" + } + } + } + }, + "eslint-plugin-node": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-6.0.1.tgz", + "integrity": "sha512-Q/Cc2sW1OAISDS+Ji6lZS2KV4b7ueA/WydVWd1BECTQwVvfQy5JAi3glhINoKzoMnfnuRgNP+ZWKrGAbp3QDxw==", + "dev": true, + "requires": { + "ignore": "3.3.10", + "minimatch": "3.0.4", + "resolve": "1.8.1", + "semver": "5.5.0" + } + }, + "eslint-plugin-promise": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.7.0.tgz", + "integrity": "sha512-2WO+ZFh7vxUKRfR0cOIMrWgYKdR6S1AlOezw6pC52B6oYpd5WFghN+QHxvrRdZMtbo8h3dfUZ2o1rWb0UPbKtg==", + "dev": true + }, + "eslint-plugin-react": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.7.0.tgz", + "integrity": "sha512-KC7Snr4YsWZD5flu6A5c0AcIZidzW3Exbqp7OT67OaD2AppJtlBr/GuPrW/vaQM/yfZotEvKAdrxrO+v8vwYJA==", + "dev": true, + "requires": { + "doctrine": "2.1.0", + "has": "1.0.3", + "jsx-ast-utils": "2.0.1", + "prop-types": "15.6.2" + } + }, + "eslint-plugin-standard": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-3.0.1.tgz", + "integrity": "sha1-NNDJFbRe3G8BA5PH7vOCOwhWXPI=", + "dev": true + }, + "eslint-scope": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.3.tgz", + "integrity": "sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA==", + "dev": true, + "requires": { + "esrecurse": "4.2.1", + "estraverse": "4.2.0" + } + }, + "eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", + "dev": true + }, + "espree": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "dev": true, + "requires": { + "acorn": "5.7.1", + "acorn-jsx": "3.0.1" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "esquery": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "dev": true, + "requires": { + "estraverse": "4.2.0" + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "4.2.0" + } + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "exceljs": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/exceljs/-/exceljs-1.6.0.tgz", + "integrity": "sha512-Inn/eeoLpIb3hiTqpgE4otDBg8KImvQZQZ7tEzKQqOBg7Qzg2dQrtfz3NzHKdx9+vvZeqVsOQx8F/D7ysbIaiQ==", + "requires": { + "archiver": "1.3.0", + "fast-csv": "2.4.1", + "jszip": "3.1.3", + "moment": "2.22.2", + "node-unzip-2": "0.2.7", + "promish": "5.1.1", + "sax": "1.2.4" + } + }, + "expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" + }, + "express": { + "version": "4.16.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.3.tgz", + "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", + "requires": { + "accepts": "1.3.5", + "array-flatten": "1.1.1", + "body-parser": "1.18.2", + "content-disposition": "0.5.2", + "content-type": "1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "1.1.2", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "etag": "1.8.1", + "finalhandler": "1.1.1", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "1.1.2", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "2.0.4", + "qs": "6.5.1", + "range-parser": "1.2.0", + "safe-buffer": "5.1.1", + "send": "0.16.2", + "serve-static": "1.13.2", + "setprototypeof": "1.1.0", + "statuses": "1.4.0", + "type-is": "1.6.16", + "utils-merge": "1.0.1", + "vary": "1.1.2" + }, + "dependencies": { + "body-parser": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", + "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", + "requires": { + "bytes": "3.0.0", + "content-type": "1.0.4", + "debug": "2.6.9", + "depd": "1.1.2", + "http-errors": "1.6.3", + "iconv-lite": "0.4.19", + "on-finished": "2.3.0", + "qs": "6.5.1", + "raw-body": "2.3.2", + "type-is": "1.6.16" + } + }, + "iconv-lite": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" + }, + "raw-body": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", + "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.2", + "iconv-lite": "0.4.19", + "unpipe": "1.0.0" + }, + "dependencies": { + "depd": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", + "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" + }, + "http-errors": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", + "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", + "requires": { + "depd": "1.1.1", + "inherits": "2.0.3", + "setprototypeof": "1.0.3", + "statuses": "1.4.0" + } + }, + "setprototypeof": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", + "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" + } + } + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extended": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/extended/-/extended-0.0.6.tgz", + "integrity": "sha1-f7i/e52uOXWG5IVwrP1kLHjlBmk=", + "requires": { + "extender": "0.0.10" + } + }, + "extender": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/extender/-/extender-0.0.10.tgz", + "integrity": "sha1-WJwHSCvmGhRgttgfnCSqZ+jzJM0=", + "requires": { + "declare.js": "0.0.8" + } + }, + "external-editor": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", + "dev": true, + "requires": { + "chardet": "0.4.2", + "iconv-lite": "0.4.23", + "tmp": "0.0.33" + } + }, + "eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=", + "dev": true + }, + "faker": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/faker/-/faker-4.1.0.tgz", + "integrity": "sha1-HkW7vsxndLPBlfrSg1EJxtdIzD8=" + }, + "fast-csv": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/fast-csv/-/fast-csv-2.4.1.tgz", + "integrity": "sha1-vX3SaDkfcpNntZRFuN0K0CaIGyY=", + "requires": { + "extended": "0.0.6", + "is-extended": "0.0.10", + "object-extended": "0.0.7", + "string-extended": "0.0.8" + } + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "1.0.5" + } + }, + "file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "dev": true, + "requires": { + "flat-cache": "1.3.0", + "object-assign": "4.1.1" + } + }, + "finalhandler": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "statuses": "1.4.0", + "unpipe": "1.0.0" + }, + "dependencies": { + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" + } + } + }, + "find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "dev": true + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + }, + "flat-cache": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", + "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", + "dev": true, + "requires": { + "circular-json": "0.3.3", + "del": "2.2.2", + "graceful-fs": "4.1.11", + "write": "0.2.1" + } + }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "requires": { + "debug": "3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", + "dev": true + }, + "form-data": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", + "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "dev": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.6", + "mime-types": "2.1.19" + } + }, + "format-util": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/format-util/-/format-util-1.0.3.tgz", + "integrity": "sha1-Ay3KShFiYqEsQ/TD7IVmQWxbLZU=" + }, + "formidable": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.1.tgz", + "integrity": "sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg==", + "dev": true + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, + "fs-copy-file-sync": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/fs-copy-file-sync/-/fs-copy-file-sync-1.1.1.tgz", + "integrity": "sha512-2QY5eeqVv4m2PfyMiEuy9adxNP+ajf+8AR05cEi+OAzPcOj90hvFImeZhTmKLBgSd9EvG33jsD7ZRxsx9dThkQ==" + }, + "fs-extra": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.0.tgz", + "integrity": "sha512-EglNDLRpmaTWiD/qraZn6HREAEAHJcJOmxNEYwq6xeMKnVMAy3GUcFB+wXt2C6k4CNvB/mP1y/U3dzvKKj5OtQ==", + "requires": { + "graceful-fs": "4.1.11", + "jsonfile": "4.0.0", + "universalify": "0.1.2" + } + }, + "fs-minipass": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.6.tgz", + "integrity": "sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ==", + "requires": { + "minipass": "2.3.5" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fstream": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", + "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", + "requires": { + "graceful-fs": "4.1.11", + "inherits": "2.0.3", + "mkdirp": "0.5.1", + "rimraf": "2.6.2" + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "requires": { + "aproba": "1.2.0", + "console-control-strings": "1.1.0", + "has-unicode": "2.0.1", + "object-assign": "4.1.1", + "signal-exit": "3.0.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wide-align": "1.1.3" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "1.0.1" + } + }, + "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.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "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.1.1" + } + } + } + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true + }, + "get-stdin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "dev": true + }, + "github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=" + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "globals": { + "version": "11.7.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.7.0.tgz", + "integrity": "sha512-K8BNSPySfeShBQXsahYB/AbbWruVOTyVpgoIDnl8odPpeSfP2J5QO2oLFFdl2j7GfDCtZj2bMKar2T49itTPCg==", + "dev": true + }, + "globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "dev": true, + "requires": { + "array-union": "1.0.2", + "arrify": "1.0.1", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "has-color": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz", + "integrity": "sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, + "hosted-git-info": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", + "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", + "dev": true + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "requires": { + "depd": "1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": "1.5.0" + } + }, + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "requires": { + "safer-buffer": "2.1.2" + } + }, + "ieee754": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz", + "integrity": "sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==" + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=" + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" + }, + "inquirer": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", + "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", + "dev": true, + "requires": { + "ansi-escapes": "3.1.0", + "chalk": "2.4.1", + "cli-cursor": "2.1.0", + "cli-width": "2.2.0", + "external-editor": "2.2.0", + "figures": "2.0.0", + "lodash": "4.17.10", + "mute-stream": "0.0.7", + "run-async": "2.3.0", + "rx-lite": "4.0.8", + "rx-lite-aggregates": "4.0.8", + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "through": "2.3.8" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "1.9.2" + } + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.4.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + } + } + }, + "ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", + "dev": true + }, + "ipaddr.js": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", + "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=" + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-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=", + "dev": true, + "requires": { + "builtin-modules": "1.1.1" + } + }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, + "is-extended": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/is-extended/-/is-extended-0.0.10.tgz", + "integrity": "sha1-JE4UDfdbscmjEG9BL/GC+1NKbWI=", + "requires": { + "extended": "0.0.6" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "is-ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ip/-/is-ip-2.0.0.tgz", + "integrity": "sha1-aO6gfooKCpTC0IDdZ0xzGrKkYas=", + "dev": true, + "requires": { + "ip-regex": "2.1.0" + } + }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true + }, + "is-path-in-cwd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", + "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", + "dev": true, + "requires": { + "is-path-inside": "1.0.1" + } + }, + "is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "dev": true, + "requires": { + "path-is-inside": "1.0.2" + } + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "requires": { + "has": "1.0.3" + } + }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", + "dev": true + }, + "is-symbol": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz", + "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=", + "dev": true + }, + "is_js": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/is_js/-/is_js-0.9.0.tgz", + "integrity": "sha1-CrlFQFArp6+iTIVqqYVWFmnpxS0=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "jison": { + "version": "0.4.13", + "resolved": "https://registry.npmjs.org/jison/-/jison-0.4.13.tgz", + "integrity": "sha1-kEFwfWIkE2f1iDRTK58ZwsNvrHg=", + "requires": { + "JSONSelect": "0.4.0", + "cjson": "0.2.1", + "ebnf-parser": "0.1.10", + "escodegen": "0.0.21", + "esprima": "1.0.4", + "jison-lex": "0.2.1", + "lex-parser": "0.1.4", + "nomnom": "1.5.2" + }, + "dependencies": { + "colors": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/colors/-/colors-0.5.1.tgz", + "integrity": "sha1-fQAj6usVTo7p/Oddy5I9DtFmd3Q=" + }, + "esprima": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", + "integrity": "sha1-n1V+CPw7TSbs6d00+Pv0drYlha0=" + }, + "nomnom": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.5.2.tgz", + "integrity": "sha1-9DRUSKhTz71cDSYyDyR3qwUm/i8=", + "requires": { + "colors": "0.5.1", + "underscore": "1.1.7" + } + }, + "underscore": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.1.7.tgz", + "integrity": "sha1-QLq4S60Z0jAJbo1u9ii/8FXYPbA=" + } + } + }, + "jison-lex": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/jison-lex/-/jison-lex-0.2.1.tgz", + "integrity": "sha1-rEuBXozOUTLrErXfz+jXB7iETf4=", + "requires": { + "lex-parser": "0.1.4", + "nomnom": "1.5.2" + }, + "dependencies": { + "colors": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/colors/-/colors-0.5.1.tgz", + "integrity": "sha1-fQAj6usVTo7p/Oddy5I9DtFmd3Q=" + }, + "nomnom": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.5.2.tgz", + "integrity": "sha1-9DRUSKhTz71cDSYyDyR3qwUm/i8=", + "requires": { + "colors": "0.5.1", + "underscore": "1.1.7" + } + }, + "underscore": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.1.7.tgz", + "integrity": "sha1-QLq4S60Z0jAJbo1u9ii/8FXYPbA=" + } + } + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "js-yaml": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", + "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", + "requires": { + "argparse": "1.0.10", + "esprima": "4.0.1" + } + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-schema-faker": { + "version": "0.5.0-rc15", + "resolved": "https://registry.npmjs.org/json-schema-faker/-/json-schema-faker-0.5.0-rc15.tgz", + "integrity": "sha512-q9my8/67q/JHTvZCuT75LQGfj8Ar4uRUK0rSvOWMu6VbYyrfR9b4GQOmgjHm8ez052+GVNfK+nSiM/WUsU/4Zw==", + "requires": { + "deref": "0.7.3", + "json-schema-ref-parser": "5.1.2", + "jsonpath": "1.0.0", + "randexp": "0.4.9", + "tslib": "1.9.3" + } + }, + "json-schema-ref-parser": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-5.1.2.tgz", + "integrity": "sha512-gP0mSqqkG99xNeA4F6bf2pXQYv5fFqe9SybbKO9qSMmyzzfFFIqd16s9Y65mRWKzZ0muTjyEtcSE/hLZLvIjZw==", + "requires": { + "call-me-maybe": "1.0.1", + "debug": "3.1.0", + "js-yaml": "3.12.0", + "ono": "4.0.5" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "requires": { + "graceful-fs": "4.1.11" + } + }, + "jsonpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/jsonpath/-/jsonpath-1.0.0.tgz", + "integrity": "sha1-Rc2dTE0NaCXZC9fkD4PxGCsT3Qc=", + "requires": { + "esprima": "1.2.2", + "jison": "0.4.13", + "static-eval": "2.0.0", + "underscore": "1.7.0" + }, + "dependencies": { + "esprima": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.2.tgz", + "integrity": "sha1-dqD9Zvz+FU/SkmZ9wmQBl1CxZXs=" + }, + "underscore": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", + "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=" + } + } + }, + "jsonwebtoken": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.3.0.tgz", + "integrity": "sha512-oge/hvlmeJCH+iIz1DwcO7vKPkNGJHhgkspk8OH3VKlw+mbi42WtD4ig1+VXRln765vxptAv+xT26Fd3cteqag==", + "requires": { + "jws": "3.1.5", + "lodash.includes": "4.3.0", + "lodash.isboolean": "3.0.3", + "lodash.isinteger": "4.0.4", + "lodash.isnumber": "3.0.3", + "lodash.isplainobject": "4.0.6", + "lodash.isstring": "4.0.1", + "lodash.once": "4.1.1", + "ms": "2.1.1" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "jsx-ast-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz", + "integrity": "sha1-6AGxs5mF4g//yHtA43SAgOLcrH8=", + "dev": true, + "requires": { + "array-includes": "3.0.3" + } + }, + "jszip": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.1.3.tgz", + "integrity": "sha1-ipIEA7KxZRwPwSa+kBktkICVfDc=", + "requires": { + "core-js": "2.3.0", + "es6-promise": "3.0.2", + "lie": "3.1.1", + "pako": "1.0.6", + "readable-stream": "2.0.6" + }, + "dependencies": { + "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=" + }, + "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.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "0.10.31", + "util-deprecate": "1.0.2" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, + "jwa": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.1.6.tgz", + "integrity": "sha512-tBO/cf++BUsJkYql/kBbJroKOgHWEigTKBAjjBEmrMGYd1QMBC74Hr4Wo2zCZw6ZrVhlJPvoMrkcOnlWR/DJfw==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.10", + "safe-buffer": "5.1.1" + } + }, + "jws": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.1.5.tgz", + "integrity": "sha512-GsCSexFADNQUr8T5HPJvayTjvPIfoyJPtLQBwn5a4WZQchcrPMPMAWcC1AzJVRDKyD6ZPROPAxgv6rfHViO4uQ==", + "requires": { + "jwa": "1.1.6", + "safe-buffer": "5.1.1" + } + }, + "klaw-sync": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-2.1.0.tgz", + "integrity": "sha1-PTvNhgDnv971MjHHOf8FOu1WDkQ=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11" + } + }, + "lazystream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", + "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", + "requires": { + "readable-stream": "2.3.6" + } + }, + "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" + } + }, + "lex-parser": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/lex-parser/-/lex-parser-0.1.4.tgz", + "integrity": "sha1-ZMTwJfF/1Tv7RXY/rrFvAVp0dVA=" + }, + "lie": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz", + "integrity": "sha1-mkNrLMd0bKWd56QfpGmz77dr2H4=", + "requires": { + "immediate": "3.0.6" + } + }, + "linkify-it": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.0.3.tgz", + "integrity": "sha1-2UpGSPmxwXnWT6lykSaL22zpQ08=", + "dev": true, + "requires": { + "uc.micro": "1.0.5" + } + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "strip-bom": "3.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "2.0.0", + "path-exists": "3.0.0" + }, + "dependencies": { + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, + "lodash": { + "version": "4.17.10", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", + "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" + }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "3.0.2" + } + }, + "lru-cache": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", + "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", + "dev": true, + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" + } + }, + "markdown-it": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz", + "integrity": "sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==", + "dev": true, + "requires": { + "argparse": "1.0.10", + "entities": "1.1.1", + "linkify-it": "2.0.3", + "mdurl": "1.0.1", + "uc.micro": "1.0.5" + } + }, + "match-stream": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/match-stream/-/match-stream-0.0.2.tgz", + "integrity": "sha1-mesFAJOzTf+t5CG5rAtBCpz6F88=", + "requires": { + "buffers": "0.1.1", + "readable-stream": "1.0.34" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, + "mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", + "dev": true + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" + }, + "mime-db": { + "version": "1.35.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz", + "integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg==" + }, + "mime-types": { + "version": "2.1.19", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz", + "integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==", + "requires": { + "mime-db": "1.35.0" + } + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "1.1.11" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "minipass": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz", + "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", + "requires": { + "safe-buffer": "5.2.0", + "yallist": "3.0.3" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" + }, + "yallist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" + } + } + }, + "minizlib": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz", + "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==", + "requires": { + "minipass": "2.3.5" + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", + "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", + "dev": true, + "requires": { + "browser-stdout": "1.3.1", + "commander": "2.15.1", + "debug": "3.1.0", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.2", + "growl": "1.10.5", + "he": "1.1.1", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "supports-color": "5.4.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "moment": { + "version": "2.22.2", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz", + "integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y=" + }, + "mongodb": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.1.1.tgz", + "integrity": "sha512-GU9oWK4pi8PC7NyGiwjFMwZyMqwGWoMEMvM0LZh7UKW/FFAqgmZKjjriD+5MEOCDUJE2dtHX93/K5UtDxO0otg==", + "requires": { + "mongodb-core": "3.1.0" + } + }, + "mongodb-core": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-3.1.0.tgz", + "integrity": "sha512-qRjG62Fu//CZhkgn0jA/k8jh5MhACIq8cOJUryH6sck87pgt+C222MSD02tsCq5zNo/B6ZFHtNodZ2qpf8E86g==", + "requires": { + "bson": "1.0.9", + "require_optional": "1.0.1", + "saslprep": "1.0.1" + } + }, + "morgan": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.0.tgz", + "integrity": "sha1-0B+mxlhZt2/PMbPLU6OCGjEdgFE=", + "requires": { + "basic-auth": "2.0.0", + "debug": "2.6.9", + "depd": "1.1.2", + "on-finished": "2.3.0", + "on-headers": "1.0.1" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "multer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.1.tgz", + "integrity": "sha512-zzOLNRxzszwd+61JFuAo0fxdQfvku12aNJgnla0AQ+hHxFmfc/B7jBVuPr5Rmvu46Jze/iJrFpSOsD7afO8SDw==", + "requires": { + "append-field": "1.0.0", + "busboy": "0.2.14", + "concat-stream": "1.6.2", + "mkdirp": "0.5.1", + "object-assign": "4.1.1", + "on-finished": "2.3.0", + "type-is": "1.6.16", + "xtend": "4.0.1" + } + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, + "nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" + }, + "napi-build-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.1.tgz", + "integrity": "sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA==" + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + }, + "node-abi": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.9.0.tgz", + "integrity": "sha512-jmEOvv0eanWjhX8dX1pmjb7oJl1U1oR4FOh0b2GnvALwSYoOdU7sj+kLDSAyjo4pfC9aj/IxkloxdLJQhSSQBA==", + "requires": { + "semver": "5.5.0" + } + }, + "node-unzip-2": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/node-unzip-2/-/node-unzip-2-0.2.7.tgz", + "integrity": "sha512-eSZZY23JRoU0Y32T2LjH4vGbv7NyIFdMVb+GYAcFc0Av7at3cw4zeGOrrAy/dL8LjHFwb4YuH7ghYLWqkpQ+Dg==", + "requires": { + "binary": "0.3.0", + "fstream": "1.0.11", + "match-stream": "0.0.2", + "pullstream": "0.4.1", + "readable-stream": "1.0.34", + "setimmediate": "1.0.5" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, + "nomnom": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.8.1.tgz", + "integrity": "sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc=", + "dev": true, + "requires": { + "chalk": "0.4.0", + "underscore": "1.6.0" + } + }, + "noop-logger": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", + "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=" + }, + "normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "dev": true, + "requires": { + "hosted-git-info": "2.7.1", + "is-builtin-module": "1.0.0", + "semver": "5.5.0", + "validate-npm-package-license": "3.0.4" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "requires": { + "remove-trailing-separator": "1.1.0" + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "requires": { + "are-we-there-yet": "1.1.5", + "console-control-strings": "1.1.0", + "gauge": "2.7.4", + "set-blocking": "2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-extended": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/object-extended/-/object-extended-0.0.7.tgz", + "integrity": "sha1-hP0j9WsVWCrrPoiwXLVdJDLWijM=", + "requires": { + "array-extended": "0.0.11", + "extended": "0.0.6", + "is-extended": "0.0.10" + } + }, + "object-keys": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", + "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==", + "dev": true + }, + "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.0.2" + } + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "1.2.0" + } + }, + "ono": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/ono/-/ono-4.0.5.tgz", + "integrity": "sha512-ZVNuV9kJbr/2tWs83I2snrYo+WIS0DISF/xUfX9p9b6GyDD6F5N9PzHjW+p/dep6IGwSYylf1HCub5I/nM0R5Q==", + "requires": { + "format-util": "1.0.3" + } + }, + "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.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "over": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/over/-/over-0.0.5.tgz", + "integrity": "sha1-8phS5w/X4l82DgE6jsRMgq7bVwg=" + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "1.3.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "pako": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz", + "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==" + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "1.3.2" + } + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "2.0.1" + } + }, + "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-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": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "2.3.0" + } + }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "2.0.4" + } + }, + "pkg-conf": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz", + "integrity": "sha1-ISZRTKbyq/69FoWW3xi6V4Z/AFg=", + "dev": true, + "requires": { + "find-up": "2.1.0", + "load-json-file": "4.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "2.0.0" + } + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "4.0.0", + "pify": "3.0.0", + "strip-bom": "3.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "1.3.2", + "json-parse-better-errors": "1.0.2" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "pkg-config": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pkg-config/-/pkg-config-1.1.1.tgz", + "integrity": "sha1-VX7yLXPaPIg3EHdmxS6tq94pj+Q=", + "dev": true, + "requires": { + "debug-log": "1.0.1", + "find-root": "1.1.0", + "xtend": "4.0.1" + } + }, + "pkg-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", + "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", + "dev": true, + "requires": { + "find-up": "1.1.2" + } + }, + "pluralize": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", + "dev": true + }, + "prebuild-install": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.0.tgz", + "integrity": "sha512-aaLVANlj4HgZweKttFNUVNRxDukytuIuxeK2boIMHjagNJCiVKWFsKF4tCE3ql3GbrD2tExPQ7/pwtEJcHNZeg==", + "requires": { + "detect-libc": "1.0.3", + "expand-template": "2.0.3", + "github-from-package": "0.0.0", + "minimist": "1.2.0", + "mkdirp": "0.5.1", + "napi-build-utils": "1.0.1", + "node-abi": "2.9.0", + "noop-logger": "0.1.1", + "npmlog": "4.1.2", + "os-homedir": "1.0.2", + "pump": "2.0.1", + "rc": "1.2.8", + "simple-get": "2.8.1", + "tar-fs": "1.16.3", + "tunnel-agent": "0.6.0", + "which-pm-runs": "1.0.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + }, + "simple-get": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.1.tgz", + "integrity": "sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw==", + "requires": { + "decompress-response": "3.3.0", + "once": "1.4.0", + "simple-concat": "1.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=" + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + }, + "progress": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", + "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=", + "dev": true + }, + "promish": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/promish/-/promish-5.1.1.tgz", + "integrity": "sha512-37xEzvSas6JIYI/BcKh5TwhaqWepI44u/hC+tQStkX1sxMf+L756beESPgSWirxRCPqtXHzosoNzpjLnTnP8FA==", + "requires": { + "es6-promise": "3.0.2" + } + }, + "prop-types": { + "version": "15.6.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz", + "integrity": "sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ==", + "dev": true, + "requires": { + "loose-envify": "1.4.0", + "object-assign": "4.1.1" + } + }, + "proxy-addr": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", + "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", + "requires": { + "forwarded": "0.1.2", + "ipaddr.js": "1.8.0" + } + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "pullstream": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/pullstream/-/pullstream-0.4.1.tgz", + "integrity": "sha1-1vs79a7Wl+gxFQ6xACwlo/iuExQ=", + "requires": { + "over": "0.0.5", + "readable-stream": "1.0.34", + "setimmediate": "1.0.5", + "slice-stream": "1.0.0" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "requires": { + "end-of-stream": "1.4.1", + "once": "1.4.0" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + }, + "randexp": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.4.9.tgz", + "integrity": "sha512-maAX1cnBkzIZ89O4tSQUOF098xjGMC8N+9vuY/WfHwg87THw6odD2Br35donlj5e6KnB1SB0QBHhTQhhDHuTPQ==", + "requires": { + "drange": "1.0.2", + "ret": "0.2.2" + } + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" + }, + "raw-body": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", + "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", + "unpipe": "1.0.0" + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "requires": { + "deep-extend": "0.6.0", + "ini": "1.3.5", + "minimist": "1.2.0", + "strip-json-comments": "2.0.1" + }, + "dependencies": { + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + } + } + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "2.0.0", + "normalize-package-data": "2.4.0", + "path-type": "2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "2.1.0", + "read-pkg": "2.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "2.0.0" + } + } + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.1", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" + }, + "request-ip": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/request-ip/-/request-ip-2.1.1.tgz", + "integrity": "sha512-cxNIoWf9JDuZM6YKdfTWdRsOi/hI4eIG6rGeodFyo8cCnTePoTW4qYbcKkQUz6evJkVXw+y0++BDz+Dh78M1pQ==", + "requires": { + "is_js": "0.9.0" + } + }, + "require-uncached": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "dev": true, + "requires": { + "caller-path": "0.1.0", + "resolve-from": "1.0.1" + }, + "dependencies": { + "resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "dev": true + } + } + }, + "require_optional": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", + "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==", + "requires": { + "resolve-from": "2.0.0", + "semver": "5.5.0" + } + }, + "resolve": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", + "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", + "dev": true, + "requires": { + "path-parse": "1.0.6" + } + }, + "resolve-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", + "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=" + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "2.0.1", + "signal-exit": "3.0.2" + } + }, + "ret": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.2.2.tgz", + "integrity": "sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==" + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "requires": { + "glob": "7.1.2" + } + }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "requires": { + "is-promise": "2.1.0" + } + }, + "run-parallel": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", + "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", + "dev": true + }, + "rx-lite": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", + "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=", + "dev": true + }, + "rx-lite-aggregates": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", + "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", + "dev": true, + "requires": { + "rx-lite": "4.0.8" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "saslprep": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.1.tgz", + "integrity": "sha512-ntN6SbE3hRqd45PKKadRPgA+xHPWg5lPSj2JWJdJvjTwXDDfkPVtXWvP8jJojvnm+rAsZ2b299C5NwZqq818EA==", + "optional": true + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" + }, + "send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "requires": { + "debug": "2.6.9", + "depd": "1.1.2", + "destroy": "1.0.4", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "etag": "1.8.1", + "fresh": "0.5.2", + "http-errors": "1.6.3", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "2.3.0", + "range-parser": "1.2.0", + "statuses": "1.4.0" + }, + "dependencies": { + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" + } + } + }, + "serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "requires": { + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "parseurl": "1.3.2", + "send": "0.16.2" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "sharp": { + "version": "0.22.1", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.22.1.tgz", + "integrity": "sha512-lXzSk/FL5b/MpWrT1pQZneKe25stVjEbl6uhhJcTULm7PhmJgKKRbTDM/vtjyUuC/RLqL2PRyC4rpKwbv3soEw==", + "requires": { + "color": "3.1.2", + "detect-libc": "1.0.3", + "fs-copy-file-sync": "1.1.1", + "nan": "2.14.0", + "npmlog": "4.1.2", + "prebuild-install": "5.3.0", + "semver": "6.2.0", + "simple-get": "3.0.3", + "tar": "4.4.10", + "tunnel-agent": "0.6.0" + }, + "dependencies": { + "semver": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.2.0.tgz", + "integrity": "sha512-jdFC1VdUGT/2Scgbimf7FSx9iJLXoqfglSF+gJeuNWVpiE37OIbc1jywR/GJyFdz3mnkz2/id0L0J/cr0izR5A==" + } + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + }, + "simple-concat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz", + "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=" + }, + "simple-get": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.0.3.tgz", + "integrity": "sha512-Wvre/Jq5vgoz31Z9stYWPLn0PqRqmBDpFSdypAnHu5AvRVCYPRYGnvryNLiXu8GOBNDH82J2FRHUGMjjHUpXFw==", + "requires": { + "decompress-response": "3.3.0", + "once": "1.4.0", + "simple-concat": "1.0.0" + } + }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "requires": { + "is-arrayish": "0.3.2" + }, + "dependencies": { + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + } + } + }, + "slice-ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", + "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "2.0.0" + } + }, + "slice-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slice-stream/-/slice-stream-1.0.0.tgz", + "integrity": "sha1-WzO9ZvATsaf4ZGCwPUY97DmtPqA=", + "requires": { + "readable-stream": "1.0.34" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, + "slug": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/slug/-/slug-0.9.1.tgz", + "integrity": "sha1-rwj2CKfBFRa2F3iqgA3OhMUYz9o=", + "requires": { + "unicode": "11.0.1" + } + }, + "slugify": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.3.1.tgz", + "integrity": "sha512-6BwyhjF5tG5P8s+0DPNyJmBSBePG6iMyhjvIW5zGdA3tFik9PtK+yNkZgTeiroCRGZYgkHftFA62tGVK1EI9Kw==" + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "optional": true + }, + "spdx-correct": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", + "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", + "dev": true, + "requires": { + "spdx-expression-parse": "3.0.0", + "spdx-license-ids": "3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", + "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "requires": { + "spdx-exceptions": "2.1.0", + "spdx-license-ids": "3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", + "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "dev": true + }, + "standard": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/standard/-/standard-11.0.1.tgz", + "integrity": "sha512-nu0jAcHiSc8H+gJCXeiziMVZNDYi8MuqrYJKxTgjP4xKXZMKm311boqQIzDrYI/ktosltxt2CbDjYQs9ANC8IA==", + "dev": true, + "requires": { + "eslint": "4.18.2", + "eslint-config-standard": "11.0.0", + "eslint-config-standard-jsx": "5.0.0", + "eslint-plugin-import": "2.9.0", + "eslint-plugin-node": "6.0.1", + "eslint-plugin-promise": "3.7.0", + "eslint-plugin-react": "7.7.0", + "eslint-plugin-standard": "3.0.1", + "standard-engine": "8.0.1" + } + }, + "standard-engine": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-8.0.1.tgz", + "integrity": "sha512-LA531C3+nljom/XRvdW/hGPXwmilRkaRkENhO3FAGF1Vtq/WtCXzgmnc5S6vUHHsgv534MRy02C1ikMwZXC+tw==", + "dev": true, + "requires": { + "deglob": "2.1.1", + "get-stdin": "6.0.0", + "minimist": "1.2.0", + "pkg-conf": "2.1.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "static-eval": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.0.0.tgz", + "integrity": "sha512-6flshd3F1Gwm+Ksxq463LtFd1liC77N/PX1FVVc3OzL3hAmo2fwHFbuArkcfi7s9rTNsLEhcRmXGFZhlgy40uw==", + "requires": { + "escodegen": "1.11.0" + }, + "dependencies": { + "escodegen": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.0.tgz", + "integrity": "sha512-IeMV45ReixHS53K/OmfKAIztN/igDHzTJUhZM3k1jMhIZWjk45SMwAtBsEXiJp3vSPmTcu6CXn7mDvFHRN66fw==", + "requires": { + "esprima": "3.1.3", + "estraverse": "4.2.0", + "esutils": "2.0.2", + "optionator": "0.8.2", + "source-map": "0.6.1" + } + }, + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true + } + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "streamsearch": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", + "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" + }, + "string-extended": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/string-extended/-/string-extended-0.0.8.tgz", + "integrity": "sha1-dBlX3/SHsCcqee7FpE8jnubxfM0=", + "requires": { + "array-extended": "0.0.11", + "date-extended": "0.0.6", + "extended": "0.0.6", + "is-extended": "0.0.10" + } + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "3.0.0" + } + } + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "strip-ansi": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", + "integrity": "sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=", + "dev": true + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + }, + "superagent": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.3.tgz", + "integrity": "sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "cookiejar": "2.1.2", + "debug": "3.1.0", + "extend": "3.0.2", + "form-data": "2.3.2", + "formidable": "1.2.1", + "methods": "1.1.2", + "mime": "1.4.1", + "qs": "6.5.2", + "readable-stream": "2.3.6" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + }, + "table": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", + "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", + "dev": true, + "requires": { + "ajv": "5.5.2", + "ajv-keywords": "2.1.1", + "chalk": "2.4.1", + "lodash": "4.17.10", + "slice-ansi": "1.0.0", + "string-width": "2.1.1" + }, + "dependencies": { + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.1.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "1.9.2" + } + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.4.0" + } + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true + } + } + }, + "tar": { + "version": "4.4.10", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.10.tgz", + "integrity": "sha512-g2SVs5QIxvo6OLp0GudTqEf05maawKUxXru104iaayWA09551tFCTI8f1Asb4lPfkBr91k07iL4c11XO3/b0tA==", + "requires": { + "chownr": "1.1.2", + "fs-minipass": "1.2.6", + "minipass": "2.3.5", + "minizlib": "1.2.1", + "mkdirp": "0.5.1", + "safe-buffer": "5.2.0", + "yallist": "3.0.3" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" + }, + "yallist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" + } + } + }, + "tar-fs": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz", + "integrity": "sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw==", + "requires": { + "chownr": "1.1.2", + "mkdirp": "0.5.1", + "pump": "1.0.3", + "tar-stream": "1.6.1" + }, + "dependencies": { + "pump": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", + "integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==", + "requires": { + "end-of-stream": "1.4.1", + "once": "1.4.0" + } + } + } + }, + "tar-stream": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.1.tgz", + "integrity": "sha512-IFLM5wp3QrJODQFPm6/to3LJZrONdBY/otxcvDIQzu217zKye6yVR3hhi9lAjrC2Z+m/j5oDxMPb1qcd8cIvpA==", + "requires": { + "bl": "1.2.2", + "buffer-alloc": "1.2.0", + "end-of-stream": "1.4.1", + "fs-constants": "1.0.0", + "readable-stream": "2.3.6", + "to-buffer": "1.1.1", + "xtend": "4.0.1" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "1.0.2" + } + }, + "to-buffer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", + "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==" + }, + "traverse": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", + "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=" + }, + "tslib": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "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": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "type-is": { + "version": "1.6.16", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "2.1.19" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "uc.micro": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.5.tgz", + "integrity": "sha512-JoLI4g5zv5qNyT09f4YAvEZIIV1oOjqnewYg5D38dkQljIzpPT296dbIGvKro3digYI1bkb7W6EP1y4uDlmzLg==", + "dev": true + }, + "underscore": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=", + "dev": true + }, + "unicode": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/unicode/-/unicode-11.0.1.tgz", + "integrity": "sha512-+cHtykLb+eF1yrSLWTwcYBrqJkTfX7Quoyg7Juhe6uylF43ZbMdxMuSHNYlnyLT8T7POAvavgBthzUF9AIaQvQ==" + }, + "uniq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", + "dev": true + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "requires": { + "punycode": "2.1.1" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "3.0.0", + "spdx-expression-parse": "3.0.0" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "walkdir": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/walkdir/-/walkdir-0.0.11.tgz", + "integrity": "sha1-oW0CXrkxvQO1LzCMrtD0D86+lTI=" + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "2.0.0" + } + }, + "which-pm-runs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz", + "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=" + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "requires": { + "string-width": "2.1.1" + } + }, + "winston": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/winston/-/winston-2.3.1.tgz", + "integrity": "sha1-C0hCDZeMAYBM8CMLZIhhWYIloRk=", + "dev": true, + "requires": { + "async": "1.0.0", + "colors": "1.0.3", + "cycle": "1.0.3", + "eyes": "0.1.8", + "isstream": "0.1.2", + "stack-trace": "0.0.10" + }, + "dependencies": { + "async": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", + "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=", + "dev": true + }, + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", + "dev": true + } + } + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "dev": true, + "requires": { + "mkdirp": "0.5.1" + } + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "zip-stream": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-1.2.0.tgz", + "integrity": "sha1-qLxF9MG0lpnGuQGYuqyqzbzUugQ=", + "requires": { + "archiver-utils": "1.3.0", + "compress-commons": "1.2.2", + "lodash": "4.17.10", + "readable-stream": "2.3.6" + } + } + } +} diff --git a/service/package.json b/service/package.json new file mode 100644 index 0000000..df10f61 --- /dev/null +++ b/service/package.json @@ -0,0 +1,55 @@ +{ + "name": "ground", + "version": "1.0.0", + "description": "Services and more for Earth ground", + "main": "index.js", + "scripts": { + "test": "mocha mocha.entry.js", + "test:all": "mocha './{,!(node_modules)/**/}*.spec.js'", + "lint": "standard", + "doc:api": "apidoc -i . -o ../doc/api -f services/ -f ./apidoc.js", + "doc:pdf": "pxdoc ../doc/PXEN302-0014_DSN_AIR_PMP_SERVER.md", + "doc": "npm run doc:api && npm run doc:pdf", + "dev": "ENV=dev nodemon" + }, + "repository": { + "type": "git", + "url": "ssh://gitolite@tuleap.pxcom.aero/airpmp/airpmp-server.git" + }, + "keywords": [], + "apidoc": { + "title": "Earth - Cloud", + "url": "http://earth.codeisalie.fr" + }, + "author": "P.BARRY", + "license": "ISC", + "dependencies": { + "ajv": "^6.5.2", + "async": "^2.6.1", + "axios": "^0.18.0", + "body-parser": "^1.18.3", + "camelcase": "^5.0.0", + "colors": "^1.3.2", + "exceljs": "^1.6.0", + "express": "^4.16.3", + "faker": "^4.1.0", + "fs-extra": "^7.0.0", + "json-schema-faker": "^0.5.0-rc15", + "jsonwebtoken": "^8.3.0", + "moment": "^2.22.2", + "mongodb": "^3.1.1", + "morgan": "^1.9.0", + "multer": "^1.4.1", + "request-ip": "^2.1.1", + "sharp": "^0.22.1", + "slug": "^0.9.1", + "slugify": "^1.3.1" + }, + "devDependencies": { + "apidoc": "^0.17.6", + "chai": "^4.1.2", + "chai-http": "^4.0.0", + "mocha": "^5.2.0", + "standard": "^11.0.1" + } +} diff --git a/service/services/core/config/router.js b/service/services/core/config/router.js new file mode 100644 index 0000000..969a15d --- /dev/null +++ b/service/services/core/config/router.js @@ -0,0 +1,8 @@ +const express = require('express') +const router = express.Router() + +const CFG = require('../../../config') + +module.exports = function (pCtx) { + return router +} diff --git a/service/services/core/config/router.spec.js b/service/services/core/config/router.spec.js new file mode 100644 index 0000000..f275d73 --- /dev/null +++ b/service/services/core/config/router.spec.js @@ -0,0 +1,24 @@ +/* eslint-env mocha */ +/* eslint no-unused-expressions: 0 */ + +const chai = require('chai') +const chaiHttp = require('chai-http') +const expect = chai.expect + +chai.use(chaiHttp) + +describe('Core - Config', function () { + describe('# Foo', function () { + it.skip('GET /core/config/foo', function (done) { + chai.request(global.server) + .get('/core/config/foo') + .set('token', global.jwtAccess || '') + .end((err, res) => { + // console.log(res.body) + expect(err).to.be.null + expect(res).to.have.status(200) + done() + }) + }) + }) +}) diff --git a/service/services/media/router.js b/service/services/media/router.js new file mode 100644 index 0000000..3712f65 --- /dev/null +++ b/service/services/media/router.js @@ -0,0 +1,201 @@ +const express = require('express') +const router = express.Router() +const async = require('async') +const path = require('path') +const multer = require('multer') +const fs = require('fs-extra') +const upload = multer({ dest: 'uploads' }) + +const sharp = require('sharp') + +const TOL = require('../../tools/common') +const CFG = require('../../config') +var CTX = null + +module.exports = function (pCtx) { + CTX = pCtx + router.post('/upload', upload.single('media'), handleUploadedMedia) + + router.get('/get/:id', function (req, res) { + let mediaId = req.params.id + CTX.restapi.media.__services.readOne(mediaId, {projection: {path: 1}}, function (pErr, pResult) { + if (pErr) { + return res.status(404).send('Media:Media:NotFound') + } + let mediaPath = path.join(CFG.media.documents, pResult.data.path) + fs.access(mediaPath, fs.constants.F_OK, function (pErr) { + if (pErr) { + return res.status(404).send('Media:File:NotFound') + } + res.sendFile(mediaPath) + }) + }) + }) + + router.get('/preview/:id', function (req, res) { + let mediaId = req.params.id + CTX.restapi.media.__services.readOne(mediaId, {projection: {mimetype: 1, path: 1}}, function (pErr, pResult) { + if (pErr) { + return res.sendFile(CFG.media['404']) + } + + let media = pResult.data + let mimetypes = media.mimetype.split('/') + let type = mimetypes[0] + let subtype = mimetypes[1] + + switch (type) { + case 'image': + let mediaPath = path.join(CFG.media.documents, media.path) + getPreviewFromImage(res, mediaPath, req.query) + break + default: + res.sendFile(CFG.media['404']) + } + }) + }) + + return router +} + +function getPreviewFromImage (res, pPath, pQuery, pMedia) { + let query = pQuery + query.width = parseInt(query.width) || null + query.height = parseInt(query.height) || null + query.fit = query.fit || 'cover' + if (!query.width && !query.height) { + query.width = 1024 + } + + let outName = TOL.createHash(JSON.stringify(query), 'sha1') + let outPath = path.join(CFG.media.cache, generatePathFromMediaId(outName)) + let outFull = path.join(outPath, `${outName}.jpg`) + + let tasks = [] + + tasks.push(function (pCb) { + fs.ensureDir(outPath, pErr => pCb(pErr)) + }) + + tasks.push(function (pCb) { + sharp(pPath) + .resize(query.width, query.height, {fit: query.fit}) + .toFile(outFull, function (pErr) { + pCb(pErr) + }) + }) + + async.waterfall(tasks, function (pErr) { + if (pErr) { + console.log(pErr) + res.sendFile(CFG.media['404']) + } else { + res.sendFile(outFull) + } + }) +} + +function handleUploadedMedia (req, res) { + let tasks = [] + let file = req.file + let fileKey = { + coll: '__default', + id: '', + path: '' + } + let ext = getExtensionFromMimetype(file.mimetype) + let currentDate = new Date() + + if (req.body.docColl && req.body.docId && req.body.docPath) { + fileKey = { + coll: req.body.docColl, + id: req.body.docId, + path: req.body.docPath + } + } + + let mediaId = TOL.createHash(JSON.stringify(fileKey.coll === '__default' ? file : fileKey), 'sha1') + let outPath = path.join(CFG.media.documents, generatePathFromMediaId(mediaId)) + let outName = `media.${ext}` + let outFull = path.join(outPath, outName) + let isAlreadyExisting = false + + file.createdAt = currentDate + file.fileKey = fileKey + + tasks.push(function (pCb) { + fs.ensureDir(outPath, pErr => pCb(pErr)) + }) + + tasks.push(function (pCb) { + fs.move(file.path, outFull, { overwrite: true }, pErr => pCb(pErr)) + }) + + tasks.push(function (pCb) { + fs.writeFile(path.join(outPath, 'info'), JSON.stringify(file, null, 2), 'utf8', pErr => pCb(pErr)) + }) + + tasks.push(function (pCb) { + CTX.restapi.media.__services.readOne(mediaId, {projection: {_id: 1}}, function (pErr, pResult) { + if (pResult && pResult.ok) { + isAlreadyExisting = true + } + pCb() + }) + }) + + tasks.push(function (pCb) { + let doc = { + _id: mediaId, + name: outName, + originalName: file.originalname, + extension: ext, + path: path.join(generatePathFromMediaId(mediaId), outName), + fileKey: fileKey, + mimetype: file.mimetype, + size: file.size + } + + if (isAlreadyExisting) { + CTX.restapi.media.__services.update(mediaId, doc, req.user, 'media', function (pErr, pResult) { + pCb(pErr) + }) + } else { + CTX.restapi.media.__services.create(doc, req.user, function (pErr, pResult) { + pCb(pErr) + }) + } + }) + + async.waterfall(tasks, function (pErr) { + res.done(pErr, { + ok: pErr ? 0 : 1, + mediaId: mediaId + }) + }) +} + +function generatePathFromMediaId (pMediaId) { + let outSubf = pMediaId.slice(0, 4) + return path.join(outSubf, pMediaId) +} + +function getExtensionFromMimetype (pMimetype) { + let ext = 'unknown' + let mimetypes = pMimetype.split('/') + let type = mimetypes[0] + let subtype = mimetypes[1] + switch (type) { + case 'audio': + case 'video': + case 'image': + ext = subtype + break + case 'application/pdf': + ext = 'pdf' + break + default: + } + + return ext +} diff --git a/service/services/media/rsc/default/404.jpg b/service/services/media/rsc/default/404.jpg new file mode 100644 index 0000000000000000000000000000000000000000..02cac0190228abda1f05d9cb2027c6525b3af65d GIT binary patch literal 11864 zcmeHtcU)6Vx9(1%w3~K}m7w1O&m_Kye6ga0n4m_Kti>)&}l z`yf+%268{k*6#q+On?0v>yw|_Uj#BjCAX})V9y^4t~PT2Cvnlg(0&3gIA?KJo0JE> z1Gr3z5%Pl{QrCa#e-X-13fW8qP9e`7~kbX!&^QTvBRfz=ex)}-P$ydThhub{o` z)t)1QevS}M2)px9_t!QmER3Z7y4DYmB<4zF-PF!Yt-lg~AmB>a5?k!kA3c2AlB`v= zv}4)8$xy{U=Tpl}KNy68%2^e8Ki>TBtl%+vvfD2SB3;{NEX3F~SKsB(|wRH91>LN&otJb29;Oiwaw*Dq@H~Hb%>c4K9O=;kKy9W68Mj z07yHMmwndm>@mhzn1oXabJ~2&A8RVEy8teQb6`y|0Fe76kV-!VD;!fGsybOj$)09q z^DxrkdYStQssy~XW&pskk&TnUmUWC379NbZ1;1rX=B|fA9-P+ZdV%m)Kb4HlnS`yZ zHM;0{J1KP}ar-Legg_(Ga|w6Gj0{%>1XsH^iLj~%fWmRTNK|wkTGcDRZYw*h^gBmgL0s|C5Awz2G{HO zF#ucw%_w!qWzD?a!+8OfGUX5nnK7EXsK5Dx5#frgOp+S%`%Kae*2Mtqa-CT7V+$GK zga>r^yBgnUA)NWfvDAMQ{~-g|E#@g0b_b0I#)1CagyKK}?Cuj64<>9zK}kg|NX{!H z14khFqMfmOPkii-6odml0Mb~UK$_O0i}dCFLehNtZ>Du?N)jXaz5~PxelD+1l(6<< z%wS*bFZS1sio^?Hjarc1 zmKGM0z zs)aZu!6r{Lh3i=?5cZwYiZsy5l}Ym{Xvk3F6y+@{+Hjd~=gRAB9A2#iyCND)@D;=)BOGR`mF?0lYOzq57Ii)w7I}Ch^Of{pbq^jYo1XF#`+r#^Mjq2fSt!Q~rA7g=wheU+Vja+I0?b*qdTV@A9|Ln{C zb6wu)KUVd8oNR{Mvpw-^aE&+#=yG;}k z48{?0)h#U6?B+EDCD*IJ^q$&wn|hnrtX>eKpQPF2Bzm1VY#ALIJdzW-X3dqC8*A~F zJ^EvUC=1yR&TvOSg?Dm>H=6;gV|uRk1ghQW?(HCUU(oH5;B+k$REOt{g+bhc;&-=k zGxt@rgw)%%H>+MMJLtCdENK^yYs0IIyY=K=Flo_ifQ7v|v*n7d6Cdz6%1u!z3=Q>Z z2z)Bwz6~(yLC(a?Cn#&?;#%3pA|q$+<`)wim;HhQ$;&UKV^KA;F0ZTS?vD}(h_-az z$o;X_;!0!JS`$7gGz?BmC2#R0&LPLhXf!TN`m&o`thb|jq!5q0tTGA2DH+zHDPKNx#d){WvSy`lp><$JBa*hSc*fjCq_LF2 zcQDIzDoU(c4i=k#f>Rpt$ao~7Po~zIh$ym#aP`yPM`kJz`v{f63cXEeq;}1qqh0^a zy`6h0=^_9mR&8SC8ws;;5`4{T`^mNUnSe=eedF~PP2lTMhCyc zt(aO*ElP&$E1gC|$(QzKyF>B=DUksydx=l;_=yfV{TrjR= z=Y6!(83U)FWAJv-lKi@2bNlwmkP1>q-$4Q}<`k&;Way=$LBeNg*V|Pmbad~~W+14- zC;~6qU6T9^>p*BcB`7-=v+Iz-jE#sB8`0)yvkqb0HALeL=IOxo$QV_aWB4alt*4l>Wf}y7smyiN*1BNs&ko7s0fO} z>q(l2+U4$a8sQ0xLi4m^Y)O{k6!-g(_azc%`?z(=*rU8u>^XFGRBIxuV@Tvs6YV)u zF}phA8)4Ku%n!trm$fvvE|ajWFuC7X@U_i==WxmySecq%Wu{u`!f9YYZ zSD})96+2talS*4Y5H&|9&bN=I)i+#vPgGX27>~seU11Am)`+;=wbLc$P+VFtiBKg6 zud6Boh6H9>9)T6?4Udh;C(U^X-d7|-cZ}4)-X*BI#Bn{@(^O06%;!YyRP_~PT3#Df z-*xhkMEYnBRT+^pvKi6;_sh^jlJF!^ykqPI&jynA-HdYe4L;@dXqD$-imHM|ui3o3 zWN}x*a0dOT`bCc&^4+QS(wx9i-P~wijUi_`6zQ$PT<;yO&wBhXUzGX|Svv03Eud?C zA<!-G@mO|cdyYx2)fs#B0o&rUr-+rZ8EeUd5gmgW<`s% zb0sunQog#U0GFkS*m{(nK%#8*?CXLwS2M#UmKrO36Mb&2B0|u4yQJ#uJ-#zG^4k`s z{lTjp&FN%gq26LAs}T|BkxYX%RaN+k?@X=8%VjF&!W18HQuWnS&D@p8XKQ!>4tLZ4 zLb;j&BBJc6(vzKiD9TA;Os5*<{hHlI_C^6oM^*3uiHCis@WSfS&1Y(317DJVH<+?; zU|{x{Qcjf)?!wS-VTsFdYl!3-5)lp&GW%<%@Sl*5zSQf}o7uCLQMgoYwN7WFlg{Ap zad&LMv|L{Qmh0j(oA8BN;*dM@)E_hX3qN|>6z_76N#Nccwoyi=U-opTzCSQ>a-#k( z+S$)n0+?AoUee$1zhyP4^}@90jbMMSm?-p}Ky_BL z@!9`PM{C%KsCdHWYbsPuEJGF&niTWB)JPA2`9}n&nWE*Hm0_8b0N!gfV)<0|P`_-J(KNOvp<2CEb(U$^wj|WVfacEIhBeno zB0iQmMY^H{xU-saNALZ{2#h@+$Of~}^P$J$-TVB+&Mlq+)P>@;>#C0oo}!mptbB4f z&k1}|sn=4@KcPjDHNAXqSrUPN@6>g%M+S{{OD!ly^WmnkraU?&G-ooBc@~cdlSymL zJgrv<>kuHBvkvstV6cSuqY^EP0z>vEaJ;N;%rcvh2&T^WsLPMa%X-(TJ)e0SG<$9}rV(#2CFdp~GK?3DWu$SSnv5jY+8UjB+Qq*ecJx zFK5IUvG-aB@imd}<(>Lg${FSha?CG2*qz%Y4!xX<+`>Eam~17@I>)FkgO`ucN&w~BBQ2=q1D%B2x$q@n75gma)>DI#t&_&Ra|&G z7ae(zB)%ffxwos#>(irgW$dno2ZlY=fpG94hhIf}+xLLrOaPy(jvvg-+$AQvZ5=67 z$@{`NdSmA32q?{j-InkYC1Wc1dmp~5-CDx4BEE`G4BaigAOF;#b#}b@Msj1wn|uD& zmacSf;8CImL-t)gDpuuo6)+&{q+T$6G-7;rf>zD53(&#vRU`u1og-V~F|O^@)a{eC zbKT{lOD7E!W#Bi@4n&p>hrYZ?_g>EbJWfiT{HqCiTjwpOuXMiW3r^77k|hzI1k&Gn zaMqL2wVgo=jzj1KZto1d>IDJjTeNm=t!g&R*9QwN07MPA4UU&9jaM@r)PIl@4!t!y4*u3EuU%)ih&ut{%=YPnBo3kokZth-_Y8#x?<;A-U+ zdfj|@)0t9;8I*(Oq+VGFO#MQLC7ksYqV3!$2jf-FiLiayJLe$|@F=k_kS+aZ7@>>X zn_1_#n_dY`_@U-_iC(J=hlr8j3(wi@(n{Tn?CdsdN;O2Vy}>@1H3(sNxEpt|>XHGC zg{_+9CvBROy3}@~Fzpfl!K?=scP}Q5dj#Bwd{L``K9N2^i2=jkriKGfLc_ceH?Jka;R_sv7 zt7SNDPYY-W4r#>45gQ}y9;lc_*mPv?J?_7L)B2T<<%gChHfW#3G->~YriTtxcgILK z^&;Eu<0Q`Mn>HGvvh=DN9(^;fMsabbL8+lf;OW_s$lZQjAu# zJ|$I8c^L1zYtKlL@4JMl?rEeIUH12;m)!PNzD!hS_UVd58Fi%Y>ZedD*X*#+_xr0@ zeub|TFBo`D8axKIv-J_{;h(6_SfrZv%~%ihhQ$p@_Md9mlbk_pGqD$Vr(N*f_HJNZ zmD8dHnCMfzcf!Bdix3dz^@r+RIn$1tYg~kz4HE)>SRvjE@A~ z$Ac_w4Nd>=q_i9rI99%qZr*pCx&>ASlA^Vo^z)=iso) z0{JJG8&xJ0o@cMPi$II@MTHZ1{m|>{j~1P`7wzX=9M$lT)1>?UY<-uW5p{>fU0)N2c=8ZYY%>=_+bo+Jn!0NG|~-JXW;q^K6{FwC{^YMGx!iG(o3Z zw5g9@d4*I+TxMYWdKTZVG~4n8&1d8 z<@jIHMiqT0|MKZ_P_HLwE(z0Ffec>pdK_PKQ{+ZZmBe)y&x#lI`%YRU&#t+K<}&vT z_lDi{YQfi>q9Yz@>mN(2zB9heu$J7%bUk(Q)*T)?B8D`<>c>rqrql)1{r$ZA6tjlx zXE4`Qb25Y3y7~=Lo=x-!rNtCAMu=Xlgyf0g1ydgYS1?0FpGx0#e)Yi#Gu>V6`! zN3IBvKe1l~=#eXEw9GHcp8&y;ghn1oziFe7u-GHvH!b=H23Glv@(6++xq@PjpkG_q zk*mWWM;u#FN3KwqV>tjq=7;W&Q61$Igu?uw|E7tRMa9Yh2s9G>P52E13lX4V(MSXu z6%9HRe$N50PEfHRR5Zai;W!cjDjGYM3h>Pp^f(p(pke_O=G#2}VRpdZU17ZtApc)o z0l;BY$9p-_{D|tP`}_7ESKspTKgtyX{qy$ueKNnh`ojnBrx^_U3H;glgYa{G_ygyE zqQZyzAAdU>Ie^AuqxuiD?;KRL%8}7;TLKiIf&yc&e<&d6w+ul2RgiyR0pH^R{W`&8p3X#z-Hh!K5VF!SSOYn9hCZ1S}O2P}Yu~F&FT-)JW(!882C4kRMTe8s=@xD#y zvm&9z`HzYd3rf5its9o?X|k@XDWZfRfCjXNN|U|IZf4iuWPdf<5uY9pXhG&{V7R$J zacc@Y^Wl$TUSGm%K=!)gc=rHaQ-Hhz?C5W9PMX;Mp5d^(vbMa?5>YBb0( zfaJD#Wc6J739Cf3VD!AdyL<(Rs{u!{^|W~LfMnf-avqZr|B{x@cI}s@e4od9otA^K zZ%7@<40@;uW|2$Hm9`L;%wQ-Y|XdYhD?Ka8Ul z=Vd6ehQ5XHMGv(ArJ%M($I6@wBGlm{qudS2(hOUYMX7UVsiSZY0MwheZSzruFTIG1 zD~Pn2yJ%@vo1?_~9B+rdos)Xm_4dgqLMUcw&XzKiBwh%%WfBwYRl9L7QvAiNnHsgg zbL&-|3VbtW;1!vjgdHV<@e|3o&!>?TWdl{eDA}3HRe3#8m`z{^ToJC`?xF_0Cg0LuBkzmiyO$?JZ-0c^ymT zhTPcP0|4P#Na^NFbO5Xt4`g^Uo-iT%{1=G-gSVt~&OH5UvvCX+NfM_(&He!pfF5WW zR;l5;q1`%pPd5O=6Y^%`8t$cJynEK0CIJ@_tfgl8p@z*~>6t|`+u77Z!ek2uh)xuKRP%ZJNU__mmDa$?P>ScS!kz+E5z)u4 zL%hZ6EBb2M=(Eg2XP@Ifv$nWh;=hG@*zfRG>u@Zep8eQq(ek^}hXee@{udF}yXi@L z%6)Z)TBRq%zLb~4@4yq*_7m(!?!nN>pQY44;6U_g*A>50VUMq5+((_% z(GxX;U3E>5*Bx(doiz01gc7S=%*h`WxY%MK%3&YL#PvSRn#Irm6U9ulzZ4|}O@*Ma z!DI^cdw_JE_kGcWEaq_lZ+IY-wclVZ&|gmH8Vgn4Ab|VMOl-4M)^~ETMNpGdVB@KtsL$2+h#6V70z5N;j$9-bofRkR-az zKB7CJ-f>5FOi^LfCbCM+-EO!Ogv?QR9#<%n)7ec_03`IrZE{cL@H}8S*Zoy0h|!90 zm_q2m(t0Ma94lcXnGVaj|wP;X=S8T6|jKhspsS-O~9_ijJMfaJ5plmwY<9R00w+I%-7 z^l=K={I2QMS@bv~fjPwG8?}55vdY}{1Xn-SNtK35*ryy_Ot5r z2LJ{X7n0S_TCtGTzs$bA&_OOF&PKpS9Ck*J7pB5SHWZR0aaU-_A{gEn;1VA4LHk^k z|D}QW*1$aBr=)eE7Y7=5cj7J!ps&e%Fzgh*Th$hv4ME_A90+gOU6XF5~RzMGzm}K6YQ1<-J$7>XpZLvu>b6C6&(Nv GWB&!`Nd!;; literal 0 HcmV?d00001 diff --git a/service/services/restapi/collections/__template.js b/service/services/restapi/collections/__template.js new file mode 100644 index 0000000..54ff1c9 --- /dev/null +++ b/service/services/restapi/collections/__template.js @@ -0,0 +1,70 @@ +module.exports = function (pName, pLabel, pIcon, pDesc) { + return { + name: pName, + label: pLabel || pName, + icon: pIcon || 'mdi-hexagon', + description: pDesc || '---', + /** MongoDB indexes - format: {keys:, options:} */ + indexes: [], + /** JSON Schema */ + schema: {}, + hooks: { + read: { + before: (pCtx, next) => { + next() + }, + after: (pCtx, docs, next) => { + next() + } + }, + readOne: { + before: (pCtx, id, next) => { + next() + }, + after: (pCtx, doc, next) => { + next() + } + }, + update: { + before: (pCtx, id, doc, origin, next) => { + next() + }, + after: (pCtx, doc, origin, next) => { + next() + } + }, + create: { + before: (pCtx, doc, next) => { + next() + }, + after: (pCtx, doc, next) => { + next() + } + }, + delete: { + before: (pCtx, id, next) => { + next() + }, + after: (pCtx, ok, next) => { + next() + } + } + }, + tools: {}, + /** Db handler of collection */ + __db: null, + __services: { + read: function (pArgs, pCallback) { pCallback() }, + readOne: function (pId, pArgs, pCallback) { pCallback() }, + create: function (pDoc, pUser, pCallback) { pCallback() }, + update: function (pId, pDoc, pUser, pCallback) { pCallback() }, + delete: function (pId, pUser, pCallback) { pCallback() } + }, + __internal: { + router: require('express').Router(), + addRoute: function (pMethod, pUrl, pFunc) { + this.router[pMethod.toLowerCase()](pUrl, pFunc) + } + } + } +} \ No newline at end of file diff --git a/service/services/restapi/collections/config/config.form.js b/service/services/restapi/collections/config/config.form.js new file mode 100644 index 0000000..8247b47 --- /dev/null +++ b/service/services/restapi/collections/config/config.form.js @@ -0,0 +1,36 @@ + +module.exports = function (pCtx, coll) { + + coll.formCreate = [ + { + size: '', + list: [ + { field: 'name', label: 'Nom du champ', type: 'text', rules: {required: 'Nom manquant'} }, + { field: '_id', label: 'Clé', type: 'text', rules: {required: 'Clé manquante'} } + ] + } + ] + + coll.form = [ + { + label: 'General', + field: '', + form: [ + { + size: '', + list: [ + { field: 'name', label: 'Nom', type: 'text' }, + { field: '_id', label: 'Clé', type: 'text', disabled: true }, + { field: 'value', label: 'Value', type: 'text' } + ] + } + ] + } + ] + + coll.listingHeader = [ + { text: 'Nom', align: 'left', value: 'name' }, + { text: 'Clé', align: 'center', value: '_id' }, + { text: 'Valeur', align: 'center', value: 'value' } + ] +} diff --git a/service/services/restapi/collections/config/config.js b/service/services/restapi/collections/config/config.js new file mode 100644 index 0000000..eb2ada8 --- /dev/null +++ b/service/services/restapi/collections/config/config.js @@ -0,0 +1,18 @@ +const Template = require('../__template') +const coll = new Template('config', 'Configuration', 'mdi-bookmark', 'Configuration du nubium artifex') + +coll.customId = true + +coll.schema = { + type: 'object', + properties: { + _id: { type: 'string' }, + name: { type: 'string' }, + value: {} + } +} + +module.exports = function (pCtx) { + require('./config.form')(pCtx, coll) + return coll +} diff --git a/service/services/restapi/collections/landingpages/landingpages.form.js b/service/services/restapi/collections/landingpages/landingpages.form.js new file mode 100644 index 0000000..e4e18f5 --- /dev/null +++ b/service/services/restapi/collections/landingpages/landingpages.form.js @@ -0,0 +1,38 @@ + +module.exports = function (pCtx, coll) { + + coll.formCreate = [ + { + size: '', + list: [ + { field: 'name', label: 'Nom', type: 'text', rules: {required: 'Nom manquant'} } + ] + } + ] + + coll.form = [ + { + label: 'General', + field: '', + form: [ + { + size: '', + list: [ + { field: 'name', label: 'Nom', type: 'text' }, + { field: 'description', label: 'Description', type: 'textarea' } + ] + }, + { + size: '', + list: [ + { field: 'preview', label: 'Preview', type: 'media' } + ] + } + ] + } + ] + + coll.listingHeader = [ + { text: 'Nom', align: 'left', value: 'name' } + ] +} diff --git a/service/services/restapi/collections/landingpages/landingpages.js b/service/services/restapi/collections/landingpages/landingpages.js new file mode 100644 index 0000000..6e5edce --- /dev/null +++ b/service/services/restapi/collections/landingpages/landingpages.js @@ -0,0 +1,32 @@ +const Template = require('../__template') +const coll = new Template('landingpages', 'Landing Pages', 'mdi-home', 'Pages d\'accueil') + +coll.indexes.push({keys: {name: 1}, options: {unique: true}}) + +coll.schema = { + type: 'object', + additionalProperties: false, + required: ['name'], + properties: { + name: { + type: 'string' + }, + description: { + type: 'string' + }, + preview: { + type: 'string' + }, + page: { + type: 'array', + items: { + type: 'array' + } + } + } +} + +module.exports = function (pCtx) { + require('./landingpages.form')(pCtx, coll) + return coll +} diff --git a/service/services/restapi/collections/media/media.js b/service/services/restapi/collections/media/media.js new file mode 100644 index 0000000..ea94ec6 --- /dev/null +++ b/service/services/restapi/collections/media/media.js @@ -0,0 +1,21 @@ +const Template = require('../__template') +const coll = new Template('media') + +coll.customId = true + +coll.schema = { + type: 'object', + properties: { + name: { type: 'string' }, + originalName: { type: 'string' }, + mimetype: { type: 'string' }, + extension: { type: 'string' }, + path: { type: 'string' }, + fileKey: { type: 'object' }, + size: { type: 'number' } + } +} + +module.exports = function (pCtx) { + return coll +} diff --git a/service/services/restapi/collections/users-filters/users-filters.js b/service/services/restapi/collections/users-filters/users-filters.js new file mode 100644 index 0000000..a9f5e52 --- /dev/null +++ b/service/services/restapi/collections/users-filters/users-filters.js @@ -0,0 +1,14 @@ +const Template = require('../__template') +const coll = new Template('users-filters') + +coll.schema = { + type: 'object', + properties: { + name: { type: 'string' }, + rules: { type: 'object' } + } +} + +module.exports = function (pCtx) { + return coll +} diff --git a/service/services/restapi/collections/users/users.form.js b/service/services/restapi/collections/users/users.form.js new file mode 100644 index 0000000..81d0497 --- /dev/null +++ b/service/services/restapi/collections/users/users.form.js @@ -0,0 +1,58 @@ + +module.exports = function (pCtx, coll) { + + coll.formCreate = [ + { + size: '', + list: [ + { + field: 'username', + label: 'Nom d\'utilisateur', + type: 'text', + rules: {required: 'Nom manquant', regex: '[a-zA-Z0-9_-];i;Le nom doit respecter le format [a-zA-Z0-9]'} + }, + { field: 'email', label: 'Courriel', type: 'text', rules: {required: 'Courriel manquant'} } + ] + } + ] + + coll.form = [ + { + label: 'General', + field: '', + form: [ + { + size: '', + list: [ + { field: 'username', label: 'Nom d\'utilisateur', type: 'text' }, + { field: 'email', label: 'Courriel', type: 'text' } + ] + }, + { + size: '', + list: [ + { field: 'avatar', label: 'Avatar', type: 'media' } + ] + } + ] + }, + { + label: 'Details', + field: 'details', + form: [ + { + size: '', + list: [ + { field: 'firstname', label: 'Prénom', type: 'text' }, + { field: 'lastname', label: 'Nom', type: 'text' } + ] + } + ] + } + ] + + coll.listingHeader = [ + { text: 'Username', align: 'left', value: 'username' }, + { text: 'Courriel', align: 'center', value: 'email' } + ] +} diff --git a/service/services/restapi/collections/users/users.js b/service/services/restapi/collections/users/users.js new file mode 100644 index 0000000..0398000 --- /dev/null +++ b/service/services/restapi/collections/users/users.js @@ -0,0 +1,47 @@ +const Template = require('../__template') +const users = new Template('users') + +users.indexes.push({keys: {email: 1}, options: {unique: true}}) + +users.schema = { + type: 'object', + additionalProperties: false, + required: ['username', 'email'], + properties: { + username: { + type: 'string' + }, + email: { + type: 'string', + format: 'email' + }, + details: { + type: 'object', + properties: { + firstname: { type: 'string' }, + lastname: { type: 'string' }, + language: { type: 'string' }, + company: { type: 'string' }, + corporateTitle: { type: 'string' } + } + }, + multipass: { + type: 'object', + properties: { + hash: { + type: 'string' + } + } + } + } +} + +users.hooks.readOne.after = function (ctx, doc, next) { + doc.name = `${doc.username}` + next() +} + +module.exports = function (pCtx) { + require('./users.form')(pCtx, users) + return users +} diff --git a/service/services/restapi/collections/users/users.spec.js b/service/services/restapi/collections/users/users.spec.js new file mode 100644 index 0000000..906c4bc --- /dev/null +++ b/service/services/restapi/collections/users/users.spec.js @@ -0,0 +1,39 @@ +/* eslint-env mocha */ +/* eslint no-unused-expressions: 0 */ + +const chai = require('chai') +const chaiHttp = require('chai-http') +const expect = chai.expect + +chai.use(chaiHttp) + +describe('# Users', function () { + it('GET /api/users', function (done) { + chai.request(global.server) + .get('/api/users') + .set('token', global.jwtAccess) + .end((err, res) => { + // console.log(res.status) + expect(err).to.be.null + expect(res).to.have.status(200) + expect(res.body).to.have.property('data') + expect(res.body.data).to.have.lengthOf.at.least(1) + done() + }) + }) +}) + +describe('# Users - Filters', function () { + it('GET /api/users-filters', function (done) { + chai.request(global.server) + .get('/api/users-filters') + .set('token', global.jwtAccess) + .end((err, res) => { + // console.log(res.status) + expect(err).to.be.null + expect(res).to.have.status(200) + expect(res.body).to.have.property('data') + done() + }) + }) +}) diff --git a/service/services/restapi/router.js b/service/services/restapi/router.js new file mode 100644 index 0000000..0829f13 --- /dev/null +++ b/service/services/restapi/router.js @@ -0,0 +1,734 @@ +const express = require('express') +const router = express.Router() +const path = require('path') +const fs = require('fs') +const ObjectId = require('mongodb').ObjectId +const async = require('async') + +const Ajv = require('ajv') +const jsf = require('json-schema-faker') + +// const CFG = require('../../config') +const TAG = 'REST' + +const REST_CTX = { + models: [], + api: [ + {method: 'GET', url: '/:collection', desc: ''}, + {method: 'POST', url: '/:collection', desc: ''}, + {method: 'PUT', url: '/:collection/:id', desc: ''}, + {method: 'DELETE', url: '/:collection', desc: ''}, + {method: 'GET', url: '/:collection/private/json-schema', desc: ''}, + {method: 'GET', url: '/:collection/private/json-schema/fake', desc: ''} + ] +} + +jsf.extend('faker', function () { + return require('faker') +}) +// router.use((req, res, next) => { +// console.log('API isAuth', req.isAuth) +// next() +// }) + +function initCollections (pCtx) { + pCtx.restapi = {} + fs.readdir(path.join(__dirname, './collections'), (pErr, pColls) => { + pColls.forEach((pColl) => { + if (/^__/.test(pColl)) return + let coll = require(path.join(__dirname, './collections', pColl, pColl))(pCtx) + if (pCtx.logEnabled) console.log(`[-] ${TAG} | Loading collection: ${coll.name}`) + // INIT INDEXES + coll.indexes = coll.indexes || [] + coll.indexes.forEach((pIndex) => { + pCtx.db.collection(coll.name).createIndex(pIndex.keys, pIndex.options) + }) + pCtx.restapi[coll.name] = coll + initRestApi(pCtx, coll) + REST_CTX.models.push(coll.name) + }) + }) + + router.get('/__intern/collections', function (req, res, next) { + let all = [] + for (let coll in pCtx.restapi) { + all.push({ + coll: coll, + label: pCtx.restapi[coll].label, + icon: pCtx.restapi[coll].icon, + description: pCtx.restapi[coll].description + }) + } + res.done(null, all.sort((a, b) => a.label.localeCompare(b.label))) + }) + + router.get('/', function (req, res, next) { + res.done(null, REST_CTX) + }) +} + +function initRestApi (pCtx, pColl) { + let collHandler = pCtx.db.collection(pColl.name) + let ajv = new Ajv({removeAdditional: true, allErrors: true}) + let collValidator = ajv.compile(pColl.schema) + if (collValidator.error) { + console.error(collValidator) + process.exit(1) + } + + router.use(function (req, res, next) { + generateFilterObject(req) + next() + }) + + pColl.__services = { + read: null, + readOne: null, + create: null, + update: null, + delete: null + } + + pColl.__db = collHandler + + pColl.__addMetadata = function (doc, user, req) { + doc.__metadata = { + owner: user ? user._id : null, + updatedBy: null, + createdAt: new Date(), + updatedAt: null, + deletedAt: null + } + } + + pColl.__updateMetadata = function (doc, user) { + delete doc.__metadata + doc['__metadata.updatedAt'] = new Date() + if (user) doc['__metadata.updatedBy'] = user ? user._id : null + } + + pColl.__generateFilterObject = generateFilterObject + pColl.__buildRestOp = buildRestOpObject + + // Add new routes + if (pColl.__internal.router) router.use('/' + pColl.name + '/methods/', pColl.__internal.router) + + /** + * @api {get} /api/:collection Get all + * @apiName get:/api/:collection + * @apiVersion 0.0.1 + * @apiGroup Restapi + * @apiDescription Get all documents from one collection + * + * @apiParam {String} collection Required collection + * + * @apiSuccess {Object} res Response. + * @apiSuccess {Object} res.ok 1 if success. + * @apiSuccess {Object} res.data List of documents. + * @apiSuccess {Object} res.limit Results limitation. + * @apiSuccess {Object} res.skip Skipped results. + * @apiSuccess {Object} res.count Total results available on server. + * @apiSuccess {Object} res.links Links to navigate into documents. + * + * @apiUse SessionError + */ + router.get(`/${pColl.name}`, (req, res) => { + pColl.__services.read(req.restOp, res.done) + }) + + pColl.__services.read = function (pArgs, pCallback) { + let restOp = pArgs || buildRestOpObject() + // Find operator + let findOp = { $and: [] } + findOp.$and.push(restOp.filter) + // Projection operator + let projOp = Object.keys(restOp.projection).length ? restOp.projection : {} + // Find all matching elements + collHandler.find(findOp).count(function (pErr, pCount) { + collHandler + // Filters elements + .find(findOp) + // Project fields + .project(projOp) + // Sort result + .sort(restOp.sort) + // Limit the number + .limit(restOp.limit) + // Skip + .skip(restOp.skip) + // Get results + .toArray(function (pErr, pResults) { + if (pErr) return pCallback(pErr) + pCallback(null, { + ok: 1, + label: pCtx.restapi[pColl.name].label, + icon: pCtx.restapi[pColl.name].icon, + description: pCtx.restapi[pColl.name].description, + data: pResults, + limit: restOp.limit, + count: pCount, + skip: restOp.skip, + links: { + base: '', + next: `/api/${pColl.name}?limit=${restOp.limit}&skip=${restOp.skip + restOp.limit}`, + prev: `/api/${pColl.name}?limit=${restOp.limit}&skip=${Math.max(0, restOp.skip - restOp.limit)}` + }, + sort: restOp.sort + }) + }) + }) + } + + /** + * @api {post} /api/:collection Create + * @apiName post:/api/:collection + * @apiVersion 0.0.1 + * @apiGroup Restapi + * @apiDescription Create one new document + * + * @apiSuccess {Object} res Response. + * @apiSuccess {Object} res.ok 1 if success. + * @apiSuccess {Object} res.data Returned document. + * + * @apiError Db:DuplicateKey When a field set as unique index has been already created + * @apiUse SessionError + */ + router.post(`/${pColl.name}`, (req, res) => { + pColl.__services.create(req.body, req.user, res.done) + }) + + pColl.__services.create = function (pDoc, pUser, pCallback) { + collValidator(pDoc) + let errors = collValidator.errors + if (errors && errors.length) return pCallback(errors) + // + + let tasks = [] + let createdDoc = {ok: 0, doc: null} + + tasks.push(function (pCb) { + pColl.hooks.create.before(pCtx, pDoc, function (pErr) { + pCb(pErr) + }) + }) + + tasks.push(function (pCb) { + // delete pDoc._id + pColl.__addMetadata(pDoc, pUser) + collHandler.insertOne(pDoc, function (pErr, pResult) { + if (pErr) { + switch (pErr.code) { + case 11000: + createdDoc = pErr + return pCb(new Error('Db:DuplicateKey'), pErr) + default: + return pCb(pErr) + } + } + createdDoc.ok = pResult.insertedCount + createdDoc.doc = pResult.ops[0] + pCb() + }) + }) + + tasks.push(function (pCb) { + pColl.hooks.create.after(pCtx, createdDoc.doc, function (pErr) { + pCb(pErr) + }) + }) + + async.waterfall(tasks, function (pErr) { + pCallback(pErr, createdDoc) + }) + } + + /** + * @api {get} /api/:collection/:id Get one + * @apiName get:/api/:collection/:id + * @apiVersion 0.0.1 + * @apiGroup Restapi + * @apiDescription Get one document + * + * @apiParam {String} collection Required collection + * @apiParam {ObjectId} id Required document Id + * + * @apiSuccess {Object} res Response. + * @apiSuccess {Object} res.ok 1 if success. + * @apiSuccess {Object} res.data Returned document. + * + * @apiError Db:WrongDbId ID parameter is not a MongoDB ObjectId + * @apiError Db:NotFound Required document ID not found in DB + * @apiUse SessionError + */ + router.get(`/${pColl.name}/:id`, (req, res) => { + pColl.__services.readOne(req.params.id, req.restOp, res.done) + }) + + pColl.__services.readOne = function (pId, pArgs, pCallback) { + // Convert ID if it's a correct one else returns one error + let objectId = getObjectId(pId, pColl.customId) + if (!objectId) { + return pCallback(new Error('Db:WrongDbId')) + } + + let tasks = [] + let oneDoc = {ok: 0, id: pId, data: null} + + // Call before hook to transform data + tasks.push(function (pCb) { + pColl.hooks.readOne.before(pCtx, objectId, function (pErr) { + pCb(pErr) + }) + }) + // Get one document + tasks.push(function (pCb) { + collHandler + .find({_id: objectId}) + .project(pArgs.projection) + .limit(1) + .next(function (pErr, pDoc) { + if (pErr) return pCallback(pErr) + if (!pDoc) return pCallback(400, new Error('Db:NotFound')) + oneDoc.ok = 1 + oneDoc.label = pCtx.restapi[pColl.name].label + oneDoc.icon = pCtx.restapi[pColl.name].icon + oneDoc.description = pCtx.restapi[pColl.name].description + oneDoc.data = pDoc + pCb() + }) + }) + // Call after hook to perform some operations + tasks.push(function (pCb) { + pColl.hooks.readOne.after(pCtx, oneDoc.data, function (pErr) { + pCb(pErr) + }) + }) + + async.waterfall(tasks, function (pErr) { + pCallback(pErr, oneDoc) + }) + } + + /** + * @api {put} /api/:collection/:id Update + * @apiName put:/api/:collection/:id + * @apiVersion 0.0.1 + * @apiGroup Restapi + * @apiDescription Update some fields of one document + * + * @apiParam {String} collection Required collection + * @apiParam {ObjectId} id Required document Id + * + * @apiSuccess {Object} res Response. + * @apiSuccess {Object} res.ok 1 if success. + * @apiSuccess {Object} res.data Returned document. + * + * @apiError Db:WrongDbId ID parameter is not a MongoDB ObjectId + * @apiError Db:NotFound Required document ID not found in DB + * @apiUse SessionError + */ + router.put(`/${pColl.name}/:id`, (req, res) => { + pColl.__services.update(req.params.id, req.body, req.user, 'router', res.done) + }) + + pColl.__services.update = function (pId, pDoc, pUser, pOrigin, pCallback) { + // console.log(pDoc) + // Convert ID if it's a correct one else returns one error + let objectId = getObjectId(pId, pColl.customId) + if (!objectId) { + return pCallback(new Error('Db:WrongDbId')) + } + // + collValidator(pDoc) + if (collValidator.errors) { + // console.dir(collValidator.errors, {depth: null, colors: true}) + let errors = collValidator.errors.filter(error => error.keyword !== 'required') + if (errors.length) return pCallback('JSONSchema:ValidationFailed', errors) + } + // + let tasks = [] + let updatedDoc = { ok: 0, id: pId, doc: null } + + // Call before hook to transform data + tasks.push(function (pCb) { + pColl.hooks.update.before(pCtx, objectId, pDoc, pOrigin, function (pErr) { + pCb(pErr) + }) + }) + // Save in DB + tasks.push(function (pCb) { + delete pDoc._id + // console.log(pDoc) + pColl.__updateMetadata(pDoc, pUser) + collHandler + .findOneAndUpdate( + {_id: objectId}, + {$set: pDoc}, + {returnOriginal: false}, + function (pErr, pResult) { + if (pErr) return pCb(pErr) + updatedDoc.ok = pResult.ok + updatedDoc.doc = pResult.value + pCb() + }) + }) + // Call after hook to perform some operations + tasks.push(function (pCb) { + pColl.hooks.update.after(pCtx, updatedDoc.doc, pOrigin, function (pErr) { + pCb(pErr) + }) + }) + + async.waterfall(tasks, function (pErr) { + pCallback(pErr, updatedDoc) + }) + } + + /** + * @api {delete} /api/:collection/:id Delete + * @apiName delete:/api/:collection/:id + * @apiVersion 0.0.1 + * @apiGroup Restapi + * @apiDescription Delete one document + * + * @apiParam {String} collection Required collection + * @apiParam {ObjectId} id Required document Id + * + * @apiSuccess {Object} res Response. + * @apiSuccess {Object} res.id [DbId] of deleted document. + * @apiSuccess {Object} res.ok 1 if success. + * + * @apiError Db:WrongDbId ID parameter is not a MongoDB ObjectId + * @apiUse SessionError + */ + router.delete(`/${pColl.name}/:id`, (req, res) => { + pColl.__services.delete(req.params.id, req.user, res.done) + }) + + pColl.__services.delete = function (pId, pUser, pCallback) { + // Convert ID if it's a correct one else returns one error + let objectId = getObjectId(pId, pColl.customId) + if (!objectId) { + return pCallback(new Error('Db:WrongDbId')) + } + + let tasks = [] + let deletedDoc = {ok: 0, id: pId} + + // Call before hook to transform data + tasks.push(function (pCb) { + pColl.hooks.delete.before(pCtx, objectId, function (pErr) { + pCb(pErr) + }) + }) + // Get one document + tasks.push(function (pCb) { + collHandler.removeOne({_id: objectId}, function (pErr, pDoc) { + if (pErr) return pCb(pErr) + deletedDoc.ok = pDoc.deletedCount + pCb() + }) + }) + // Call after hook to perform some operations + tasks.push(function (pCb) { + pColl.hooks.delete.after(pCtx, true, function (pErr) { + pCb(pErr) + }) + }) + + async.waterfall(tasks, function (pErr) { + pCallback(pErr, deletedDoc) + }) + } + + /** + * @api {get} /api/:collection/private/json-schema Get json schema + * @apiName get:/api/:collection/private/json-schema + * @apiVersion 0.0.1 + * @apiGroup Restapi + * @apiDescription Get JSON schema defined for this collection + * + * @apiParam {String} collection Required collection + * + * @apiSuccess {Json} schema JSON schema. + * + * @apiUse SessionError + */ + router.get(`/${pColl.name}/private/json-schema`, (req, res) => { + res.done(null, pColl.schema) + }) + + router.get(`/${pColl.name}/private/json-form`, (req, res) => { + res.done(null, pColl.form || []) + }) + + router.get(`/${pColl.name}/private/json-form-create`, (req, res) => { + res.done(null, pColl.formCreate || []) + }) + + router.get(`/${pColl.name}/private/listing-header`, (req, res) => { + res.done(null, pColl.listingHeader || [{ text: 'Nom', align: 'left', value: 'name' }]) + }) + + router.get(`/${pColl.name}/private/new-objectid`, (req, res) => { + res.done(null, new ObjectId()) + }) + + router.put(`/${pColl.name}/upsert/from/:field`, (req, res) => { + let findOp = { + [req.params.field]: req.body[req.params.field] + } + + let cat = req.body.categories + + delete req.body[req.params.value] + delete req.body.categories + + let upOp = {$set: req.body} + if (cat) { + upOp['$addToSet'] = {categories: cat} + } + + collHandler.findOneAndUpdate( + findOp, + upOp, + {upsert: true}, + res.done) + }) + + /** + * @api {get} /api/:collection/private/json-schema/fake Get fake schema + * @apiName get:/api/:collection/private/json-schema/fake + * @apiVersion 0.0.1 + * @apiGroup Restapi + * @apiDescription Get a fake JSON from schema defined for this collection + * + * @apiParam {String} collection Required collection + * + * @apiSuccess {Json} schema Fake JSON. + * + * @apiUse SessionError + */ + router.get(`/${pColl.name}/private/json-schema/fake`, (req, res) => { + jsf.option({ alwaysFakeOptionals: true }) + + jsf + .resolve(pColl.schema) + .then(function (result) { + if (result.planning) { + result.planning.byFormat = { + bannersHome: { + byAirline: { + AirFrance: { + deltaImpressions: 10000, + allowedFormats: ['iab-leaderboard', 'iab-squra'] + }, + TAROM: { + deltaImpressions: -10000, + allowedFormats: ['iab-squra'] + } + } + } + } + } + res.done(null, result) + }) + .catch(function (error) { + res.done(error) + }) + }) +} + +function buildRestOpObject () { + return { + filter: {}, + projection: {}, + sort: {}, + limit: 100, + skip: 0 + } +} + +function generateFilterObject (pReq) { + var filterObject = {} + var sortObject = {} + var projObject = {} + var request = null + var queries = pReq.query + var queryKeys = Object.keys(queries) + var length = queryKeys.length + var limit = 0 + var skip = 0 + var index, key, localData, lQueries, regArray, match, query, type + + var deletedDocs = null + + for (index = 0; index < length; index++) { + key = queryKeys[index] + if (key === 'limit') { + limit = parseInt(queries.limit) + } else if (key === 'skip') { + skip = parseInt(queries.skip) + } else if (key === 'projection') { + queries.projection.split(',').forEach(function (pProj) { + var projField = pProj.split(':') + projObject[projField[0]] = +projField[1] + }) + } else if (key === 'sort') { + queries.sort.split(',').forEach(function (pSort) { + if (pSort[0] === '-') { + sortObject[pSort.substring(1)] = -1 + } else { + sortObject[pSort] = 1 + } + }) + } else if (key === 'search') { + filterObject['$text'] = { '$search': queries.search } + } else if (key === 'deletedDocs') { + deletedDocs = queries.deletedDocs + } else { + request = key.split('__') + if (request.length <= 1 || !queries[key]) { + // console.log('unknown key', key); + continue + } + + match = queries[key].match(/\((.*)\)(.*)/) + if (match) { + type = match[1] + query = castValue(match[2], type) + } else { + type = null + query = queries[key] + } + + filterObject[request[0]] = filterObject[request[0]] || {} + + switch (request[1]) { + case 'eq' : + if (!type) { + switch (query) { + case 'true': + query = true + break + case 'false': + query = false + break + default: + if (!isNaN(query)) { + query = +query + } + } + } + filterObject[request[0]]['$eq'] = query + break + case 'lt' : + filterObject[request[0]]['$lt'] = query + break + case 'lte' : + filterObject[request[0]]['$lte'] = query + break + case 'gt' : + filterObject[request[0]]['$gt'] = query + break + case 'gte' : + filterObject[request[0]]['$gte'] = query + break + case 'ne' : + filterObject[request[0]]['$ne'] = query + break + case 'regex' : + regArray = query.split(',') + filterObject[request[0]]['$regex'] = new RegExp(regArray[0], regArray[1]) + break + case 'regexNot' : + regArray = query.split(',') + filterObject[request[0]]['$not'] = new RegExp(regArray[0], regArray[1]) + break + case 'exists' : + filterObject[request[0]]['$exists'] = query == 'true' + break + case 'in' : + case 'all' : + case 'nin' : + if (typeof query === 'string') { + localData = query.split(',') + } else { + localData = [query] + } + if (!type && request[0] === '_id') { + type = 'ObjectId' + } + if (type) { + lQueries = [] + localData.forEach(function (pElem) { + lQueries.push(castValue(pElem, type)) + }) + } else { + lQueries = localData + } + filterObject[request[0]]['$' + request[1]] = lQueries + break + default: + ; + } + } + } + + // if (!deletedDocs) { + // filterObject['__metadata.deletionDate'] = { $exists: false } + // } else { + // if (deletedDocs === 'only') { + // filterObject['__metadata.deletionDate'] = { $exists: true } + // } + // } + + pReq.restOp = buildRestOpObject() + pReq.restOp.filter = filterObject + pReq.restOp.projection = projObject + pReq.restOp.sort = sortObject + pReq.restOp.limit = limit || 100 + pReq.restOp.skip = skip + + return pReq.restOp +} + +function getObjectId (pId, pCustomId) { + let objectId = pCustomId ? pId : null + try { objectId = ObjectId(pId) } catch (e) {} + return objectId +} + +function castValue (pValue, pType) { + var query = pValue + switch (pType) { + case 'Number': + query = +query + break + case 'Boolean': + query = query == 'true' + break + case 'Date': + query = new Date(query) + break + case 'ObjectId': + try { + query = ObjectId(query) + } catch (e) { + // query = query + } + break + case 'NULL': + query = null + break + default: + console.warn('Unknown cast type', pType) + } + + return query +} + +module.exports = function (pCtx) { + initCollections(pCtx) + return router +} diff --git a/service/services/restapi/router.spec.js b/service/services/restapi/router.spec.js new file mode 100644 index 0000000..0a30b50 --- /dev/null +++ b/service/services/restapi/router.spec.js @@ -0,0 +1,25 @@ +/* eslint-env mocha */ +/* eslint no-unused-expressions: 0 */ + +const chai = require('chai') +const chaiHttp = require('chai-http') + +chai.use(chaiHttp) + +describe('Restapi - Router', function () { + require('./collections/users/users.spec') + + require('./collections/airports/airports.spec') + + require('./collections/media-plannings/media-plannings.spec') + + require('./collections/advertisers/advertisers.spec') + + require('./collections/airlines/airlines.spec') + require('./collections/airlines/airlines.services.spec') + + require('./collections/languages/languages.spec') + require('./collections/languages/languages.services.spec') +}) + +// require('./router.languages.spec') diff --git a/service/services/session/auth.js b/service/services/session/auth.js new file mode 100644 index 0000000..e1626b3 --- /dev/null +++ b/service/services/session/auth.js @@ -0,0 +1,89 @@ + +const jwt = require('jsonwebtoken') +const camelcase = require('camelcase') +const CFG = require('../../config') +const TOL = require('../../tools/common') +const ObjectId = require('mongodb').ObjectId + +const MSG = { + USER: { + NOT_ALLOWED: 'User:NotAllowed' + } +} + +/** + * For each received request, check the jwt token and user rights + * + * @param {HttpRequest} req Http request from client + * @param {HttpResponse} res Http context to answer to client + * @param {Function} next Callback to continue the Express pipe + */ +module.exports = function (pCtx) { + return (req, res, next) => { + if (req.method === 'OPTIONS') return next() + // Find token in the request. Can be set in: + // - header + // - token field : {token} + // - Authorization field : "Bearer {token}" + // - query + // - token field + let lToken + if (req.headers.token) { + lToken = req.headers.token + } else if (req.query.token) { + lToken = req.query.token + } else if (req.headers.authorization) { + let match = req.headers.authorization.match(/Bearer ?(.*)/) + if (match) { + lToken = match[1] + } + } else { + // To be removed when client is ready to use full auth API + if (!CFG.jwt.enable) { + return pCtx.db.collection('users') + .find({username: 'admin'}) + .limit(1) + .next(function (pErr, pUser) { + // console.log(pUser) + req.user = pUser + next() + }) + } else { + return res.done(401, 'jwtAccess:Missing') + } + } + + // Decrypt received token + jwt.verify(lToken, CFG.jwt.jwtAccess.secret, function (pErr, pToken) { + if (pErr) { + return res.done(401, new Error(`jwtAccess:${camelcase(pErr.message, {pascalCase: true})}`)) + } + + res.token = pToken + + let payloadState = TOL.jwt.checkPayload(req, res.token.data) + if (payloadState) { + return res.done(401, 'jwtAccess:CorruptedPayload:' + payloadState) + } + + req.user = res.token.data.user + try { req.user._id = ObjectId(req.user.id) } catch (e) {} + delete req.user.pass + + next() + }) + } +} + +/** + * Projects user fields to be public compliant + * @param {Object} pUser Public-ified user + */ +function JOB_getPublicUser (pUser) { + return { + id: pUser.id, + user: pUser.user, + role: pUser.role, + name: pUser.name + } +} diff --git a/service/services/session/router.js b/service/services/session/router.js new file mode 100644 index 0000000..0c41195 --- /dev/null +++ b/service/services/session/router.js @@ -0,0 +1,118 @@ +const express = require('express') +const router = express.Router() +const auth = require('../session/auth') +// const jwt = require('jsonwebtoken') + +module.exports = function (pCtx) { + const services = require('./services')(pCtx) + + /** + * @api {post} /session/login User Login + * @apiName post:/session/login + * @apiVersion 0.0.1 + * @apiGroup Session + * @apiDescription Api for User login + * Credientials must be set in a json body + * + * @apiParam {String} user Username for login + * @apiParam {String} pass Password for login + * + * @apiParamExample {json} Login Example: + * { + * "user": "User name", + * "pass": "User plain password", + * } + * + * @apiSuccess {Object} SessionCtx Context of successful login + * @apiSuccess {String} SessionCtx.jwtAuth Authentification token to use for get one jwtAccess token - Should be saved locally and set in header authorization field + * @apiSuccess {String} SessionCtx.user Just a reminder for user + * + * @apiError User:NotFound Username or email not found + * @apiError User:WrongPassword User found but password does not match + */ + router.post('/login', services.login) + + /** + * @api {post} /session/access User Acces + * @apiName post:/session/access + * @apiVersion 0.0.1 + * @apiGroup Session + * @apiDescription Get an jwtAccess from jwtAuth to access to all API with a short period + * Futermore, jwtAuth token TTL is updated + * + * @apiParam {String} jwtAuth jwtAuth token generated from /session/login + * + * @apiParamExample {json} jwtAuth: + * { + * "jwtAuth": "[Authentification JWT token]", + * } + * + * @apiSuccess {Object} SessionCtx Context of successful login + * @apiSuccess {String} SessionCtx.jwtAuth Updated jwtAuth token + * @apiSuccess {String} SessionCtx.jwtAccess Access token to use for each request to server - Should be saved locally and set in header authorization field + * + * @apiError User:NotFound Username or email not found + * @apiError User:PasswordChanged User found but password does not match from login one + * @apiError jwtAuth:Missing jwtAuth is missing in body request + * @apiError jwtAuth:InvalidSignature Signature of jwtAuth is invalid + * @apiError jwtAuth:JwtExpired Token is expired. A login try to login again + * @apiError jwtAuth:CorruptedPayload Token payload is corrupted (server version changes, wrong userAgent ou client ip address) + */ + // router.post('/access', services.access) + + router.use(auth(pCtx)) + + /** + * @api {get} /session/me About me + * @apiName get:/session/me + * @apiVersion 0.0.1 + * @apiGroup Session + * @apiDescription Get information about user of jwtAccess token + * Common case: check if user has still has access rights + * + * @apiParam {Header} token jwtAccess token + * + * @apiSuccess {Object} res Response + * @apiSuccess {String} res.user User information + * + * @apiUse SessionError + */ + router.get('/me', services.me) + + /** + * @api {get} /session/me/filters My filters - Get + * @apiName get:/session/me/filters + * @apiVersion 0.0.1 + * @apiGroup Session + * @apiDescription Get all custom filters created by current user + * + * @apiParam {Header} token jwtAccess token + * + * @apiSuccess {Object} res Response + * @apiSuccess {String} res.data All filters + * + * @apiUse SessionError + */ + router.get('/me/filters', services.filtersGet) + + /** + * @api {post} /session/me/filters My filters - Create + * @apiName post:/session/me/filters + * @apiVersion 0.0.1 + * @apiGroup Session + * @apiDescription Create new custom filter for current user + * + * @apiParam (Header) {String} token jwtAccess token + * @apiParam (Body) {Object} filter New Filter to create + * @apiParam (Body) {String} filter.name Name of filter + * @apiParam (Body) {Object} filter.rules Rules to build this filter + * + * @apiSuccess {Object} res Response + * @apiSuccess {String} res.doc New Filter + * + * @apiUse SessionError + */ + router.post('/me/filters', services.filtersCreate) + + return router +} diff --git a/service/services/session/router.spec.js b/service/services/session/router.spec.js new file mode 100644 index 0000000..58bf3ac --- /dev/null +++ b/service/services/session/router.spec.js @@ -0,0 +1,171 @@ +/* eslint-env mocha */ +/* eslint no-unused-expressions: 0 */ + +const chai = require('chai') +const chaiHttp = require('chai-http') +const expect = chai.expect +const jwt = require('jsonwebtoken') + +const CFG = require('../../config') + +chai.use(chaiHttp) + +describe('Session - Router', function () { + describe('# login', function () { + it('POST /session/login with unknown user', function (done) { + chai.request(global.server) + .post('/session/login') + .send({user: 'airpmpA', pass: 'admin'}) + .end((err, res) => { + expect(err).to.be.null + expect(res).to.have.status(401) + expect(res.body).to.have.property('error', 'User:NotFound') + done() + }) + }) + + it('POST /session/login with wrong password', function (done) { + chai.request(global.server) + .post('/session/login') + .send({user: 'airpmp', pass: 'toto'}) + .end((err, res) => { + expect(err).to.be.null + expect(res).to.have.status(401) + expect(res.body).to.have.property('error', 'User:WrongPassword') + done() + }) + }) + + it('POST /session/login', function (done) { + chai.request(global.server) + .post('/session/login') + .send(global.login) + .end((err, res) => { + // console.log(res.body) + expect(err).to.be.null + expect(res).to.have.status(200) + expect(res.body).to.have.nested.property('user.username', global.login.user) + expect(res.body).to.have.property('jwtAuth') + global.jwtAuth = res.body.jwtAuth + done() + }) + }) + + it('POST /session/access with no jwtAuth', function (done) { + chai.request(global.server) + .post('/session/access') + .send({}) + .end((err, res) => { + expect(err).to.be.null + expect(res).to.have.status(401) + done() + }) + }) + + it('POST /session/access', function (done) { + chai.request(global.server) + .post('/session/access') + .send({jwtAuth: global.jwtAuth}) + .end((err, res) => { + expect(err).to.be.null + expect(res).to.have.status(200) + expect(res.body).to.have.property('jwtAuth') + expect(res.body).to.have.property('jwtAccess') + let clearToken = jwt.decode(res.body.jwtAccess) + expect(clearToken).to.have.nested.property('data.user.rights') + global.jwtAuth = res.body.jwtAuth + global.jwtAccess = res.body.jwtAccess + done() + }) + }) + + it('POST /session/access with updated jwtAuth', function (done) { + chai.request(global.server) + .post('/session/access') + .send({jwtAuth: global.jwtAuth}) + .end((err, res) => { + expect(err).to.be.null + expect(res).to.have.status(200) + expect(res.body).to.have.property('jwtAuth') + expect(res.body).to.have.property('jwtAccess') + global.jwtAuth = res.body.jwtAuth + global.jwtAccess = res.body.jwtAccess + done() + }) + }) + }) + + describe('# session me', function () { + it('GET /session/me with no jwtAccess', function (done) { + chai.request(global.server) + .get('/session/me') + .end((err, res) => { + expect(err).to.be.null + if (CFG.jwt.enable) { + expect(res).to.have.status(401) + } + done() + }) + }) + + it('GET /session/me', function (done) { + chai.request(global.server) + .get('/session/me') + .set('token', global.jwtAccess) + .end((err, res) => { + // console.log(res.body) + expect(err).to.be.null + expect(res.body).to.not.have.property('error') + expect(res).to.have.status(200) + done() + }) + }) + }) + + describe('# session - my filters', function () { + let createdFilter = null + it('GET /session/me/filters', function (done) { + chai.request(global.server) + .get('/session/me/filters') + .set('token', global.jwtAccess || '') + .end((err, res) => { + // console.log(res.body) + expect(err).to.be.null + // expect(res.body).to.have.property('data') + // expect(res.body).to.not.have.property('error') + expect(res).to.have.status(200) + done() + }) + }) + + it('CREATE /session/me/filters', function (done) { + chai.request(global.server) + .post('/session/me/filters') + .set('token', global.jwtAccess || '') + .send({name: 'test-test', rules: {test: ''}}) + .end((err, res) => { + expect(err).to.be.null + // expect(res.body).to.have.property('data') + // expect(res.body).to.not.have.property('error') + expect(res).to.have.status(200) + createdFilter = res.body.doc + done() + }) + }) + + it('DELETE users-filters by api', function (done) { + chai.request(global.server) + .delete('/api/users-filters/' + createdFilter._id) + .set('token', global.jwtAccess || '') + .end((err, res) => { + expect(err).to.be.null + // expect(res.body).to.have.property('data') + // expect(res.body).to.not.have.property('error') + expect(res).to.have.status(200) + done() + }) + }) + }) +}) + +// https://scotch.io/tutorials/test-a-node-restful-api-with-mocha-and-chai diff --git a/service/services/session/services.js b/service/services/session/services.js new file mode 100644 index 0000000..cdbe750 --- /dev/null +++ b/service/services/session/services.js @@ -0,0 +1,107 @@ +/* eslint operator-linebreak: 0 */ + +const jwt = require('jsonwebtoken') +const camelcase = require('camelcase') +const ObjectId = require('mongodb').ObjectId + +const CFG = require('../../config') +const TOL = require('../../tools/common') + +module.exports = function (pCtx) { + const services = {} + let dbUsers = pCtx.db.collection('users') + + services.login = function (req, res, next) { + dbUsers + .find({username: req.body.user}) + .limit(1) + .next(function (pErr, pUser) { + if (pErr) { + return res.done(555, pErr) + } + + if (!pUser) { + return res.done(401, new Error('User:NotFound')) + } + + if (!pUser.multipass || pUser.multipass.hash !== req.body.pass) { + return res.done(401, new Error('User:WrongPassword')) + } + + let payload = buildDefaultPayload(req, pUser) + let token = jwt.sign({data: payload}, CFG.jwt.jwtAuth.secret, { expiresIn: CFG.jwt.jwtAuth.expiresIn }) + + res.done(null, {user: pUser, token: token}) + }) + } + + // services.access = function (req, res, next) { + // if (!req.body.jwtAuth) { + // return res.done(401, new Error('jwtAuth:Missing')) + // } + + // jwt.verify(req.body.jwtAuth, CFG.jwt.jwtAuth.secret, function (pErr, pDecoded) { + // if (pErr) { + // return res.done(401, new Error(`jwtAuth:${camelcase(pErr.message, {pascalCase: true})}`)) + // } + + // let payloadState = TOL.jwt.checkPayload(req, pDecoded.data) + // if (payloadState) { + // return res.done(401, 'jwtAuth:CorruptedPayload:' + payloadState) + // } + + // dbUsers + // .find({_id: ObjectId(pDecoded.data.user.id)}) + // .limit(1) + // .next(function (pErr, pUser) { + // if (pErr || !pUser) { + // return res.done(401, 'User:NotFound') + // } + + // let hashPass = TOL.createHash(pUser.multipass.hash, null, CFG.jwt.jwtAuth.passSalt) + + // if (pDecoded.data.user.pass !== hashPass) { + // return res.done(401, 'User:PasswordChanged') + // } + + // let payload = buildDefaultPayload(req, pUser) + // let jwtAuth = jwt.sign({data: payload}, CFG.jwt.jwtAuth.secret, { expiresIn: CFG.jwt.jwtAuth.expiresIn }) + + // payload.user.rights = pUser.rights + + // let jwtAccess = jwt.sign({data: payload}, CFG.jwt.jwtAccess.secret, { expiresIn: CFG.jwt.jwtAccess.expiresIn }) + + // res.done(null, {jwtAuth, jwtAccess}) + // }) + // }) + // } + + services.me = function (req, res, next) { + res.done(null, {user: req.user}) + } + + services.filtersGet = function (req, res, next) { + let restOp = pCtx.restapi['users-filters'].__buildRestOp() + restOp.filter = { '__metadata.owner': req.user._id } + pCtx.restapi['users-filters'].__services.read(restOp, res.done) + } + + services.filtersCreate = function (req, res, next) { + pCtx.restapi['users-filters'].__services.create(req.body, req.user, res.done) + } + + return services +} + +function buildDefaultPayload (req, pUser) { + return { + user: { + id: pUser._id, + username: pUser.username, + details: pUser.details, + pass: TOL.createHash(pUser.multipass.hash, null, CFG.jwt.jwtAuth.passSalt) + }, + sid: CFG.jwt.sid, + clientInfo: TOL.buildClientInfo(req) + } +} diff --git a/service/services/session/services.spec.js b/service/services/session/services.spec.js new file mode 100644 index 0000000..153d8e7 --- /dev/null +++ b/service/services/session/services.spec.js @@ -0,0 +1,70 @@ +/* eslint-env mocha */ +const mongoClient = require('mongodb').MongoClient + +const CFG = require('../../config') +const CTX = { + db: {} +} +const services = require('./services')(CTX) + +const req = {} +const res = { + _done: function () { + console.error('Mocha done function not set') + process.exit(1) + }, + setDone: function (done) { + this._done = done + }, + done: function (status, err, json) { + typeof status === 'number' + ? this._done(status, err, json) + : this._done(555, status, err) + } +} + +describe('Session - Services', function () { + // LOGIN //////////////////////////////////////////////////////////////////// + describe('#login', function () { + before(function (done) { + mongoClient.connect(CFG.mongo.url, { useNewUrlParser: true }, function (pErr, pDbHandler) { + if (pErr) { + process.exit(1) + } + CTX.db.handler = pDbHandler + CTX.db.airpmp = CTX.db.handler.db('airpmp') + done() + }) + }) + + // it('should login with success', function (done) { + // req.body = { + // user: 'airpmp', + // pass: 'admin' + // } + // res.setDone(function (pStatus, pErr, pResult) { + // if (pErr) return done(pErr) + // if (pResult.user.username !== req.body.user) return done(new Error('CorruptedUser')) + // done() + // }) + // services.login(req, res) + // }) + + // it('should not login with wrong credential', function (done) { + // req.body = { + // user: 'test', + // pass: 'adminz' + // } + // res.setDone(function (pStatus, pErr, pResult) { + // if (pErr) return done() + // done(new Error('LoggedWithWrongCreditential')) + // }) + // services.login(req, res) + // }) + + after(function (done) { + CTX.db.handler.close() + done() + }) + }) +}) diff --git a/service/tools/common.js b/service/tools/common.js new file mode 100644 index 0000000..485f49f --- /dev/null +++ b/service/tools/common.js @@ -0,0 +1,43 @@ +const crypto = require('crypto') +const exec = require('child_process').exec +const CFG = require('../config') + +const tools = {} + +tools.createHash = function (pData, pHash, pSalt) { + let hash = pHash || 'md5' + let data = typeof pData === 'object' ? JSON.stringify(pData) : pData + if (pSalt) { + data = `${data}$-|-$${pSalt}` + } + return crypto.createHash(hash).update(data).digest('hex') +} + +tools.buildClientInfo = function (req) { + return { + uaHash: tools.createHash(req.headers['user-agent']), + ip: req.clientIp + } +} + +tools.jwt = {} +tools.jwt.checkPayload = function (req, pPayload) { + let clientInfo = tools.buildClientInfo(req) + if (!pPayload.user) return 'user' + if (!pPayload.user.id) return 'user.id' + if (!pPayload.user.pass) return 'user.pass' + if (!pPayload.clientInfo) return 'clientInfo' + if (pPayload.clientInfo.ip !== clientInfo.ip) return 'clientInfo.ip' + if (pPayload.clientInfo.uaHash !== clientInfo.uaHash) return 'clientInfo.uaHash' + if (pPayload.sid !== CFG.jwt.sid) return 'clientInfo.sid' + return null +} + +tools.git = {} +tools.git.currentRevision = '---' + +exec('git rev-parse --short HEAD | xargs echo -n', function (pErr, pStdout) { + if (pStdout) tools.git.currentRevision = pStdout +}) + +module.exports = tools diff --git a/service/tools/middleware-done.js b/service/tools/middleware-done.js new file mode 100644 index 0000000..1a09321 --- /dev/null +++ b/service/tools/middleware-done.js @@ -0,0 +1,53 @@ +const requestIp = require('request-ip') + +module.exports = function (req, res, next) { + // Website you wish to allow to connect + res.setHeader('Access-Control-Allow-Origin', '*') + // Request methods you wish to allow + res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE') + // Request headers you wish to allow + res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type,token,authorization') + // + req.clientIp = requestIp.getClientIp(req) + // + res.done = (pStatus, pErr, pJson) => { + let status = null + let error = null + let json = null + + if (typeof pStatus === 'number') { + status = pStatus + error = pErr + json = pJson || {} + } else { + error = pStatus + json = pErr || {} + } + + if (!error && status >= 400) { + error = 'Error:401' + } + + if (error) { + status = status || 555 + let errorToSend = { + error: '', + httpStatus: status, + stack: null, + more: json || {} + } + if (!(error instanceof Error)) { + if (typeof error === 'object') error = JSON.stringify(error) + error = new Error(error) + } + + errorToSend.error = error.message + errorToSend.stack = error.stack + + res.status(status).json(errorToSend) + } else { + res.json(json) + } + } + next() +} diff --git a/service/tools/time-profiler.js b/service/tools/time-profiler.js new file mode 100644 index 0000000..55d418a --- /dev/null +++ b/service/tools/time-profiler.js @@ -0,0 +1,22 @@ +module.exports = class TimeProfiler { + constructor (pTag, pHideIt) { + this.hideIt = !!pHideIt + this.tag = pTag || 'TimeProfile' + this.list = [{title: 'Init', date: new Date()}] + } + + tick (pTitle) { + this.list.push({title: pTitle, date: new Date()}) + } + + done () { + if (this.hideIt) return + console.log('Profiling results for:' + this.tag) + console.log(' - ' + this.list[0].title + ': 0') + for (var i = 1; i < this.list.length; i++) { + console.log(' - ' + this.list[i].title + ': ' + (this.list[i].date - this.list[i - 1].date)) + } + console.log(' - TOTAL', (new Date()) - this.list[0].date) + this.list = [] + } +}