diff --git a/.gitignore b/.gitignore
index 1e137e3f..855d0429 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,9 @@
+.idea/
+*.iml
+
config.json
config.*.json
+!config.test.json
!config.example.json
node_modules/
staticman_key
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index 3e4bdad6..70df652a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,4 +5,4 @@ cache:
notifications:
email: false
node_js:
-- '6'
\ No newline at end of file
+- '8.11.3'
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
index d600b610..29e5bdb2 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM node:6.7.0
+FROM node:8.11.3
# Create app directory
RUN mkdir -p /app
diff --git a/README.md b/README.md
index 59c5ba00..9f92a5f8 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
-# Staticman [![coverage](https://img.shields.io/badge/coverage-53%25-red.svg?style=flat)](https://github.com/eduardoboucas/staticman) [![Build Status](https://travis-ci.org/eduardoboucas/staticman.svg?branch=master)](https://travis-ci.org/eduardoboucas/staticman) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)
+# Staticman [![coverage](https://img.shields.io/badge/coverage-82%25-yellow.svg?style=flat)](https://github.com/eduardoboucas/staticman) [![Build Status](https://travis-ci.org/eduardoboucas/staticman.svg?branch=master)](https://travis-ci.org/eduardoboucas/staticman) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)
> Static sites with superpowers
@@ -14,7 +14,7 @@ You can download and run the Staticman API on your own infrastructure, or you ca
## Requirements
-- Node.js 4.8.3+
+- Node.js 8.11.3+
- npm
- A [personal access token](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/) for the GitHub account you want to run Staticman with
- An SSH key (click [here](https://help.github.com/articles/connecting-to-github-with-ssh/) to learn how to create one)
@@ -102,5 +102,6 @@ Would you like to contribute to Staticman? That's great! Here's how:
- [Tyne Time](https://www.tynetime.com) ([Source](https://github.com/Doocey/tyne-time-hugo))
- [BinaryMist](https://binarymist.io/blog) ([Source](https://github.com/binarymist/BinaryMistBlog))
- [La ruta de la cebada](https://larutadelacebada.com) ([Source](https://github.com/lasocial/larutadelacebada.github.io))
+- [Gatsby Central](https://www.gatsbycentral.com) ([Source](https://github.com/GatsbyCentral/gatsbycentral.com))
Are you using Staticman? [Let us know!](https://github.com/eduardoboucas/staticman/edit/master/README.md)
diff --git a/config.js b/config.js
index 7acb56cd..0637a046 100644
--- a/config.js
+++ b/config.js
@@ -54,12 +54,42 @@ const schema = {
default: 'development',
env: 'NODE_ENV'
},
+ githubAccessTokenUri: {
+ doc: 'URI for the GitHub authentication provider.',
+ format: String,
+ default: 'https://github.com/login/oauth/access_token',
+ env: 'GITHUB_ACCESS_TOKEN_URI'
+ },
+ githubBaseUrl: {
+ doc: 'Base URL for the GitHub API.',
+ format: String,
+ default: 'https://api.github.com',
+ env: 'GITHUB_BASE_URL'
+ },
githubToken: {
doc: 'Access token to the GitHub account being used to push files with.',
format: String,
default: null,
env: 'GITHUB_TOKEN'
},
+ gitlabAccessTokenUri: {
+ doc: 'URI for the GitLab authentication provider.',
+ format: String,
+ default: 'https://gitlab.com/oauth/token',
+ env: 'GITLAB_ACCESS_TOKEN_URI'
+ },
+ gitlabBaseUrl: {
+ doc: 'Base URL for the GitLab API.',
+ format: String,
+ default: 'https://gitlab.com',
+ env: 'GITLAB_BASE_URL'
+ },
+ gitlabToken: {
+ doc: 'Access token to the GitLab account being used to push files with.',
+ format: String,
+ default: null,
+ env: 'GITLAB_TOKEN'
+ },
port: {
doc: 'The port to bind the application to.',
format: 'port',
diff --git a/config.sample.json b/config.sample.json
index bb69d186..35581627 100644
--- a/config.sample.json
+++ b/config.sample.json
@@ -1,4 +1,5 @@
{
+ "gitlabToken": "YOUR_GITLAB_TOKEN",
"githubToken": "YOUR_GITHUB_TOKEN",
"rsaPrivateKey": "-----BEGIN RSA PRIVATE KEY-----YOUR_KEY-----END RSA PRIVATE KEY-----",
"port": 80
diff --git a/config.test.json b/config.test.json
index d5e79ba1..3bbf3f21 100644
--- a/config.test.json
+++ b/config.test.json
@@ -1,4 +1,5 @@
{
+ "gitlabToken": "r4e3w2q1",
"githubToken": "1q2w3e4r",
"rsaPrivateKey": "-----BEGIN RSA PRIVATE KEY-----MIIEpAIBAAKCAQEA2nX81/5w6nZLolEh0uKks3//FlqizKxFWi8GaEJYbud8FYwLH6l+LDfZkjQiDXvm6mxngDGCjlG9b7hgfa/sfWSuqtJUQ2D1Nenn11gwAUaI7OQNSassE+nVFL2BGedl6DOgpZFkKrDTQT7jyvvc3r/2IqWahAYyFWXImD50qwNWIGyZ2Sry2/WXeCydiUWV8ZG3GOlGZLgtlK8igdmLje/6Ja+1oRBFwdbWrf/nKsMB0fCL3R5MkWTnumR8sGx2Xud8Q3mF7cOYWQiy2AqrFQOzJ+QwH6hO6CGVk8eBh8xRkrjaZEsvolZ33N+0aS9NBxHuOyGq0Te9HMLFqwVGzwIDAQABAoIBAQDPD4gAnb0erdMQXT/m50TekdIQuQWXYy00xl+XUFMLg0L8FUmxz++0L5d72Qfxqd97kBYlzkeFZ3pbOvHSD33ieByJ8mNFnc+tMy+4z3BotRcxGRJzIdfcZAS/7MJB8C6KAO0iIQVE5WbGb7pu+XwmcOH1gutKeajc2SVhD8l7ECRARPuV3JxlhbVt+ylM05h7+5HwwnEmodNQHPeGvLEWp7eODNdcLLE5EFVjmN0dwGu9D+xCFna9bL7p921GOTGf349l3021ONaGvWd77Frhl9tHL1k40hqq4LiXDk3RkiP2oDb65+ohW128Q1QPgjMQuXbbFTCa3++pbz7OMbUhAoGBAPxt6A5B3s5GnnaCTE0YJ13aTeUyqrLimBxWEp7L/WXug8SDBW5tVAmBNHlZC4GuR089E7g26BVr0i3k/dOknKa0GLyGGJNphxrrcD05p+XB6Gd6/N1Yr6amM+8XqU1+UKLL2CBrLOSi6r4J4fPS8sb9362+FROwCJZfxd5Wznd/AoGBAN2NEz+anDBgulxLoguGuvc0FaqSsVIP/cdb5Ve5t29/uheVjLgDXSkV5P/RFfk1ygH1gNjmUrsoxfsGWQa3KMTk292maYRj7GPpOalSlp8BYyiQ9omPdOgusVzY4CEjMiDkKal0YrBswXKV8E2lTokEEkbdrQpToVdBmRCzT1ixAoGBAMNMBQ2CyO6ulEr75CyBU3O5QirhWE+uICFMNnvFNvd14VxYQgt9alcwL3jy+4QJYgJcLrWHRWfNU39Oe1MTOF+BVuIEnV7vdifNn7i+srd/nl7xOFHIG53DWMrSc5oQ8DIDo+LxCHqb0SHWY4pQ2qQ6JqQ1O/lPaFVvI5cxcevhAoGALyNtDQNgaAqsnCabe8hWz3INihVcFRHB9UDgMyIYnWiXt5ziK+TLVYqLBsL94eBH8tLBb2TSBXBPb3GST5N44SuwfCCEIt7/1OIymowv7/TjnCX7zpjvTtdgdVjPlz1d1RG2q49P0CnTnwW3801QwGZVXS6dOq1AjsguQRdlsoECgYBrFqKa3S48UbGOKkocgMb/1HzVs2sxNWMu+/jEiBvI4RrCiun9MALtrVtohgHRml4yZJaOojVk9F0z/MAak9eTgSmHpwxYZMqR1PvM4c/ekfun4hQoK04Thoexi/Z0RfsI6nBdBk8MAra03ldDvnYZY4Fat21YuNBspbrbTW8UoA==-----END RSA PRIVATE KEY-----",
"email": {
diff --git a/controllers/auth.js b/controllers/auth.js
new file mode 100644
index 00000000..ab02c80b
--- /dev/null
+++ b/controllers/auth.js
@@ -0,0 +1,64 @@
+'use strict'
+
+const gitFactory = require('../lib/GitServiceFactory')
+const oauth = require('../lib/OAuth')
+const RSA = require('../lib/RSA')
+const Staticman = require('../lib/Staticman')
+
+module.exports = (req, res) => {
+ const staticman = new Staticman(req.params)
+ staticman.setConfigPath()
+
+ let requestAccessToken
+
+ switch (req.params.service) {
+ case 'gitlab':
+ requestAccessToken = siteConfig =>
+ oauth.requestGitLabAccessToken(
+ req.query.code,
+ siteConfig.get('gitlabAuth.clientId'),
+ siteConfig.get('gitlabAuth.clientSecret'),
+ siteConfig.get('gitlabAuth.redirectUri')
+ )
+ break
+ default:
+ requestAccessToken = siteConfig =>
+ oauth.requestGitHubAccessToken(
+ req.query.code,
+ siteConfig.get('githubAuth.clientId'),
+ siteConfig.get('githubAuth.clientSecret'),
+ siteConfig.get('githubAuth.redirectUri')
+ )
+ }
+
+ return staticman.getSiteConfig()
+ .then(requestAccessToken)
+ .then((accessToken) => {
+ const git = gitFactory.create(req.params.service, {
+ oauthToken: accessToken
+ })
+
+ // TODO: Simplify this when v2 support is dropped.
+ const getUser = req.params.version === '2' && req.params.service === 'github'
+ ? git.api.users.get({}).then(({data}) => data)
+ : git.getCurrentUser()
+
+ return getUser
+ .then((user) => {
+ res.send({
+ accessToken: RSA.encrypt(accessToken),
+ user
+ })
+ })
+ })
+ .catch((err) => {
+ console.log('ERR:', err)
+
+ const statusCode = err.statusCode || 401
+
+ res.status(statusCode).send({
+ statusCode,
+ message: err.message
+ })
+ })
+}
diff --git a/controllers/connect.js b/controllers/connect.js
index b26af453..537d0d24 100644
--- a/controllers/connect.js
+++ b/controllers/connect.js
@@ -12,15 +12,14 @@ module.exports = (req, res) => {
const github = new GitHub({
username: req.params.username,
repository: req.params.repository,
- branch: req.params.branch
+ branch: req.params.branch,
+ token: config.get('githubToken')
})
- github.authenticateWithToken(config.get('githubToken'))
+ return github.api.users.getRepoInvites({}).then(({data}) => {
+ let invitationId = null
- return github.api.users.getRepoInvites({}).then(response => {
- let invitationId
-
- const invitation = response.some(invitation => {
+ const invitation = data.some(invitation => {
if (invitation.repository.full_name === (req.params.username + '/' + req.params.repository)) {
invitationId = invitation.id
@@ -30,7 +29,7 @@ module.exports = (req, res) => {
if (invitation) {
return github.api.users.acceptRepoInvite({
- id: invitationId
+ invitation_id: invitationId
})
} else {
res.status(404).send('Invitation not found')
diff --git a/controllers/githubAuth.js b/controllers/githubAuth.js
deleted file mode 100644
index d93d8c31..00000000
--- a/controllers/githubAuth.js
+++ /dev/null
@@ -1,32 +0,0 @@
-'use strict'
-
-const path = require('path')
-const GitHub = require(path.join(__dirname, '/../lib/GitHub'))
-const RSA = require('../lib/RSA')
-const Staticman = require('../lib/Staticman')
-
-module.exports = (req, res) => {
- const github = new GitHub()
- const staticman = new Staticman(req.params)
-
- staticman.authenticate()
- staticman.setConfigPath()
-
- return staticman.getSiteConfig().then(siteConfig => {
- return github.authenticateWithCode({
- code: req.query.code,
- clientId: siteConfig.get('githubAuth.clientId'),
- clientSecret: siteConfig.get('githubAuth.clientSecret')
- })
- }).then(accessToken => {
- return github.api.users.get({}).then(user => {
- res.send({
- accessToken: RSA.encrypt(accessToken),
- user
- })
- })
- }).catch(err => {
- console.log('ERR:', err)
- res.send(err)
- })
-}
diff --git a/controllers/handlePR.js b/controllers/handlePR.js
index 20a49c70..80bc057f 100644
--- a/controllers/handlePR.js
+++ b/controllers/handlePR.js
@@ -1,8 +1,7 @@
'use strict'
-const path = require('path')
-const config = require(path.join(__dirname, '/../config'))
-const GitHub = require(path.join(__dirname, '/../lib/GitHub'))
+const config = require('../config')
+const GitHub = require('../lib/GitHub')
const Staticman = require('../lib/Staticman')
module.exports = (repo, data) => {
@@ -14,45 +13,39 @@ module.exports = (repo, data) => {
return
}
- const github = new GitHub()
+ const github = new GitHub({
+ username: data.repository.owner.login,
+ repository: data.repository.name,
+ token: config.get('githubToken')
+ })
- github.authenticateWithToken(config.get('githubToken'))
+ return github.getReview(data.number).then((review) => {
+ if (review.sourceBranch.indexOf('staticman_')) {
+ return null
+ }
- return github.api.pullRequests.get({
- user: data.repository.owner.login,
- repo: data.repository.name,
- number: data.number
- }).then(response => {
- if (response.head.ref.indexOf('staticman_')) {
+ if (review.state !== 'merged' && review.state !== 'closed') {
return null
}
- if (response.merged) {
- const bodyMatch = response.body.match(/(?:.*?)(?:.*?)/i)
+ if (review.state === 'merged') {
+ const bodyMatch = review.body.match(/(?:.*?)(?:.*?)/i)
if (bodyMatch && (bodyMatch.length === 2)) {
try {
const parsedBody = JSON.parse(bodyMatch[1])
const staticman = new Staticman(parsedBody.parameters)
- staticman.authenticate()
staticman.setConfigPath(parsedBody.configPath)
- staticman.processMerge(parsedBody.fields, parsedBody.options).catch(err => {
- return Promise.reject(err)
- })
+ staticman.processMerge(parsedBody.fields, parsedBody.options)
+ .catch(err => Promise.reject(err))
} catch (err) {
return Promise.reject(err)
}
}
}
- if (response.state === 'closed') {
- return github.api.gitdata.deleteReference({
- user: data.repository.owner.login,
- repo: data.repository.name,
- ref: 'heads/' + response.head.ref
- })
- }
+ return github.deleteBranch(review.sourceBranch)
}).then(response => {
if (ua) {
ua.event('Hooks', 'Delete branch').send()
diff --git a/controllers/process.js b/controllers/process.js
index e4bb0ac4..9bcce71b 100644
--- a/controllers/process.js
+++ b/controllers/process.js
@@ -3,7 +3,6 @@
const path = require('path')
const config = require(path.join(__dirname, '/../config'))
const errorHandler = require('../lib/ErrorHandler')
-const logger = require('../lib/Logger')
const reCaptcha = require('express-recaptcha')
const Staticman = require('../lib/Staticman')
const universalAnalytics = require('universal-analytics')
@@ -69,19 +68,6 @@ function process (staticman, req, res) {
const fields = req.query.fields || req.body.fields
const options = req.query.options || req.body.options || {}
- logger.info(
- JSON.stringify(
- {
- url: req.url,
- fields,
- options,
- body: req.body
- }
- ),
- null,
- 2
- )
-
return staticman.processEntry(fields, options).then(data => {
sendResponse(res, {
redirect: data.redirect,
@@ -137,20 +123,17 @@ function sendResponse (res, data) {
module.exports = (req, res, next) => {
const staticman = new Staticman(req.params)
- staticman.authenticate()
staticman.setConfigPath()
staticman.setIp(req.headers['x-forwarded-for'] || req.connection.remoteAddress)
staticman.setUserAgent(req.headers['user-agent'])
- return checkRecaptcha(staticman, req).then(usedRecaptcha => {
- return process(staticman, req, res)
- }).catch(err => {
- return sendResponse(res, {
+ return checkRecaptcha(staticman, req)
+ .then(usedRecaptcha => process(staticman, req, res))
+ .catch(err => sendResponse(res, {
err,
redirect: req.body.options && req.body.options.redirect,
redirectError: req.body.options && req.body.options.redirectError
- })
- })
+ }))
}
module.exports.checkRecaptcha = checkRecaptcha
diff --git a/coverage/cobertura-coverage.xml b/coverage/cobertura-coverage.xml
index de0078f6..9fb167bb 100644
--- a/coverage/cobertura-coverage.xml
+++ b/coverage/cobertura-coverage.xml
@@ -1,27 +1,27 @@
-
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
@@ -39,7 +39,7 @@
-
+
@@ -68,42 +68,57 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
@@ -133,132 +148,118 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
+
+
+
+
+
@@ -268,82 +269,120 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -351,36 +390,34 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
@@ -397,86 +434,66 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -487,835 +504,1279 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
@@ -1385,16 +1846,16 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
+
@@ -1403,12 +1864,12 @@
-
+
-
+
@@ -1422,7 +1883,106 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lib/ErrorHandler.js b/lib/ErrorHandler.js
index 19f2e5ec..5790bb9f 100644
--- a/lib/ErrorHandler.js
+++ b/lib/ErrorHandler.js
@@ -1,5 +1,22 @@
-const path = require('path')
-const config = require(path.join(__dirname, '/../config'))
+'use strict'
+
+const {StatusCodeError, RequestError} = require('request-promise/errors')
+const HttpError = require('@octokit/rest/lib/request/http-error')
+
+class ApiError {
+ constructor (message, statusCode = 500, smErrorCode = '') {
+ this.message = message
+ this.statusCode = statusCode
+ this._smErrorCode = smErrorCode
+ }
+
+ toJSON () {
+ return {
+ message: this.message,
+ statusCode: this.statusCode
+ }
+ }
+}
const ErrorHandler = function () {
this.ERROR_MESSAGES = {
@@ -43,13 +60,27 @@ ErrorHandler.prototype.log = function (err, instance) {
console.log(`${prefix}`, err)
}
-ErrorHandler.prototype._save = function (errorCode, data) {
- data = data || {}
-
- if (data.err) {
- data.err._smErrorCode = data.err._smErrorCode || errorCode
-
- return data.err
+ErrorHandler.prototype._save = function (errorCode, data = {}) {
+ const {err} = data
+
+ if (err) {
+ err._smErrorCode = err._smErrorCode || errorCode
+
+ // Re-wrap API request errors as these could expose
+ // request/response details that the user should not
+ // be allowed to see e.g. access tokens.
+ // `request-promise` is the primary offender here,
+ // but we similarly do not want others to leak too.
+ if (
+ err instanceof StatusCodeError ||
+ err instanceof RequestError ||
+ err instanceof HttpError
+ ) {
+ const statusCode = err.statusCode || err.code
+ return new ApiError(err.message, statusCode, err._smErrorCode)
+ }
+
+ return err
}
let payload = {
@@ -72,3 +103,5 @@ module.exports = function () {
module.exports.getInstance = function () {
return errorHandler
}
+
+module.exports.ApiError = ApiError
diff --git a/lib/GitHub.js b/lib/GitHub.js
index 25bdef2b..93710a7d 100644
--- a/lib/GitHub.js
+++ b/lib/GitHub.js
@@ -1,169 +1,163 @@
'use strict'
-const path = require('path')
-const config = require(path.join(__dirname, '/../config'))
+const config = require('../config')
const errorHandler = require('./ErrorHandler')
-const GitHubApi = require('github')
-const request = require('request-promise-native')
-const yaml = require('js-yaml')
-
-const GitHub = function (options) {
- this.options = options || {}
-
- this.api = new GitHubApi({
- debug: config.get('env') === 'development',
- protocol: 'https',
- host: 'api.github.com',
- pathPrefix: '',
- headers: {
- 'user-agent': 'Staticman agent'
- },
- timeout: 5000,
- Promise: Promise
- })
-}
-
-GitHub.prototype.authenticateWithCode = function ({
- code,
- clientId,
- clientSecret
-} = {}) {
- return request({
- headers: {
- 'Accept': 'application/json'
- },
- json: true,
- method: 'POST',
- uri: `https://github.com/login/oauth/access_token?client_id=${clientId}&client_secret=${clientSecret}&code=${code}`
- }).then(response => {
- this.api.authenticate({
- type: 'token',
- token: response.access_token
+const githubApi = require('@octokit/rest')
+const GitService = require('./GitService')
+const Review = require('./models/Review')
+const User = require('./models/User')
+
+const normalizeResponse = ({data}) => data
+
+class GitHub extends GitService {
+ constructor (options = {}) {
+ super(options.username, options.repository, options.branch)
+
+ this.api = githubApi({
+ debug: config.get('env') === 'development',
+ baseUrl: config.get('githubBaseUrl'),
+ headers: {
+ 'user-agent': 'Staticman agent'
+ },
+ timeout: 5000
})
- return response.access_token
- }).catch(err => { // eslint-disable-line handle-callback-err
- return Promise.reject(errorHandler('GITHUB_AUTH_FAILED'))
- })
-}
-
-GitHub.prototype.authenticateWithToken = function (token, type) {
- type = type || 'oauth'
-
- this.api.authenticate({
- type,
- token
- })
-}
-
-GitHub.prototype.readFile = function (path, getFullResponse) {
- const extension = path.split('.').pop()
-
- return this.api.repos.getContent({
- user: this.options.username,
- repo: this.options.repository,
- path,
- ref: this.options.branch
- }).then(res => {
- let content = Buffer.from(res.content, 'base64').toString()
-
- try {
- switch (extension) {
- case 'yml':
- case 'yaml':
- content = yaml.safeLoad(content, 'utf8')
-
- break
-
- case 'json':
- content = JSON.parse(content)
-
- break
- }
-
- return getFullResponse ? {
- content: content,
- file: {
- content: res.content
- }
- } : content
- } catch (err) {
- let errorData = {
- err
- }
-
- if (err.message) {
- errorData.data = err.message
- }
-
- return Promise.reject(errorHandler('PARSING_ERROR', errorData))
+ if (options.oauthToken) {
+ this.api.authenticate({
+ type: 'oauth',
+ token: options.oauthToken
+ })
+ } else if (options.token) {
+ this.api.authenticate({
+ type: 'token',
+ token: options.token
+ })
+ } else {
+ throw new Error('Require an `oauthToken` or `token` option')
}
- }).catch(err => {
- return Promise.reject(errorHandler('GITHUB_READING_FILE', {err}))
- })
-}
-
-GitHub.prototype.writeFile = function (filePath, data, branch, commitTitle) {
- branch = branch || this.options.branch
- commitTitle = commitTitle || 'Add Staticman file'
-
- return this.api.repos.createFile({
- user: this.options.username,
- repo: this.options.repository,
- path: filePath,
- content: Buffer.from(data).toString('base64'),
- message: commitTitle,
- branch: branch
- }).catch(err => {
- try {
- const message = err && err.message
-
- if (message) {
- const parsedError = JSON.parse(message)
-
- if (
- parsedError &&
- parsedError.message &&
- parsedError.message.includes('"sha" wasn\'t supplied')
- ) {
- return Promise.reject(errorHandler('GITHUB_FILE_ALREADY_EXISTS', {err}))
- }
- }
- } catch (err) {} // eslint-disable-line no-empty
-
- return Promise.reject(errorHandler('GITHUB_WRITING_FILE', {err}))
- })
-}
-
-GitHub.prototype.writeFileAndSendPR = function (filePath, data, branch, commitTitle, commitBody) {
- commitTitle = commitTitle || 'Add Staticman file'
- commitBody = commitBody || ''
+ }
+
+ _pullFile (filePath, branch) {
+ return this.api.repos.getContent({
+ owner: this.username,
+ repo: this.repository,
+ path: filePath,
+ ref: branch
+ })
+ .then(normalizeResponse)
+ .catch(err => Promise.reject(errorHandler('GITHUB_READING_FILE', {err})))
+ }
+
+ _commitFile (filePath, content, commitMessage, branch) {
+ return this.api.repos.createFile({
+ owner: this.username,
+ repo: this.repository,
+ path: filePath,
+ message: commitMessage,
+ content,
+ branch
+ })
+ .then(normalizeResponse)
+ }
+
+ writeFile (filePath, data, targetBranch, commitTitle) {
+ return super.writeFile(filePath, data, targetBranch, commitTitle)
+ .catch(err => {
+ try {
+ const message = err && err.message
+
+ if (message) {
+ const parsedError = JSON.parse(message)
+
+ if (
+ parsedError &&
+ parsedError.message &&
+ parsedError.message.includes('"sha" wasn\'t supplied')
+ ) {
+ return Promise.reject(errorHandler('GITHUB_FILE_ALREADY_EXISTS', {err}))
+ }
+ }
+ } catch (err) {} // eslint-disable-line no-empty
+
+ return Promise.reject(errorHandler('GITHUB_WRITING_FILE', {err}))
+ })
+ }
+
+ getBranchHeadCommit (branch) {
+ return this.api.repos.getBranch({
+ owner: this.username,
+ repo: this.repository,
+ branch
+ })
+ .then(res => res.data.commit.sha)
+ }
- return this.api.repos.getBranch({
- user: this.options.username,
- repo: this.options.repository,
- branch: this.options.branch
- }).then(res => {
+ createBranch (branch, sha) {
return this.api.gitdata.createReference({
- user: this.options.username,
- repo: this.options.repository,
- ref: 'refs/heads/' + branch,
- sha: res.commit.sha
+ owner: this.username,
+ repo: this.repository,
+ ref: `refs/heads/${branch}`,
+ sha
+ })
+ .then(normalizeResponse)
+ }
+
+ deleteBranch (branch) {
+ return this.api.gitdata.deleteReference({
+ owner: this.username,
+ repo: this.repository,
+ ref: `heads/${branch}`
})
- }).then(res => {
- return this.writeFile(filePath, data, branch, commitTitle)
- }).then(res => {
+ }
+
+ createReview (reviewTitle, branch, reviewBody) {
return this.api.pullRequests.create({
- user: this.options.username,
- repo: this.options.repository,
- title: commitTitle,
+ owner: this.username,
+ repo: this.repository,
+ title: reviewTitle,
head: branch,
- base: this.options.branch,
- body: commitBody
+ base: this.branch,
+ body: reviewBody
+ })
+ .then(normalizeResponse)
+ }
+
+ getReview (reviewId) {
+ return this.api.pullRequests.get({
+ owner: this.username,
+ repo: this.repository,
+ number: reviewId
})
- }).catch(err => {
- return Promise.reject(errorHandler('GITHUB_CREATING_PR', {err}))
- })
+ .then(normalizeResponse)
+ .then(({base, body, head, merged, state, title}) =>
+ new Review(
+ title,
+ body,
+ (merged && state === 'closed') ? 'merged' : state,
+ head.ref,
+ base.ref
+ )
+ )
+ }
+
+ readFile (filePath, getFullResponse) {
+ return super.readFile(filePath, getFullResponse)
+ .catch(err => Promise.reject(errorHandler('GITHUB_READING_FILE', {err})))
+ }
+
+ writeFileAndSendReview (filePath, data, branch, commitTitle, reviewBody) {
+ return super.writeFileAndSendReview(filePath, data, branch, commitTitle, reviewBody)
+ .catch(err => Promise.reject(errorHandler('GITHUB_CREATING_PR', {err})))
+ }
+
+ getCurrentUser () {
+ return this.api.users.get({})
+ .then(normalizeResponse)
+ .then(({login, email, avatar_url, name, bio, company, blog}) =>
+ new User('github', login, email, name, avatar_url, bio, blog, company)
+ )
+ .catch(err => Promise.reject(errorHandler('GITHUB_GET_USER', {err})))
+ }
}
module.exports = GitHub
diff --git a/lib/GitLab.js b/lib/GitLab.js
new file mode 100644
index 00000000..f730c954
--- /dev/null
+++ b/lib/GitLab.js
@@ -0,0 +1,118 @@
+'use strict'
+
+const config = require('../config')
+const errorHandler = require('./ErrorHandler')
+const GitLabApi = require('gitlab/dist/es5').default
+const GitService = require('./GitService')
+const Review = require('./models/Review')
+const User = require('./models/User')
+
+class GitLab extends GitService {
+ constructor (options = {}) {
+ super(options.username, options.repository, options.branch)
+
+ if (options.oauthToken) {
+ this.api = new GitLabApi({
+ url: config.get('gitlabBaseUrl'),
+ oauthToken: options.oauthToken
+ })
+ } else if (options.token) {
+ this.api = new GitLabApi({
+ url: config.get('gitlabBaseUrl'),
+ token: options.token
+ })
+ } else {
+ throw new Error('Require an `oauthToken` or `token` option')
+ }
+ }
+
+ get repositoryId () {
+ if (this.username && this.repository) {
+ return `${this.username}/${this.repository}`
+ }
+
+ return ''
+ }
+
+ _pullFile (path, branch) {
+ return this.api.RepositoryFiles.show(this.repositoryId, path, branch)
+ .catch(err => Promise.reject(errorHandler('GITLAB_READING_FILE', {err})))
+ }
+
+ _commitFile (filePath, content, commitMessage, branch) {
+ return this.api.RepositoryFiles.create(this.repositoryId, filePath, branch, {
+ content,
+ commit_message: commitMessage,
+ encoding: 'base64'
+ })
+ }
+
+ getBranchHeadCommit (branch) {
+ return this.api.Branches.show(this.repositoryId, branch)
+ .then(res => res.commit.id)
+ }
+
+ createBranch (branch, sha) {
+ return this.api.Branches.create(this.repositoryId, branch, sha)
+ }
+
+ deleteBranch (branch) {
+ return this.api.Branches.remove(this.repositoryId, branch)
+ }
+
+ createReview (reviewTitle, branch, reviewBody) {
+ return this.api.MergeRequests.create(this.repositoryId, branch, this.branch, reviewTitle, {
+ description: reviewBody,
+ remove_source_branch: true
+ })
+ }
+
+ getReview (reviewId) {
+ return this.api.MergeRequests.show(this.repositoryId, reviewId)
+ .then(({
+ description: body,
+ source_branch: sourceBranch,
+ target_branch: targetBranch,
+ state,
+ title
+ }) => new Review(
+ title,
+ body,
+ state,
+ sourceBranch,
+ targetBranch
+ )
+ )
+ }
+
+ readFile (filePath, getFullResponse) {
+ return super.readFile(filePath, getFullResponse)
+ .catch(err => Promise.reject(errorHandler('GITLAB_READING_FILE', {err})))
+ }
+
+ writeFile (filePath, data, targetBranch, commitTitle) {
+ return super.writeFile(filePath, data, targetBranch, commitTitle)
+ .catch(err => {
+ if (err.error && err.error.message === 'A file with this name already exists') {
+ return Promise.reject(errorHandler('GITLAB_FILE_ALREADY_EXISTS', {err}))
+ }
+
+ return Promise.reject(errorHandler('GITLAB_WRITING_FILE', {err}))
+ })
+ }
+
+ writeFileAndSendReview (filePath, data, branch, commitTitle, reviewBody) {
+ return super.writeFileAndSendReview(filePath, data, branch, commitTitle, reviewBody)
+ .catch(err => Promise.reject(errorHandler('GITLAB_CREATING_PR', {err})))
+ }
+
+ getCurrentUser () {
+ return this.api.Users.current()
+ .then(({username, email, name, avatar_url, bio, website_url, organisation}) =>
+ new User('gitlab', username, email, name, avatar_url, bio, website_url, organisation)
+ )
+ .catch(err => Promise.reject(errorHandler('GITLAB_GET_USER', {err})))
+ }
+}
+
+module.exports = GitLab
diff --git a/lib/GitService.js b/lib/GitService.js
new file mode 100644
index 00000000..5f0da812
--- /dev/null
+++ b/lib/GitService.js
@@ -0,0 +1,97 @@
+'use strict'
+
+const errorHandler = require('./ErrorHandler')
+const yaml = require('js-yaml')
+
+class GitService {
+ constructor (username, repository, branch) {
+ this.username = username
+ this.repository = repository
+ this.branch = branch
+ }
+
+ _pullFile (filePath, branch) {
+ throw new Error('Abstract method `_pullFile` should be implemented')
+ }
+
+ _commitFile (filePath, contents, commitTitle, branch) {
+ throw new Error('Abstract method `_commitFile` should be implemented')
+ }
+
+ getBranchHeadCommit (branch) {
+ throw new Error('Abstract method `getBranchHeadCommit` should be implemented')
+ }
+
+ createBranch (branch, sha) {
+ throw new Error('Abstract method `createBranch` should be implemented')
+ }
+
+ deleteBranch (branch) {
+ throw new Error('Abstract method `deleteBranch` should be implemented')
+ }
+
+ createReview (commitTitle, branch, reviewBody) {
+ throw new Error('Abstract method `createReview` should be implemented')
+ }
+
+ getReview (reviewId) {
+ throw new Error('Abstract method `getReview` should be implemented')
+ }
+
+ getCurrentUser () {
+ throw new Error('Abstract method `getCurrentUser` should be implemented')
+ }
+
+ readFile (path, getFullResponse) {
+ const extension = path.split('.').pop()
+
+ return this._pullFile(path, this.branch).then(res => {
+ let content = Buffer.from(res.content, 'base64').toString()
+
+ try {
+ switch (extension) {
+ case 'yml':
+ case 'yaml':
+ content = yaml.safeLoad(content, 'utf8')
+
+ break
+
+ case 'json':
+ content = JSON.parse(content)
+
+ break
+ }
+
+ return getFullResponse ? {
+ content: content,
+ file: {
+ content: res.content
+ }
+ } : content
+ } catch (err) {
+ let errorData = {
+ err
+ }
+
+ if (err.message) {
+ errorData.data = err.message
+ }
+
+ return Promise.reject(errorHandler('PARSING_ERROR', errorData))
+ }
+ })
+ }
+
+ writeFile (filePath, data, branch = this.branch, commitTitle = 'Add Staticman file') {
+ return this._commitFile(filePath, Buffer.from(data).toString('base64'), commitTitle, branch)
+ }
+
+ writeFileAndSendReview (filePath, data, branch, commitTitle = 'Add Staticman file', reviewBody = '') {
+ return this.getBranchHeadCommit(this.branch)
+ .then(sha => this.createBranch(branch, sha))
+ .then(() => this.writeFile(filePath, data, branch, commitTitle))
+ .then(() => this.createReview(commitTitle, branch, reviewBody))
+ }
+}
+
+module.exports = GitService
diff --git a/lib/GitServiceFactory.js b/lib/GitServiceFactory.js
new file mode 100644
index 00000000..ce594055
--- /dev/null
+++ b/lib/GitServiceFactory.js
@@ -0,0 +1,13 @@
+'use strict'
+
+const GitLab = require('./GitLab')
+const GitHub = require('./GitHub')
+
+module.exports.create = (service, options) => {
+ switch (service) {
+ case 'gitlab':
+ return new GitLab(options)
+ default:
+ return new GitHub(options)
+ }
+}
diff --git a/lib/OAuth.js b/lib/OAuth.js
new file mode 100644
index 00000000..96f6f6f1
--- /dev/null
+++ b/lib/OAuth.js
@@ -0,0 +1,49 @@
+'use strict'
+
+const config = require('../config')
+const request = require('request-promise')
+const errorHandler = require('./ErrorHandler')
+
+const requestGitHubAccessToken = (code, clientId, clientSecret, redirectUri) => {
+ return request({
+ headers: {
+ 'Accept': 'application/json'
+ },
+ json: true,
+ method: 'POST',
+ uri: config.get('githubAccessTokenUri'),
+ qs: {
+ code,
+ client_id: clientId,
+ client_secret: clientSecret,
+ redirect_uri: redirectUri
+ }
+ })
+ .then(res => res.access_token)
+ .catch(err => Promise.reject(errorHandler('GITHUB_AUTH_FAILED', {err}))) // eslint-disable-line handle-callback-err
+}
+
+const requestGitLabAccessToken = (code, clientId, clientSecret, redirectUri) => {
+ return request({
+ headers: {
+ 'Accept': 'application/json'
+ },
+ json: true,
+ method: 'POST',
+ uri: config.get('gitlabAccessTokenUri'),
+ qs: {
+ code,
+ client_id: clientId,
+ client_secret: clientSecret,
+ grant_type: 'authorization_code',
+ redirect_uri: redirectUri
+ }
+ })
+ .then(res => res.access_token)
+ .catch(err => Promise.reject(errorHandler('GITLAB_AUTH_FAILED', {err}))) // eslint-disable-line handle-callback-err
+}
+
+module.exports = {
+ requestGitHubAccessToken,
+ requestGitLabAccessToken
+}
diff --git a/lib/Staticman.js b/lib/Staticman.js
index e56e3e89..d0b1f5f1 100644
--- a/lib/Staticman.js
+++ b/lib/Staticman.js
@@ -1,38 +1,40 @@
'use strict'
const akismetApi = require('akismet')
-const path = require('path')
-const config = require(path.join(__dirname, '/../config'))
+const config = require('../config')
const errorHandler = require('./ErrorHandler')
-const logger = require('./Logger')
-const GitHub = require('./GitHub')
+const gitFactory = require('./GitServiceFactory')
const markdownTable = require('markdown-table')
const moment = require('moment')
const Mailgun = require('mailgun-js')
const NodeRSA = require('node-rsa')
const objectPath = require('object-path')
const RSA = require('./RSA')
-const SiteConfig = require(path.join(__dirname, '/../siteConfig'))
+const SiteConfig = require('../siteConfig')
const slugify = require('slug')
const SubscriptionsManager = require('./SubscriptionsManager')
const Transforms = require('./Transforms')
-const uuid = require('node-uuid')
+const uuidv1 = require('uuid/v1')
const yaml = require('js-yaml')
const Staticman = function (parameters) {
this.parameters = parameters
- // Initialise GitHub API
- this.github = new GitHub({
- username: this.parameters.username,
- repository: this.parameters.repository,
- branch: this.parameters.branch
+ const token = parameters.service === 'gitlab'
+ ? config.get('gitlabToken')
+ : config.get('githubToken')
+
+ // Initialise the Git service API
+ this.git = gitFactory.create(parameters.service, {
+ username: parameters.username,
+ repository: parameters.repository,
+ branch: parameters.branch,
+ token
})
// Generate unique id
- this.uid = uuid.v1()
+ this.uid = uuidv1()
- // Initialise RSA
this.rsa = new NodeRSA()
this.rsa.importKey(config.get('rsaPrivateKey'))
}
@@ -55,16 +57,6 @@ Staticman.prototype._applyInternalFields = function (data) {
Staticman.prototype._applyGeneratedFields = function (data) {
const generatedFields = this.siteConfig.get('generatedFields')
- // Log what `generatedFields` looks like at this point - trying to fix #176
- logger.info(
- JSON.stringify({
- generatedFields
- }),
- null,
- 2
- )
-
-
if (!generatedFields) return data
Object.keys(generatedFields).forEach(field => {
@@ -79,9 +71,11 @@ Staticman.prototype._applyGeneratedFields = function (data) {
break
+ // TODO: Remove 'github' when v2 API is no longer supported
case 'github':
- if (this.githubUser && typeof options.property === 'string') {
- data[field] = objectPath.get(this.githubUser, options.property)
+ case 'user':
+ if (this.gitUser && typeof options.property === 'string') {
+ data[field] = objectPath.get(this.gitUser, options.property)
}
break
@@ -158,7 +152,36 @@ Staticman.prototype._checkForSpam = function (fields) {
})
}
-Staticman.prototype._checkGithubAuth = function () {
+Staticman.prototype._checkAuth = function () {
+ // TODO: Remove when v2 API is no longer supported
+ if (this.parameters.version === '2') {
+ return this._checkAuthV2()
+ }
+
+ if (!this.siteConfig.get('auth.required')) {
+ return Promise.resolve(false)
+ }
+
+ if (!this.options['auth-token']) {
+ return Promise.reject(errorHandler('AUTH_TOKEN_MISSING'))
+ }
+
+ const oauthToken = RSA.decrypt(this.options['auth-token'])
+
+ if (!oauthToken) {
+ return Promise.reject(errorHandler('AUTH_TOKEN_INVALID'))
+ }
+
+ const git = gitFactory.create(this.options['auth-type'], {oauthToken})
+
+ return git.getCurrentUser().then(user => {
+ this.gitUser = user
+ return true
+ })
+}
+
+// TODO: Remove when v2 API is no longer supported
+Staticman.prototype._checkAuthV2 = function () {
if (!this.siteConfig.get('githubAuth.required')) {
return Promise.resolve(false)
}
@@ -167,19 +190,16 @@ Staticman.prototype._checkGithubAuth = function () {
return Promise.reject(errorHandler('GITHUB_AUTH_TOKEN_MISSING'))
}
- const token = RSA.decrypt(this.options['github-token'])
+ const oauthToken = RSA.decrypt(this.options['github-token'])
- if (!token) {
+ if (!oauthToken) {
return Promise.reject(errorHandler('GITHUB_AUTH_TOKEN_INVALID'))
}
- const github = new GitHub()
-
- github.authenticateWithToken(token, 'token')
-
- return github.api.users.get({}).then(user => {
- this.githubUser = user
+ const git = gitFactory.create('github', {oauthToken})
+ return git.api.users.get({}).then(({data}) => {
+ this.gitUser = data
return true
})
}
@@ -248,7 +268,7 @@ Staticman.prototype._createFile = function (fields) {
})
}
-Staticman.prototype._generatePRBody = function (fields) {
+Staticman.prototype._generateReviewBody = function (fields) {
let table = [
['Field', 'Content']
]
@@ -323,7 +343,7 @@ Staticman.prototype._initialiseSubscriptions = function () {
})
// Initialise SubscriptionsManager
- const subscriptions = new SubscriptionsManager(this.parameters, this.github, mailgun)
+ const subscriptions = new SubscriptionsManager(this.parameters, this.git, mailgun)
return subscriptions
}
@@ -438,10 +458,6 @@ Staticman.prototype._validateFields = function (fields) {
return null
}
-Staticman.prototype.authenticate = function () {
- this.github.authenticateWithToken(config.get('githubToken'))
-}
-
Staticman.prototype.decrypt = function (encrypted) {
return this.rsa.decrypt(encrypted, 'utf8')
}
@@ -455,7 +471,7 @@ Staticman.prototype.getSiteConfig = function (force) {
if (!this.configPath) return Promise.reject(errorHandler('NO_CONFIG_PATH'))
- return this.github.readFile(this.configPath.file).then(data => {
+ return this.git.readFile(this.configPath.file).then(data => {
const config = objectPath.get(data, this.configPath.path)
const validationErrors = this._validateConfig(config)
@@ -476,7 +492,7 @@ Staticman.prototype.processEntry = function (fields, options) {
this.options = Object.assign({}, options)
return this.getSiteConfig().then(config => {
- return this._checkGithubAuth()
+ return this._checkAuth()
}).then(() => {
return this._checkForSpam(fields)
}).then(fields => {
@@ -513,18 +529,18 @@ Staticman.prototype.processEntry = function (fields, options) {
if (this.siteConfig.get('moderation')) {
const newBranch = 'staticman_' + this.uid
- return this.github.writeFileAndSendPR(
+ return this.git.writeFileAndSendReview(
filePath,
data,
newBranch,
commitMessage,
- this._generatePRBody(fields)
+ this._generateReviewBody(fields)
)
} else if (subscriptions && options.parent) {
subscriptions.send(options.parent, fields, options, this.siteConfig)
}
- return this.github.writeFile(
+ return this.git.writeFile(
filePath,
data,
this.parameters.branch,
diff --git a/lib/TypeUtils.js b/lib/TypeUtils.js
new file mode 100644
index 00000000..77e4db31
--- /dev/null
+++ b/lib/TypeUtils.js
@@ -0,0 +1,11 @@
+'use strict'
+
+const assertString = (value, message = `${value} is not a string`) => {
+ if (typeof value !== 'string') {
+ throw new TypeError(message)
+ }
+}
+
+module.exports = {
+ assertString
+}
diff --git a/lib/models/Review.js b/lib/models/Review.js
new file mode 100644
index 00000000..1d1e4f50
--- /dev/null
+++ b/lib/models/Review.js
@@ -0,0 +1,28 @@
+'use strict'
+
+const {assertString} = require('../TypeUtils')
+
+class Review {
+ /**
+ * @param {string} title
+ * @param {string} body
+ * @param {string} state
+ * @param {string} sourceBranch
+ * @param {string} targetBranch
+ */
+ constructor (title, body, state, sourceBranch, targetBranch) {
+ assertString(title)
+ assertString(body)
+ assertString(state)
+ assertString(sourceBranch)
+ assertString(targetBranch)
+
+ this.title = title
+ this.body = body
+ this.state = state
+ this.sourceBranch = sourceBranch
+ this.targetBranch = targetBranch
+ }
+}
+
+module.exports = Review
diff --git a/lib/models/User.js b/lib/models/User.js
new file mode 100644
index 00000000..2affe460
--- /dev/null
+++ b/lib/models/User.js
@@ -0,0 +1,37 @@
+'use strict'
+
+const {assertString} = require('../TypeUtils')
+
+class User {
+ /**
+ * @param {string} type
+ * @param {string} username
+ * @param {string} email
+ * @param {string} name
+ * @param {string=""} avatarUrl
+ * @param {string=""} bio
+ * @param {string=""} siteUrl
+ * @param {string=""} organisation
+ */
+ constructor (type, username, email, name, avatarUrl = '', bio = '', siteUrl = '', organisation = '') {
+ assertString(type)
+ assertString(username)
+ assertString(email)
+ assertString(name)
+ assertString(avatarUrl)
+ assertString(bio)
+ assertString(siteUrl)
+ assertString(organisation)
+
+ this.type = type
+ this.username = username
+ this.email = email
+ this.name = name
+ this.avatarUrl = avatarUrl
+ this.bio = bio
+ this.siteUrl = siteUrl
+ this.organisation = organisation
+ }
+}
+
+module.exports = User
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 00000000..45a39aa9
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,7270 @@
+{
+ "name": "staticman",
+ "version": "2.0.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "@babel/runtime": {
+ "version": "7.0.0-beta.53",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.0.0-beta.53.tgz",
+ "integrity": "sha1-nfIq40gjzon3kAYFlLg+5XLixdI=",
+ "requires": {
+ "core-js": "2.5.7",
+ "regenerator-runtime": "0.12.0"
+ },
+ "dependencies": {
+ "regenerator-runtime": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.0.tgz",
+ "integrity": "sha512-SpV2LhF5Dm9UYMEprB3WwsBnWwqTrmjrm2UZb42cl2G02WVGgx7Mg8aa9pdLEKp6hZ+/abcMc2NxKA8f02EG2w=="
+ }
+ }
+ },
+ "@dadi/log-filter": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@dadi/log-filter/-/log-filter-1.0.0.tgz",
+ "integrity": "sha512-tPtoHjlnNG71/aa2cz0YpqEB0L4EY7hBwFXVmPWOhXAwwyEI2XF8DH5WQ/TEYGc82V+TamC3Df6YsN4/MN9luQ=="
+ },
+ "@dadi/logger": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/@dadi/logger/-/logger-1.4.1.tgz",
+ "integrity": "sha512-tzw5W+gXjwmSHGIPTzFjDN0kcw8clRtoPzpQyP7uHUgMjDLXF1qlCaDaT8W0OyFKmuBd5lxRv9giJChhkzh29g==",
+ "requires": {
+ "@dadi/log-filter": "1.0.0",
+ "aws-kinesis-writable": "2.0.0",
+ "bunyan": "1.8.12",
+ "kinesis": "1.2.2",
+ "memorystream": "0.3.1",
+ "mkdirp": "0.5.1",
+ "moment": "2.22.2"
+ }
+ },
+ "@octokit/rest": {
+ "version": "15.9.4",
+ "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-15.9.4.tgz",
+ "integrity": "sha512-v3CS1qW4IjriMvGgm4lDnYFBJlkwvzIbTxiipOcwVP8xeK8ih2pJofRhk7enmLngTtNEa+sIApJNkXxyyDKqLg==",
+ "requires": {
+ "before-after-hook": "1.1.0",
+ "btoa-lite": "1.0.0",
+ "debug": "3.1.0",
+ "http-proxy-agent": "2.1.0",
+ "https-proxy-agent": "2.2.1",
+ "lodash": "4.17.10",
+ "node-fetch": "2.1.2",
+ "url-template": "2.0.8"
+ },
+ "dependencies": {
+ "agent-base": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz",
+ "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==",
+ "requires": {
+ "es6-promisify": "5.0.0"
+ }
+ },
+ "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"
+ }
+ },
+ "http-proxy-agent": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz",
+ "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==",
+ "requires": {
+ "agent-base": "4.2.1",
+ "debug": "3.1.0"
+ }
+ },
+ "https-proxy-agent": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz",
+ "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==",
+ "requires": {
+ "agent-base": "4.2.1",
+ "debug": "3.1.0"
+ }
+ },
+ "lodash": {
+ "version": "4.17.10",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
+ "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg=="
+ }
+ }
+ },
+ "@semantic-release/error": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-2.2.0.tgz",
+ "integrity": "sha512-9Tj/qn+y2j+sjCI3Jd+qseGtHjOAeg7dU2/lVcqIQ9TV3QDaDXDYXcoOHU+7o2Hwh8L8ymL4gfuO7KxDs3q2zg=="
+ },
+ "@semantic-release/npm": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-3.4.0.tgz",
+ "integrity": "sha512-sC80dYdjzaO3akUig3mnmprSMjWafTYBUdJgtp+zslDEAbJp6nDmvVM1o6s/oVBsIdf2QS2GhHRHlA9gssKF8g==",
+ "requires": {
+ "@semantic-release/error": "2.2.0",
+ "aggregate-error": "1.0.0",
+ "detect-indent": "5.0.0",
+ "detect-newline": "2.1.0",
+ "execa": "0.10.0",
+ "fs-extra": "6.0.1",
+ "lodash": "4.17.10",
+ "nerf-dart": "1.0.0",
+ "normalize-url": "3.2.0",
+ "parse-json": "4.0.0",
+ "read-pkg": "4.0.1",
+ "registry-auth-token": "3.3.2"
+ },
+ "dependencies": {
+ "detect-indent": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz",
+ "integrity": "sha1-OHHMCmoALow+Wzz38zYmRnXwa50="
+ },
+ "lodash": {
+ "version": "4.17.10",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
+ "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg=="
+ },
+ "parse-json": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
+ "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
+ "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="
+ },
+ "read-pkg": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-4.0.1.tgz",
+ "integrity": "sha1-ljYlN48+HE1IyFhytabsfV0JMjc=",
+ "requires": {
+ "normalize-package-data": "2.4.0",
+ "parse-json": "4.0.0",
+ "pify": "3.0.0"
+ }
+ }
+ }
+ },
+ "abab": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz",
+ "integrity": "sha1-X6rZwsB/YN12dw9xzwJbYqY8/U4=",
+ "dev": true
+ },
+ "accepts": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz",
+ "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=",
+ "requires": {
+ "mime-types": "2.1.18",
+ "negotiator": "0.6.1"
+ }
+ },
+ "acorn": {
+ "version": "4.0.13",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz",
+ "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=",
+ "dev": true
+ },
+ "acorn-globals": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-3.1.0.tgz",
+ "integrity": "sha1-/YJw9x+7SZawBPqIDuXUZXOnMb8=",
+ "dev": true,
+ "requires": {
+ "acorn": "4.0.13"
+ }
+ },
+ "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
+ }
+ }
+ },
+ "agent-base": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.1.1.tgz",
+ "integrity": "sha1-1t4Q1a9hMtW9aSQn1G/FOFOQlMc=",
+ "requires": {
+ "extend": "3.0.1",
+ "semver": "5.0.3"
+ }
+ },
+ "aggregate-error": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-1.0.0.tgz",
+ "integrity": "sha1-iINE2tAiCnLjr1CQYRf0h3GSX6w=",
+ "requires": {
+ "clean-stack": "1.3.0",
+ "indent-string": "3.2.0"
+ }
+ },
+ "ajv": {
+ "version": "5.5.2",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
+ "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
+ "requires": {
+ "co": "4.6.0",
+ "fast-deep-equal": "1.1.0",
+ "fast-json-stable-stringify": "2.0.0",
+ "json-schema-traverse": "0.3.1"
+ }
+ },
+ "ajv-keywords": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz",
+ "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=",
+ "dev": true
+ },
+ "akismet": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/akismet/-/akismet-1.0.0.tgz",
+ "integrity": "sha1-qKb0KtB69m1ziWeofkCOFxib/YU=",
+ "requires": {
+ "request": "2.87.0"
+ }
+ },
+ "align-text": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz",
+ "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=",
+ "dev": true,
+ "requires": {
+ "kind-of": "3.2.2",
+ "longest": "1.0.1",
+ "repeat-string": "1.6.1"
+ }
+ },
+ "amdefine": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
+ "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
+ "dev": true
+ },
+ "ansi-escapes": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz",
+ "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=",
+ "dev": true
+ },
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true
+ },
+ "anymatch": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz",
+ "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==",
+ "dev": true,
+ "requires": {
+ "micromatch": "2.3.11",
+ "normalize-path": "2.1.1"
+ }
+ },
+ "append-transform": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz",
+ "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==",
+ "dev": true,
+ "requires": {
+ "default-require-extensions": "2.0.0"
+ }
+ },
+ "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"
+ }
+ },
+ "arr-diff": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
+ "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
+ "dev": true,
+ "requires": {
+ "arr-flatten": "1.1.0"
+ }
+ },
+ "arr-flatten": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+ "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
+ "dev": true
+ },
+ "arr-union": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
+ "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
+ "dev": true
+ },
+ "array-equal": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz",
+ "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=",
+ "dev": true
+ },
+ "array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
+ },
+ "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
+ },
+ "array-unique": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
+ "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=",
+ "dev": true
+ },
+ "array.prototype.find": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/array.prototype.find/-/array.prototype.find-2.0.4.tgz",
+ "integrity": "sha1-VWpcU2LAhkgyPdrrnenRS8GGTJA=",
+ "dev": true,
+ "requires": {
+ "define-properties": "1.1.2",
+ "es-abstract": "1.12.0"
+ }
+ },
+ "arrify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
+ "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=",
+ "dev": true
+ },
+ "asn1": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
+ "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y="
+ },
+ "assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
+ },
+ "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
+ },
+ "assign-symbols": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
+ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
+ "dev": true
+ },
+ "ast-types": {
+ "version": "0.11.5",
+ "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.11.5.tgz",
+ "integrity": "sha512-oJjo+5e7/vEc2FBK8gUalV0pba4L3VdBIs2EKhOLHLcOd2FgQIVQN9xb0eZ9IjEWyAL7vq6fGJxOvVvdCHNyMw=="
+ },
+ "async": {
+ "version": "0.9.2",
+ "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz",
+ "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0="
+ },
+ "asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
+ },
+ "atob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.1.tgz",
+ "integrity": "sha1-ri1acpR38onWDdf5amMUoi3Wwio=",
+ "dev": true
+ },
+ "aws-kinesis-writable": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/aws-kinesis-writable/-/aws-kinesis-writable-2.0.0.tgz",
+ "integrity": "sha1-80c2QcpgdKMA6JpCYy+AMblI0iQ=",
+ "requires": {
+ "aws-sdk": "2.273.1",
+ "lodash": "3.10.1",
+ "retry": "0.9.0"
+ },
+ "dependencies": {
+ "lodash": {
+ "version": "3.10.1",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz",
+ "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y="
+ }
+ }
+ },
+ "aws-sdk": {
+ "version": "2.273.1",
+ "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.273.1.tgz",
+ "integrity": "sha512-JFsL+YCQGEjV/cZp6BlJ11Sg4O0wchCtBANqeOGRvEd2hPKey04p2nmwZVy+vApkA7IOI/pARbIwZRZ+V5ntng==",
+ "requires": {
+ "buffer": "4.9.1",
+ "events": "1.1.1",
+ "ieee754": "1.1.8",
+ "jmespath": "0.15.0",
+ "querystring": "0.2.0",
+ "sax": "1.2.1",
+ "url": "0.10.3",
+ "uuid": "3.1.0",
+ "xml2js": "0.4.17"
+ },
+ "dependencies": {
+ "uuid": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz",
+ "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g=="
+ }
+ }
+ },
+ "aws-sign2": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
+ "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
+ },
+ "aws4": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-0.3.0.tgz",
+ "integrity": "sha1-rLKGeN4AUWd5NC6/GHbzGqr8f9Q=",
+ "requires": {
+ "lru-cache": "2.3.1"
+ },
+ "dependencies": {
+ "lru-cache": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.3.1.tgz",
+ "integrity": "sha1-s632s9hW6VTiw5DmzvIggSRaU9Y="
+ }
+ }
+ },
+ "awscred": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/awscred/-/awscred-1.4.1.tgz",
+ "integrity": "sha512-s88FlBqt3lfqli39RuhsDrdAfT25RqfaKm2X1PuBWQFR5BBzeQ6Ri+QO9vc4NaBFtJmtfYW9q8/VrZxLTfhwiw=="
+ },
+ "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"
+ }
+ },
+ "babel-core": {
+ "version": "6.26.3",
+ "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz",
+ "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==",
+ "dev": true,
+ "requires": {
+ "babel-code-frame": "6.26.0",
+ "babel-generator": "6.26.1",
+ "babel-helpers": "6.24.1",
+ "babel-messages": "6.23.0",
+ "babel-register": "6.26.0",
+ "babel-runtime": "6.26.0",
+ "babel-template": "6.26.0",
+ "babel-traverse": "6.26.0",
+ "babel-types": "6.26.0",
+ "babylon": "6.18.0",
+ "convert-source-map": "1.5.1",
+ "debug": "2.6.9",
+ "json5": "0.5.1",
+ "lodash": "4.17.10",
+ "minimatch": "3.0.4",
+ "path-is-absolute": "1.0.1",
+ "private": "0.1.8",
+ "slash": "1.0.0",
+ "source-map": "0.5.7"
+ },
+ "dependencies": {
+ "json5": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
+ "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=",
+ "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==",
+ "dev": true
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true
+ }
+ }
+ },
+ "babel-generator": {
+ "version": "6.26.1",
+ "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz",
+ "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==",
+ "dev": true,
+ "requires": {
+ "babel-messages": "6.23.0",
+ "babel-runtime": "6.26.0",
+ "babel-types": "6.26.0",
+ "detect-indent": "4.0.0",
+ "jsesc": "1.3.0",
+ "lodash": "4.17.10",
+ "source-map": "0.5.7",
+ "trim-right": "1.0.1"
+ },
+ "dependencies": {
+ "lodash": {
+ "version": "4.17.10",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
+ "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
+ "dev": true
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true
+ }
+ }
+ },
+ "babel-helpers": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz",
+ "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "6.26.0",
+ "babel-template": "6.26.0"
+ }
+ },
+ "babel-jest": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-20.0.3.tgz",
+ "integrity": "sha1-5KA7E9wQOJ4UD8ZF0J/8TO0wFnE=",
+ "dev": true,
+ "requires": {
+ "babel-core": "6.26.3",
+ "babel-plugin-istanbul": "4.1.6",
+ "babel-preset-jest": "20.0.3"
+ }
+ },
+ "babel-messages": {
+ "version": "6.23.0",
+ "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
+ "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "6.26.0"
+ }
+ },
+ "babel-plugin-istanbul": {
+ "version": "4.1.6",
+ "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz",
+ "integrity": "sha512-PWP9FQ1AhZhS01T/4qLSKoHGY/xvkZdVBGlKM/HuxxS3+sC66HhTNR7+MpbO/so/cz/wY94MeSWJuP1hXIPfwQ==",
+ "dev": true,
+ "requires": {
+ "babel-plugin-syntax-object-rest-spread": "6.13.0",
+ "find-up": "2.1.0",
+ "istanbul-lib-instrument": "1.10.1",
+ "test-exclude": "4.2.1"
+ }
+ },
+ "babel-plugin-jest-hoist": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-20.0.3.tgz",
+ "integrity": "sha1-r+3IU70/jcNUjqZx++adA8wsF2c=",
+ "dev": true
+ },
+ "babel-plugin-syntax-object-rest-spread": {
+ "version": "6.13.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz",
+ "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=",
+ "dev": true
+ },
+ "babel-preset-jest": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-20.0.3.tgz",
+ "integrity": "sha1-y6yq3stdaJyh4d4TYOv8ZoYsF4o=",
+ "dev": true,
+ "requires": {
+ "babel-plugin-jest-hoist": "20.0.3"
+ }
+ },
+ "babel-register": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz",
+ "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=",
+ "dev": true,
+ "requires": {
+ "babel-core": "6.26.3",
+ "babel-runtime": "6.26.0",
+ "core-js": "2.5.7",
+ "home-or-tmp": "2.0.0",
+ "lodash": "4.17.10",
+ "mkdirp": "0.5.1",
+ "source-map-support": "0.4.18"
+ },
+ "dependencies": {
+ "lodash": {
+ "version": "4.17.10",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
+ "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
+ "dev": true
+ }
+ }
+ },
+ "babel-runtime": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
+ "dev": true,
+ "requires": {
+ "core-js": "2.5.7",
+ "regenerator-runtime": "0.11.1"
+ }
+ },
+ "babel-template": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz",
+ "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "6.26.0",
+ "babel-traverse": "6.26.0",
+ "babel-types": "6.26.0",
+ "babylon": "6.18.0",
+ "lodash": "4.17.10"
+ },
+ "dependencies": {
+ "lodash": {
+ "version": "4.17.10",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
+ "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
+ "dev": true
+ }
+ }
+ },
+ "babel-traverse": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz",
+ "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=",
+ "dev": true,
+ "requires": {
+ "babel-code-frame": "6.26.0",
+ "babel-messages": "6.23.0",
+ "babel-runtime": "6.26.0",
+ "babel-types": "6.26.0",
+ "babylon": "6.18.0",
+ "debug": "2.6.9",
+ "globals": "9.18.0",
+ "invariant": "2.2.4",
+ "lodash": "4.17.10"
+ },
+ "dependencies": {
+ "lodash": {
+ "version": "4.17.10",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
+ "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
+ "dev": true
+ }
+ }
+ },
+ "babel-types": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
+ "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "6.26.0",
+ "esutils": "2.0.2",
+ "lodash": "4.17.10",
+ "to-fast-properties": "1.0.3"
+ },
+ "dependencies": {
+ "lodash": {
+ "version": "4.17.10",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
+ "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
+ "dev": true
+ }
+ }
+ },
+ "babylon": {
+ "version": "6.18.0",
+ "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
+ "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==",
+ "dev": true
+ },
+ "balanced-match": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
+ },
+ "base": {
+ "version": "0.11.2",
+ "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
+ "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
+ "dev": true,
+ "requires": {
+ "cache-base": "1.0.1",
+ "class-utils": "0.3.6",
+ "component-emitter": "1.2.1",
+ "define-property": "1.0.0",
+ "isobject": "3.0.1",
+ "mixin-deep": "1.3.1",
+ "pascalcase": "0.1.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "1.0.2"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "6.0.2"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "6.0.2"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "1.0.0",
+ "is-data-descriptor": "1.0.0",
+ "kind-of": "6.0.2"
+ }
+ },
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true
+ },
+ "kind-of": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
+ "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
+ "dev": true
+ }
+ }
+ },
+ "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=="
+ },
+ "bcrypt-pbkdf": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
+ "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
+ "optional": true,
+ "requires": {
+ "tweetnacl": "0.14.5"
+ }
+ },
+ "before-after-hook": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-1.1.0.tgz",
+ "integrity": "sha512-VOMDtYPwLbIncTxNoSzRyvaMxtXmLWLUqr8k5AfC1BzLk34HvBXaQX8snOwQZ4c0aX8aSERqtJSiI9/m2u5kuA=="
+ },
+ "bluebird": {
+ "version": "3.5.1",
+ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
+ "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA=="
+ },
+ "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"
+ }
+ },
+ "boom": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz",
+ "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=",
+ "requires": {
+ "hoek": "4.2.1"
+ }
+ },
+ "brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "requires": {
+ "balanced-match": "1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "braces": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
+ "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
+ "dev": true,
+ "requires": {
+ "expand-range": "1.8.2",
+ "preserve": "0.2.0",
+ "repeat-element": "1.1.2"
+ }
+ },
+ "browser-resolve": {
+ "version": "1.11.3",
+ "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz",
+ "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==",
+ "dev": true,
+ "requires": {
+ "resolve": "1.1.7"
+ },
+ "dependencies": {
+ "resolve": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz",
+ "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=",
+ "dev": true
+ }
+ }
+ },
+ "bser": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz",
+ "integrity": "sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk=",
+ "dev": true,
+ "requires": {
+ "node-int64": "0.4.0"
+ }
+ },
+ "btoa-lite": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz",
+ "integrity": "sha1-M3dm2hWAEhD92VbCLpxokaudAzc="
+ },
+ "buffer": {
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
+ "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=",
+ "requires": {
+ "base64-js": "1.3.0",
+ "ieee754": "1.1.8",
+ "isarray": "1.0.0"
+ }
+ },
+ "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-from": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz",
+ "integrity": "sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ==",
+ "dev": true
+ },
+ "builtin-modules": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
+ "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8="
+ },
+ "bunyan": {
+ "version": "1.8.12",
+ "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.12.tgz",
+ "integrity": "sha1-8VDw9nSKvdcq6uhPBEA74u8RN5c=",
+ "requires": {
+ "dtrace-provider": "0.8.7",
+ "moment": "2.22.2",
+ "mv": "2.1.1",
+ "safe-json-stringify": "1.2.0"
+ }
+ },
+ "bunyan-slack": {
+ "version": "0.0.10",
+ "resolved": "https://registry.npmjs.org/bunyan-slack/-/bunyan-slack-0.0.10.tgz",
+ "integrity": "sha1-IPAJMugS/PZBnnfhUeguE+obRhA=",
+ "requires": {
+ "extend.js": "0.0.2",
+ "request": "2.87.0"
+ }
+ },
+ "bytes": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
+ "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg="
+ },
+ "cache-base": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
+ "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
+ "dev": true,
+ "requires": {
+ "collection-visit": "1.0.0",
+ "component-emitter": "1.2.1",
+ "get-value": "2.0.6",
+ "has-value": "1.0.0",
+ "isobject": "3.0.1",
+ "set-value": "2.0.0",
+ "to-object-path": "0.3.0",
+ "union-value": "1.0.0",
+ "unset-value": "1.0.0"
+ },
+ "dependencies": {
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true
+ }
+ }
+ },
+ "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"
+ },
+ "dependencies": {
+ "callsites": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz",
+ "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=",
+ "dev": true
+ }
+ }
+ },
+ "callsites": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz",
+ "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=",
+ "dev": true
+ },
+ "camelcase": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
+ "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0="
+ },
+ "caseless": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
+ },
+ "center-align": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz",
+ "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "align-text": "0.1.4",
+ "lazy-cache": "1.0.4"
+ }
+ },
+ "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"
+ }
+ },
+ "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"
+ }
+ },
+ "charenc": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
+ "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc="
+ },
+ "check-error": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
+ "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=",
+ "dev": true
+ },
+ "ci-info": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.1.3.tgz",
+ "integrity": "sha512-SK/846h/Rcy8q9Z9CAwGBLfCJ6EkjJWdpelWDufQpqVDYq2Wnnv8zlSO6AMQap02jvhVruKKpEtQOufo3pFhLg==",
+ "dev": true
+ },
+ "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
+ },
+ "class-utils": {
+ "version": "0.3.6",
+ "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
+ "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
+ "dev": true,
+ "requires": {
+ "arr-union": "3.1.0",
+ "define-property": "0.2.5",
+ "isobject": "3.0.1",
+ "static-extend": "0.1.2"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "0.1.6"
+ }
+ },
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true
+ }
+ }
+ },
+ "clean-stack": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-1.3.0.tgz",
+ "integrity": "sha1-noIVAa6XmYbEax1m0tQy2y/UrjE="
+ },
+ "cli-cursor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz",
+ "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=",
+ "dev": true,
+ "requires": {
+ "restore-cursor": "1.0.1"
+ }
+ },
+ "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
+ },
+ "cliui": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz",
+ "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "center-align": "0.1.3",
+ "right-align": "0.1.3",
+ "wordwrap": "0.0.2"
+ },
+ "dependencies": {
+ "wordwrap": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz",
+ "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=",
+ "dev": true,
+ "optional": true
+ }
+ }
+ },
+ "clone": {
+ "version": "0.1.19",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-0.1.19.tgz",
+ "integrity": "sha1-YT+2hjmyaklKxTJT4Vsaa9iK2oU=",
+ "dev": true
+ },
+ "co": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
+ "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
+ },
+ "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=",
+ "dev": true
+ },
+ "collection-visit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
+ "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=",
+ "dev": true,
+ "requires": {
+ "map-visit": "1.0.0",
+ "object-visit": "1.0.1"
+ }
+ },
+ "color-convert": {
+ "version": "1.9.2",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz",
+ "integrity": "sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg==",
+ "dev": true,
+ "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=",
+ "dev": true
+ },
+ "combined-stream": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz",
+ "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=",
+ "requires": {
+ "delayed-stream": "1.0.0"
+ }
+ },
+ "commander": {
+ "version": "2.16.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.16.0.tgz",
+ "integrity": "sha512-sVXqklSaotK9at437sFlFpyOcJonxe0yST/AG9DkQKUdIE6IqGIMv4SfAQSKaJbSdVEJYItASCrBiVQHq1HQew==",
+ "dev": true
+ },
+ "compare-versions": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.3.0.tgz",
+ "integrity": "sha512-MAAAIOdi2s4Gl6rZ76PNcUa9IOYB+5ICdT41o5uMRf09aEu/F9RK+qhe8RjXNPwcTjGV7KU7h2P/fljThFVqyQ==",
+ "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
+ },
+ "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==",
+ "dev": true,
+ "requires": {
+ "buffer-from": "1.1.0",
+ "inherits": "2.0.3",
+ "readable-stream": "2.3.6",
+ "typedarray": "0.0.6"
+ }
+ },
+ "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=="
+ },
+ "content-type-parser": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/content-type-parser/-/content-type-parser-1.0.2.tgz",
+ "integrity": "sha512-lM4l4CnMEwOLHAHr/P6MEZwZFPJFtAAKgL6pogbXmVZggIqXhdB6RbBtPOTsw2FcXwYhehRGERJmRrjOiIB8pQ==",
+ "dev": true
+ },
+ "convert-source-map": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz",
+ "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=",
+ "dev": true
+ },
+ "convict": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/convict/-/convict-4.3.1.tgz",
+ "integrity": "sha512-BLgyHUJREKCHVZ8rbXKIuNTDX/Is2GB/HZyUqh1IwvV0EeYBWtX+54OCG8tkIiAxB2yKowdP19+RHY5kCQ/SOg==",
+ "requires": {
+ "depd": "1.1.2",
+ "json5": "1.0.1",
+ "lodash.clonedeep": "4.5.0",
+ "moment": "2.22.2",
+ "validator": "7.2.0",
+ "yargs-parser": "10.0.0"
+ }
+ },
+ "cookie": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
+ "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s="
+ },
+ "cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
+ },
+ "copy-descriptor": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
+ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
+ "dev": true
+ },
+ "core-js": {
+ "version": "2.5.7",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz",
+ "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw=="
+ },
+ "core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
+ },
+ "cross-spawn": {
+ "version": "6.0.5",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
+ "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+ "requires": {
+ "nice-try": "1.0.4",
+ "path-key": "2.0.1",
+ "semver": "5.5.0",
+ "shebang-command": "1.2.0",
+ "which": "1.3.1"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
+ "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA=="
+ }
+ }
+ },
+ "crypt": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
+ "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs="
+ },
+ "cryptiles": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz",
+ "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=",
+ "requires": {
+ "boom": "5.2.0"
+ },
+ "dependencies": {
+ "boom": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz",
+ "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==",
+ "requires": {
+ "hoek": "4.2.1"
+ }
+ }
+ }
+ },
+ "cssom": {
+ "version": "0.3.4",
+ "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.4.tgz",
+ "integrity": "sha512-+7prCSORpXNeR4/fUP3rL+TzqtiFfhMvTd7uEqMdgPvLPt4+uzFUeufx5RHjGTACCargg/DiEt/moMQmvnfkog==",
+ "dev": true
+ },
+ "cssstyle": {
+ "version": "0.2.37",
+ "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.37.tgz",
+ "integrity": "sha1-VBCXI0yyUTyDzu06zdwn/yeYfVQ=",
+ "dev": true,
+ "requires": {
+ "cssom": "0.3.4"
+ }
+ },
+ "d": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz",
+ "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=",
+ "dev": true,
+ "requires": {
+ "es5-ext": "0.10.45"
+ }
+ },
+ "dashdash": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+ "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+ "requires": {
+ "assert-plus": "1.0.0"
+ }
+ },
+ "data-uri-to-buffer": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-1.2.0.tgz",
+ "integrity": "sha512-vKQ9DTQPN1FLYiiEEOQ6IBGFqvjCa5rSK3cWMy/Nespm5d/x3dGFT9UBZnkLxCwua/IXBi2TYnwTEpsOvhC4UQ=="
+ },
+ "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
+ },
+ "decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+ "dev": true
+ },
+ "decode-uri-component": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
+ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
+ "dev": true
+ },
+ "deep-eql": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz",
+ "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==",
+ "dev": true,
+ "requires": {
+ "type-detect": "4.0.8"
+ }
+ },
+ "deep-equal": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
+ "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=",
+ "dev": true
+ },
+ "deep-extend": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+ "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
+ },
+ "deep-is": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
+ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ="
+ },
+ "default-require-extensions": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz",
+ "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=",
+ "dev": true,
+ "requires": {
+ "strip-bom": "3.0.0"
+ }
+ },
+ "define-properties": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz",
+ "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=",
+ "requires": {
+ "foreach": "2.0.5",
+ "object-keys": "1.0.12"
+ }
+ },
+ "define-property": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+ "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "1.0.2",
+ "isobject": "3.0.1"
+ },
+ "dependencies": {
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "6.0.2"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "6.0.2"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "1.0.0",
+ "is-data-descriptor": "1.0.0",
+ "kind-of": "6.0.2"
+ }
+ },
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true
+ },
+ "kind-of": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
+ "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
+ "dev": true
+ }
+ }
+ },
+ "degenerator": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-1.0.4.tgz",
+ "integrity": "sha1-/PSQo37OJmRk2cxDGrmMWBnO0JU=",
+ "requires": {
+ "ast-types": "0.11.5",
+ "escodegen": "1.10.0",
+ "esprima": "3.1.3"
+ },
+ "dependencies": {
+ "esprima": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz",
+ "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM="
+ }
+ }
+ },
+ "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"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
+ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
+ "dev": true,
+ "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"
+ }
+ }
+ }
+ },
+ "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.4.5"
+ }
+ },
+ "delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
+ },
+ "depd": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+ "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
+ },
+ "destroy": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
+ "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
+ },
+ "detect-indent": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz",
+ "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=",
+ "dev": true,
+ "requires": {
+ "repeating": "2.0.1"
+ }
+ },
+ "detect-newline": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz",
+ "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I="
+ },
+ "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"
+ }
+ },
+ "dom-walk": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz",
+ "integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg="
+ },
+ "dtrace-provider": {
+ "version": "0.8.7",
+ "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.7.tgz",
+ "integrity": "sha1-3JObTT4GIM/gwc2APQ0tftBP/QQ=",
+ "optional": true,
+ "requires": {
+ "nan": "2.10.0"
+ }
+ },
+ "ecc-jsbn": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
+ "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=",
+ "optional": true,
+ "requires": {
+ "jsbn": "0.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="
+ },
+ "errno": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz",
+ "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==",
+ "dev": true,
+ "requires": {
+ "prr": "1.0.1"
+ }
+ },
+ "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==",
+ "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==",
+ "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=",
+ "requires": {
+ "is-callable": "1.1.4",
+ "is-date-object": "1.0.1",
+ "is-symbol": "1.0.1"
+ }
+ },
+ "es5-ext": {
+ "version": "0.10.45",
+ "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.45.tgz",
+ "integrity": "sha512-FkfM6Vxxfmztilbxxz5UKSD4ICMf5tSpRFtDNtkAhOxZ0EKtX6qwmXNyH/sFyIbX2P/nU5AMiA9jilWsUGJzCQ==",
+ "dev": true,
+ "requires": {
+ "es6-iterator": "2.0.3",
+ "es6-symbol": "3.1.1",
+ "next-tick": "1.0.0"
+ }
+ },
+ "es6-iterator": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
+ "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=",
+ "dev": true,
+ "requires": {
+ "d": "1.0.0",
+ "es5-ext": "0.10.45",
+ "es6-symbol": "3.1.1"
+ }
+ },
+ "es6-map": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz",
+ "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=",
+ "dev": true,
+ "requires": {
+ "d": "1.0.0",
+ "es5-ext": "0.10.45",
+ "es6-iterator": "2.0.3",
+ "es6-set": "0.1.5",
+ "es6-symbol": "3.1.1",
+ "event-emitter": "0.3.5"
+ }
+ },
+ "es6-promise": {
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz",
+ "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ=="
+ },
+ "es6-promisify": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
+ "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
+ "requires": {
+ "es6-promise": "4.2.4"
+ }
+ },
+ "es6-set": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz",
+ "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=",
+ "dev": true,
+ "requires": {
+ "d": "1.0.0",
+ "es5-ext": "0.10.45",
+ "es6-iterator": "2.0.3",
+ "es6-symbol": "3.1.1",
+ "event-emitter": "0.3.5"
+ }
+ },
+ "es6-symbol": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz",
+ "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=",
+ "dev": true,
+ "requires": {
+ "d": "1.0.0",
+ "es5-ext": "0.10.45"
+ }
+ },
+ "es6-weak-map": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz",
+ "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=",
+ "dev": true,
+ "requires": {
+ "d": "1.0.0",
+ "es5-ext": "0.10.45",
+ "es6-iterator": "2.0.3",
+ "es6-symbol": "3.1.1"
+ }
+ },
+ "escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
+ },
+ "escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+ "dev": true
+ },
+ "escodegen": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.10.0.tgz",
+ "integrity": "sha512-fjUOf8johsv23WuIKdNQU4P9t9jhQ4Qzx6pC2uW890OloK3Zs1ZAoCNpg/2larNF501jLl3UNy0kIRcF6VI22g==",
+ "requires": {
+ "esprima": "3.1.3",
+ "estraverse": "4.2.0",
+ "esutils": "2.0.2",
+ "optionator": "0.8.2",
+ "source-map": "0.6.1"
+ },
+ "dependencies": {
+ "esprima": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz",
+ "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM="
+ }
+ }
+ },
+ "escope": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz",
+ "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=",
+ "dev": true,
+ "requires": {
+ "es6-map": "0.1.5",
+ "es6-weak-map": "2.0.2",
+ "esrecurse": "4.2.1",
+ "estraverse": "4.2.0"
+ }
+ },
+ "eslint": {
+ "version": "3.19.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-3.19.0.tgz",
+ "integrity": "sha1-yPxiAcf0DdCJQbh8CFdnOGpnmsw=",
+ "dev": true,
+ "requires": {
+ "babel-code-frame": "6.26.0",
+ "chalk": "1.1.3",
+ "concat-stream": "1.6.2",
+ "debug": "2.6.9",
+ "doctrine": "2.1.0",
+ "escope": "3.6.0",
+ "espree": "3.5.4",
+ "esquery": "1.0.1",
+ "estraverse": "4.2.0",
+ "esutils": "2.0.2",
+ "file-entry-cache": "2.0.0",
+ "glob": "7.1.2",
+ "globals": "9.18.0",
+ "ignore": "3.3.10",
+ "imurmurhash": "0.1.4",
+ "inquirer": "0.12.0",
+ "is-my-json-valid": "2.17.2",
+ "is-resolvable": "1.1.0",
+ "js-yaml": "3.12.0",
+ "json-stable-stringify": "1.0.1",
+ "levn": "0.3.0",
+ "lodash": "4.17.10",
+ "mkdirp": "0.5.1",
+ "natural-compare": "1.4.0",
+ "optionator": "0.8.2",
+ "path-is-inside": "1.0.2",
+ "pluralize": "1.2.1",
+ "progress": "1.1.8",
+ "require-uncached": "1.0.3",
+ "shelljs": "0.7.8",
+ "strip-bom": "3.0.0",
+ "strip-json-comments": "2.0.1",
+ "table": "3.8.3",
+ "text-table": "0.2.0",
+ "user-home": "2.0.0"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
+ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
+ "dev": true,
+ "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"
+ }
+ },
+ "lodash": {
+ "version": "4.17.10",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
+ "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
+ "dev": true
+ }
+ }
+ },
+ "eslint-config-standard": {
+ "version": "10.2.1",
+ "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-10.2.1.tgz",
+ "integrity": "sha1-wGHk0GbzedwXzVYsZOgZtN1FRZE=",
+ "dev": true
+ },
+ "eslint-config-standard-jsx": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-4.0.2.tgz",
+ "integrity": "sha512-F8fRh2WFnTek7dZH9ZaE0PCBwdVGkwVWZmizla/DDNOmg7Tx6B/IlK5+oYpiX29jpu73LszeJj5i1axEZv6VMw==",
+ "dev": true
+ },
+ "eslint-import-resolver-node": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.2.3.tgz",
+ "integrity": "sha1-Wt2BBujJKNssuiMrzZ76hG49oWw=",
+ "dev": true,
+ "requires": {
+ "debug": "2.6.9",
+ "object-assign": "4.1.1",
+ "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.2.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.2.0.tgz",
+ "integrity": "sha1-crowb60wXWfEgWNIpGmaQimsi04=",
+ "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.2.3",
+ "eslint-module-utils": "2.2.0",
+ "has": "1.0.3",
+ "lodash.cond": "4.5.2",
+ "minimatch": "3.0.4",
+ "pkg-up": "1.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": "4.2.3",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-4.2.3.tgz",
+ "integrity": "sha512-vIUQPuwbVYdz/CYnlTLsJrRy7iXHQjdEe5wz0XhhdTym3IInM/zZLlPf9nZ2mThsH0QcsieCOWs2vOeCy/22LQ==",
+ "dev": true,
+ "requires": {
+ "ignore": "3.3.10",
+ "minimatch": "3.0.4",
+ "object-assign": "4.1.1",
+ "resolve": "1.8.1",
+ "semver": "5.3.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
+ "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=",
+ "dev": true
+ }
+ }
+ },
+ "eslint-plugin-promise": {
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.5.0.tgz",
+ "integrity": "sha1-ePu2/+BHIBYnVp6FpsU3OvKmj8o=",
+ "dev": true
+ },
+ "eslint-plugin-react": {
+ "version": "6.10.3",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-6.10.3.tgz",
+ "integrity": "sha1-xUNb6wZ3ThLH2y9qut3L+QDNP3g=",
+ "dev": true,
+ "requires": {
+ "array.prototype.find": "2.0.4",
+ "doctrine": "1.5.0",
+ "has": "1.0.3",
+ "jsx-ast-utils": "1.4.1",
+ "object.assign": "4.1.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-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
+ },
+ "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"
+ },
+ "dependencies": {
+ "acorn": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.1.tgz",
+ "integrity": "sha512-d+nbxBUGKg7Arpsvbnlq61mc12ek3EY8EQldM3GPAhWJ1UVxC6TDGbIvUMNU6obBX3i1+ptCIzV4vq0gFPEGVQ==",
+ "dev": true
+ }
+ }
+ },
+ "esprima": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz",
+ "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw=="
+ },
+ "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="
+ },
+ "event-emitter": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
+ "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=",
+ "dev": true,
+ "requires": {
+ "d": "1.0.0",
+ "es5-ext": "0.10.45"
+ }
+ },
+ "events": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
+ "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ="
+ },
+ "exec-sh": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.2.tgz",
+ "integrity": "sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw==",
+ "dev": true,
+ "requires": {
+ "merge": "1.2.0"
+ }
+ },
+ "execa": {
+ "version": "0.10.0",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz",
+ "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==",
+ "requires": {
+ "cross-spawn": "6.0.5",
+ "get-stream": "3.0.0",
+ "is-stream": "1.1.0",
+ "npm-run-path": "2.0.2",
+ "p-finally": "1.0.0",
+ "signal-exit": "3.0.2",
+ "strip-eof": "1.0.0"
+ }
+ },
+ "exit-hook": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz",
+ "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=",
+ "dev": true
+ },
+ "expand-brackets": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
+ "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
+ "dev": true,
+ "requires": {
+ "is-posix-bracket": "0.1.1"
+ }
+ },
+ "expand-range": {
+ "version": "1.8.2",
+ "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz",
+ "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=",
+ "dev": true,
+ "requires": {
+ "fill-range": "2.2.4"
+ }
+ },
+ "express": {
+ "version": "4.16.3",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.16.3.tgz",
+ "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=",
+ "requires": {
+ "accepts": "1.3.5",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.18.2",
+ "content-disposition": "0.5.2",
+ "content-type": "1.0.4",
+ "cookie": "0.3.1",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "1.1.2",
+ "encodeurl": "1.0.2",
+ "escape-html": "1.0.3",
+ "etag": "1.8.1",
+ "finalhandler": "1.1.1",
+ "fresh": "0.5.2",
+ "merge-descriptors": "1.0.1",
+ "methods": "1.1.2",
+ "on-finished": "2.3.0",
+ "parseurl": "1.3.2",
+ "path-to-regexp": "0.1.7",
+ "proxy-addr": "2.0.3",
+ "qs": "6.5.1",
+ "range-parser": "1.2.0",
+ "safe-buffer": "5.1.1",
+ "send": "0.16.2",
+ "serve-static": "1.13.2",
+ "setprototypeof": "1.1.0",
+ "statuses": "1.4.0",
+ "type-is": "1.6.16",
+ "utils-merge": "1.0.1",
+ "vary": "1.1.2"
+ },
+ "dependencies": {
+ "body-parser": {
+ "version": "1.18.2",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz",
+ "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=",
+ "requires": {
+ "bytes": "3.0.0",
+ "content-type": "1.0.4",
+ "debug": "2.6.9",
+ "depd": "1.1.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="
+ }
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
+ "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
+ },
+ "statuses": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz",
+ "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew=="
+ }
+ }
+ },
+ "express-brute": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/express-brute/-/express-brute-0.6.0.tgz",
+ "integrity": "sha1-TU7rTV35T5rx/S9/3IbDSrrxdeE=",
+ "requires": {
+ "long-timeout": "0.0.2",
+ "underscore": "1.5.2"
+ }
+ },
+ "express-github-webhook": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/express-github-webhook/-/express-github-webhook-1.0.6.tgz",
+ "integrity": "sha1-qYDKCriLjL2ke5Sh6RjD8KaPTK0=",
+ "requires": {
+ "buffer-equal-constant-time": "1.0.1"
+ }
+ },
+ "express-recaptcha": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/express-recaptcha/-/express-recaptcha-2.3.0.tgz",
+ "integrity": "sha1-bP+VV7tqE9vWtI79ftB4VWPx4LE="
+ },
+ "extend": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz",
+ "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ="
+ },
+ "extend-shallow": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
+ "dev": true,
+ "requires": {
+ "assign-symbols": "1.0.0",
+ "is-extendable": "1.0.1"
+ },
+ "dependencies": {
+ "is-extendable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+ "dev": true,
+ "requires": {
+ "is-plain-object": "2.0.4"
+ }
+ }
+ }
+ },
+ "extend.js": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/extend.js/-/extend.js-0.0.2.tgz",
+ "integrity": "sha1-D5x6gaHyCLcD6wwxMf5XFqxuzRU="
+ },
+ "extglob": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
+ "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
+ "dev": true,
+ "requires": {
+ "is-extglob": "1.0.0"
+ }
+ },
+ "extsprintf": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
+ },
+ "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="
+ },
+ "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="
+ },
+ "fb-watchman": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz",
+ "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=",
+ "dev": true,
+ "requires": {
+ "bser": "2.0.0"
+ }
+ },
+ "figures": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz",
+ "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=",
+ "dev": true,
+ "requires": {
+ "escape-string-regexp": "1.0.5",
+ "object-assign": "4.1.1"
+ }
+ },
+ "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"
+ }
+ },
+ "file-uri-to-path": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
+ "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="
+ },
+ "filename-regex": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz",
+ "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=",
+ "dev": true
+ },
+ "fileset": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz",
+ "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=",
+ "dev": true,
+ "requires": {
+ "glob": "7.1.2",
+ "minimatch": "3.0.4"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
+ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
+ "dev": true,
+ "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"
+ }
+ }
+ }
+ },
+ "fill-range": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz",
+ "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==",
+ "dev": true,
+ "requires": {
+ "is-number": "2.1.0",
+ "isobject": "2.1.0",
+ "randomatic": "3.0.0",
+ "repeat-element": "1.1.2",
+ "repeat-string": "1.6.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": "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"
+ }
+ },
+ "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"
+ }
+ },
+ "for-each": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
+ "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
+ "requires": {
+ "is-callable": "1.1.4"
+ }
+ },
+ "for-in": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
+ "dev": true
+ },
+ "for-own": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz",
+ "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=",
+ "dev": true,
+ "requires": {
+ "for-in": "1.0.2"
+ }
+ },
+ "foreach": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz",
+ "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k="
+ },
+ "forever-agent": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+ "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
+ },
+ "form-data": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz",
+ "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=",
+ "requires": {
+ "asynckit": "0.4.0",
+ "combined-stream": "1.0.6",
+ "mime-types": "2.1.18"
+ }
+ },
+ "forwarded": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
+ "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
+ },
+ "fragment-cache": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
+ "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
+ "dev": true,
+ "requires": {
+ "map-cache": "0.2.2"
+ }
+ },
+ "fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
+ },
+ "front-matter": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/front-matter/-/front-matter-2.3.0.tgz",
+ "integrity": "sha1-cgOviWzjV+4E4qpFFp6pHtf2dQQ=",
+ "dev": true,
+ "requires": {
+ "js-yaml": "3.12.0"
+ }
+ },
+ "fs-extra": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz",
+ "integrity": "sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA==",
+ "requires": {
+ "graceful-fs": "4.1.11",
+ "jsonfile": "4.0.0",
+ "universalify": "0.1.2"
+ }
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+ "dev": true
+ },
+ "ftp": {
+ "version": "0.3.10",
+ "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz",
+ "integrity": "sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0=",
+ "requires": {
+ "readable-stream": "1.1.14",
+ "xregexp": "2.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.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"
+ }
+ }
+ }
+ },
+ "function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+ },
+ "generate-function": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz",
+ "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=",
+ "dev": true
+ },
+ "generate-object-property": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz",
+ "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=",
+ "dev": true,
+ "requires": {
+ "is-property": "1.0.2"
+ }
+ },
+ "get-caller-file": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
+ "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==",
+ "dev": true
+ },
+ "get-func-name": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
+ "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=",
+ "dev": true
+ },
+ "get-stdin": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.1.tgz",
+ "integrity": "sha1-Ei4WFZHiH/TFJTAwVpPyDmOTo5g=",
+ "dev": true
+ },
+ "get-stream": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
+ "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
+ },
+ "get-uri": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-2.0.2.tgz",
+ "integrity": "sha512-ZD325dMZOgerGqF/rF6vZXyFGTAay62svjQIT+X/oU2PtxYpFxvSkbsdi+oxIrsNxlZVd4y8wUDqkaExWTI/Cw==",
+ "requires": {
+ "data-uri-to-buffer": "1.2.0",
+ "debug": "2.6.9",
+ "extend": "3.0.1",
+ "file-uri-to-path": "1.0.0",
+ "ftp": "0.3.10",
+ "readable-stream": "2.3.6"
+ }
+ },
+ "get-value": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
+ "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=",
+ "dev": true
+ },
+ "getpass": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+ "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+ "requires": {
+ "assert-plus": "1.0.0"
+ }
+ },
+ "gitlab": {
+ "version": "3.5.1",
+ "resolved": "https://registry.npmjs.org/gitlab/-/gitlab-3.5.1.tgz",
+ "integrity": "sha512-WGm3LQs5z451PLFnFk8CldJ0KAOnPo6Lenup+refzeUTso34AKk7mQIl8aaiCOrfI1aG+D0PlznX2TaOyz++NQ==",
+ "requires": {
+ "@babel/runtime": "7.0.0-beta.53",
+ "@semantic-release/npm": "3.4.0",
+ "humps": "2.0.1",
+ "lodash.pick": "4.4.0",
+ "parse-link-header": "1.0.1",
+ "qs": "6.5.2",
+ "request": "2.87.0",
+ "request-promise": "4.2.2",
+ "request-promise-core": "1.1.1",
+ "url-join": "4.0.0",
+ "util.promisify": "1.0.0",
+ "xhr": "2.5.0"
+ }
+ },
+ "glob": {
+ "version": "6.0.4",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz",
+ "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=",
+ "requires": {
+ "inflight": "1.0.6",
+ "inherits": "2.0.3",
+ "minimatch": "3.0.4",
+ "once": "1.4.0",
+ "path-is-absolute": "1.0.1"
+ }
+ },
+ "glob-base": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
+ "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=",
+ "dev": true,
+ "requires": {
+ "glob-parent": "2.0.0",
+ "is-glob": "2.0.1"
+ }
+ },
+ "glob-parent": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
+ "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=",
+ "dev": true,
+ "requires": {
+ "is-glob": "2.0.1"
+ }
+ },
+ "global": {
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/global/-/global-4.3.2.tgz",
+ "integrity": "sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=",
+ "requires": {
+ "min-document": "2.19.0",
+ "process": "0.5.2"
+ }
+ },
+ "globals": {
+ "version": "9.18.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
+ "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==",
+ "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"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
+ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
+ "dev": true,
+ "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"
+ }
+ }
+ }
+ },
+ "graceful-fs": {
+ "version": "4.1.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
+ "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg="
+ },
+ "growly": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
+ "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=",
+ "dev": true
+ },
+ "handlebars": {
+ "version": "4.0.11",
+ "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz",
+ "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=",
+ "dev": true,
+ "requires": {
+ "async": "1.5.2",
+ "optimist": "0.6.1",
+ "source-map": "0.4.4",
+ "uglify-js": "2.8.29"
+ },
+ "dependencies": {
+ "async": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
+ "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=",
+ "dev": true
+ },
+ "source-map": {
+ "version": "0.4.4",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
+ "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
+ "dev": true,
+ "requires": {
+ "amdefine": "1.0.1"
+ }
+ }
+ }
+ },
+ "har-schema": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
+ "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
+ },
+ "har-validator": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz",
+ "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=",
+ "requires": {
+ "ajv": "5.5.2",
+ "har-schema": "2.0.0"
+ }
+ },
+ "has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "requires": {
+ "function-bind": "1.1.1"
+ }
+ },
+ "has-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-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
+ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
+ "dev": true
+ },
+ "has-symbols": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz",
+ "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=",
+ "dev": true
+ },
+ "has-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
+ "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
+ "dev": true,
+ "requires": {
+ "get-value": "2.0.6",
+ "has-values": "1.0.0",
+ "isobject": "3.0.1"
+ },
+ "dependencies": {
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true
+ }
+ }
+ },
+ "has-values": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
+ "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=",
+ "dev": true,
+ "requires": {
+ "is-number": "3.0.0",
+ "kind-of": "4.0.0"
+ },
+ "dependencies": {
+ "is-number": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+ "dev": true,
+ "requires": {
+ "kind-of": "3.2.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "1.1.6"
+ }
+ }
+ }
+ },
+ "kind-of": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
+ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "1.1.6"
+ }
+ }
+ }
+ },
+ "hawk": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz",
+ "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==",
+ "requires": {
+ "boom": "4.3.1",
+ "cryptiles": "3.1.2",
+ "hoek": "4.2.1",
+ "sntp": "2.1.0"
+ }
+ },
+ "hoek": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz",
+ "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA=="
+ },
+ "home-or-tmp": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
+ "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=",
+ "dev": true,
+ "requires": {
+ "os-homedir": "1.0.2",
+ "os-tmpdir": "1.0.2"
+ }
+ },
+ "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=="
+ },
+ "html-encoding-sniffer": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz",
+ "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==",
+ "dev": true,
+ "requires": {
+ "whatwg-encoding": "1.0.3"
+ }
+ },
+ "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"
+ }
+ },
+ "http-proxy-agent": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-1.0.0.tgz",
+ "integrity": "sha1-zBzjjkU7+YSg93AtLdWcc9CBKEo=",
+ "requires": {
+ "agent-base": "2.1.1",
+ "debug": "2.6.9",
+ "extend": "3.0.1"
+ }
+ },
+ "http-signature": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
+ "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
+ "requires": {
+ "assert-plus": "1.0.0",
+ "jsprim": "1.4.1",
+ "sshpk": "1.14.2"
+ }
+ },
+ "https-proxy-agent": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz",
+ "integrity": "sha1-NffabEjOTdv6JkiRrFk+5f+GceY=",
+ "requires": {
+ "agent-base": "2.1.1",
+ "debug": "2.6.9",
+ "extend": "3.0.1"
+ }
+ },
+ "humps": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/humps/-/humps-2.0.1.tgz",
+ "integrity": "sha1-3QLqYIG9BWjcXQcxhEY5V7qe+ao="
+ },
+ "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.8",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz",
+ "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q="
+ },
+ "ignore": {
+ "version": "3.3.10",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz",
+ "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==",
+ "dev": true
+ },
+ "imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
+ "dev": true
+ },
+ "indent-string": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz",
+ "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok="
+ },
+ "inflection": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.10.0.tgz",
+ "integrity": "sha1-W//LEZetPoEFD44X4hZoCH7p6y8="
+ },
+ "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": "0.12.0",
+ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz",
+ "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=",
+ "dev": true,
+ "requires": {
+ "ansi-escapes": "1.4.0",
+ "ansi-regex": "2.1.1",
+ "chalk": "1.1.3",
+ "cli-cursor": "1.0.2",
+ "cli-width": "2.2.0",
+ "figures": "1.7.0",
+ "lodash": "4.17.10",
+ "readline2": "1.0.1",
+ "run-async": "0.1.0",
+ "rx-lite": "3.1.2",
+ "string-width": "1.0.2",
+ "strip-ansi": "3.0.1",
+ "through": "2.3.8"
+ },
+ "dependencies": {
+ "lodash": {
+ "version": "4.17.10",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
+ "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
+ "dev": true
+ }
+ }
+ },
+ "interpret": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz",
+ "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=",
+ "dev": true
+ },
+ "invariant": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
+ "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
+ "dev": true,
+ "requires": {
+ "loose-envify": "1.4.0"
+ }
+ },
+ "invert-kv": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
+ "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=",
+ "dev": true
+ },
+ "ip": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/ip/-/ip-1.0.1.tgz",
+ "integrity": "sha1-x+NWzeoiWucbNtcPLnGpK6TkJZA="
+ },
+ "ipaddr.js": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.6.0.tgz",
+ "integrity": "sha1-4/o1e3c9phnybpXwSdBVxyeW+Gs="
+ },
+ "is-accessor-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+ "dev": true,
+ "requires": {
+ "kind-of": "3.2.2"
+ }
+ },
+ "is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0="
+ },
+ "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=",
+ "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=="
+ },
+ "is-ci": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.1.0.tgz",
+ "integrity": "sha512-c7TnwxLePuqIlxHgr7xtxzycJPegNHFuIrBkwbf8hc58//+Op1CqFkyS+xnIMkwn9UsJIwc174BIjkyBmSpjKg==",
+ "dev": true,
+ "requires": {
+ "ci-info": "1.1.3"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+ "dev": true,
+ "requires": {
+ "kind-of": "3.2.2"
+ }
+ },
+ "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="
+ },
+ "is-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "0.1.6",
+ "is-data-descriptor": "0.1.4",
+ "kind-of": "5.1.0"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+ "dev": true
+ }
+ }
+ },
+ "is-dotfile": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz",
+ "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=",
+ "dev": true
+ },
+ "is-equal-shallow": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz",
+ "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=",
+ "dev": true,
+ "requires": {
+ "is-primitive": "2.0.0"
+ }
+ },
+ "is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
+ "dev": true
+ },
+ "is-extglob": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+ "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+ "dev": true
+ },
+ "is-finite": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz",
+ "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=",
+ "dev": true,
+ "requires": {
+ "number-is-nan": "1.0.1"
+ }
+ },
+ "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=",
+ "dev": true,
+ "requires": {
+ "number-is-nan": "1.0.1"
+ }
+ },
+ "is-function": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.1.tgz",
+ "integrity": "sha1-Es+5i2W1fdPRk6MSH19uL0N2ArU="
+ },
+ "is-glob": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+ "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+ "dev": true,
+ "requires": {
+ "is-extglob": "1.0.0"
+ }
+ },
+ "is-my-ip-valid": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz",
+ "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==",
+ "dev": true
+ },
+ "is-my-json-valid": {
+ "version": "2.17.2",
+ "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.17.2.tgz",
+ "integrity": "sha512-IBhBslgngMQN8DDSppmgDv7RNrlFotuuDsKcrCP3+HbFaVivIBU7u9oiiErw8sH4ynx3+gOGQ3q2otkgiSi6kg==",
+ "dev": true,
+ "requires": {
+ "generate-function": "2.0.0",
+ "generate-object-property": "1.2.0",
+ "is-my-ip-valid": "1.0.0",
+ "jsonpointer": "4.0.1",
+ "xtend": "4.0.1"
+ }
+ },
+ "is-number": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz",
+ "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=",
+ "dev": true,
+ "requires": {
+ "kind-of": "3.2.2"
+ }
+ },
+ "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-plain-object": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+ "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+ "dev": true,
+ "requires": {
+ "isobject": "3.0.1"
+ },
+ "dependencies": {
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true
+ }
+ }
+ },
+ "is-posix-bracket": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz",
+ "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=",
+ "dev": true
+ },
+ "is-primitive": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz",
+ "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=",
+ "dev": true
+ },
+ "is-property": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
+ "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=",
+ "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=",
+ "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-stream": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
+ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
+ },
+ "is-symbol": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz",
+ "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI="
+ },
+ "is-typedarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
+ },
+ "is-utf8": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
+ "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
+ "dev": true
+ },
+ "is-windows": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+ "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+ "dev": true
+ },
+ "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="
+ },
+ "isobject": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+ "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+ "dev": true,
+ "requires": {
+ "isarray": "1.0.0"
+ }
+ },
+ "isstream": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
+ },
+ "istanbul-api": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-1.3.1.tgz",
+ "integrity": "sha512-duj6AlLcsWNwUpfyfHt0nWIeRiZpuShnP40YTxOGQgtaN8fd6JYSxsvxUphTDy8V5MfDXo4s/xVCIIvVCO808g==",
+ "dev": true,
+ "requires": {
+ "async": "2.6.1",
+ "compare-versions": "3.3.0",
+ "fileset": "2.0.3",
+ "istanbul-lib-coverage": "1.2.0",
+ "istanbul-lib-hook": "1.2.1",
+ "istanbul-lib-instrument": "1.10.1",
+ "istanbul-lib-report": "1.1.4",
+ "istanbul-lib-source-maps": "1.2.5",
+ "istanbul-reports": "1.3.0",
+ "js-yaml": "3.12.0",
+ "mkdirp": "0.5.1",
+ "once": "1.4.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==",
+ "dev": true,
+ "requires": {
+ "lodash": "4.17.10"
+ }
+ },
+ "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"
+ }
+ },
+ "glob": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
+ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
+ "dev": true,
+ "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"
+ }
+ },
+ "istanbul-lib-source-maps": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.5.tgz",
+ "integrity": "sha512-8O2T/3VhrQHn0XcJbP1/GN7kXMiRAlPi+fj3uEHrjBD8Oz7Py0prSC25C09NuAZS6bgW1NNKAvCSHZXB0irSGA==",
+ "dev": true,
+ "requires": {
+ "debug": "3.1.0",
+ "istanbul-lib-coverage": "1.2.0",
+ "mkdirp": "0.5.1",
+ "rimraf": "2.6.2",
+ "source-map": "0.5.7"
+ }
+ },
+ "lodash": {
+ "version": "4.17.10",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
+ "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
+ "dev": true
+ },
+ "rimraf": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
+ "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
+ "dev": true,
+ "requires": {
+ "glob": "7.1.2"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true
+ }
+ }
+ },
+ "istanbul-cobertura-badger": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/istanbul-cobertura-badger/-/istanbul-cobertura-badger-1.3.1.tgz",
+ "integrity": "sha1-PNkMQrZSRthYmOA7TWn3tsis4zQ=",
+ "dev": true,
+ "requires": {
+ "commander": "2.16.0",
+ "xml-splitter": "1.2.1",
+ "xtend": "4.0.1"
+ }
+ },
+ "istanbul-lib-coverage": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.0.tgz",
+ "integrity": "sha512-GvgM/uXRwm+gLlvkWHTjDAvwynZkL9ns15calTrmhGgowlwJBbWMYzWbKqE2DT6JDP1AFXKa+Zi0EkqNCUqY0A==",
+ "dev": true
+ },
+ "istanbul-lib-hook": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.2.1.tgz",
+ "integrity": "sha512-eLAMkPG9FU0v5L02lIkcj/2/Zlz9OuluaXikdr5iStk8FDbSwAixTK9TkYxbF0eNnzAJTwM2fkV2A1tpsIp4Jg==",
+ "dev": true,
+ "requires": {
+ "append-transform": "1.0.0"
+ }
+ },
+ "istanbul-lib-instrument": {
+ "version": "1.10.1",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.1.tgz",
+ "integrity": "sha512-1dYuzkOCbuR5GRJqySuZdsmsNKPL3PTuyPevQfoCXJePT9C8y1ga75neU+Tuy9+yS3G/dgx8wgOmp2KLpgdoeQ==",
+ "dev": true,
+ "requires": {
+ "babel-generator": "6.26.1",
+ "babel-template": "6.26.0",
+ "babel-traverse": "6.26.0",
+ "babel-types": "6.26.0",
+ "babylon": "6.18.0",
+ "istanbul-lib-coverage": "1.2.0",
+ "semver": "5.5.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
+ "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==",
+ "dev": true
+ }
+ }
+ },
+ "istanbul-lib-report": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.1.4.tgz",
+ "integrity": "sha512-Azqvq5tT0U09nrncK3q82e/Zjkxa4tkFZv7E6VcqP0QCPn6oNljDPfrZEC/umNXds2t7b8sRJfs6Kmpzt8m2kA==",
+ "dev": true,
+ "requires": {
+ "istanbul-lib-coverage": "1.2.0",
+ "mkdirp": "0.5.1",
+ "path-parse": "1.0.5",
+ "supports-color": "3.2.3"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
+ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
+ "dev": true,
+ "requires": {
+ "has-flag": "1.0.0"
+ }
+ }
+ }
+ },
+ "istanbul-lib-source-maps": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.3.tgz",
+ "integrity": "sha512-fDa0hwU/5sDXwAklXgAoCJCOsFsBplVQ6WBldz5UwaqOzmDhUK4nfuR7/G//G2lERlblUNJB8P6e8cXq3a7MlA==",
+ "dev": true,
+ "requires": {
+ "debug": "3.1.0",
+ "istanbul-lib-coverage": "1.2.0",
+ "mkdirp": "0.5.1",
+ "rimraf": "2.6.2",
+ "source-map": "0.5.7"
+ },
+ "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"
+ }
+ },
+ "glob": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
+ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
+ "dev": true,
+ "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"
+ }
+ },
+ "rimraf": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
+ "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
+ "dev": true,
+ "requires": {
+ "glob": "7.1.2"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true
+ }
+ }
+ },
+ "istanbul-reports": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.3.0.tgz",
+ "integrity": "sha512-y2Z2IMqE1gefWUaVjrBm0mSKvUkaBy9Vqz8iwr/r40Y9hBbIteH5wqHG/9DLTfJ9xUnUT2j7A3+VVJ6EaYBllA==",
+ "dev": true,
+ "requires": {
+ "handlebars": "4.0.11"
+ }
+ },
+ "jest": {
+ "version": "20.0.4",
+ "resolved": "https://registry.npmjs.org/jest/-/jest-20.0.4.tgz",
+ "integrity": "sha1-PdJgwpidba1nix6cxNkZRPbWAqw=",
+ "dev": true,
+ "requires": {
+ "jest-cli": "20.0.4"
+ },
+ "dependencies": {
+ "jest-cli": {
+ "version": "20.0.4",
+ "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-20.0.4.tgz",
+ "integrity": "sha1-5TKxnYiuW8bEF+iwWTpv6VSx3JM=",
+ "dev": true,
+ "requires": {
+ "ansi-escapes": "1.4.0",
+ "callsites": "2.0.0",
+ "chalk": "1.1.3",
+ "graceful-fs": "4.1.11",
+ "is-ci": "1.1.0",
+ "istanbul-api": "1.3.1",
+ "istanbul-lib-coverage": "1.2.0",
+ "istanbul-lib-instrument": "1.10.1",
+ "istanbul-lib-source-maps": "1.2.3",
+ "jest-changed-files": "20.0.3",
+ "jest-config": "20.0.4",
+ "jest-docblock": "20.0.3",
+ "jest-environment-jsdom": "20.0.3",
+ "jest-haste-map": "20.0.5",
+ "jest-jasmine2": "20.0.4",
+ "jest-message-util": "20.0.3",
+ "jest-regex-util": "20.0.3",
+ "jest-resolve-dependencies": "20.0.3",
+ "jest-runtime": "20.0.4",
+ "jest-snapshot": "20.0.3",
+ "jest-util": "20.0.3",
+ "micromatch": "2.3.11",
+ "node-notifier": "5.2.1",
+ "pify": "2.3.0",
+ "slash": "1.0.0",
+ "string-length": "1.0.1",
+ "throat": "3.2.0",
+ "which": "1.3.1",
+ "worker-farm": "1.6.0",
+ "yargs": "7.1.0"
+ }
+ }
+ }
+ },
+ "jest-changed-files": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-20.0.3.tgz",
+ "integrity": "sha1-k5TVzGXEOEBhSb7xv01Sto4D4/g=",
+ "dev": true
+ },
+ "jest-config": {
+ "version": "20.0.4",
+ "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-20.0.4.tgz",
+ "integrity": "sha1-43kwqyIXyRNgXv8T5712PsSPruo=",
+ "dev": true,
+ "requires": {
+ "chalk": "1.1.3",
+ "glob": "7.1.2",
+ "jest-environment-jsdom": "20.0.3",
+ "jest-environment-node": "20.0.3",
+ "jest-jasmine2": "20.0.4",
+ "jest-matcher-utils": "20.0.3",
+ "jest-regex-util": "20.0.3",
+ "jest-resolve": "20.0.4",
+ "jest-validate": "20.0.3",
+ "pretty-format": "20.0.3"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
+ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
+ "dev": true,
+ "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"
+ }
+ }
+ }
+ },
+ "jest-diff": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-20.0.3.tgz",
+ "integrity": "sha1-gfKI/Z5nXw+yPHXxwrGURf5YZhc=",
+ "dev": true,
+ "requires": {
+ "chalk": "1.1.3",
+ "diff": "3.5.0",
+ "jest-matcher-utils": "20.0.3",
+ "pretty-format": "20.0.3"
+ }
+ },
+ "jest-docblock": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-20.0.3.tgz",
+ "integrity": "sha1-F76phDQswz2DxQ++FUXqDvqkRxI=",
+ "dev": true
+ },
+ "jest-environment-jsdom": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-20.0.3.tgz",
+ "integrity": "sha1-BIqKwS7iJfcZBBdxODS7mZeH3pk=",
+ "dev": true,
+ "requires": {
+ "jest-mock": "20.0.3",
+ "jest-util": "20.0.3",
+ "jsdom": "9.12.0"
+ }
+ },
+ "jest-environment-node": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-20.0.3.tgz",
+ "integrity": "sha1-1Ii8RhKvLCRumG6K52caCZFj1AM=",
+ "dev": true,
+ "requires": {
+ "jest-mock": "20.0.3",
+ "jest-util": "20.0.3"
+ }
+ },
+ "jest-haste-map": {
+ "version": "20.0.5",
+ "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-20.0.5.tgz",
+ "integrity": "sha512-0IKAQjUvuZjMCNi/0VNQQF74/H9KB67hsHJqGiwTWQC6XO5Azs7kLWm+6Q/dwuhvDUvABDOBMFK2/FwZ3sZ07Q==",
+ "dev": true,
+ "requires": {
+ "fb-watchman": "2.0.0",
+ "graceful-fs": "4.1.11",
+ "jest-docblock": "20.0.3",
+ "micromatch": "2.3.11",
+ "sane": "1.6.0",
+ "worker-farm": "1.6.0"
+ }
+ },
+ "jest-jasmine2": {
+ "version": "20.0.4",
+ "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-20.0.4.tgz",
+ "integrity": "sha1-/MWxQReA2RHQQpAu8YWehS5g1eE=",
+ "dev": true,
+ "requires": {
+ "chalk": "1.1.3",
+ "graceful-fs": "4.1.11",
+ "jest-diff": "20.0.3",
+ "jest-matcher-utils": "20.0.3",
+ "jest-matchers": "20.0.3",
+ "jest-message-util": "20.0.3",
+ "jest-snapshot": "20.0.3",
+ "once": "1.4.0",
+ "p-map": "1.2.0"
+ }
+ },
+ "jest-matcher-utils": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-20.0.3.tgz",
+ "integrity": "sha1-s6a443yld4A7CDKpixZPRLeBVhI=",
+ "dev": true,
+ "requires": {
+ "chalk": "1.1.3",
+ "pretty-format": "20.0.3"
+ }
+ },
+ "jest-matchers": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/jest-matchers/-/jest-matchers-20.0.3.tgz",
+ "integrity": "sha1-ymnbHDLbWm9wf6XgQBq7VXAN/WA=",
+ "dev": true,
+ "requires": {
+ "jest-diff": "20.0.3",
+ "jest-matcher-utils": "20.0.3",
+ "jest-message-util": "20.0.3",
+ "jest-regex-util": "20.0.3"
+ }
+ },
+ "jest-message-util": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-20.0.3.tgz",
+ "integrity": "sha1-auwoRDBvyw5udNV5bBAG2W/dgxw=",
+ "dev": true,
+ "requires": {
+ "chalk": "1.1.3",
+ "micromatch": "2.3.11",
+ "slash": "1.0.0"
+ }
+ },
+ "jest-mock": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-20.0.3.tgz",
+ "integrity": "sha1-i8Bw6QQUqhVcEajWTIaaDVxx2lk=",
+ "dev": true
+ },
+ "jest-regex-util": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-20.0.3.tgz",
+ "integrity": "sha1-hburXRM+RGJbGfr4xqpRItCF12I=",
+ "dev": true
+ },
+ "jest-resolve": {
+ "version": "20.0.4",
+ "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-20.0.4.tgz",
+ "integrity": "sha1-lEiz6La6/BVHlETGSZBFt//ll6U=",
+ "dev": true,
+ "requires": {
+ "browser-resolve": "1.11.3",
+ "is-builtin-module": "1.0.0",
+ "resolve": "1.8.1"
+ }
+ },
+ "jest-resolve-dependencies": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-20.0.3.tgz",
+ "integrity": "sha1-bhSntxevDyyzZnxUneQK8Bexcjo=",
+ "dev": true,
+ "requires": {
+ "jest-regex-util": "20.0.3"
+ }
+ },
+ "jest-runtime": {
+ "version": "20.0.4",
+ "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-20.0.4.tgz",
+ "integrity": "sha1-osgCIZxCA/dU3xQE5JAYYWnRJNg=",
+ "dev": true,
+ "requires": {
+ "babel-core": "6.26.3",
+ "babel-jest": "20.0.3",
+ "babel-plugin-istanbul": "4.1.6",
+ "chalk": "1.1.3",
+ "convert-source-map": "1.5.1",
+ "graceful-fs": "4.1.11",
+ "jest-config": "20.0.4",
+ "jest-haste-map": "20.0.5",
+ "jest-regex-util": "20.0.3",
+ "jest-resolve": "20.0.4",
+ "jest-util": "20.0.3",
+ "json-stable-stringify": "1.0.1",
+ "micromatch": "2.3.11",
+ "strip-bom": "3.0.0",
+ "yargs": "7.1.0"
+ }
+ },
+ "jest-snapshot": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-20.0.3.tgz",
+ "integrity": "sha1-W4R+GtsaTZCFKn+fElCG4YfHZWY=",
+ "dev": true,
+ "requires": {
+ "chalk": "1.1.3",
+ "jest-diff": "20.0.3",
+ "jest-matcher-utils": "20.0.3",
+ "jest-util": "20.0.3",
+ "natural-compare": "1.4.0",
+ "pretty-format": "20.0.3"
+ }
+ },
+ "jest-util": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-20.0.3.tgz",
+ "integrity": "sha1-DAf32A2C9OWmfG+LnD/n9lz9Mq0=",
+ "dev": true,
+ "requires": {
+ "chalk": "1.1.3",
+ "graceful-fs": "4.1.11",
+ "jest-message-util": "20.0.3",
+ "jest-mock": "20.0.3",
+ "jest-validate": "20.0.3",
+ "leven": "2.1.0",
+ "mkdirp": "0.5.1"
+ }
+ },
+ "jest-validate": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-20.0.3.tgz",
+ "integrity": "sha1-0M/R3k9XnymEhJJcKA+PHZTsPKs=",
+ "dev": true,
+ "requires": {
+ "chalk": "1.1.3",
+ "jest-matcher-utils": "20.0.3",
+ "leven": "2.1.0",
+ "pretty-format": "20.0.3"
+ }
+ },
+ "jmespath": {
+ "version": "0.15.0",
+ "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz",
+ "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc="
+ },
+ "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.0"
+ }
+ },
+ "jsbn": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
+ "optional": true
+ },
+ "jsdom": {
+ "version": "9.12.0",
+ "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-9.12.0.tgz",
+ "integrity": "sha1-6MVG//ywbADUgzyoRBD+1/igl9Q=",
+ "dev": true,
+ "requires": {
+ "abab": "1.0.4",
+ "acorn": "4.0.13",
+ "acorn-globals": "3.1.0",
+ "array-equal": "1.0.0",
+ "content-type-parser": "1.0.2",
+ "cssom": "0.3.4",
+ "cssstyle": "0.2.37",
+ "escodegen": "1.10.0",
+ "html-encoding-sniffer": "1.0.2",
+ "nwmatcher": "1.4.4",
+ "parse5": "1.5.1",
+ "request": "2.87.0",
+ "sax": "1.2.1",
+ "symbol-tree": "3.2.2",
+ "tough-cookie": "2.3.4",
+ "webidl-conversions": "4.0.2",
+ "whatwg-encoding": "1.0.3",
+ "whatwg-url": "4.8.0",
+ "xml-name-validator": "2.0.1"
+ }
+ },
+ "jsesc": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz",
+ "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=",
+ "dev": true
+ },
+ "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=="
+ },
+ "json-schema": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
+ "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
+ },
+ "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="
+ },
+ "json-stable-stringify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
+ "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
+ "dev": true,
+ "requires": {
+ "jsonify": "0.0.0"
+ }
+ },
+ "json-stringify-safe": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
+ },
+ "json5": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
+ "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
+ "requires": {
+ "minimist": "1.2.0"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
+ }
+ }
+ },
+ "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"
+ }
+ },
+ "jsonify": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
+ "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
+ "dev": true
+ },
+ "jsonpointer": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz",
+ "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=",
+ "dev": true
+ },
+ "jsprim": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
+ "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
+ "requires": {
+ "assert-plus": "1.0.0",
+ "extsprintf": "1.3.0",
+ "json-schema": "0.2.3",
+ "verror": "1.10.0"
+ }
+ },
+ "jsx-ast-utils": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz",
+ "integrity": "sha1-OGchPo3Xm/Ho8jAMDPwe+xgsDfE=",
+ "dev": true
+ },
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "1.1.6"
+ }
+ },
+ "kinesis": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/kinesis/-/kinesis-1.2.2.tgz",
+ "integrity": "sha1-YYVWE2u1zegvK2/qTKZT/d64DDc=",
+ "requires": {
+ "async": "0.9.2",
+ "aws4": "0.3.0",
+ "awscred": "1.4.1",
+ "lru-cache": "2.7.3",
+ "once": "1.4.0"
+ }
+ },
+ "lazy-cache": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
+ "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=",
+ "dev": true,
+ "optional": true
+ },
+ "lcid": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
+ "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=",
+ "dev": true,
+ "requires": {
+ "invert-kv": "1.0.0"
+ }
+ },
+ "leven": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz",
+ "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=",
+ "dev": true
+ },
+ "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"
+ }
+ },
+ "load-json-file": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
+ "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "4.1.11",
+ "parse-json": "2.2.0",
+ "pify": "2.3.0",
+ "pinkie-promise": "2.0.1",
+ "strip-bom": "2.0.0"
+ },
+ "dependencies": {
+ "strip-bom": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
+ "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
+ "dev": true,
+ "requires": {
+ "is-utf8": "0.2.1"
+ }
+ }
+ }
+ },
+ "locate-path": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
+ "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
+ "dev": true,
+ "requires": {
+ "p-locate": "2.0.0",
+ "path-exists": "3.0.0"
+ }
+ },
+ "lodash": {
+ "version": "4.17.10",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
+ "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
+ "dev": true
+ },
+ "lodash.clonedeep": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
+ "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8="
+ },
+ "lodash.cond": {
+ "version": "4.5.2",
+ "resolved": "https://registry.npmjs.org/lodash.cond/-/lodash.cond-4.5.2.tgz",
+ "integrity": "sha1-9HGh2khr5g9quVXRcRVSPdHSVdU=",
+ "dev": true
+ },
+ "lodash.pick": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz",
+ "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM="
+ },
+ "long-timeout": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/long-timeout/-/long-timeout-0.0.2.tgz",
+ "integrity": "sha1-82RJuolinROnorJSOk253Wbj/2g="
+ },
+ "longest": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
+ "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=",
+ "dev": true
+ },
+ "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": "2.7.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz",
+ "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI="
+ },
+ "mailgun-js": {
+ "version": "0.7.15",
+ "resolved": "https://registry.npmjs.org/mailgun-js/-/mailgun-js-0.7.15.tgz",
+ "integrity": "sha1-7jZqINrGTDwVwD1sGz4O15UlKrs=",
+ "requires": {
+ "async": "2.1.5",
+ "debug": "2.2.0",
+ "form-data": "2.1.4",
+ "inflection": "1.10.0",
+ "is-stream": "1.1.0",
+ "path-proxy": "1.0.0",
+ "proxy-agent": "2.0.0",
+ "q": "1.4.1",
+ "tsscmp": "1.0.5"
+ },
+ "dependencies": {
+ "async": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/async/-/async-2.1.5.tgz",
+ "integrity": "sha1-5YfGhYCZSsZ/xW/4bTrFa9voELw=",
+ "requires": {
+ "lodash": "4.17.10"
+ }
+ },
+ "debug": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
+ "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
+ "requires": {
+ "ms": "0.7.1"
+ }
+ },
+ "form-data": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz",
+ "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=",
+ "requires": {
+ "asynckit": "0.4.0",
+ "combined-stream": "1.0.6",
+ "mime-types": "2.1.18"
+ }
+ },
+ "lodash": {
+ "version": "4.17.10",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
+ "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg=="
+ },
+ "ms": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
+ "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg="
+ }
+ }
+ },
+ "makeerror": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz",
+ "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=",
+ "dev": true,
+ "requires": {
+ "tmpl": "1.0.4"
+ }
+ },
+ "map-cache": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
+ "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=",
+ "dev": true
+ },
+ "map-visit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
+ "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=",
+ "dev": true,
+ "requires": {
+ "object-visit": "1.0.1"
+ }
+ },
+ "markdown-table": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-1.1.2.tgz",
+ "integrity": "sha512-NcWuJFHDA8V3wkDgR/j4+gZx+YQwstPgfQDV8ndUeWWzta3dnDTBxpVzqS9lkmJAuV5YX35lmyojl6HO5JXAgw=="
+ },
+ "math-random": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz",
+ "integrity": "sha1-izqsWIuKZuSXXjzepn97sylgH6w=",
+ "dev": true
+ },
+ "md5": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz",
+ "integrity": "sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=",
+ "requires": {
+ "charenc": "0.0.2",
+ "crypt": "0.0.2",
+ "is-buffer": "1.1.6"
+ }
+ },
+ "media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
+ },
+ "memorystream": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
+ "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI="
+ },
+ "merge": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz",
+ "integrity": "sha1-dTHjnUlJwoGma4xabgJl6LBYlNo=",
+ "dev": true
+ },
+ "merge-descriptors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+ "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
+ },
+ "methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
+ },
+ "micromatch": {
+ "version": "2.3.11",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
+ "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
+ "dev": true,
+ "requires": {
+ "arr-diff": "2.0.0",
+ "array-unique": "0.2.1",
+ "braces": "1.8.5",
+ "expand-brackets": "0.1.5",
+ "extglob": "0.3.2",
+ "filename-regex": "2.0.1",
+ "is-extglob": "1.0.0",
+ "is-glob": "2.0.1",
+ "kind-of": "3.2.2",
+ "normalize-path": "2.1.1",
+ "object.omit": "2.0.1",
+ "parse-glob": "3.0.4",
+ "regex-cache": "0.4.4"
+ }
+ },
+ "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.33.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz",
+ "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ=="
+ },
+ "mime-types": {
+ "version": "2.1.18",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz",
+ "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==",
+ "requires": {
+ "mime-db": "1.33.0"
+ }
+ },
+ "min-document": {
+ "version": "2.19.0",
+ "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz",
+ "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=",
+ "requires": {
+ "dom-walk": "0.1.1"
+ }
+ },
+ "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="
+ },
+ "mixin-deep": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz",
+ "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==",
+ "dev": true,
+ "requires": {
+ "for-in": "1.0.2",
+ "is-extendable": "1.0.1"
+ },
+ "dependencies": {
+ "is-extendable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+ "dev": true,
+ "requires": {
+ "is-plain-object": "2.0.4"
+ }
+ }
+ }
+ },
+ "mkdirp": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+ "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+ "requires": {
+ "minimist": "0.0.8"
+ }
+ },
+ "moment": {
+ "version": "2.22.2",
+ "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz",
+ "integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y="
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ },
+ "mute-stream": {
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz",
+ "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=",
+ "dev": true
+ },
+ "mv": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz",
+ "integrity": "sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI=",
+ "optional": true,
+ "requires": {
+ "mkdirp": "0.5.1",
+ "ncp": "2.0.0",
+ "rimraf": "2.4.5"
+ }
+ },
+ "nan": {
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz",
+ "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==",
+ "optional": true
+ },
+ "nanomatch": {
+ "version": "1.2.13",
+ "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
+ "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
+ "dev": true,
+ "requires": {
+ "arr-diff": "4.0.0",
+ "array-unique": "0.3.2",
+ "define-property": "2.0.2",
+ "extend-shallow": "3.0.2",
+ "fragment-cache": "0.2.1",
+ "is-windows": "1.0.2",
+ "kind-of": "6.0.2",
+ "object.pick": "1.3.0",
+ "regex-not": "1.0.2",
+ "snapdragon": "0.8.2",
+ "to-regex": "3.0.2"
+ },
+ "dependencies": {
+ "arr-diff": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+ "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
+ "dev": true
+ },
+ "array-unique": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
+ "dev": true
+ },
+ "kind-of": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
+ "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
+ "dev": true
+ }
+ }
+ },
+ "natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
+ "dev": true
+ },
+ "ncp": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz",
+ "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=",
+ "optional": true
+ },
+ "negotiator": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
+ "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk="
+ },
+ "nerf-dart": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/nerf-dart/-/nerf-dart-1.0.0.tgz",
+ "integrity": "sha1-5tq3/r9a2Bbqgc9cYpxaDr3nLBo="
+ },
+ "netmask": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/netmask/-/netmask-1.0.6.tgz",
+ "integrity": "sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU="
+ },
+ "next-tick": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
+ "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=",
+ "dev": true
+ },
+ "nice-try": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.4.tgz",
+ "integrity": "sha512-2NpiFHqC87y/zFke0fC0spBXL3bBsoh/p5H1EFhshxjCR5+0g2d6BiXbUFz9v1sAcxsk2htp2eQnNIci2dIYcA=="
+ },
+ "nock": {
+ "version": "9.4.2",
+ "resolved": "https://registry.npmjs.org/nock/-/nock-9.4.2.tgz",
+ "integrity": "sha512-WFRlGfJJ17uyXKAIFKXqoq5o49W7aYjfH3Zges133kYGwL6PuSjthP50osQJJNMQoz0f0SodmREjzo8eLh/Bxw==",
+ "dev": true,
+ "requires": {
+ "chai": "4.1.2",
+ "debug": "3.1.0",
+ "deep-equal": "1.0.1",
+ "json-stringify-safe": "5.0.1",
+ "lodash": "4.17.10",
+ "mkdirp": "0.5.1",
+ "propagate": "1.0.0",
+ "qs": "6.5.2",
+ "semver": "5.5.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"
+ }
+ },
+ "lodash": {
+ "version": "4.17.10",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
+ "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
+ "dev": true
+ },
+ "semver": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
+ "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==",
+ "dev": true
+ }
+ }
+ },
+ "node-fetch": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz",
+ "integrity": "sha1-q4hOjn5X44qUR1POxwb3iNF2i7U="
+ },
+ "node-int64": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
+ "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=",
+ "dev": true
+ },
+ "node-notifier": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.2.1.tgz",
+ "integrity": "sha512-MIBs+AAd6dJ2SklbbE8RUDRlIVhU8MaNLh1A9SUZDUHPiZkWLFde6UNwG41yQHZEToHgJMXqyVZ9UcS/ReOVTg==",
+ "dev": true,
+ "requires": {
+ "growly": "1.3.0",
+ "semver": "5.5.0",
+ "shellwords": "0.1.1",
+ "which": "1.3.1"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
+ "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==",
+ "dev": true
+ }
+ }
+ },
+ "node-rsa": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/node-rsa/-/node-rsa-0.4.2.tgz",
+ "integrity": "sha1-1jkXKewWqDDtWjgEKzFX0tXXJTA=",
+ "requires": {
+ "asn1": "0.2.3"
+ }
+ },
+ "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==",
+ "requires": {
+ "hosted-git-info": "2.7.1",
+ "is-builtin-module": "1.0.0",
+ "semver": "5.0.3",
+ "validate-npm-package-license": "3.0.3"
+ }
+ },
+ "normalize-path": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+ "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+ "dev": true,
+ "requires": {
+ "remove-trailing-separator": "1.1.0"
+ }
+ },
+ "normalize-url": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.2.0.tgz",
+ "integrity": "sha512-WvF3Myk0NhXkG8S9bygFM4IC1KOvnVJGq0QoGeoqOYOBeinBZp5ybW3QuYbTc89lkWBMM9ZBO4QGRoc0353kKA=="
+ },
+ "npm-run-path": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
+ "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
+ "requires": {
+ "path-key": "2.0.1"
+ }
+ },
+ "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=",
+ "dev": true
+ },
+ "nwmatcher": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.4.4.tgz",
+ "integrity": "sha512-3iuY4N5dhgMpCUrOVnuAdGrgxVqV2cJpM+XNccjR2DKOB1RUP0aA+wGXEiNziG/UKboFyGBIoKOaNlJxx8bciQ==",
+ "dev": true
+ },
+ "oauth-sign": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
+ "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM="
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+ "dev": true
+ },
+ "object-copy": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
+ "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=",
+ "dev": true,
+ "requires": {
+ "copy-descriptor": "0.1.1",
+ "define-property": "0.2.5",
+ "kind-of": "3.2.2"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "0.1.6"
+ }
+ }
+ }
+ },
+ "object-keys": {
+ "version": "1.0.12",
+ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz",
+ "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag=="
+ },
+ "object-path": {
+ "version": "0.11.4",
+ "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.11.4.tgz",
+ "integrity": "sha1-NwrnUvvzfePqcKhhwju6iRVpGUk="
+ },
+ "object-visit": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
+ "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
+ "dev": true,
+ "requires": {
+ "isobject": "3.0.1"
+ },
+ "dependencies": {
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true
+ }
+ }
+ },
+ "object.assign": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz",
+ "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==",
+ "dev": true,
+ "requires": {
+ "define-properties": "1.1.2",
+ "function-bind": "1.1.1",
+ "has-symbols": "1.0.0",
+ "object-keys": "1.0.12"
+ }
+ },
+ "object.getownpropertydescriptors": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz",
+ "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=",
+ "requires": {
+ "define-properties": "1.1.2",
+ "es-abstract": "1.12.0"
+ }
+ },
+ "object.omit": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz",
+ "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=",
+ "dev": true,
+ "requires": {
+ "for-own": "0.1.5",
+ "is-extendable": "0.1.1"
+ }
+ },
+ "object.pick": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
+ "dev": true,
+ "requires": {
+ "isobject": "3.0.1"
+ },
+ "dependencies": {
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "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"
+ }
+ },
+ "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": "1.1.0",
+ "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz",
+ "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=",
+ "dev": true
+ },
+ "optimist": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
+ "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
+ "dev": true,
+ "requires": {
+ "minimist": "0.0.8",
+ "wordwrap": "0.0.3"
+ },
+ "dependencies": {
+ "wordwrap": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
+ "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=",
+ "dev": true
+ }
+ }
+ },
+ "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=",
+ "dev": true
+ },
+ "os-locale": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
+ "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
+ "dev": true,
+ "requires": {
+ "lcid": "1.0.0"
+ }
+ },
+ "os-tmpdir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
+ "dev": true
+ },
+ "p-finally": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
+ "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
+ },
+ "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-map": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz",
+ "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==",
+ "dev": true
+ },
+ "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
+ },
+ "pac-proxy-agent": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-1.1.0.tgz",
+ "integrity": "sha512-QBELCWyLYPgE2Gj+4wUEiMscHrQ8nRPBzYItQNOHWavwBt25ohZHQC4qnd5IszdVVrFbLsQ+dPkm6eqdjJAmwQ==",
+ "requires": {
+ "agent-base": "2.1.1",
+ "debug": "2.6.9",
+ "extend": "3.0.1",
+ "get-uri": "2.0.2",
+ "http-proxy-agent": "1.0.0",
+ "https-proxy-agent": "1.0.0",
+ "pac-resolver": "2.0.0",
+ "raw-body": "2.3.3",
+ "socks-proxy-agent": "2.1.1"
+ }
+ },
+ "pac-resolver": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-2.0.0.tgz",
+ "integrity": "sha1-mbiNLxk/ve78HJpSnB8yYKtSd80=",
+ "requires": {
+ "co": "3.0.6",
+ "degenerator": "1.0.4",
+ "ip": "1.0.1",
+ "netmask": "1.0.6",
+ "thunkify": "2.1.2"
+ },
+ "dependencies": {
+ "co": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/co/-/co-3.0.6.tgz",
+ "integrity": "sha1-FEXyJsXrlWE45oyawwFn6n0ua9o="
+ }
+ }
+ },
+ "parse-glob": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz",
+ "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=",
+ "dev": true,
+ "requires": {
+ "glob-base": "0.3.0",
+ "is-dotfile": "1.0.3",
+ "is-extglob": "1.0.0",
+ "is-glob": "2.0.1"
+ }
+ },
+ "parse-headers": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.1.tgz",
+ "integrity": "sha1-aug6eqJanZtwCswoaYzR8e1+lTY=",
+ "requires": {
+ "for-each": "0.3.3",
+ "trim": "0.0.1"
+ }
+ },
+ "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"
+ }
+ },
+ "parse-link-header": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parse-link-header/-/parse-link-header-1.0.1.tgz",
+ "integrity": "sha1-vt/g0hGK64S+deewJUGeyKYRQKc=",
+ "requires": {
+ "xtend": "4.0.1"
+ }
+ },
+ "parse5": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz",
+ "integrity": "sha1-m387DeMr543CQBsXVzzK8Pb1nZQ=",
+ "dev": true
+ },
+ "parseurl": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
+ "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M="
+ },
+ "pascalcase": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
+ "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=",
+ "dev": true
+ },
+ "path-exists": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+ "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+ "dev": true
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
+ },
+ "path-is-inside": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
+ "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=",
+ "dev": true
+ },
+ "path-key": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
+ "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A="
+ },
+ "path-parse": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz",
+ "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=",
+ "dev": true
+ },
+ "path-proxy": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/path-proxy/-/path-proxy-1.0.0.tgz",
+ "integrity": "sha1-GOijaFn8nS8aU7SN7hOFQ8Ag3l4=",
+ "requires": {
+ "inflection": "1.3.8"
+ },
+ "dependencies": {
+ "inflection": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.3.8.tgz",
+ "integrity": "sha1-y9Fg2p91sUw8xjV41POWeEvzAU4="
+ }
+ }
+ },
+ "path-to-regexp": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+ "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
+ },
+ "path-type": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
+ "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "4.1.11",
+ "pify": "2.3.0",
+ "pinkie-promise": "2.0.1"
+ }
+ },
+ "pathval": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz",
+ "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=",
+ "dev": true
+ },
+ "performance-now": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
+ },
+ "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": {
+ "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"
+ },
+ "dependencies": {
+ "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"
+ }
+ },
+ "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"
+ }
+ }
+ }
+ },
+ "pkg-up": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-1.0.0.tgz",
+ "integrity": "sha1-Pgj7RhUlxEIWJKM7n35tCvWwWiY=",
+ "dev": true,
+ "requires": {
+ "find-up": "1.1.2"
+ },
+ "dependencies": {
+ "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"
+ }
+ },
+ "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"
+ }
+ }
+ }
+ },
+ "pluralize": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz",
+ "integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=",
+ "dev": true
+ },
+ "posix-character-classes": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
+ "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=",
+ "dev": true
+ },
+ "prelude-ls": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ="
+ },
+ "preserve": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz",
+ "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=",
+ "dev": true
+ },
+ "pretty-format": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-20.0.3.tgz",
+ "integrity": "sha1-Ag41ClYKH+GpjcO+tsz/s4beixQ=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "2.1.1",
+ "ansi-styles": "3.2.1"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "requires": {
+ "color-convert": "1.9.2"
+ }
+ }
+ }
+ },
+ "private": {
+ "version": "0.1.8",
+ "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz",
+ "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==",
+ "dev": true
+ },
+ "process": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz",
+ "integrity": "sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8="
+ },
+ "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": "1.1.8",
+ "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz",
+ "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=",
+ "dev": true
+ },
+ "propagate": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/propagate/-/propagate-1.0.0.tgz",
+ "integrity": "sha1-AMLa7t2iDofjeCs0Stuhzd1q1wk=",
+ "dev": true
+ },
+ "proxy-addr": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.3.tgz",
+ "integrity": "sha512-jQTChiCJteusULxjBp8+jftSQE5Obdl3k4cnmLA6WXtK6XFuWRnvVL7aCiBqaLPM8c4ph0S4tKna8XvmIwEnXQ==",
+ "requires": {
+ "forwarded": "0.1.2",
+ "ipaddr.js": "1.6.0"
+ }
+ },
+ "proxy-agent": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-2.0.0.tgz",
+ "integrity": "sha1-V+tTR6qAXXTsaByyVknbo5yTNJk=",
+ "requires": {
+ "agent-base": "2.1.1",
+ "debug": "2.6.9",
+ "extend": "3.0.1",
+ "http-proxy-agent": "1.0.0",
+ "https-proxy-agent": "1.0.0",
+ "lru-cache": "2.6.5",
+ "pac-proxy-agent": "1.1.0",
+ "socks-proxy-agent": "2.1.1"
+ },
+ "dependencies": {
+ "lru-cache": {
+ "version": "2.6.5",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.6.5.tgz",
+ "integrity": "sha1-5W1jVBSO3o13B7WNFDIg/QjfD9U="
+ }
+ }
+ },
+ "prr": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
+ "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=",
+ "dev": true
+ },
+ "punycode": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
+ "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0="
+ },
+ "q": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz",
+ "integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4="
+ },
+ "qs": {
+ "version": "6.5.2",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
+ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
+ },
+ "querystring": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
+ "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA="
+ },
+ "randomatic": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.0.0.tgz",
+ "integrity": "sha512-VdxFOIEY3mNO5PtSRkkle/hPJDHvQhK21oa73K4yAc9qmp6N429gAyF1gZMOTMeS0/AYzaV/2Trcef+NaIonSA==",
+ "dev": true,
+ "requires": {
+ "is-number": "4.0.0",
+ "kind-of": "6.0.2",
+ "math-random": "1.0.1"
+ },
+ "dependencies": {
+ "is-number": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
+ "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==",
+ "dev": true
+ },
+ "kind-of": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
+ "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
+ "dev": true
+ }
+ }
+ },
+ "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": {
+ "minimist": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
+ }
+ }
+ },
+ "read-pkg": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
+ "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
+ "dev": true,
+ "requires": {
+ "load-json-file": "1.1.0",
+ "normalize-package-data": "2.4.0",
+ "path-type": "1.1.0"
+ }
+ },
+ "read-pkg-up": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
+ "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
+ "dev": true,
+ "requires": {
+ "find-up": "1.1.2",
+ "read-pkg": "1.1.0"
+ },
+ "dependencies": {
+ "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"
+ }
+ },
+ "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"
+ }
+ }
+ }
+ },
+ "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.2",
+ "string_decoder": "1.1.1",
+ "util-deprecate": "1.0.2"
+ },
+ "dependencies": {
+ "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.2"
+ }
+ }
+ }
+ },
+ "readline2": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz",
+ "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=",
+ "dev": true,
+ "requires": {
+ "code-point-at": "1.1.0",
+ "is-fullwidth-code-point": "1.0.0",
+ "mute-stream": "0.0.5"
+ }
+ },
+ "rechoir": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
+ "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=",
+ "dev": true,
+ "requires": {
+ "resolve": "1.8.1"
+ }
+ },
+ "regenerator-runtime": {
+ "version": "0.11.1",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
+ "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==",
+ "dev": true
+ },
+ "regex-cache": {
+ "version": "0.4.4",
+ "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz",
+ "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==",
+ "dev": true,
+ "requires": {
+ "is-equal-shallow": "0.1.3"
+ }
+ },
+ "regex-not": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
+ "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "3.0.2",
+ "safe-regex": "1.1.0"
+ }
+ },
+ "registry-auth-token": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz",
+ "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==",
+ "requires": {
+ "rc": "1.2.8",
+ "safe-buffer": "5.1.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=",
+ "dev": true
+ },
+ "repeat-element": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz",
+ "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=",
+ "dev": true
+ },
+ "repeat-string": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+ "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
+ "dev": true
+ },
+ "repeating": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
+ "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=",
+ "dev": true,
+ "requires": {
+ "is-finite": "1.0.2"
+ }
+ },
+ "request": {
+ "version": "2.87.0",
+ "resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz",
+ "integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==",
+ "requires": {
+ "aws-sign2": "0.7.0",
+ "aws4": "1.7.0",
+ "caseless": "0.12.0",
+ "combined-stream": "1.0.6",
+ "extend": "3.0.1",
+ "forever-agent": "0.6.1",
+ "form-data": "2.3.2",
+ "har-validator": "5.0.3",
+ "http-signature": "1.2.0",
+ "is-typedarray": "1.0.0",
+ "isstream": "0.1.2",
+ "json-stringify-safe": "5.0.1",
+ "mime-types": "2.1.18",
+ "oauth-sign": "0.8.2",
+ "performance-now": "2.1.0",
+ "qs": "6.5.2",
+ "safe-buffer": "5.1.2",
+ "tough-cookie": "2.3.4",
+ "tunnel-agent": "0.6.0",
+ "uuid": "3.3.2"
+ },
+ "dependencies": {
+ "aws4": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz",
+ "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w=="
+ },
+ "uuid": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
+ "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
+ }
+ }
+ },
+ "request-promise": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.2.tgz",
+ "integrity": "sha1-0epG1lSm7k+O5qT+oQGMIpEZBLQ=",
+ "requires": {
+ "bluebird": "3.5.1",
+ "request-promise-core": "1.1.1",
+ "stealthy-require": "1.1.1",
+ "tough-cookie": "2.3.4"
+ }
+ },
+ "request-promise-core": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz",
+ "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=",
+ "requires": {
+ "lodash": "4.17.10"
+ },
+ "dependencies": {
+ "lodash": {
+ "version": "4.17.10",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
+ "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg=="
+ }
+ }
+ },
+ "require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
+ "dev": true
+ },
+ "require-main-filename": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
+ "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=",
+ "dev": true
+ },
+ "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"
+ }
+ },
+ "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.5"
+ }
+ },
+ "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
+ },
+ "resolve-url": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
+ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
+ "dev": true
+ },
+ "restore-cursor": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz",
+ "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=",
+ "dev": true,
+ "requires": {
+ "exit-hook": "1.1.1",
+ "onetime": "1.1.0"
+ }
+ },
+ "ret": {
+ "version": "0.1.15",
+ "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
+ "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
+ "dev": true
+ },
+ "retry": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/retry/-/retry-0.9.0.tgz",
+ "integrity": "sha1-b2l+UKDk3cjI9/tUeptg3q1DZ40="
+ },
+ "right-align": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz",
+ "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "align-text": "0.1.4"
+ }
+ },
+ "rimraf": {
+ "version": "2.4.5",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz",
+ "integrity": "sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto=",
+ "requires": {
+ "glob": "6.0.4"
+ }
+ },
+ "run-async": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz",
+ "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=",
+ "dev": true,
+ "requires": {
+ "once": "1.4.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": "3.1.2",
+ "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz",
+ "integrity": "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=",
+ "dev": true
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ },
+ "safe-json-stringify": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz",
+ "integrity": "sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==",
+ "optional": true
+ },
+ "safe-regex": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
+ "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
+ "dev": true,
+ "requires": {
+ "ret": "0.1.15"
+ }
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
+ "sane": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/sane/-/sane-1.6.0.tgz",
+ "integrity": "sha1-lhDEUjB6E10pwf3+JUcDQYDEZ3U=",
+ "dev": true,
+ "requires": {
+ "anymatch": "1.3.2",
+ "exec-sh": "0.2.2",
+ "fb-watchman": "1.9.2",
+ "minimatch": "3.0.4",
+ "minimist": "1.2.0",
+ "walker": "1.0.7",
+ "watch": "0.10.0"
+ },
+ "dependencies": {
+ "bser": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/bser/-/bser-1.0.2.tgz",
+ "integrity": "sha1-OBEWlwsqbe6lZG3RXdcnhES1YWk=",
+ "dev": true,
+ "requires": {
+ "node-int64": "0.4.0"
+ }
+ },
+ "fb-watchman": {
+ "version": "1.9.2",
+ "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-1.9.2.tgz",
+ "integrity": "sha1-okz0eCf4LTj7Waaa1wt247auc4M=",
+ "dev": true,
+ "requires": {
+ "bser": "1.0.2"
+ }
+ },
+ "minimist": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+ "dev": true
+ }
+ }
+ },
+ "sax": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz",
+ "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o="
+ },
+ "semver": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz",
+ "integrity": "sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no="
+ },
+ "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=",
+ "dev": true
+ },
+ "set-value": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz",
+ "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "2.0.1",
+ "is-extendable": "0.1.1",
+ "is-plain-object": "2.0.4",
+ "split-string": "3.1.0"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "0.1.1"
+ }
+ }
+ }
+ },
+ "setprototypeof": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
+ "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="
+ },
+ "sha1": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/sha1/-/sha1-1.1.1.tgz",
+ "integrity": "sha1-rdqnqTFo85PxnrKxUJFhjicA+Eg=",
+ "requires": {
+ "charenc": "0.0.2",
+ "crypt": "0.0.2"
+ }
+ },
+ "shebang-command": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+ "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="
+ },
+ "shelljs": {
+ "version": "0.7.8",
+ "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz",
+ "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=",
+ "dev": true,
+ "requires": {
+ "glob": "7.1.2",
+ "interpret": "1.1.0",
+ "rechoir": "0.6.2"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
+ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
+ "dev": true,
+ "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"
+ }
+ }
+ }
+ },
+ "shellwords": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz",
+ "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==",
+ "dev": true
+ },
+ "signal-exit": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
+ },
+ "slash": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
+ "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=",
+ "dev": true
+ },
+ "slice-ansi": {
+ "version": "0.0.4",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz",
+ "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=",
+ "dev": true
+ },
+ "slug": {
+ "version": "0.9.1",
+ "resolved": "https://registry.npmjs.org/slug/-/slug-0.9.1.tgz",
+ "integrity": "sha1-rwj2CKfBFRa2F3iqgA3OhMUYz9o=",
+ "requires": {
+ "unicode": "11.0.1"
+ }
+ },
+ "smart-buffer": {
+ "version": "1.1.15",
+ "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-1.1.15.tgz",
+ "integrity": "sha1-fxFLW2X6s+KjWqd1uxLw0cZJvxY="
+ },
+ "snapdragon": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
+ "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
+ "dev": true,
+ "requires": {
+ "base": "0.11.2",
+ "debug": "2.6.9",
+ "define-property": "0.2.5",
+ "extend-shallow": "2.0.1",
+ "map-cache": "0.2.2",
+ "source-map": "0.5.7",
+ "source-map-resolve": "0.5.2",
+ "use": "3.1.0"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "0.1.6"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "0.1.1"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true
+ }
+ }
+ },
+ "snapdragon-node": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
+ "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
+ "dev": true,
+ "requires": {
+ "define-property": "1.0.0",
+ "isobject": "3.0.1",
+ "snapdragon-util": "3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "1.0.2"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "6.0.2"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "6.0.2"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "1.0.0",
+ "is-data-descriptor": "1.0.0",
+ "kind-of": "6.0.2"
+ }
+ },
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true
+ },
+ "kind-of": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
+ "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
+ "dev": true
+ }
+ }
+ },
+ "snapdragon-util": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
+ "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "3.2.2"
+ }
+ },
+ "sntp": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz",
+ "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==",
+ "requires": {
+ "hoek": "4.2.1"
+ }
+ },
+ "socks": {
+ "version": "1.1.10",
+ "resolved": "https://registry.npmjs.org/socks/-/socks-1.1.10.tgz",
+ "integrity": "sha1-W4t/x8jzQcU+0FbpKbe/Tei6e1o=",
+ "requires": {
+ "ip": "1.1.5",
+ "smart-buffer": "1.1.15"
+ },
+ "dependencies": {
+ "ip": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
+ "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo="
+ }
+ }
+ },
+ "socks-proxy-agent": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-2.1.1.tgz",
+ "integrity": "sha512-sFtmYqdUK5dAMh85H0LEVFUCO7OhJJe1/z2x/Z6mxp3s7/QPf1RkZmpZy+BpuU0bEjcV9npqKjq9Y3kwFUjnxw==",
+ "requires": {
+ "agent-base": "2.1.1",
+ "extend": "3.0.1",
+ "socks": "1.1.10"
+ }
+ },
+ "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
+ },
+ "source-map-resolve": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz",
+ "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==",
+ "dev": true,
+ "requires": {
+ "atob": "2.1.1",
+ "decode-uri-component": "0.2.0",
+ "resolve-url": "0.2.1",
+ "source-map-url": "0.4.0",
+ "urix": "0.1.0"
+ }
+ },
+ "source-map-support": {
+ "version": "0.4.18",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz",
+ "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==",
+ "dev": true,
+ "requires": {
+ "source-map": "0.5.7"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true
+ }
+ }
+ },
+ "source-map-url": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
+ "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
+ "dev": 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==",
+ "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=="
+ },
+ "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==",
+ "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=="
+ },
+ "split-string": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
+ "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "3.0.2"
+ }
+ },
+ "sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
+ },
+ "sshpk": {
+ "version": "1.14.2",
+ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz",
+ "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=",
+ "requires": {
+ "asn1": "0.2.3",
+ "assert-plus": "1.0.0",
+ "bcrypt-pbkdf": "1.0.2",
+ "dashdash": "1.14.1",
+ "ecc-jsbn": "0.1.1",
+ "getpass": "0.1.7",
+ "jsbn": "0.1.1",
+ "safer-buffer": "2.1.2",
+ "tweetnacl": "0.14.5"
+ }
+ },
+ "standard": {
+ "version": "10.0.3",
+ "resolved": "https://registry.npmjs.org/standard/-/standard-10.0.3.tgz",
+ "integrity": "sha512-JURZ+85ExKLQULckDFijdX5WHzN6RC7fgiZNSV4jFQVo+3tPoQGHyBrGekye/yf0aOfb4210EM5qPNlc2cRh4w==",
+ "dev": true,
+ "requires": {
+ "eslint": "3.19.0",
+ "eslint-config-standard": "10.2.1",
+ "eslint-config-standard-jsx": "4.0.2",
+ "eslint-plugin-import": "2.2.0",
+ "eslint-plugin-node": "4.2.3",
+ "eslint-plugin-promise": "3.5.0",
+ "eslint-plugin-react": "6.10.3",
+ "eslint-plugin-standard": "3.0.1",
+ "standard-engine": "7.0.0"
+ }
+ },
+ "standard-engine": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-7.0.0.tgz",
+ "integrity": "sha1-67d7nI/CyBZf+jU72Rug3/Qa9pA=",
+ "dev": true,
+ "requires": {
+ "deglob": "2.1.1",
+ "get-stdin": "5.0.1",
+ "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-extend": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
+ "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=",
+ "dev": true,
+ "requires": {
+ "define-property": "0.2.5",
+ "object-copy": "0.1.0"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "0.1.6"
+ }
+ }
+ }
+ },
+ "statuses": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+ "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
+ },
+ "stealthy-require": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
+ "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks="
+ },
+ "string-length": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/string-length/-/string-length-1.0.1.tgz",
+ "integrity": "sha1-VpcPscOFWOnnC3KL894mmsRa36w=",
+ "dev": true,
+ "requires": {
+ "strip-ansi": "3.0.1"
+ }
+ },
+ "string-width": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+ "dev": true,
+ "requires": {
+ "code-point-at": "1.1.0",
+ "is-fullwidth-code-point": "1.0.0",
+ "strip-ansi": "3.0.1"
+ }
+ },
+ "string_decoder": {
+ "version": "0.10.31",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
+ },
+ "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"
+ }
+ },
+ "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-eof": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
+ "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8="
+ },
+ "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="
+ },
+ "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
+ },
+ "symbol-tree": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz",
+ "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=",
+ "dev": true
+ },
+ "table": {
+ "version": "3.8.3",
+ "resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz",
+ "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=",
+ "dev": true,
+ "requires": {
+ "ajv": "4.11.8",
+ "ajv-keywords": "1.5.1",
+ "chalk": "1.1.3",
+ "lodash": "4.17.10",
+ "slice-ansi": "0.0.4",
+ "string-width": "2.1.1"
+ },
+ "dependencies": {
+ "ajv": {
+ "version": "4.11.8",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz",
+ "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=",
+ "dev": true,
+ "requires": {
+ "co": "4.6.0",
+ "json-stable-stringify": "1.0.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
+ },
+ "is-fullwidth-code-point": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+ "dev": true
+ },
+ "lodash": {
+ "version": "4.17.10",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
+ "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
+ "dev": true
+ },
+ "string-width": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+ "dev": true,
+ "requires": {
+ "is-fullwidth-code-point": "2.0.0",
+ "strip-ansi": "4.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "3.0.0"
+ }
+ }
+ }
+ },
+ "test-exclude": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.2.1.tgz",
+ "integrity": "sha512-qpqlP/8Zl+sosLxBcVKl9vYy26T9NPalxSzzCP/OY6K7j938ui2oKgo+kRZYfxAeIpLqpbVnsHq1tyV70E4lWQ==",
+ "dev": true,
+ "requires": {
+ "arrify": "1.0.1",
+ "micromatch": "3.1.10",
+ "object-assign": "4.1.1",
+ "read-pkg-up": "1.0.1",
+ "require-main-filename": "1.0.1"
+ },
+ "dependencies": {
+ "arr-diff": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+ "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
+ "dev": true
+ },
+ "array-unique": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
+ "dev": true
+ },
+ "braces": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+ "dev": true,
+ "requires": {
+ "arr-flatten": "1.1.0",
+ "array-unique": "0.3.2",
+ "extend-shallow": "2.0.1",
+ "fill-range": "4.0.0",
+ "isobject": "3.0.1",
+ "repeat-element": "1.1.2",
+ "snapdragon": "0.8.2",
+ "snapdragon-node": "2.1.1",
+ "split-string": "3.1.0",
+ "to-regex": "3.0.2"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "0.1.1"
+ }
+ }
+ }
+ },
+ "expand-brackets": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
+ "dev": true,
+ "requires": {
+ "debug": "2.6.9",
+ "define-property": "0.2.5",
+ "extend-shallow": "2.0.1",
+ "posix-character-classes": "0.1.1",
+ "regex-not": "1.0.2",
+ "snapdragon": "0.8.2",
+ "to-regex": "3.0.2"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "0.1.6"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "0.1.1"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+ "dev": true,
+ "requires": {
+ "kind-of": "3.2.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "1.1.6"
+ }
+ }
+ }
+ },
+ "is-data-descriptor": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+ "dev": true,
+ "requires": {
+ "kind-of": "3.2.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "1.1.6"
+ }
+ }
+ }
+ },
+ "is-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "0.1.6",
+ "is-data-descriptor": "0.1.4",
+ "kind-of": "5.1.0"
+ }
+ },
+ "kind-of": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+ "dev": true
+ }
+ }
+ },
+ "extglob": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+ "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+ "dev": true,
+ "requires": {
+ "array-unique": "0.3.2",
+ "define-property": "1.0.0",
+ "expand-brackets": "2.1.4",
+ "extend-shallow": "2.0.1",
+ "fragment-cache": "0.2.1",
+ "regex-not": "1.0.2",
+ "snapdragon": "0.8.2",
+ "to-regex": "3.0.2"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "dev": true,
+ "requires": {
+ "is-descriptor": "1.0.2"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "0.1.1"
+ }
+ }
+ }
+ },
+ "fill-range": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "2.0.1",
+ "is-number": "3.0.0",
+ "repeat-string": "1.6.1",
+ "to-regex-range": "2.1.1"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "0.1.1"
+ }
+ }
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "6.0.2"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "requires": {
+ "kind-of": "6.0.2"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "requires": {
+ "is-accessor-descriptor": "1.0.0",
+ "is-data-descriptor": "1.0.0",
+ "kind-of": "6.0.2"
+ }
+ },
+ "is-number": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+ "dev": true,
+ "requires": {
+ "kind-of": "3.2.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "requires": {
+ "is-buffer": "1.1.6"
+ }
+ }
+ }
+ },
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true
+ },
+ "kind-of": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
+ "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
+ "dev": true
+ },
+ "micromatch": {
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+ "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+ "dev": true,
+ "requires": {
+ "arr-diff": "4.0.0",
+ "array-unique": "0.3.2",
+ "braces": "2.3.2",
+ "define-property": "2.0.2",
+ "extend-shallow": "3.0.2",
+ "extglob": "2.0.4",
+ "fragment-cache": "0.2.1",
+ "kind-of": "6.0.2",
+ "nanomatch": "1.2.13",
+ "object.pick": "1.3.0",
+ "regex-not": "1.0.2",
+ "snapdragon": "0.8.2",
+ "to-regex": "3.0.2"
+ }
+ }
+ }
+ },
+ "text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
+ "dev": true
+ },
+ "throat": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/throat/-/throat-3.2.0.tgz",
+ "integrity": "sha512-/EY8VpvlqJ+sFtLPeOgc8Pl7kQVOWv0woD87KTXVHPIAE842FGT+rokxIhe8xIUP1cfgrkt0as0vDLjDiMtr8w==",
+ "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
+ },
+ "thunkify": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/thunkify/-/thunkify-2.1.2.tgz",
+ "integrity": "sha1-+qDp0jDFGsyVyhOjYawFyn4EVT0="
+ },
+ "tmpl": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz",
+ "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=",
+ "dev": true
+ },
+ "to-fast-properties": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz",
+ "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=",
+ "dev": true
+ },
+ "to-object-path": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
+ "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=",
+ "dev": true,
+ "requires": {
+ "kind-of": "3.2.2"
+ }
+ },
+ "to-regex": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
+ "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
+ "dev": true,
+ "requires": {
+ "define-property": "2.0.2",
+ "extend-shallow": "3.0.2",
+ "regex-not": "1.0.2",
+ "safe-regex": "1.1.0"
+ }
+ },
+ "to-regex-range": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+ "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
+ "dev": true,
+ "requires": {
+ "is-number": "3.0.0",
+ "repeat-string": "1.6.1"
+ },
+ "dependencies": {
+ "is-number": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+ "dev": true,
+ "requires": {
+ "kind-of": "3.2.2"
+ }
+ }
+ }
+ },
+ "tough-cookie": {
+ "version": "2.3.4",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz",
+ "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==",
+ "requires": {
+ "punycode": "1.4.1"
+ },
+ "dependencies": {
+ "punycode": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+ "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
+ }
+ }
+ },
+ "tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=",
+ "dev": true
+ },
+ "trim": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz",
+ "integrity": "sha1-WFhUf2spB1fulczMZm+1AITEYN0="
+ },
+ "trim-right": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",
+ "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=",
+ "dev": true
+ },
+ "tsscmp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.5.tgz",
+ "integrity": "sha1-fcSjOvcVgatDN9qR2FylQn69mpc="
+ },
+ "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.2"
+ }
+ },
+ "tweetnacl": {
+ "version": "0.14.5",
+ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
+ "optional": true
+ },
+ "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.18"
+ }
+ },
+ "typedarray": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
+ "dev": true
+ },
+ "uglify-js": {
+ "version": "2.8.29",
+ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz",
+ "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "source-map": "0.5.7",
+ "uglify-to-browserify": "1.0.2",
+ "yargs": "3.10.0"
+ },
+ "dependencies": {
+ "camelcase": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz",
+ "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=",
+ "dev": true,
+ "optional": true
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true,
+ "optional": true
+ },
+ "yargs": {
+ "version": "3.10.0",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
+ "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "camelcase": "1.2.1",
+ "cliui": "2.1.0",
+ "decamelize": "1.2.0",
+ "window-size": "0.1.0"
+ }
+ }
+ }
+ },
+ "uglify-to-browserify": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz",
+ "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=",
+ "dev": true,
+ "optional": true
+ },
+ "underscore": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.5.2.tgz",
+ "integrity": "sha1-EzXF5PXm0zu7SwBrqMhqAPVW3gg="
+ },
+ "unicode": {
+ "version": "11.0.1",
+ "resolved": "https://registry.npmjs.org/unicode/-/unicode-11.0.1.tgz",
+ "integrity": "sha512-+cHtykLb+eF1yrSLWTwcYBrqJkTfX7Quoyg7Juhe6uylF43ZbMdxMuSHNYlnyLT8T7POAvavgBthzUF9AIaQvQ=="
+ },
+ "union-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
+ "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=",
+ "dev": true,
+ "requires": {
+ "arr-union": "3.1.0",
+ "get-value": "2.0.6",
+ "is-extendable": "0.1.1",
+ "set-value": "0.4.3"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "requires": {
+ "is-extendable": "0.1.1"
+ }
+ },
+ "set-value": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz",
+ "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=",
+ "dev": true,
+ "requires": {
+ "extend-shallow": "2.0.1",
+ "is-extendable": "0.1.1",
+ "is-plain-object": "2.0.4",
+ "to-object-path": "0.3.0"
+ }
+ }
+ }
+ },
+ "uniq": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz",
+ "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=",
+ "dev": true
+ },
+ "universal-analytics": {
+ "version": "0.4.17",
+ "resolved": "https://registry.npmjs.org/universal-analytics/-/universal-analytics-0.4.17.tgz",
+ "integrity": "sha512-N2JFymxv4q2N5Wmftc5JCcM5t1tp+sc1kqeDRhDL4XLY5X6PBZ0kav2wvVUZJJMvmSq3WXrmzDu062p+cSFYfQ==",
+ "requires": {
+ "debug": "3.1.0",
+ "request": "2.86.0",
+ "uuid": "3.3.2"
+ },
+ "dependencies": {
+ "aws4": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz",
+ "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w=="
+ },
+ "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"
+ }
+ },
+ "request": {
+ "version": "2.86.0",
+ "resolved": "https://registry.npmjs.org/request/-/request-2.86.0.tgz",
+ "integrity": "sha512-BQZih67o9r+Ys94tcIW4S7Uu8pthjrQVxhsZ/weOwHbDfACxvIyvnAbzFQxjy1jMtvFSzv5zf4my6cZsJBbVzw==",
+ "requires": {
+ "aws-sign2": "0.7.0",
+ "aws4": "1.7.0",
+ "caseless": "0.12.0",
+ "combined-stream": "1.0.6",
+ "extend": "3.0.1",
+ "forever-agent": "0.6.1",
+ "form-data": "2.3.2",
+ "har-validator": "5.0.3",
+ "hawk": "6.0.2",
+ "http-signature": "1.2.0",
+ "is-typedarray": "1.0.0",
+ "isstream": "0.1.2",
+ "json-stringify-safe": "5.0.1",
+ "mime-types": "2.1.18",
+ "oauth-sign": "0.8.2",
+ "performance-now": "2.1.0",
+ "qs": "6.5.2",
+ "safe-buffer": "5.1.2",
+ "tough-cookie": "2.3.4",
+ "tunnel-agent": "0.6.0",
+ "uuid": "3.3.2"
+ }
+ },
+ "uuid": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
+ "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
+ }
+ }
+ },
+ "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="
+ },
+ "unset-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
+ "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=",
+ "dev": true,
+ "requires": {
+ "has-value": "0.3.1",
+ "isobject": "3.0.1"
+ },
+ "dependencies": {
+ "has-value": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
+ "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
+ "dev": true,
+ "requires": {
+ "get-value": "2.0.6",
+ "has-values": "0.1.4",
+ "isobject": "2.1.0"
+ },
+ "dependencies": {
+ "isobject": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+ "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+ "dev": true,
+ "requires": {
+ "isarray": "1.0.0"
+ }
+ }
+ }
+ },
+ "has-values": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
+ "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=",
+ "dev": true
+ },
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true
+ }
+ }
+ },
+ "urix": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
+ "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
+ "dev": true
+ },
+ "url": {
+ "version": "0.10.3",
+ "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz",
+ "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=",
+ "requires": {
+ "punycode": "1.3.2",
+ "querystring": "0.2.0"
+ }
+ },
+ "url-join": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.0.tgz",
+ "integrity": "sha1-TTNA6AfTdzvamZH4MFrNzCpmXSo="
+ },
+ "url-template": {
+ "version": "2.0.8",
+ "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz",
+ "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE="
+ },
+ "use": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/use/-/use-3.1.0.tgz",
+ "integrity": "sha512-6UJEQM/L+mzC3ZJNM56Q4DFGLX/evKGRg15UJHGB9X5j5Z3AFbgZvjUh2yq/UJUY4U5dh7Fal++XbNg1uzpRAw==",
+ "dev": true,
+ "requires": {
+ "kind-of": "6.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
+ "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
+ "dev": true
+ }
+ }
+ },
+ "user-home": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz",
+ "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=",
+ "dev": true,
+ "requires": {
+ "os-homedir": "1.0.2"
+ }
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+ },
+ "util.promisify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz",
+ "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==",
+ "requires": {
+ "define-properties": "1.1.2",
+ "object.getownpropertydescriptors": "2.0.3"
+ }
+ },
+ "utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
+ },
+ "uuid": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
+ "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
+ },
+ "validate-npm-package-license": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz",
+ "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==",
+ "requires": {
+ "spdx-correct": "3.0.0",
+ "spdx-expression-parse": "3.0.0"
+ }
+ },
+ "validator": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/validator/-/validator-7.2.0.tgz",
+ "integrity": "sha512-c8NGTUYeBEcUIGeMppmNVKHE7wwfm3mYbNZxV+c5mlv9fDHI7Ad3p07qfNrn/CvpdkK2k61fOLRO2sTEhgQXmg=="
+ },
+ "vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
+ },
+ "verror": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+ "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+ "requires": {
+ "assert-plus": "1.0.0",
+ "core-util-is": "1.0.2",
+ "extsprintf": "1.3.0"
+ }
+ },
+ "walker": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz",
+ "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=",
+ "dev": true,
+ "requires": {
+ "makeerror": "1.0.11"
+ }
+ },
+ "watch": {
+ "version": "0.10.0",
+ "resolved": "https://registry.npmjs.org/watch/-/watch-0.10.0.tgz",
+ "integrity": "sha1-d3mLLaD5kQ1ZXxrOWwwiWFIfIdw=",
+ "dev": true
+ },
+ "webidl-conversions": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
+ "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==",
+ "dev": true
+ },
+ "whatwg-encoding": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.3.tgz",
+ "integrity": "sha512-jLBwwKUhi8WtBfsMQlL4bUUcT8sMkAtQinscJAe/M4KHCkHuUJAF6vuB0tueNIw4c8ziO6AkRmgY+jL3a0iiPw==",
+ "dev": true,
+ "requires": {
+ "iconv-lite": "0.4.19"
+ },
+ "dependencies": {
+ "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==",
+ "dev": true
+ }
+ }
+ },
+ "whatwg-url": {
+ "version": "4.8.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-4.8.0.tgz",
+ "integrity": "sha1-0pgaqRSMHgCkHFphMRZqtGg7vMA=",
+ "dev": true,
+ "requires": {
+ "tr46": "0.0.3",
+ "webidl-conversions": "3.0.1"
+ },
+ "dependencies": {
+ "webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=",
+ "dev": true
+ }
+ }
+ },
+ "which": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+ "requires": {
+ "isexe": "2.0.0"
+ }
+ },
+ "which-module": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz",
+ "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=",
+ "dev": true
+ },
+ "window-size": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",
+ "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=",
+ "dev": true,
+ "optional": true
+ },
+ "wordwrap": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+ "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus="
+ },
+ "worker-farm": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.6.0.tgz",
+ "integrity": "sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ==",
+ "dev": true,
+ "requires": {
+ "errno": "0.1.7"
+ }
+ },
+ "wrap-ansi": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
+ "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
+ "dev": true,
+ "requires": {
+ "string-width": "1.0.2",
+ "strip-ansi": "3.0.1"
+ }
+ },
+ "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"
+ }
+ },
+ "xhr": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.5.0.tgz",
+ "integrity": "sha512-4nlO/14t3BNUZRXIXfXe+3N6w3s1KoxcJUUURctd64BLRe67E4gRwp4PjywtDY72fXpZ1y6Ch0VZQRY/gMPzzQ==",
+ "requires": {
+ "global": "4.3.2",
+ "is-function": "1.0.1",
+ "parse-headers": "2.0.1",
+ "xtend": "4.0.1"
+ }
+ },
+ "xml-name-validator": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz",
+ "integrity": "sha1-TYuPHszTQZqjYgYb7O9RXh5VljU=",
+ "dev": true
+ },
+ "xml-splitter": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/xml-splitter/-/xml-splitter-1.2.1.tgz",
+ "integrity": "sha1-s/0oyIBj5RCrajXtCUMpJAnEyBI=",
+ "dev": true,
+ "requires": {
+ "clone": "0.1.19",
+ "sax": "0.5.8"
+ },
+ "dependencies": {
+ "sax": {
+ "version": "0.5.8",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-0.5.8.tgz",
+ "integrity": "sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE=",
+ "dev": true
+ }
+ }
+ },
+ "xml2js": {
+ "version": "0.4.17",
+ "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.17.tgz",
+ "integrity": "sha1-F76T6q4/O3eTWceVtBlwWogX6Gg=",
+ "requires": {
+ "sax": "1.2.1",
+ "xmlbuilder": "4.2.1"
+ }
+ },
+ "xmlbuilder": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-4.2.1.tgz",
+ "integrity": "sha1-qlijBBoGb5DqoWwvU4n/GfP0YaU=",
+ "requires": {
+ "lodash": "4.17.10"
+ },
+ "dependencies": {
+ "lodash": {
+ "version": "4.17.10",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
+ "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg=="
+ }
+ }
+ },
+ "xregexp": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz",
+ "integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM="
+ },
+ "xtend": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
+ "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68="
+ },
+ "y18n": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
+ "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=",
+ "dev": true
+ },
+ "yargs": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz",
+ "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=",
+ "dev": true,
+ "requires": {
+ "camelcase": "3.0.0",
+ "cliui": "3.2.0",
+ "decamelize": "1.2.0",
+ "get-caller-file": "1.0.3",
+ "os-locale": "1.4.0",
+ "read-pkg-up": "1.0.1",
+ "require-directory": "2.1.1",
+ "require-main-filename": "1.0.1",
+ "set-blocking": "2.0.0",
+ "string-width": "1.0.2",
+ "which-module": "1.0.0",
+ "y18n": "3.2.1",
+ "yargs-parser": "5.0.0"
+ },
+ "dependencies": {
+ "camelcase": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
+ "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",
+ "dev": true
+ },
+ "cliui": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
+ "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
+ "dev": true,
+ "requires": {
+ "string-width": "1.0.2",
+ "strip-ansi": "3.0.1",
+ "wrap-ansi": "2.1.0"
+ }
+ },
+ "yargs-parser": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz",
+ "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=",
+ "dev": true,
+ "requires": {
+ "camelcase": "3.0.0"
+ }
+ }
+ }
+ },
+ "yargs-parser": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.0.0.tgz",
+ "integrity": "sha512-+DHejWujTVYeMHLff8U96rLc4uE4Emncoftvn5AjhB1Jw1pWxLzgBUT/WYbPrHmy6YPEBTZQx5myHhVcuuu64g==",
+ "requires": {
+ "camelcase": "4.1.0"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
index 266c78af..2e7910fc 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "staticman",
- "version": "2.0.0",
+ "version": "3.0.0",
"description": "Static sites with superpowers",
"main": "index.js",
"scripts": {
@@ -9,6 +9,9 @@
"test": "standard && jest && node test/utils/coverage.js",
"test-dev": "TEST_DEV=true jest --watch"
},
+ "engines": {
+ "node": ">=8.11.3"
+ },
"repository": {
"type": "git",
"url": "git+https://github.com/eduardoboucas/staticman.git"
@@ -21,6 +24,7 @@
"homepage": "https://github.com/eduardoboucas/staticman#readme",
"dependencies": {
"@dadi/logger": "^1.3.0",
+ "@octokit/rest": "^15.9.4",
"akismet": "^1.0.0",
"body-parser": "^1.17.x",
"bunyan-slack": "0.0.10",
@@ -29,24 +33,25 @@
"express-brute": "^0.6.0",
"express-github-webhook": "^1.0.5",
"express-recaptcha": "^2.1.0",
- "github": "^3.0.0",
+ "gitlab": "^3.5.1",
"js-yaml": "^3.10.0",
"mailgun-js": "^0.7.13",
"markdown-table": "^1.0.0",
"md5": "^2.1.0",
"moment": "^2.18.1",
"node-rsa": "^0.4.2",
- "node-uuid": "^1.4.7",
"object-path": "^0.11.1",
- "request-promise-native": "^1.0.4",
+ "request-promise": "^4.2.2",
"sha1": "^1.1.1",
"slug": "^0.9.1",
- "universal-analytics": "^0.4.2"
+ "universal-analytics": "^0.4.2",
+ "uuid": "^3.3.2"
},
"devDependencies": {
"front-matter": "^2.1.2",
"istanbul-cobertura-badger": "^1.3.0",
"jest": "^20.0.4",
+ "lodash": "^4.17.10",
"nock": "^9.0.13",
"standard": "^10.0.2"
},
@@ -66,6 +71,9 @@
]
},
"standard": {
+ "env": [
+ "jest"
+ ],
"ignore": [
"test/**/*"
]
diff --git a/server.js b/server.js
index 98f77274..34838e60 100644
--- a/server.js
+++ b/server.js
@@ -11,7 +11,7 @@ const StaticmanAPI = function () {
this.controllers = {
connect: require('./controllers/connect'),
encrypt: require('./controllers/encrypt'),
- githubAuth: require('./controllers/githubAuth'),
+ auth: require('./controllers/auth'),
handlePR: require('./controllers/handlePR'),
home: require('./controllers/home'),
process: require('./controllers/process')
@@ -54,6 +54,14 @@ StaticmanAPI.prototype.initialiseRoutes = function () {
this.controllers.connect
)
+ this.server.get(
+ '/v:version/connect/:service/:username/:repository',
+ this.bruteforce.prevent,
+ this.requireApiVersion([3]),
+ this.requireService(['github']),
+ this.controllers.connect
+ )
+
// Route: process
this.server.post(
'/v:version/entry/:username/:repository/:branch',
@@ -71,20 +79,30 @@ StaticmanAPI.prototype.initialiseRoutes = function () {
this.controllers.process
)
+ this.server.post(
+ '/v:version/entry/:service/:username/:repository/:branch/:property',
+ this.bruteforce.prevent,
+ this.requireApiVersion([3]),
+ this.requireService(['github', 'gitlab']),
+ this.requireParams(['fields']),
+ this.controllers.process
+ )
+
// Route: encrypt
this.server.get(
'/v:version/encrypt/:text',
this.bruteforce.prevent,
- this.requireApiVersion([2]),
+ this.requireApiVersion([2, 3]),
this.controllers.encrypt
)
- // Route: GitHub auth
+ // Route: oauth
this.server.get(
- '/v:version/auth/github/:username/:repository/:branch/:property',
+ '/v:version/auth/:service/:username/:repository/:branch/:property',
this.bruteforce.prevent,
- this.requireApiVersion([2]),
- this.controllers.githubAuth
+ this.requireApiVersion([2, 3]),
+ this.requireService(['github', 'gitlab']),
+ this.controllers.auth
)
// Route: root
@@ -111,7 +129,7 @@ StaticmanAPI.prototype.requireApiVersion = function (versions) {
})
if (!versionMatch) {
- return res.status(500).send({
+ return res.status(400).send({
success: false,
errorCode: 'INVALID_VERSION'
})
@@ -121,6 +139,21 @@ StaticmanAPI.prototype.requireApiVersion = function (versions) {
}
}
+StaticmanAPI.prototype.requireService = function (services) {
+ return (req, res, next) => {
+ const serviceMatch = services.some(service => service === req.params.service)
+
+ if (!serviceMatch) {
+ return res.status(400).send({
+ success: false,
+ errorCode: 'INVALID_SERVICE'
+ })
+ }
+
+ return next()
+ }
+}
+
StaticmanAPI.prototype.requireParams = function (params) {
return function (req, res, next) {
let missingParams = []
diff --git a/siteConfig.js b/siteConfig.js
index f5741891..63a6da30 100644
--- a/siteConfig.js
+++ b/siteConfig.js
@@ -1,7 +1,6 @@
'use strict'
const convict = require('convict')
-const logger = require('./lib/Logger')
const schema = {
allowedFields: {
@@ -42,6 +41,13 @@ const schema = {
default: 'comment'
}
},
+ auth: {
+ required: {
+ doc: 'Whether authentication is required for an entry to be accepted.',
+ format: Boolean,
+ default: false
+ }
+ },
branch: {
doc: 'Name of the branch being used within the GitHub repository.',
format: String,
@@ -75,23 +81,43 @@ const schema = {
},
githubAuth: {
clientId: {
- doc: 'The client ID to the GitHub Application used for GitHub authentication.',
+ doc: 'The client ID to the GitHub Application used for GitHub OAuth.',
format: 'EncryptedString',
- default: null,
- env: 'GITHUB_AUTH_CLIENT_ID'
+ default: null
},
clientSecret: {
- doc: 'The client secret to the GitHub Application used for GitHub authentication.',
+ doc: 'The client secret to the GitHub Application used for GitHub OAuth.',
format: 'EncryptedString',
- default: null,
- env: 'GITHUB_AUTH_CLIENT_SECRET'
+ default: null
+ },
+ redirectUri: {
+ doc: 'The URL to redirect to after authenticating with GitHub.',
+ format: String,
+ default: ''
},
required: {
- doc: 'Whether GitHub Auth is required for an entry to be accepted.',
+ doc: 'Whether GitHub Auth is required for an entry to be accepted. This is only included for backwards compatibility with the v2 API. For the v3 API, please use the `auth.required` option instead.',
format: Boolean,
default: false
}
},
+ gitlabAuth: {
+ clientId: {
+ doc: 'The client ID to the GitLab Application used for GitLab OAuth.',
+ format: 'EncryptedString',
+ default: null
+ },
+ clientSecret: {
+ doc: 'The client secret to the GitLab Application used for GitLab OAuth.',
+ format: 'EncryptedString',
+ default: null
+ },
+ redirectUri: {
+ doc: 'The URL to redirect to after authenticating with GitLab.',
+ format: String,
+ default: ''
+ }
+ },
moderation: {
doc: 'When set to `true`, a pull request with the data files will be created to allow site administrators to approve or reject an entry. Otherwise, entries will be pushed to `branch` immediately.',
format: Boolean,
@@ -175,17 +201,6 @@ module.exports = (data, rsa) => {
config.load(data)
config.validate()
- // After loading config, check what `generatedFields` looks like - #176
- logger.info(
- JSON.stringify({
- stage: 'config.load',
- generatedFields: config.get('generatedFields')
- }),
- null,
- 2
- )
-
-
return config
} catch (e) {
throw e
diff --git a/test/acceptance/api.test.js b/test/acceptance/api.test.js
index 8a98099f..ad02e857 100644
--- a/test/acceptance/api.test.js
+++ b/test/acceptance/api.test.js
@@ -7,6 +7,8 @@ const request = helpers.wrappedRequest
const sampleData = require('./../helpers/sampleData')
const StaticmanAPI = require('./../../server')
+const btoa = contents => Buffer.from(contents).toString('base64')
+
let server
beforeAll(done => {
@@ -68,7 +70,7 @@ describe('Connect endpoint', () => {
expect(reqListInvititations.isDone()).toBe(true)
expect(reqAcceptInvitation.isDone()).toBe(false)
expect(err.response.body).toBe('Invitation not found')
- expect(err.statusCode).toBe(404)
+ expect(err.statusCode).toBe(404)
})
})
})
@@ -82,8 +84,12 @@ describe.only('Entry endpoint', () => {
const mockConfig = sampleData.config1
.replace('@reCaptchaSecret@', reCaptchaSecret)
- const mockGetConfig = nock(/api\.github\.com/)
- .get(`/repos/${data.username}/${data.repository}/contents/${data.path}?ref=${data.branch}&access_token=${githubToken}`)
+ nock(/api\.github\.com/, {
+ reqHeaders: {
+ Authorization: `token ${githubToken}`
+ }
+ })
+ .get(`/repos/${data.username}/${data.repository}/contents/${data.path}?ref=${data.branch}`)
.reply(200, {
type: 'file',
encoding: 'base64',
@@ -117,7 +123,7 @@ describe.only('Entry endpoint', () => {
headers: {
'content-type': 'application/x-www-form-urlencoded'
}
- }).catch(response => {
+ }).catch((response) => {
const error = JSON.parse(response.error)
expect(error.success).toBe(false)
@@ -134,8 +140,12 @@ describe.only('Entry endpoint', () => {
const mockConfig = sampleData.config1
.replace('@reCaptchaSecret@', helpers.encrypt(reCaptchaSecret))
- const mockGetConfig = nock(/api\.github\.com/)
- .get(`/repos/${data.username}/${data.repository}/contents/${data.path}?ref=${data.branch}&access_token=${githubToken}`)
+ nock(/api\.github\.com/, {
+ reqHeaders: {
+ Authorization: `token ${githubToken}`
+ }
+ })
+ .get(`/repos/${data.username}/${data.repository}/contents/${data.path}?ref=${data.branch}`)
.reply(200, {
type: 'file',
encoding: 'base64',
@@ -183,8 +193,12 @@ describe.only('Entry endpoint', () => {
path: 'staticman.yml'
})
- const mockGetConfig = nock(/api\.github\.com/)
- .get(`/repos/${data.username}/${data.repository}/contents/${data.path}?ref=${data.branch}&access_token=${githubToken}`)
+ const mockGetConfig = nock(/api\.github\.com/, {
+ reqHeaders: {
+ Authorization: `token ${githubToken}`
+ }
+ })
+ .get(`/repos/${data.username}/${data.repository}/contents/${data.path}?ref=${data.branch}`)
.reply(200, {
type: 'file',
encoding: 'base64',
diff --git a/test/helpers/index.js b/test/helpers/index.js
index 8449f1ab..f4b56786 100644
--- a/test/helpers/index.js
+++ b/test/helpers/index.js
@@ -1,9 +1,10 @@
const CatchAllApiMock = require('./CatchAllApiMock')
+const cloneDeep = require('lodash/cloneDeep')
const config = require('./../../config')
const objectPath = require('object-path')
const markdownTable = require('markdown-table')
const NodeRSA = require('node-rsa')
-const request = require('request-promise-native')
+const request = require('request-promise')
const sampleData = require('./sampleData')
const SiteConfig = require('./../../siteConfig')
const yaml = require('js-yaml')
@@ -30,10 +31,13 @@ const parameters = {
property: 'comments',
repository: 'foobar',
username: 'johndoe',
- version: 'v2'
+ version: '3'
}
-module.exports.baseUrl =
+const parsedConfig = yaml.safeLoad(sampleData.config1, 'utf8')
+const siteConfig = SiteConfig(parsedConfig.comments, rsa)
+
+module.exports.baseUrl = ''
module.exports.decrypt = text => {
return rsa.decrypt(text, 'utf8')
@@ -48,19 +52,10 @@ module.exports.getCatchAllApiMock = callback => {
}
module.exports.getConfig = () => {
- const parsedConfig = yaml.safeLoad(sampleData.config1, 'utf8')
- const reCaptchaSecret = rsa.encrypt('This is a nice little secret', 'base64')
-
- // For some reason, node-rsa is failing the tests if the secret is encrypted
- // beforehand. As a workaround, we generate a new secret when we retrieve the
- // config object. We can still obtain its raw value with `getRaw().
- parsedConfig.comments.reCaptcha.secret = reCaptchaSecret
-
- const siteConfig = SiteConfig(parsedConfig.comments, rsa)
-
- siteConfig.getRaw = key => objectPath.get(parsedConfig, `comments.${key}`)
+ const config = cloneDeep(siteConfig)
+ config.getRaw = key => objectPath.get(parsedConfig, `comments.${key}`)
- return siteConfig
+ return config
}
module.exports.getConfigObject = () => {
@@ -91,7 +86,7 @@ module.exports.getMockRequest = () => {
headers: {
'x-forwarded-for': '123.456.78.9'
},
- params: parameters
+ params: Object.assign({}, parameters)
}
}
@@ -109,7 +104,7 @@ module.exports.getMockResponse = () => {
}
}
-module.exports.getParameters = () => parameters
+module.exports.getParameters = () => Object.assign({}, parameters)
module.exports.getParsedConfig = () => {
return yaml.safeLoad(sampleData.config1, 'utf8')
diff --git a/test/helpers/sampleData.js b/test/helpers/sampleData.js
index 2523b9cb..35aab01f 100644
--- a/test/helpers/sampleData.js
+++ b/test/helpers/sampleData.js
@@ -13,6 +13,9 @@ comments:
# listed will be accepted.
allowedOrigins: ["localhost", "eduardoboucas.com"]
+ auth:
+ required: false
+
# (*) REQUIRED
#
# Name of the branch being used. Must match the one sent in the URL of the
@@ -66,11 +69,17 @@ comments:
reCaptcha:
enabled: true
siteKey: "123456789"
- secret: "@reCaptchaSecret@"
+ secret: "DTK5WxH6117ez/piZpmkvyAtieYWlu60+SApt9hFRMfNs4WBC0mvRtsW9Jmhz4fJYDcIX18wKHV6KYh3PXYN3d/pozCskwwkuJq0qHJQHrTycjgrGS5mti4QgrMYP0rq2p5hMTgPL/UK0lwkxuRRcxnvxqRlkZHMv6o/CUkZOVnkJ8lGqWa8uJAEIv/9rd6Bm12+F1ezLJZ+LogebHEDpyJWz9kwum9bFBQqZbun+43rxzJBQmAGQEWZ4hshY2aLSAyBpr/pjSDUwRGtwoBh8Ee1qKNuMzY0XVUOn+dcHrkpQotmKL4TMFQN4slo/lVKmfXW5N6t9vdP/lGmIiVXdw=="
githubAuth:
clientId: "L4M3LIshioHbe3j+vMxEbGlCGDhyIcQF2jhmVOUp8DqC+RqNgvZSQp7qYYmjPPoyjFCVOsu5aHwcD1FkMlEaxLTqYOYUeq49Wb6uxePTBycmW14JI6fiM/PYTm6nqKH5fB/7wnohVgK+/1IVAF6DA7UAs0Ju+srlnqEbn30f84sySOeR+V6t9aF7OiF9DsGedsTfVrfj8opptwQe7nycsxQaTxvmwgQgP9FrDYH+PGy/3ThpQsPj+/Mnvbnn7PMJEJlZFtGZsMWWcE2anJlJ7fbHKNPNNg6l2qosh6/kMTrloCU6wA67ouai0OFiNR+gyQaqUiL3NMgN4k39nZuwOg=="
- clientSecret: "0anSY5FBW+YF8BuFRRYxKX0yjDGU8/HhdirQMh+xFOEIvBQ8n/PdYi3qv2p4ngpFo5gb3PY2W6oWvHYLGgbFFse3YvzP5cbKRG0BN90hanlpVwmtAsapC7UepvOOUmNCRKHJ/pYICYcleUX/xGRiTugl9rcVw1MLg7kxcCuEMWcsBc9qCA9YHRcN3ucP+rT9x/2hLMiUmv3glYYZNgyQ3x1iqpOuTAIMeIkxMQo83vxGR57fpAx4+Yn1+hALhSl3sGaesUZhY9Py/OEZDFVWiN9RvrM4ND0IcfqyaQ4DuRPu2g8Es5fbmgSQoqkNPOcHT2+40pDbz3FPgz6QJou+pQ=="`
+ clientSecret: "0anSY5FBW+YF8BuFRRYxKX0yjDGU8/HhdirQMh+xFOEIvBQ8n/PdYi3qv2p4ngpFo5gb3PY2W6oWvHYLGgbFFse3YvzP5cbKRG0BN90hanlpVwmtAsapC7UepvOOUmNCRKHJ/pYICYcleUX/xGRiTugl9rcVw1MLg7kxcCuEMWcsBc9qCA9YHRcN3ucP+rT9x/2hLMiUmv3glYYZNgyQ3x1iqpOuTAIMeIkxMQo83vxGR57fpAx4+Yn1+hALhSl3sGaesUZhY9Py/OEZDFVWiN9RvrM4ND0IcfqyaQ4DuRPu2g8Es5fbmgSQoqkNPOcHT2+40pDbz3FPgz6QJou+pQ=="
+ redirectUri: "https://my-test-site.com"
+
+ gitlabAuth:
+ clientId: "Rr9d1XmVVMe8ogldH6rBtdGhf49c29ldwcBVsiMn6DLRAiYWmHY08eKC6xLnP6mXwMe/qCHJ6JMKURDODL8Yjm+nQf09zynkIRCr4J7tRHh4bPAYXPG+W1+TK7l8QD4gC+WXamxJiggwGCaDtNylI1QQhbKtevv7n/T+Iq98rBj8SLxxpi3qR0oZeN/zsoQsDYgzZ+HgvA3hY+5H897ijx1oBjoTsfI1Sfx8Qqix/QLZoXorOUJyEo+83WWvTEgo8X3OyFbXGZ758Kw6A7fcHxu8oVAjDvtFJFiwrDb4iBz9rffx7llZXjkcjzYzfwFcjG7mzZnfYgn9WcCwO7zlsA=="
+ clientSecret: "1zzjCrOZQ9dVs1p/WLgT8Lvwez3EKd1tp3D+7P5uGlEdqP1RN7kQvcaqOmOpm5SIY6g+yKJQGZq9G/IqUoKdsZDhA2VGYGXVzETU6eB48AL0OXlFumhjzJoGAXpnqDWzfevglkVuAkivBv6o9S1r/FL1GydwlRwWcYU6NNJjjkB04A00B4s0J7FRR3VFRxpJqDznHgXgT32E2+F3s6enh9/aErqi9uqn+iVtw7gvbd9PN1ejlo95R3BVNKUxNi2Dn4BbsH3MjQG4DyuzX8BiS9Nb+Xt+CwLygTT/i4C5Aj+KkMjAEiYOyttFbk3jkvYVXJ1XtW+taloBVPYCHgDzmg=="
+ redirectUri: "https://my-test-site-2.com"`
module.exports.config2 = `{
"comments": {
diff --git a/test/unit/controllers/auth.test.js b/test/unit/controllers/auth.test.js
new file mode 100644
index 00000000..61e2fdfe
--- /dev/null
+++ b/test/unit/controllers/auth.test.js
@@ -0,0 +1,310 @@
+const auth = require('../../../controllers/auth')
+const helpers = require('./../../helpers')
+const nock = require('nock')
+const Staticman = require('./../../../lib/Staticman')
+const User = require('../../../lib/models/User')
+
+Staticman.prototype.getSiteConfig = function () {
+ return Promise.resolve(helpers.getConfig())
+}
+
+let req
+let res
+
+beforeEach(() => {
+ req = helpers.getMockRequest()
+ res = helpers.getMockResponse()
+})
+
+describe('Auth controller', () => {
+ describe('GitHub', () => {
+ test('authenticates to GitHub with the given code and returns the authenticated user', () => {
+ const mockAccessToken = 'qwertyuiop'
+ const mockCode = '1q2w3e4r'
+ const mockUser = {
+ login: 'johndoe',
+ name: 'John Doe',
+ email: 'johndoe@test.com'
+ }
+
+ const siteConfig = helpers.getConfig()
+
+ nock(/github\.com/)
+ .post('/login/oauth/access_token')
+ .query({
+ client_id: siteConfig.get('githubAuth.clientId'),
+ client_secret: siteConfig.get('githubAuth.clientSecret'),
+ code: mockCode,
+ redirect_uri: siteConfig.get('githubAuth.redirectUri')
+ })
+ .reply(200, {
+ access_token: mockAccessToken
+ })
+
+ nock(/github\.com/)
+ .get('/user')
+ .query({
+ access_token: mockAccessToken
+ })
+ .reply(200, mockUser)
+
+ const reqWithQuery = Object.assign({}, req, {
+ query: {
+ code: mockCode
+ }
+ })
+
+ return auth(reqWithQuery, res).then(result => {
+ expect(res.send).toHaveBeenCalledTimes(1)
+ expect(helpers.decrypt(res.send.mock.calls[0][0].accessToken)).toBe(mockAccessToken)
+ expect(res.send.mock.calls[0][0].user)
+ .toEqual(new User('github', mockUser.login, mockUser.email, mockUser.name))
+ })
+ })
+
+ test('authenticates to GitHub with the given code and returns the original GitHub user when using v2 API', () => {
+ const mockAccessToken = 'qwertyuiop'
+ const mockCode = '1q2w3e4r'
+ const mockUser = {
+ login: 'johndoe'
+ }
+
+ const siteConfig = helpers.getConfig()
+
+ nock(/github\.com/)
+ .post('/login/oauth/access_token')
+ .query({
+ client_id: siteConfig.get('githubAuth.clientId'),
+ client_secret: siteConfig.get('githubAuth.clientSecret'),
+ code: mockCode,
+ redirect_uri: siteConfig.get('githubAuth.redirectUri')
+ })
+ .reply(200, {
+ access_token: mockAccessToken
+ })
+
+ nock(/github\.com/)
+ .get('/user')
+ .query({
+ access_token: mockAccessToken
+ })
+ .reply(200, mockUser)
+
+ const reqWithQuery = Object.assign({}, req, {
+ params: {
+ service: 'github',
+ version: '2'
+ },
+ query: {
+ code: mockCode
+ }
+ })
+
+ return auth(reqWithQuery, res).then(result => {
+ expect(res.send).toHaveBeenCalledTimes(1)
+ expect(helpers.decrypt(res.send.mock.calls[0][0].accessToken)).toBe(mockAccessToken)
+ expect(res.send.mock.calls[0][0].user).toEqual(mockUser)
+ })
+ })
+
+ test('returns a 401 response when unable to get an access token from GitHub', () => {
+ const mockCode = '1q2w3e4r'
+ const siteConfig = helpers.getConfig()
+
+ nock(/github\.com/)
+ .post('/login/oauth/access_token')
+ .query({
+ client_id: siteConfig.get('githubAuth.clientId'),
+ client_secret: siteConfig.get('githubAuth.clientSecret'),
+ code: mockCode,
+ redirect_uri: siteConfig.get('githubAuth.redirectUri')
+ })
+ .reply(401, {
+ error: 'invalid_code'
+ })
+
+ const reqWithQuery = Object.assign({}, req, {
+ params: {
+ service: 'github'
+ },
+ query: {
+ code: mockCode
+ }
+ })
+
+ return auth(reqWithQuery, res).then(result => {
+ expect(res.status.mock.calls[0][0]).toBe(401)
+ expect(res.send.mock.calls[0][0].statusCode).toBe(401)
+ expect(res.send.mock.calls[0][0].message).toContain('invalid_code')
+ })
+ })
+
+ test('returns a 401 response when an incorrect access token is used for the GitHub API', () => {
+ const mockAccessToken = 'qwertyuiop'
+ const mockCode = '1q2w3e4r'
+
+ const siteConfig = helpers.getConfig()
+
+ nock(/github\.com/)
+ .post('/login/oauth/access_token')
+ .query({
+ client_id: siteConfig.get('githubAuth.clientId'),
+ client_secret: siteConfig.get('githubAuth.clientSecret'),
+ code: mockCode,
+ redirect_uri: siteConfig.get('githubAuth.redirectUri')
+ })
+ .reply(200, {
+ access_token: mockAccessToken
+ })
+
+ nock(/github\.com/).get('/user')
+ .query({
+ access_token: mockAccessToken
+ })
+ .reply(401, {
+ message: 'Unauthorized'
+ })
+
+ const reqWithQuery = Object.assign({}, req, {
+ query: {
+ code: mockCode
+ }
+ })
+
+ return auth(reqWithQuery, res).then(result => {
+ expect(res.status.mock.calls[0][0]).toBe(401)
+ expect(res.send.mock.calls[0][0].statusCode).toBe(401)
+ expect(res.send.mock.calls[0][0].message).toContain('Unauthorized')
+ })
+ })
+ })
+
+ describe('GitLab', () => {
+ test('authenticates to GitLab with the given code and returns the authenticated user', () => {
+ const mockAccessToken = 'qwertyuiop'
+ const mockCode = '1q2w3e4r'
+ const mockUser = {
+ username: 'johndoe',
+ name: 'John Doe',
+ email: 'johndoe@test.com'
+ }
+
+ const siteConfig = helpers.getConfig()
+
+ nock(/gitlab\.com/)
+ .post('/oauth/token')
+ .query({
+ client_id: siteConfig.get('gitlabAuth.clientId'),
+ client_secret: siteConfig.get('gitlabAuth.clientSecret'),
+ code: mockCode,
+ grant_type: 'authorization_code',
+ redirect_uri: siteConfig.get('gitlabAuth.redirectUri')
+ })
+ .reply(200, {
+ access_token: mockAccessToken
+ })
+
+ nock(/gitlab\.com/, {
+ reqheaders: {
+ authorization: `Bearer ${mockAccessToken}`
+ }
+ })
+ .get('/api/v4/user')
+ .reply(200, mockUser)
+
+ const reqWithQuery = Object.assign({}, req, {
+ params: {
+ service: 'gitlab'
+ },
+ query: {
+ code: mockCode
+ }
+ })
+
+ return auth(reqWithQuery, res).then(result => {
+ expect(res.send).toHaveBeenCalledTimes(1)
+ expect(helpers.decrypt(res.send.mock.calls[0][0].accessToken)).toBe(mockAccessToken)
+ expect(res.send.mock.calls[0][0].user)
+ .toEqual(new User('gitlab', mockUser.username, mockUser.email, mockUser.name))
+ })
+ })
+
+ test('returns a 401 response when unable to get an access token from GitLab', () => {
+ const mockCode = '1q2w3e4r'
+ const siteConfig = helpers.getConfig()
+
+ nock(/gitlab\.com/)
+ .post('/oauth/token')
+ .query({
+ client_id: siteConfig.get('gitlabAuth.clientId'),
+ client_secret: siteConfig.get('gitlabAuth.clientSecret'),
+ code: mockCode,
+ grant_type: 'authorization_code',
+ redirect_uri: siteConfig.get('gitlabAuth.redirectUri')
+ })
+ .reply(401, {
+ error: 'invalid_code'
+ })
+
+ const reqWithQuery = Object.assign({}, req, {
+ params: {
+ service: 'gitlab'
+ },
+ query: {
+ code: mockCode
+ }
+ })
+
+ return auth(reqWithQuery, res).then(result => {
+ expect(res.status.mock.calls[0][0]).toBe(401)
+ expect(res.send.mock.calls[0][0].statusCode).toBe(401)
+ expect(res.send.mock.calls[0][0].message).toContain('invalid_code')
+ })
+ })
+
+ test('returns a 401 response when an incorrect access token is used for the GitLab API', () => {
+ const mockAccessToken = 'qwertyuiop'
+ const mockCode = '1q2w3e4r'
+
+ const siteConfig = helpers.getConfig()
+
+ nock(/gitlab\.com/)
+ .post('/oauth/token')
+ .query({
+ client_id: siteConfig.get('gitlabAuth.clientId'),
+ client_secret: siteConfig.get('gitlabAuth.clientSecret'),
+ code: mockCode,
+ grant_type: 'authorization_code',
+ redirect_uri: siteConfig.get('gitlabAuth.redirectUri')
+ })
+ .reply(200, {
+ access_token: mockAccessToken
+ })
+
+ nock(/gitlab\.com/, {
+ reqheaders: {
+ authorization: `Bearer ${mockAccessToken}`
+ }
+ })
+ .get('/api/v4/user')
+ .reply(401, {
+ message: '401 Unauthorized'
+ })
+
+ const reqWithQuery = Object.assign({}, req, {
+ params: {
+ service: 'gitlab'
+ },
+ query: {
+ code: mockCode
+ }
+ })
+
+ return auth(reqWithQuery, res).then(result => {
+ expect(res.status.mock.calls[0][0]).toBe(401)
+ expect(res.send.mock.calls[0][0].statusCode).toBe(401)
+ expect(res.send.mock.calls[0][0].message).toContain('401 Unauthorized')
+ })
+ })
+ })
+})
diff --git a/test/unit/controllers/connect.test.js b/test/unit/controllers/connect.test.js
index 8e52c1c0..b4ae294b 100644
--- a/test/unit/controllers/connect.test.js
+++ b/test/unit/controllers/connect.test.js
@@ -1,7 +1,4 @@
-const config = require('./../../../config')
const helpers = require('./../../helpers')
-const githubToken = config.get('githubToken')
-const nock = require('nock')
let req, res
@@ -10,33 +7,33 @@ beforeEach(() => {
res = helpers.getMockResponse()
jest.resetModules()
- jest.unmock('github')
+ jest.unmock('@octokit/rest')
})
describe('Connect controller', () => {
test('accepts the invitation if one is found and replies with "OK!"', () => {
const invitationId = 123
const mockAcceptRepoInvite = jest.fn(() => Promise.resolve())
- const mockGetRepoInvites = jest.fn(() => Promise.resolve([
- {
- id: invitationId,
- repository: {
- full_name: `${req.params.username}/${req.params.repository}`
+ const mockGetRepoInvites = jest.fn(() => Promise.resolve({
+ data: [
+ {
+ id: invitationId,
+ repository: {
+ full_name: `${req.params.username}/${req.params.repository}`
+ }
}
- }
- ]))
-
- jest.mock('github', () => {
- const GithubApi = function () {}
-
- GithubApi.prototype.authenticate = jest.fn()
- GithubApi.prototype.users = {
- acceptRepoInvite: mockAcceptRepoInvite,
- getRepoInvites: mockGetRepoInvites
- }
+ ]
+ }))
- return GithubApi
- })
+ jest.mock('@octokit/rest', () =>
+ _ => ({
+ authenticate: jest.fn(),
+ users: {
+ acceptRepoInvite: mockAcceptRepoInvite,
+ getRepoInvites: mockGetRepoInvites
+ }
+ })
+ )
const connect = require('./../../../controllers/connect')
@@ -50,26 +47,26 @@ describe('Connect controller', () => {
test('returns a 404 and an error message if a matching invitation is not found', () => {
const invitationId = 123
const mockAcceptRepoInvite = jest.fn(() => Promise.resolve())
- const mockGetRepoInvites = jest.fn(() => Promise.resolve([
- {
- id: invitationId,
- repository: {
- full_name: `${req.params.username}/anotherrepo`
+ const mockGetRepoInvites = jest.fn(() => Promise.resolve({
+ data: [
+ {
+ id: invitationId,
+ repository: {
+ full_name: `${req.params.username}/anotherrepo`
+ }
}
- }
- ]))
-
- jest.mock('github', () => {
- const GithubApi = function () {}
-
- GithubApi.prototype.authenticate = jest.fn()
- GithubApi.prototype.users = {
- acceptRepoInvite: mockAcceptRepoInvite,
- getRepoInvites: mockGetRepoInvites
- }
+ ]
+ }))
- return GithubApi
- })
+ jest.mock('@octokit/rest', () =>
+ _ => ({
+ authenticate: jest.fn(),
+ users: {
+ acceptRepoInvite: mockAcceptRepoInvite,
+ getRepoInvites: mockGetRepoInvites
+ }
+ })
+ )
const connect = require('./../../../controllers/connect')
@@ -82,23 +79,22 @@ describe('Connect controller', () => {
})
test('returns a 500 and an error message if the response from GitHub is invalid', () => {
- const invitationId = 123
const mockAcceptRepoInvite = jest.fn(() => Promise.resolve())
const mockGetRepoInvites = jest.fn(() => Promise.resolve({
- invalidProperty: 'invalidValue'
- }))
-
- jest.mock('github', () => {
- const GithubApi = function () {}
-
- GithubApi.prototype.authenticate = jest.fn()
- GithubApi.prototype.users = {
- acceptRepoInvite: mockAcceptRepoInvite,
- getRepoInvites: mockGetRepoInvites
+ data: {
+ invalidProperty: 'invalidValue'
}
+ }))
- return GithubApi
- })
+ jest.mock('@octokit/rest', () =>
+ _ => ({
+ authenticate: jest.fn(),
+ users: {
+ acceptRepoInvite: mockAcceptRepoInvite,
+ getRepoInvites: mockGetRepoInvites
+ }
+ })
+ )
const connect = require('./../../../controllers/connect')
diff --git a/test/unit/controllers/githubAuth.test.js b/test/unit/controllers/githubAuth.test.js
deleted file mode 100644
index 360c630a..00000000
--- a/test/unit/controllers/githubAuth.test.js
+++ /dev/null
@@ -1,66 +0,0 @@
-const config = require('./../../../config')
-const githubAuth = require('./../../../controllers/githubAuth')
-const helpers = require('./../../helpers')
-const nock = require('nock')
-const Staticman = require('./../../../lib/Staticman')
-
-Staticman.prototype.getSiteConfig = function () {
- return Promise.resolve(helpers.getConfig())
-}
-
-let req
-let res
-
-const mockSiteConfig = helpers.getConfig()
-
-// const mockConfig = helpers.getConfig()
-// .replace('@githubAuthClientId@', helpers.encrypt('testClient'))
-// .replace('@githubAuthClientSecret@', helpers.enrypt('superSecret'))
-
-beforeEach(() => {
- //jest.resetModules()
- //jest.unmock('github')
-
- req = helpers.getMockRequest()
- res = helpers.getMockResponse()
-})
-
-describe('GitHub Auth controller', () => {
- test('authenticates with the given code and returns the authenticated user', () => {
- const mockAccessToken = 'qwertyuiop'
- const mockCode = '1q2w3e4r'
- const mockUser = {
- login: 'johndoe'
- }
-
- nock(/github\.com/)
- .post('/login/oauth/access_token')
- .query({
- client_id: 'testClient',
- client_secret: 'superSecret',
- code: mockCode
- })
- .reply(200, {
- access_token: mockAccessToken
- })
-
- nock(/github\.com/, {
- reqheaders: {
- authorization: `token ${mockAccessToken}`
- }
- }).get('/user')
- .reply(200, mockUser)
-
- const reqWithQuery = Object.assign({}, req, {
- query: {
- code: mockCode
- }
- })
-
- return githubAuth(reqWithQuery, res).then(result => {
- expect(res.send).toHaveBeenCalledTimes(1)
- expect(helpers.decrypt(res.send.mock.calls[0][0].accessToken)).toBe(mockAccessToken)
- expect(res.send.mock.calls[0][0].user.login).toBe(mockUser.login)
- })
- })
-})
diff --git a/test/unit/controllers/handlePR.test.js b/test/unit/controllers/handlePR.test.js
index a21009a4..21057d27 100644
--- a/test/unit/controllers/handlePR.test.js
+++ b/test/unit/controllers/handlePR.test.js
@@ -1,9 +1,6 @@
-const config = require('./../../../config')
const helpers = require('./../../helpers')
-const githubToken = config.get('githubToken')
const sampleData = require('./../../helpers/sampleData')
-let catchAllMock
let mockAuthenticate
let mockSetConfigPathFn
let mockProcessMergeFn
@@ -27,42 +24,47 @@ beforeEach(() => {
res = helpers.getMockResponse()
jest.resetModules()
- jest.unmock('github')
+ jest.unmock('@octokit/rest')
})
describe('HandlePR controller', () => {
test('ignores pull requests from branches not prefixed with `staticman_`', () => {
const pr = {
number: 123,
+ title: 'Some random PR',
+ body: 'Unrelated review body',
head: {
ref: 'some-other-branch'
},
+ base: {
+ ref: 'master'
+ },
+ merged: false,
repository: {
name: req.params.repository,
owner: {
login: req.params.username
}
- }
+ },
+ state: 'open'
}
- const mockPullRequestsGet = jest.fn(() => Promise.resolve(pr))
-
- jest.mock('github', () => {
- const GithubApi = function () {}
-
- GithubApi.prototype.authenticate = jest.fn()
- GithubApi.prototype.pullRequests = {
- get: mockPullRequestsGet
- }
+ const mockPullRequestsGet = jest.fn(() => Promise.resolve({data: pr}))
- return GithubApi
- })
+ jest.mock('@octokit/rest', () =>
+ _ => ({
+ authenticate: jest.fn(),
+ pullRequests: {
+ get: mockPullRequestsGet
+ }
+ })
+ )
const handlePR = require('./../../../controllers/handlePR')
return handlePR(req.params.repository, pr).then(response => {
expect(mockPullRequestsGet).toHaveBeenCalledTimes(1)
expect(mockPullRequestsGet.mock.calls[0][0]).toEqual({
- user: req.params.username,
+ owner: req.params.username,
repo: req.params.repository,
number: pr.number
})
@@ -74,10 +76,14 @@ describe('HandlePR controller', () => {
test('do nothing if PR body doesn\'t match template', () => {
const pr = {
number: 123,
+ title: 'Add Staticman data',
body: sampleData.prBody2,
head: {
ref: 'staticman_1234567'
},
+ base: {
+ ref: 'master'
+ },
merged: true,
repository: {
name: req.params.repository,
@@ -88,21 +94,19 @@ describe('HandlePR controller', () => {
state: 'open'
}
const mockDeleteReference = jest.fn()
- const mockPullRequestsGet = jest.fn(() => Promise.resolve(pr))
-
- jest.mock('github', () => {
- const GithubApi = function () {}
-
- GithubApi.prototype.authenticate = jest.fn()
- GithubApi.prototype.pullRequests = {
- get: mockPullRequestsGet
- }
- GithubApi.prototype.gitdata = {
- deleteReference: mockDeleteReference
- }
-
- return GithubApi
- })
+ const mockPullRequestsGet = jest.fn(() => Promise.resolve({data: pr}))
+
+ jest.mock('@octokit/rest', () =>
+ _ => ({
+ authenticate: jest.fn(),
+ gitdata: {
+ deleteReference: mockDeleteReference
+ },
+ pullRequests: {
+ get: mockPullRequestsGet
+ }
+ })
+ )
const handlePR = require('./../../../controllers/handlePR')
@@ -115,10 +119,14 @@ describe('HandlePR controller', () => {
test('abort and return an error if `processMerge` fails', () => {
const pr = {
number: 123,
+ title: 'Add Staticman data',
body: sampleData.prBody1,
head: {
ref: 'staticman_1234567'
},
+ base: {
+ ref: 'master'
+ },
merged: true,
repository: {
name: req.params.repository,
@@ -128,18 +136,18 @@ describe('HandlePR controller', () => {
},
state: 'closed'
}
- const mockPullRequestsGet = jest.fn(() => Promise.resolve(pr))
-
- jest.mock('github', () => {
- const GithubApi = function () {}
-
- GithubApi.prototype.authenticate = jest.fn()
- GithubApi.prototype.pullRequests = {
- get: mockPullRequestsGet
- }
-
- return GithubApi
- })
+ const mockPullRequestsGet = jest.fn(() => Promise.resolve({
+ data: pr
+ }))
+
+ jest.mock('@octokit/rest', () =>
+ _ => ({
+ authenticate: jest.fn(),
+ pullRequests: {
+ get: mockPullRequestsGet
+ }
+ })
+ )
const handlePR = require('./../../../controllers/handlePR')
const errorMessage = 'some error'
@@ -159,10 +167,14 @@ describe('HandlePR controller', () => {
test('delete the branch if the pull request is closed', () => {
const pr = {
number: 123,
+ title: 'Add Staticman data',
body: sampleData.prBody1,
head: {
ref: 'staticman_1234567'
},
+ base: {
+ ref: 'master'
+ },
merged: true,
repository: {
name: req.params.repository,
@@ -173,40 +185,38 @@ describe('HandlePR controller', () => {
state: 'closed'
}
const mockDeleteReference = jest.fn()
- const mockPullRequestsGet = jest.fn(() => Promise.resolve(pr))
-
- jest.mock('github', () => {
- const GithubApi = function () {}
-
- GithubApi.prototype.authenticate = jest.fn()
- GithubApi.prototype.pullRequests = {
- get: mockPullRequestsGet
- }
- GithubApi.prototype.gitdata = {
- deleteReference: mockDeleteReference
- }
-
- return GithubApi
- })
+ const mockPullRequestsGet = jest.fn(() => Promise.resolve({data: pr}))
+
+ jest.mock('@octokit/rest', () =>
+ _ => ({
+ authenticate: jest.fn(),
+ gitdata: {
+ deleteReference: mockDeleteReference
+ },
+ pullRequests: {
+ get: mockPullRequestsGet
+ }
+ })
+ )
const handlePR = require('./../../../controllers/handlePR')
return handlePR(req.params.repository, pr).then(response => {
expect(mockPullRequestsGet).toHaveBeenCalledTimes(1)
expect(mockPullRequestsGet.mock.calls[0][0]).toEqual({
- user: req.params.username,
+ owner: req.params.username,
repo: req.params.repository,
number: pr.number
- })
+ })
expect(mockDeleteReference).toHaveBeenCalledTimes(1)
expect(mockDeleteReference.mock.calls[0][0]).toEqual({
- user: req.params.username,
+ owner: req.params.username,
repo: req.params.repository,
ref: `heads/${pr.head.ref}`
})
expect(mockSetConfigPathFn.mock.calls.length).toBe(1)
expect(mockProcessMergeFn.mock.calls.length).toBe(1)
})
- })
+ })
})
})
diff --git a/test/unit/lib/GitHub.test.js b/test/unit/lib/GitHub.test.js
index 726df434..edc815bf 100644
--- a/test/unit/lib/GitHub.test.js
+++ b/test/unit/lib/GitHub.test.js
@@ -1,16 +1,17 @@
-const config = require('./../../../config')
const mockHelpers = require('./../../helpers')
-const nock = require('nock')
const sampleData = require('./../../helpers/sampleData')
+const User = require('../../../lib/models/User')
const yaml = require('js-yaml')
-let req, res
+let req
+
+const btoa = contents => Buffer.from(contents).toString('base64')
beforeEach(() => {
jest.resetModules()
req = mockHelpers.getMockRequest()
- res = mockHelpers.getMockResponse()
+ req.params.token = 'test-token'
})
describe('GitHub interface', () => {
@@ -22,77 +23,70 @@ describe('GitHub interface', () => {
})
test('authenticates with the GitHub API using a personal access token', () => {
- const token = config.get('githubToken')
+ jest.mock('@octokit/rest', () =>
+ _ => ({
+ authenticate: jest.fn()
+ })
+ )
+
const GitHub = require('./../../../lib/GitHub')
const githubInstance = new GitHub(req.params)
- const spy = jest.spyOn(githubInstance.api, 'authenticate')
-
- githubInstance.authenticateWithToken(token)
- expect(spy.mock.calls[0][0]).toEqual({
- type: 'oauth',
- token
+ expect(githubInstance.api.authenticate.mock.calls[0][0]).toEqual({
+ type: 'token',
+ token: req.params.token
})
})
- test('authenticates with the GitHub API using a temporary access code', () => {
- const accessToken = 'asdfghjkl'
- const clientId = '123456789'
- const clientSecret = '1q2w3e4r5t6y7u8i9o'
- const code = 'abcdefghijklmnopqrst'
-
- nock(/github\.com/)
- .post('/login/oauth/access_token')
- .query({
- client_id: clientId,
- client_secret: clientSecret,
- code
- })
- .reply(200, {
- access_token: accessToken
+ test('authenticates with the GitHub API using an OAuth token', () => {
+ jest.mock('@octokit/rest', () =>
+ _ => ({
+ authenticate: jest.fn()
})
+ )
const GitHub = require('./../../../lib/GitHub')
- const githubInstance = new GitHub(req.params)
- const spy = jest.spyOn(githubInstance.api, 'authenticate')
-
- return githubInstance.authenticateWithCode({
- clientId,
- clientSecret,
- code
- }).then(() => {
- expect(spy.mock.calls[0][0]).toEqual({
- type: 'token',
- token: accessToken
- })
+
+ const oauthToken = 'test-oauth-token'
+ const githubInstance = new GitHub(Object.assign({}, req.params, {oauthToken}))
+
+ expect(githubInstance.api.authenticate.mock.calls[0][0]).toEqual({
+ type: 'oauth',
+ token: oauthToken
})
})
+ test('throws error if no personal access token or OAuth token is provided', () => {
+ const GitHub = require('./../../../lib/GitHub')
+
+ expect(() => new GitHub({})).toThrowError('Require an `oauthToken` or `token` option')
+ })
+
describe('readFile', () => {
test('reads a file and returns its contents', () => {
const fileContents = 'This is a text file!'
const filePath = 'path/to/file.txt'
const mockReposGetContent = jest.fn(() => Promise.resolve({
- content: btoa(fileContents)
- }))
-
- jest.mock('github', () => {
- const GithubApi = function () {}
-
- GithubApi.prototype.authenticate = jest.fn()
- GithubApi.prototype.repos = {
- getContent: mockReposGetContent
+ data: {
+ content: btoa(fileContents)
}
+ }))
- return GithubApi
- })
+ jest.mock('@octokit/rest', () =>
+ _ => ({
+ authenticate: jest.fn(),
+ repos: {
+ getContent: mockReposGetContent
+ }
+ })
+ )
const GitHub = require('./../../../lib/GitHub')
const githubInstance = new GitHub(req.params)
-
+
return githubInstance.readFile(filePath).then(contents => {
expect(mockReposGetContent.mock.calls[0][0]).toEqual({
- user: req.params.username,
+ owner: req.params.username,
repo: req.params.repository,
path: filePath,
ref: req.params.branch
@@ -102,25 +96,23 @@ describe('GitHub interface', () => {
test('returns an error if GitHub API call errors', () => {
const filePath = 'path/to/file.yml'
- const mockReposGetContent = jest.fn(() => Promise.reject())
-
- jest.mock('github', () => {
- const GithubApi = function () {}
-
- GithubApi.prototype.authenticate = jest.fn()
- GithubApi.prototype.repos = {
- getContent: mockReposGetContent
- }
-
- return GithubApi
- })
+ const mockReposGetContent = jest.fn(() => Promise.reject()) // eslint-disable-line prefer-promise-reject-errors
+
+ jest.mock('@octokit/rest', () =>
+ _ => ({
+ authenticate: jest.fn(),
+ repos: {
+ getContent: mockReposGetContent
+ }
+ })
+ )
const GitHub = require('./../../../lib/GitHub')
const githubInstance = new GitHub(req.params)
return githubInstance.readFile(filePath).catch(err => {
expect(mockReposGetContent.mock.calls[0][0]).toEqual({
- user: req.params.username,
+ owner: req.params.username,
repo: req.params.repository,
path: filePath,
ref: req.params.branch
@@ -138,26 +130,26 @@ describe('GitHub interface', () => {
`
const filePath = 'path/to/file.yml'
const mockReposGetContent = jest.fn(() => Promise.resolve({
- content: btoa(fileContents)
- }))
-
- jest.mock('github', () => {
- const GithubApi = function () {}
-
- GithubApi.prototype.authenticate = jest.fn()
- GithubApi.prototype.repos = {
- getContent: mockReposGetContent
+ data: {
+ content: btoa(fileContents)
}
+ }))
- return GithubApi
- })
+ jest.mock('@octokit/rest', () =>
+ _ => ({
+ authenticate: jest.fn(),
+ repos: {
+ getContent: mockReposGetContent
+ }
+ })
+ )
const GitHub = require('./../../../lib/GitHub')
const githubInstance = new GitHub(req.params)
return githubInstance.readFile(filePath).catch(err => {
expect(mockReposGetContent.mock.calls[0][0]).toEqual({
- user: req.params.username,
+ owner: req.params.username,
repo: req.params.repository,
path: filePath,
ref: req.params.branch
@@ -171,26 +163,26 @@ describe('GitHub interface', () => {
const filePath = 'path/to/file.yml'
const parsedConfig = yaml.safeLoad(sampleData.config1, 'utf8')
const mockReposGetContent = jest.fn(() => Promise.resolve({
- content: btoa(sampleData.config1)
- }))
-
- jest.mock('github', () => {
- const GithubApi = function () {}
-
- GithubApi.prototype.authenticate = jest.fn()
- GithubApi.prototype.repos = {
- getContent: mockReposGetContent
+ data: {
+ content: btoa(sampleData.config1)
}
+ }))
- return GithubApi
- })
+ jest.mock('@octokit/rest', () =>
+ _ => ({
+ authenticate: jest.fn(),
+ repos: {
+ getContent: mockReposGetContent
+ }
+ })
+ )
const GitHub = require('./../../../lib/GitHub')
const githubInstance = new GitHub(req.params)
return githubInstance.readFile(filePath).then(contents => {
expect(mockReposGetContent.mock.calls[0][0]).toEqual({
- user: req.params.username,
+ owner: req.params.username,
repo: req.params.repository,
path: filePath,
ref: req.params.branch
@@ -205,25 +197,25 @@ describe('GitHub interface', () => {
content: btoa(sampleData.config1)
}
const filePath = 'path/to/file.yml'
- const mockReposGetContent = jest.fn(() => Promise.resolve(fileContents))
-
- jest.mock('github', () => {
- const GithubApi = function () {}
-
- GithubApi.prototype.authenticate = jest.fn()
- GithubApi.prototype.repos = {
- getContent: mockReposGetContent
- }
+ const mockReposGetContent = jest.fn(() => Promise.resolve({
+ data: fileContents
+ }))
- return GithubApi
- })
+ jest.mock('@octokit/rest', () =>
+ _ => ({
+ authenticate: jest.fn(),
+ repos: {
+ getContent: mockReposGetContent
+ }
+ })
+ )
const GitHub = require('./../../../lib/GitHub')
const githubInstance = new GitHub(req.params)
return githubInstance.readFile(filePath, true).then(response => {
expect(mockReposGetContent.mock.calls[0][0]).toEqual({
- user: req.params.username,
+ owner: req.params.username,
repo: req.params.repository,
path: filePath,
ref: req.params.branch
@@ -231,32 +223,32 @@ describe('GitHub interface', () => {
expect(response.content).toEqual(parsedConfig)
expect(response.file).toEqual(fileContents)
})
- })
+ })
test('reads a JSON file and returns its parsed contents', () => {
const filePath = 'path/to/file.json'
const parsedConfig = yaml.safeLoad(sampleData.config2, 'utf8')
const mockReposGetContent = jest.fn(() => Promise.resolve({
- content: btoa(sampleData.config2)
- }))
-
- jest.mock('github', () => {
- const GithubApi = function () {}
-
- GithubApi.prototype.authenticate = jest.fn()
- GithubApi.prototype.repos = {
- getContent: mockReposGetContent
+ data: {
+ content: btoa(sampleData.config2)
}
+ }))
- return GithubApi
- })
+ jest.mock('@octokit/rest', () =>
+ _ => ({
+ authenticate: jest.fn(),
+ repos: {
+ getContent: mockReposGetContent
+ }
+ })
+ )
const GitHub = require('./../../../lib/GitHub')
const githubInstance = new GitHub(req.params)
-
+
return githubInstance.readFile(filePath).then(contents => {
expect(mockReposGetContent.mock.calls[0][0]).toEqual({
- user: req.params.username,
+ owner: req.params.username,
repo: req.params.repository,
path: filePath,
ref: req.params.branch
@@ -271,25 +263,25 @@ describe('GitHub interface', () => {
}
const filePath = 'path/to/file.json'
const parsedConfig = yaml.safeLoad(sampleData.config2, 'utf8')
- const mockReposGetContent = jest.fn(() => Promise.resolve(fileContents))
-
- jest.mock('github', () => {
- const GithubApi = function () {}
-
- GithubApi.prototype.authenticate = jest.fn()
- GithubApi.prototype.repos = {
- getContent: mockReposGetContent
- }
+ const mockReposGetContent = jest.fn(() => Promise.resolve({
+ data: fileContents
+ }))
- return GithubApi
- })
+ jest.mock('@octokit/rest', () =>
+ _ => ({
+ authenticate: jest.fn(),
+ repos: {
+ getContent: mockReposGetContent
+ }
+ })
+ )
const GitHub = require('./../../../lib/GitHub')
const githubInstance = new GitHub(req.params)
return githubInstance.readFile(filePath, true).then(response => {
expect(mockReposGetContent.mock.calls[0][0]).toEqual({
- user: req.params.username,
+ owner: req.params.username,
repo: req.params.repository,
path: filePath,
ref: req.params.branch
@@ -307,19 +299,19 @@ describe('GitHub interface', () => {
commitTitle: 'Adds a new file',
content: 'This is a new file',
path: 'path/to/file.txt'
- }
- const mockReposCreateFile = jest.fn(() => Promise.resolve())
-
- jest.mock('github', () => {
- const GithubApi = function () {}
-
- GithubApi.prototype.authenticate = jest.fn()
- GithubApi.prototype.repos = {
- createFile: mockReposCreateFile
- }
+ }
+ const mockReposCreateFile = jest.fn(() => Promise.resolve({
+ data: null
+ }))
- return GithubApi
- })
+ jest.mock('@octokit/rest', () =>
+ _ => ({
+ authenticate: jest.fn(),
+ repos: {
+ createFile: mockReposCreateFile
+ }
+ })
+ )
const GitHub = require('./../../../lib/GitHub')
const githubInstance = new GitHub(req.params)
@@ -329,13 +321,13 @@ describe('GitHub interface', () => {
options.content,
options.branch,
options.commitTitle
- ).then(response => {
+ ).then(response => {
expect(mockReposCreateFile).toHaveBeenCalledTimes(1)
expect(mockReposCreateFile.mock.calls[0][0]).toEqual({
- user: req.params.username,
+ owner: req.params.username,
repo: req.params.repository,
path: options.path,
- content: new Buffer(options.content).toString('base64'),
+ content: btoa(options.content),
message: options.commitTitle,
branch: options.branch
})
@@ -343,38 +335,36 @@ describe('GitHub interface', () => {
})
test('creates a file using the branch present in the request, if one is not provided to the method, and the default commit title', () => {
- const mockReposCreateFile = jest.fn(() => Promise.resolve())
-
- jest.mock('github', () => {
- const GithubApi = function () {}
-
- GithubApi.prototype.authenticate = jest.fn()
- GithubApi.prototype.repos = {
- createFile: mockReposCreateFile
- }
+ const mockReposCreateFile = jest.fn(() => Promise.resolve({
+ data: null
+ }))
- return GithubApi
- })
+ jest.mock('@octokit/rest', () =>
+ _ => ({
+ authenticate: jest.fn(),
+ repos: {
+ createFile: mockReposCreateFile
+ }
+ })
+ )
const GitHub = require('./../../../lib/GitHub')
const githubInstance = new GitHub(req.params)
const options = {
content: 'This is a new file',
- commitTitle: 'New Staticman data',
+ commitTitle: 'Add Staticman file',
path: 'path/to/file.txt'
}
return githubInstance.writeFile(
options.path,
- options.content,
- options.branch,
- options.commitTitle
+ options.content
).then(response => {
expect(mockReposCreateFile.mock.calls[0][0]).toEqual({
- user: req.params.username,
+ owner: req.params.username,
repo: req.params.repository,
path: options.path,
- content: new Buffer(options.content).toString('base64'),
+ content: btoa(options.content),
message: options.commitTitle,
branch: req.params.branch
})
@@ -382,16 +372,14 @@ describe('GitHub interface', () => {
})
test('returns an error object if the save operation fails', () => {
- jest.mock('github', () => {
- const GithubApi = function () {}
-
- GithubApi.prototype.authenticate = jest.fn()
- GithubApi.prototype.repos = {
- createFile: () => Promise.reject()
- }
-
- return GithubApi
- })
+ jest.mock('@octokit/rest', () =>
+ _ => ({
+ authenticate: jest.fn(),
+ repos: {
+ createFile: () => Promise.reject()
+ }
+ })
+ )
const GitHub = require('./../../../lib/GitHub')
const githubInstance = new GitHub(req.params)
@@ -415,7 +403,7 @@ describe('GitHub interface', () => {
})
})
- describe('writeFileAndSendPR', () => {
+ describe('writeFileAndSendReview', () => {
test('writes a file to a new branch and sends a PR to the base branch provided, using the given title and body for the commit/PR', () => {
const options = {
commitBody: 'This is a very cool file indeed...',
@@ -427,39 +415,45 @@ describe('GitHub interface', () => {
sha: '7fd1a60b01f91b314f59955a4e4d4e80d8edf11d'
}
const mockCreatePullRequest = jest.fn(() => Promise.resolve({
- number: 123
+ data: {
+ number: 123
+ }
}))
const mockCreateReference = jest.fn(() => Promise.resolve({
- ref: `refs/heads/${options.newBranch}`
+ data: {
+ ref: `refs/heads/${options.newBranch}`
+ }
}))
const mockGetBranch = jest.fn(() => Promise.resolve({
- commit: {
- sha: options.sha
+ data: {
+ commit: {
+ sha: options.sha
+ }
}
}))
- jest.mock('github', () => {
- const GithubApi = function () {}
-
- GithubApi.prototype.authenticate = jest.fn()
- GithubApi.prototype.gitdata = {
- createReference: mockCreateReference
- }
- GithubApi.prototype.pullRequests = {
- create: mockCreatePullRequest
- }
- GithubApi.prototype.repos = {
- createFile: () => Promise.resolve(),
- getBranch: mockGetBranch
- }
-
- return GithubApi
- })
+ jest.mock('@octokit/rest', () =>
+ _ => ({
+ authenticate: jest.fn(),
+ gitdata: {
+ createReference: mockCreateReference
+ },
+ repos: {
+ createFile: () => Promise.resolve({
+ data: null
+ }),
+ getBranch: mockGetBranch
+ },
+ pullRequests: {
+ create: mockCreatePullRequest
+ }
+ })
+ )
const GitHub = require('./../../../lib/GitHub')
const githubInstance = new GitHub(req.params)
- return githubInstance.writeFileAndSendPR(
+ return githubInstance.writeFileAndSendReview(
options.path,
options.content,
options.newBranch,
@@ -467,7 +461,7 @@ describe('GitHub interface', () => {
options.commitBody
).then(response => {
expect(mockCreatePullRequest.mock.calls[0][0]).toEqual({
- user: req.params.username,
+ owner: req.params.username,
repo: req.params.repository,
title: options.commitTitle,
head: options.newBranch,
@@ -475,13 +469,13 @@ describe('GitHub interface', () => {
body: options.commitBody
})
expect(mockCreateReference.mock.calls[0][0]).toEqual({
- user: req.params.username,
+ owner: req.params.username,
repo: req.params.repository,
ref: `refs/heads/${options.newBranch}`,
sha: options.sha
})
expect(mockGetBranch.mock.calls[0][0]).toEqual({
- user: req.params.username,
+ owner: req.params.username,
repo: req.params.repository,
branch: req.params.branch
})
@@ -489,17 +483,15 @@ describe('GitHub interface', () => {
})
test('returns an error if any of the API calls fail', () => {
- jest.mock('github', () => {
- const GithubApi = function () {}
-
- GithubApi.prototype.authenticate = jest.fn()
- GithubApi.prototype.repos = {
- createFile: () => Promise.resolve(),
- getBranch: () => Promise.reject()
- }
-
- return GithubApi
- })
+ jest.mock('@octokit/rest', () =>
+ _ => ({
+ authenticate: jest.fn(),
+ repos: {
+ createFile: () => Promise.resolve(),
+ getBranch: () => Promise.reject()
+ }
+ })
+ )
const GitHub = require('./../../../lib/GitHub')
const githubInstance = new GitHub(req.params)
@@ -513,7 +505,7 @@ describe('GitHub interface', () => {
sha: '7fd1a60b01f91b314f59955a4e4d4e80d8edf11d'
}
- return githubInstance.writeFileAndSendPR(
+ return githubInstance.writeFileAndSendReview(
options.path,
options.content,
options.newBranch,
@@ -526,4 +518,50 @@ describe('GitHub interface', () => {
})
})
})
+
+ describe('getCurrentUser', () => {
+ test('returns the current authenticated user', () => {
+ const mockUser = {
+ login: 'johndoe',
+ email: 'johndoe@test.com',
+ name: 'John Doe'
+ }
+
+ jest.mock('@octokit/rest', () =>
+ _ => ({
+ authenticate: jest.fn(),
+ users: {
+ get: () => Promise.resolve({data: mockUser})
+ }
+ })
+ )
+
+ const GitHub = require('./../../../lib/GitHub')
+ const githubInstance = new GitHub(req.params)
+
+ return githubInstance.getCurrentUser().then((user) => {
+ expect(user).toEqual(new User('github', 'johndoe', 'johndoe@test.com', 'John Doe'))
+ })
+ })
+
+ test('throws an error if unable to retrieve the current unauthenticated user', () => {
+ jest.mock('@octokit/rest', () =>
+ _ => ({
+ authenticate: jest.fn(),
+ users: {
+ get: () => Promise.reject()
+ }
+ })
+ )
+
+ const GitHub = require('./../../../lib/GitHub')
+ const githubInstance = new GitHub(req.params)
+
+ return githubInstance.getCurrentUser().catch((err) => {
+ expect(err).toEqual({
+ _smErrorCode: 'GITHUB_GET_USER'
+ })
+ })
+ })
+ })
})
diff --git a/test/unit/lib/GitLab.test.js b/test/unit/lib/GitLab.test.js
new file mode 100644
index 00000000..3d13d873
--- /dev/null
+++ b/test/unit/lib/GitLab.test.js
@@ -0,0 +1,565 @@
+const mockHelpers = require('./../../helpers')
+const sampleData = require('./../../helpers/sampleData')
+const User = require('../../../lib/models/User')
+const yaml = require('js-yaml')
+
+let req
+
+const btoa = contents => Buffer.from(contents).toString('base64')
+
+beforeEach(() => {
+ jest.resetModules()
+
+ req = mockHelpers.getMockRequest()
+ req.params.token = 'test-token'
+})
+
+describe('GitLab interface', () => {
+ test('initialises the GitLab API wrapper', () => {
+ const GitLab = require('./../../../lib/GitLab')
+ const gitlab = new GitLab(req.params)
+
+ expect(gitlab.api).toBeDefined()
+ })
+
+ test('authenticates with the GitLab API using a personal access token', () => {
+ const mockConstructor = jest.fn()
+ jest.mock('gitlab/dist/es5', () => {
+ return {
+ default: class {
+ constructor (params) {
+ mockConstructor(params)
+ }
+ }
+ }
+ })
+
+ const GitLab = require('./../../../lib/GitLab')
+ const gitlab = new GitLab(req.params) // eslint-disable-line no-unused-vars
+
+ expect(mockConstructor.mock.calls[0][0]).toEqual({
+ url: 'https://gitlab.com',
+ token: req.params.token
+ })
+ })
+
+ test('authenticates with the GitLab API using an OAuth token', () => {
+ const mockConstructor = jest.fn()
+ jest.mock('gitlab/dist/es5', () => {
+ return {
+ default: class {
+ constructor (params) {
+ mockConstructor(params)
+ }
+ }
+ }
+ })
+
+ const GitLab = require('./../../../lib/GitLab')
+
+ const oauthToken = 'test-oauth-token'
+ const gitlab = new GitLab(Object.assign({}, req.params, {oauthToken})) // eslint-disable-line no-unused-vars
+
+ expect(mockConstructor.mock.calls[0][0]).toEqual({
+ url: 'https://gitlab.com',
+ oauthToken: oauthToken
+ })
+ })
+
+ test('throws error if no personal access token or OAuth token is provided', () => {
+ const GitLab = require('../../../lib/GitLab')
+
+ expect(() => new GitLab({})).toThrowError('Require an `oauthToken` or `token` option')
+ })
+
+ describe('readFile', () => {
+ test('reads a file and returns its contents', () => {
+ const fileContents = 'This is a text file!'
+ const filePath = 'path/to/file.txt'
+ const mockRepoShowFile = jest.fn(() => Promise.resolve({
+ content: btoa(fileContents)
+ }))
+
+ jest.mock('gitlab/dist/es5', () => {
+ return {
+ default: function () {
+ return {
+ RepositoryFiles: {
+ show: mockRepoShowFile
+ }
+ }
+ }
+ }
+ })
+
+ const GitLab = require('./../../../lib/GitLab')
+ const gitlab = new GitLab(req.params)
+
+ return gitlab.readFile(filePath).then(contents => {
+ expect(mockRepoShowFile.mock.calls[0][0]).toBe(`${req.params.username}/${req.params.repository}`)
+ expect(mockRepoShowFile.mock.calls[0][1]).toBe(filePath)
+ expect(mockRepoShowFile.mock.calls[0][2]).toBe(req.params.branch)
+ })
+ })
+
+ test('returns an error if GitLab API call errors', () => {
+ const filePath = 'path/to/file.yml'
+ const mockShowRepoFile = jest.fn(() => Promise.reject()) // eslint-disable-line prefer-promise-reject-errors
+
+ jest.mock('gitlab/dist/es5', () => {
+ return {
+ default: function () {
+ return {
+ RepositoryFiles: {
+ show: mockShowRepoFile
+ }
+ }
+ }
+ }
+ })
+
+ const GitLab = require('./../../../lib/GitLab')
+ const gitlab = new GitLab(req.params)
+
+ return gitlab.readFile(filePath).catch(err => {
+ expect(mockShowRepoFile.mock.calls[0][0]).toBe(`${req.params.username}/${req.params.repository}`)
+ expect(mockShowRepoFile.mock.calls[0][1]).toBe(filePath)
+ expect(mockShowRepoFile.mock.calls[0][2]).toBe(req.params.branch)
+
+ expect(err).toEqual({
+ _smErrorCode: 'GITLAB_READING_FILE'
+ })
+ })
+ })
+
+ test('returns an error if parsing fails for the given file', () => {
+ const fileContents = `
+ foo: "bar"
+ baz
+ `
+ const filePath = 'path/to/file.yml'
+ const mockShowRepoFile = jest.fn(() => Promise.resolve({
+ content: btoa(fileContents)
+ }))
+
+ jest.mock('gitlab/dist/es5', () => {
+ return {
+ default: function () {
+ return {
+ RepositoryFiles: {
+ show: mockShowRepoFile
+ }
+ }
+ }
+ }
+ })
+
+ const GitLab = require('./../../../lib/GitLab')
+ const gitlab = new GitLab(req.params)
+
+ return gitlab.readFile(filePath).catch(err => {
+ expect(mockShowRepoFile.mock.calls[0][0]).toBe(`${req.params.username}/${req.params.repository}`)
+ expect(mockShowRepoFile.mock.calls[0][1]).toBe(filePath)
+ expect(mockShowRepoFile.mock.calls[0][2]).toBe(req.params.branch)
+ expect(err._smErrorCode).toBe('PARSING_ERROR')
+ expect(err.message).toBeDefined()
+ })
+ })
+
+ test('reads a YAML file and returns its parsed contents', () => {
+ const filePath = 'path/to/file.yml'
+ const parsedConfig = yaml.safeLoad(sampleData.config1, 'utf8')
+ const mockShowRepoFile = jest.fn(() => Promise.resolve({
+ content: btoa(sampleData.config1)
+ }))
+
+ jest.mock('gitlab/dist/es5', () => {
+ return {
+ default: function () {
+ return {
+ RepositoryFiles: {
+ show: mockShowRepoFile
+ }
+ }
+ }
+ }
+ })
+
+ const GitLab = require('./../../../lib/GitLab')
+ const gitlab = new GitLab(req.params)
+
+ return gitlab.readFile(filePath).then(contents => {
+ expect(mockShowRepoFile.mock.calls[0][0]).toBe(`${req.params.username}/${req.params.repository}`)
+ expect(mockShowRepoFile.mock.calls[0][1]).toBe(filePath)
+ expect(mockShowRepoFile.mock.calls[0][2]).toBe(req.params.branch)
+ expect(contents).toEqual(parsedConfig)
+ })
+ })
+
+ test('reads a YAML file and returns its parsed and raw contents if `getFullResponse` is `true`', () => {
+ const parsedConfig = yaml.safeLoad(sampleData.config1, 'utf8')
+ const fileContents = {
+ content: btoa(sampleData.config1)
+ }
+ const filePath = 'path/to/file.yml'
+ const mockShowRepoFile = jest.fn(() => Promise.resolve(fileContents))
+
+ jest.mock('gitlab/dist/es5', () => {
+ return {
+ default: function () {
+ return {
+ RepositoryFiles: {
+ show: mockShowRepoFile
+ }
+ }
+ }
+ }
+ })
+
+ const GitLab = require('./../../../lib/GitLab')
+ const gitlab = new GitLab(req.params)
+
+ return gitlab.readFile(filePath, true).then(response => {
+ expect(response.content).toEqual(parsedConfig)
+ expect(response.file).toEqual(fileContents)
+ })
+ })
+
+ test('reads a JSON file and returns its parsed contents', () => {
+ const filePath = 'path/to/file.json'
+ const parsedConfig = yaml.safeLoad(sampleData.config2, 'utf8')
+ const mockShowRepoFile = jest.fn(() => Promise.resolve({
+ content: btoa(sampleData.config2)
+ }))
+
+ jest.mock('gitlab/dist/es5', () => {
+ return {
+ default: function () {
+ return {
+ RepositoryFiles: {
+ show: mockShowRepoFile
+ }
+ }
+ }
+ }
+ })
+
+ const GitLab = require('./../../../lib/GitLab')
+ const gitlab = new GitLab(req.params)
+
+ return gitlab.readFile(filePath).then(contents => {
+ expect(contents).toEqual(parsedConfig)
+ })
+ })
+
+ test('reads a JSON file and returns its parsed and raw contents if `getFullResponse` is `true`', () => {
+ const fileContents = {
+ content: btoa(sampleData.config2)
+ }
+ const filePath = 'path/to/file.json'
+ const parsedConfig = yaml.safeLoad(sampleData.config2, 'utf8')
+ const mockShowRepoFile = jest.fn(() => Promise.resolve(fileContents))
+
+ jest.mock('gitlab/dist/es5', () => {
+ return {
+ default: function () {
+ return {
+ RepositoryFiles: {
+ show: mockShowRepoFile
+ }
+ }
+ }
+ }
+ })
+
+ const GitLab = require('./../../../lib/GitLab')
+ const gitlab = new GitLab(req.params)
+
+ return gitlab.readFile(filePath, true).then(response => {
+ expect(response.content).toEqual(parsedConfig)
+ expect(response.file).toEqual(fileContents)
+ })
+ })
+ })
+
+ describe('writeFile', () => {
+ test('creates a file on the given branch using the commit title provided', () => {
+ const options = {
+ branch: 'master',
+ commitTitle: 'Adds a new file',
+ content: 'This is a new file',
+ path: 'path/to/file.txt'
+ }
+ const mockCreateRepoFile = jest.fn(() => Promise.resolve(null))
+
+ jest.mock('gitlab/dist/es5', () => {
+ return {
+ default: function () {
+ return {
+ RepositoryFiles: {
+ create: mockCreateRepoFile
+ }
+ }
+ }
+ }
+ })
+
+ const GitLab = require('./../../../lib/GitLab')
+ const gitlab = new GitLab(req.params)
+
+ return gitlab.writeFile(
+ options.path,
+ options.content,
+ options.branch,
+ options.commitTitle
+ ).then(response => {
+ expect(mockCreateRepoFile).toHaveBeenCalledTimes(1)
+ expect(mockCreateRepoFile.mock.calls[0][0]).toBe(`${req.params.username}/${req.params.repository}`)
+ expect(mockCreateRepoFile.mock.calls[0][1]).toBe(options.path)
+ expect(mockCreateRepoFile.mock.calls[0][2]).toBe(options.branch)
+ expect(mockCreateRepoFile.mock.calls[0][3]).toEqual({
+ content: btoa(options.content),
+ commit_message: options.commitTitle,
+ encoding: 'base64'
+ })
+ })
+ })
+
+ test(
+ 'creates a file using the branch present in the request, if one is not provided to the method, and the default commit title',
+ () => {
+ const mockCreateRepoFile = jest.fn(() => Promise.resolve(null))
+
+ jest.mock('gitlab/dist/es5', () => {
+ return {
+ default: function () {
+ return {
+ RepositoryFiles: {
+ create: mockCreateRepoFile
+ }
+ }
+ }
+ }
+ })
+
+ const GitLab = require('./../../../lib/GitLab')
+ const gitlab = new GitLab(req.params)
+ const options = {
+ content: 'This is a new file',
+ commitTitle: 'Add Staticman file',
+ path: 'path/to/file.txt'
+ }
+
+ return gitlab.writeFile(
+ options.path,
+ options.content
+ ).then(response => {
+ expect(mockCreateRepoFile.mock.calls[0][0]).toBe(`${req.params.username}/${req.params.repository}`)
+ expect(mockCreateRepoFile.mock.calls[0][1]).toBe(options.path)
+ expect(mockCreateRepoFile.mock.calls[0][2]).toBe(req.params.branch)
+ expect(mockCreateRepoFile.mock.calls[0][3]).toEqual({
+ content: btoa(options.content),
+ commit_message: options.commitTitle,
+ encoding: 'base64'
+ })
+ })
+ }
+ )
+
+ test('returns an error object if the save operation fails', () => {
+ jest.mock('gitlab/dist/es5', () => {
+ return {
+ default: function () {
+ return {
+ RepositoryFiles: {
+ create: () => Promise.reject(new Error())
+ }
+ }
+ }
+ }
+ })
+
+ const GitLab = require('./../../../lib/GitLab')
+ const gitlab = new GitLab(req.params)
+ const options = {
+ branch: 'master',
+ commitTitle: 'Adds a new file',
+ content: 'This is a new file',
+ path: 'path/to/file.txt'
+ }
+
+ return gitlab.writeFile(
+ options.path,
+ options.content,
+ options.branch,
+ options.commitTitle
+ ).catch(err => {
+ expect(err._smErrorCode).toBe('GITLAB_WRITING_FILE')
+ })
+ })
+ })
+
+ describe('writeFileAndSendReview', () => {
+ test(
+ 'writes a file to a new branch and sends a PR to the base branch provided, using the given title and body for the commit/PR',
+ () => {
+ const options = {
+ commitBody: 'This is a very cool file indeed...',
+ commitTitle: 'Adds a new file',
+ content: 'This is a new file',
+ name: 'file.txt',
+ newBranch: 'staticman_123456789',
+ path: 'path/to/file.txt',
+ sha: '7fd1a60b01f91b314f59955a4e4d4e80d8edf11d'
+ }
+ const mockCreateMergeRequest = jest.fn(() => Promise.resolve({
+ number: 123
+ }))
+ const mockCreateBranch = jest.fn(() => Promise.resolve({
+ ref: `refs/heads/${options.newBranch}`
+ }))
+ const mockShowBranch = jest.fn(() => Promise.resolve({
+ commit: {
+ id: options.sha
+ }
+ }))
+
+ jest.mock('gitlab/dist/es5', () => {
+ return {
+ default: function () {
+ return {
+ Branches: {
+ create: mockCreateBranch,
+ show: mockShowBranch
+ },
+ MergeRequests: {
+ create: mockCreateMergeRequest
+ },
+ RepositoryFiles: {
+ create: () => Promise.resolve(null)
+ }
+ }
+ }
+ }
+ })
+
+ const GitLab = require('./../../../lib/GitLab')
+ const gitlab = new GitLab(req.params)
+
+ return gitlab.writeFileAndSendReview(
+ options.path,
+ options.content,
+ options.newBranch,
+ options.commitTitle,
+ options.commitBody
+ ).then(response => {
+ expect(mockCreateMergeRequest.mock.calls[0][0]).toBe(`${req.params.username}/${req.params.repository}`)
+ expect(mockCreateMergeRequest.mock.calls[0][1]).toBe(options.newBranch)
+ expect(mockCreateMergeRequest.mock.calls[0][2]).toBe(req.params.branch)
+ expect(mockCreateMergeRequest.mock.calls[0][3]).toBe(options.commitTitle)
+ expect(mockCreateMergeRequest.mock.calls[0][4]).toEqual({
+ description: options.commitBody,
+ remove_source_branch: true
+ })
+
+ expect(mockCreateBranch.mock.calls[0][0]).toBe(`${req.params.username}/${req.params.repository}`)
+ expect(mockCreateBranch.mock.calls[0][1]).toBe(options.newBranch)
+ expect(mockCreateBranch.mock.calls[0][2]).toBe(options.sha)
+
+ expect(mockShowBranch.mock.calls[0][0]).toBe(`${req.params.username}/${req.params.repository}`)
+ expect(mockShowBranch.mock.calls[0][1]).toBe(req.params.branch)
+ })
+ }
+ )
+
+ test('returns an error if any of the API calls fail', () => {
+ jest.mock('gitlab/dist/es5', () => {
+ return {
+ default: function () {
+ return {
+ Branches: {
+ create: () => Promise.resolve(),
+ show: () => Promise.reject(new Error())
+ },
+ RepositoryFiles: {
+ create: () => Promise.reject(new Error())
+ }
+ }
+ }
+ }
+ })
+
+ const GitLab = require('./../../../lib/GitLab')
+ const gitlab = new GitLab(req.params)
+ const options = {
+ commitBody: '',
+ commitTitle: 'Add Staticman file',
+ content: 'This is a new file',
+ name: 'file.txt',
+ newBranch: 'staticman_123456789',
+ path: 'path/to/file.txt',
+ sha: '7fd1a60b01f91b314f59955a4e4d4e80d8edf11d'
+ }
+
+ return gitlab.writeFileAndSendReview(
+ options.path,
+ options.content,
+ options.newBranch,
+ options.commitTitle,
+ options.commitBody
+ ).catch(err => {
+ expect(err._smErrorCode).toBe('GITLAB_CREATING_PR')
+ })
+ })
+ })
+
+ describe('getCurrentUser', () => {
+ test('returns the current authenticated user', () => {
+ const mockUser = {
+ username: 'johndoe',
+ email: 'johndoe@test.com',
+ name: 'John Doe'
+ }
+
+ jest.mock('gitlab/dist/es5', () => {
+ return {
+ default: function () {
+ return {
+ Users: {
+ current: () => Promise.resolve(mockUser)
+ }
+ }
+ }
+ }
+ })
+
+ const GitLab = require('./../../../lib/GitLab')
+ const gitlab = new GitLab(req.params)
+
+ return gitlab.getCurrentUser().then((user) => {
+ expect(user).toEqual(new User('gitlab', 'johndoe', 'johndoe@test.com', 'John Doe'))
+ })
+ })
+
+ test('throws an error if unable to retrieve the current unauthenticated user', () => {
+ jest.mock('gitlab/dist/es5', () => {
+ return {
+ default: function () {
+ return {
+ Users: {
+ current: () => Promise.reject(new Error())
+ }
+ }
+ }
+ }
+ })
+
+ const GitLab = require('./../../../lib/GitLab')
+ const gitlab = new GitLab(req.params)
+
+ return gitlab.getCurrentUser().catch((err) => {
+ expect(err._smErrorCode).toBe('GITLAB_GET_USER')
+ })
+ })
+ })
+})
diff --git a/test/unit/lib/OAuth.test.js b/test/unit/lib/OAuth.test.js
new file mode 100644
index 00000000..bcd08b49
--- /dev/null
+++ b/test/unit/lib/OAuth.test.js
@@ -0,0 +1,51 @@
+const nock = require('nock')
+const oauth = require('../../../lib/OAuth')
+
+describe('OAuth access tokens', () => {
+ test('requests OAuth access token from GitHub', () => {
+ const accessToken = 'asdfghjkl'
+ const clientId = '123456789'
+ const clientSecret = '1q2w3e4r5t6y7u8i9o'
+ const code = 'abcdefghijklmnopqrst'
+ const redirectUri = 'http://my-test-site.com'
+
+ nock(/github\.com/)
+ .post('/login/oauth/access_token')
+ .query({
+ client_id: clientId,
+ client_secret: clientSecret,
+ code,
+ redirect_uri: redirectUri
+ })
+ .reply(200, {
+ access_token: accessToken
+ })
+
+ oauth.requestGitHubAccessToken(code, clientId, clientSecret, redirectUri)
+ .then(token => expect(token).toEqual(accessToken))
+ })
+
+ test('requests OAuth access token from GitLab', () => {
+ const accessToken = 'asdfghjkl'
+ const clientId = '123456789'
+ const clientSecret = '1q2w3e4r5t6y7u8i9o'
+ const code = 'abcdefghijklmnopqrst'
+ const redirectUri = 'http://my-test-site.com'
+
+ nock(/gitlab\.com/)
+ .post('/oauth/token')
+ .query({
+ client_id: clientId,
+ client_secret: clientSecret,
+ code,
+ grant_type: 'authorization_code',
+ redirect_uri: redirectUri
+ })
+ .reply(200, {
+ access_token: accessToken
+ })
+
+ oauth.requestGitLabAccessToken(code, clientId, clientSecret, redirectUri)
+ .then(token => expect(token).toEqual(accessToken))
+ })
+})
diff --git a/test/unit/lib/Staticman.test.js b/test/unit/lib/Staticman.test.js
index 99c65897..6a60d196 100644
--- a/test/unit/lib/Staticman.test.js
+++ b/test/unit/lib/Staticman.test.js
@@ -1,12 +1,11 @@
const config = require('./../../../config')
const errorHandler = require('./../../../lib/ErrorHandler')
const frontMatter = require('front-matter')
-const md5 = require('md5')
const moment = require('moment')
const mockHelpers = require('./../../helpers')
-const querystring = require('querystring')
const slugify = require('slug')
const yaml = require('js-yaml')
+const User = require('../../../lib/models/User')
let mockConfig
let mockParameters
@@ -23,13 +22,25 @@ beforeEach(() => {
describe('Staticman interface', () => {
describe('initialisation', () => {
test('creates an instance of the GitHub module', () => {
+ const GitHub = require('../../../lib/GitHub')
const Staticman = require('./../../../lib/Staticman')
const staticman = new Staticman(mockParameters)
- expect(staticman.github.options.username).toBe(mockParameters.username)
- expect(staticman.github.options.repository).toBe(mockParameters.repository)
- expect(staticman.github.options.branch).toBe(mockParameters.branch)
- expect(staticman.github.api).toBeDefined()
+ expect(staticman.git).toBeInstanceOf(GitHub)
+ expect(staticman.git.username).toBe(mockParameters.username)
+ expect(staticman.git.repository).toBe(mockParameters.repository)
+ expect(staticman.git.branch).toBe(mockParameters.branch)
+ })
+
+ test('creates an instance of the GitLab module', () => {
+ const GitLab = require('../../../lib/GitLab')
+ const Staticman = require('./../../../lib/Staticman')
+ const staticman = new Staticman(Object.assign({}, mockParameters, {service: 'gitlab'}))
+
+ expect(staticman.git).toBeInstanceOf(GitLab)
+ expect(staticman.git.username).toBe(mockParameters.username)
+ expect(staticman.git.repository).toBe(mockParameters.repository)
+ expect(staticman.git.branch).toBe(mockParameters.branch)
})
test('generates a new unique ID', () => {
@@ -110,7 +121,7 @@ describe('Staticman interface', () => {
const staticman = new Staticman(mockParameters)
staticman.options = {}
-
+
const data = mockHelpers.getFields()
const extendedData = staticman._applyInternalFields(data)
@@ -129,7 +140,7 @@ describe('Staticman interface', () => {
}
staticman2.options = {}
-
+
const data = mockHelpers.getFields()
const extendedData1 = staticman1._applyInternalFields(data)
const extendedData2 = staticman2._applyInternalFields(data)
@@ -189,6 +200,71 @@ describe('Staticman interface', () => {
slug: slugify(data.name).toLowerCase()
}))
})
+
+ test('adds the `user` generated fields to the data object', () => {
+ const Staticman = require('./../../../lib/Staticman')
+ const staticman = new Staticman(mockParameters)
+
+ mockConfig.set('generatedFields', {
+ username: {
+ options: {
+ property: 'username'
+ },
+ type: 'user'
+ },
+ name: {
+ options: {
+ property: 'name'
+ },
+ type: 'user'
+ }
+ })
+ staticman.siteConfig = mockConfig
+
+ staticman.gitUser = new User('github', 'johndoe', 'johndoe@test.com', 'John Doe')
+
+ const data = mockHelpers.getFields()
+ const extendedData = staticman._applyGeneratedFields(data)
+
+ expect(extendedData).toEqual(Object.assign({}, data, {
+ name: 'John Doe',
+ username: 'johndoe'
+ }))
+ })
+
+ test('adds the `github` generated fields to the data object in the v2 API', () => {
+ const Staticman = require('./../../../lib/Staticman')
+ const staticman = new Staticman(mockParameters)
+
+ mockConfig.set('generatedFields', {
+ username: {
+ options: {
+ property: 'login'
+ },
+ type: 'github'
+ },
+ name: {
+ options: {
+ property: 'name'
+ },
+ type: 'github'
+ }
+ })
+ staticman.siteConfig = mockConfig
+
+ staticman.gitUser = {
+ login: 'johndoe',
+ name: 'John Doe'
+ }
+
+ const data = mockHelpers.getFields()
+ const extendedData = staticman._applyGeneratedFields(data)
+
+ expect(extendedData).toEqual(Object.assign({}, data, {
+ name: 'John Doe',
+ username: 'johndoe'
+ }))
+ })
})
describe('field transforms', () => {
@@ -216,8 +292,8 @@ describe('Staticman interface', () => {
})
staticman.siteConfig = mockConfig
staticman._transforms = {
- testTransformName() { return 'transformed-name' },
- testTransformEmail() { return 'transformed-email' }
+ testTransformName () { return 'transformed-name' },
+ testTransformEmail () { return 'transformed-email' }
}
const data = mockHelpers.getFields()
@@ -240,8 +316,8 @@ describe('Staticman interface', () => {
})
staticman.siteConfig = mockConfig
staticman._transforms = {
- testTransform1() { return 'transformed:1' },
- testTransform2(v) { return `${v}-transformed:2` },
+ testTransform1 () { return 'transformed:1' },
+ testTransform2 (v) { return `${v}-transformed:2` }
}
const data = mockHelpers.getFields()
@@ -346,7 +422,6 @@ describe('Staticman interface', () => {
})
test('throws an error if the content is flagged as spam', () => {
- const akismetError = new Error('Akismet error')
const fields = mockHelpers.getFields()
const mockCheckSpamFn = jest.fn((options, callback) => {
callback(null, true)
@@ -377,11 +452,309 @@ describe('Staticman interface', () => {
})
})
+ describe('authentication ', () => {
+ beforeEach(() => {
+ mockConfig.set('auth.required', true)
+ })
+
+ test('returns false if `auth.required` config is false', () => {
+ mockConfig.set('auth.required', false)
+
+ const fields = mockHelpers.getFields()
+ const options = {}
+
+ const Staticman = require('./../../../lib/Staticman')
+ const staticman = new Staticman(mockParameters)
+
+ staticman.fields = fields
+ staticman.options = options
+ staticman.siteConfig = mockConfig
+
+ return staticman._checkAuth().then(result => expect(result).toBeFalsy())
+ })
+
+ test('throws an error if `auth-token` field is missing', () => {
+ const fields = mockHelpers.getFields()
+ const options = {}
+
+ const Staticman = require('./../../../lib/Staticman')
+ const staticman = new Staticman(mockParameters)
+
+ staticman.fields = fields
+ staticman.options = options
+ staticman.siteConfig = mockConfig
+
+ return staticman._checkAuth().catch(err => {
+ expect(err).toEqual({
+ _smErrorCode: 'AUTH_TOKEN_MISSING'
+ })
+ })
+ })
+
+ test('throws an error if unable to decrypt the `auth-token` option', () => {
+ const fields = mockHelpers.getFields()
+ const options = {
+ 'auth-token': 'invalid token',
+ 'auth-type': 'github'
+ }
+
+ const Staticman = require('./../../../lib/Staticman')
+ const staticman = new Staticman(mockParameters)
+
+ staticman.fields = fields
+ staticman.options = options
+ staticman.siteConfig = mockConfig
+
+ return staticman._checkAuth().catch(err => {
+ expect(err).toEqual({
+ _smErrorCode: 'AUTH_TOKEN_INVALID'
+ })
+ })
+ })
+
+ test('authenticates with GitHub by default using the OAuth access token', () => {
+ const mockConstructor = jest.fn()
+ const mockUser = new User('github', 'johndoe', 'johndoe@test.com', 'John Doe')
+
+ jest.mock('../../../lib/GitHub', () => {
+ return mockConstructor.mockImplementation(() => {
+ return {
+ getCurrentUser: () => Promise.resolve(mockUser)
+ }
+ })
+ })
+
+ const fields = mockHelpers.getFields()
+ const options = {
+ 'auth-token': mockHelpers.encrypt('test-token'),
+ }
+
+ const Staticman = require('./../../../lib/Staticman')
+ const staticman = new Staticman(mockParameters)
+
+ staticman.fields = fields
+ staticman.options = options
+ staticman.siteConfig = mockConfig
+
+ return staticman._checkAuth().then((result) => {
+ expect(mockConstructor.mock.calls[1][0]).toEqual({
+ oauthToken: 'test-token'
+ })
+ })
+ })
+
+ test('authenticates with GitLab (using `auth-type` option) using OAuth access token', () => {
+ const mockConstructor = jest.fn()
+ const mockUser = new User('gitlab', 'johndoe', 'johndoe@test.com', 'John Doe')
+
+ jest.mock('../../../lib/GitLab', () => {
+ return mockConstructor.mockImplementation(() => {
+ return {
+ getCurrentUser: () => Promise.resolve(mockUser)
+ }
+ })
+ })
+
+ const fields = mockHelpers.getFields()
+ const options = {
+ 'auth-token': mockHelpers.encrypt('test-token'),
+ 'auth-type': 'gitlab'
+ }
+
+ const Staticman = require('./../../../lib/Staticman')
+ const staticman = new Staticman(mockParameters)
+
+ staticman.fields = fields
+ staticman.options = options
+ staticman.siteConfig = mockConfig
+
+ return staticman._checkAuth().then((result) => {
+ expect(mockConstructor.mock.calls[0][0]).toEqual({
+ oauthToken: 'test-token'
+ })
+ })
+ })
+
+ test('sets the `gitUser` property to the authenticated User and returns true for GitHub authentication', () => {
+ const mockGetCurrentUser = jest.fn(() => Promise.resolve(mockUser))
+
+ jest.mock('../../../lib/GitHub', () => {
+ return function () {
+ return {
+ getCurrentUser: mockGetCurrentUser
+ }
+ }
+ })
+
+ const fields = mockHelpers.getFields()
+ const options = {
+ 'auth-token': mockHelpers.encrypt('test-token')
+ }
+
+ const Staticman = require('./../../../lib/Staticman')
+ const staticman = new Staticman(mockParameters)
+
+ staticman.fields = fields
+ staticman.options = options
+ staticman.siteConfig = mockConfig
+
+ const mockUser = new User('github', 'johndoe', 'johndoe@test.com', 'John Doe')
+
+ return staticman._checkAuth().then((result) => {
+ expect(mockGetCurrentUser).toHaveBeenCalledTimes(1)
+ expect(staticman.gitUser).toEqual(mockUser)
+ expect(result).toBeTruthy()
+ })
+ })
+
+ test('sets the `gitUser` property to the authenticated User and returns true for GitLab authentication', () => {
+ const mockGetCurrentUser = jest.fn(() => Promise.resolve(mockUser))
+
+ jest.mock('../../../lib/GitLab', () => {
+ return function () {
+ return {
+ getCurrentUser: mockGetCurrentUser
+ }
+ }
+ })
+
+ const fields = mockHelpers.getFields()
+ const options = {
+ 'auth-token': mockHelpers.encrypt('test-token'),
+ 'auth-type': 'gitlab'
+ }
+
+ const Staticman = require('./../../../lib/Staticman')
+ const staticman = new Staticman(mockParameters)
+
+ staticman.fields = fields
+ staticman.options = options
+ staticman.siteConfig = mockConfig
+
+ const mockUser = new User('github', 'johndoe', 'johndoe@test.com', 'John Doe')
+
+ return staticman._checkAuth().then((result) => {
+ expect(mockGetCurrentUser).toHaveBeenCalledTimes(1)
+ expect(staticman.gitUser).toEqual(mockUser)
+ expect(result).toBeTruthy()
+ })
+ })
+ })
+
+ describe('authentication v2', () => {
+ beforeEach(() => {
+ mockConfig.set('githubAuth.required', true)
+ })
+
+ test('returns false if `githubAuth.required` config is false', () => {
+ mockConfig.set('githubAuth.required', false)
+
+ const fields = mockHelpers.getFields()
+ const options = {}
+
+ mockParameters.version = '2'
+
+ const Staticman = require('./../../../lib/Staticman')
+ const staticman = new Staticman(mockParameters)
+
+ staticman.fields = fields
+ staticman.options = options
+ staticman.siteConfig = mockConfig
+
+ return staticman._checkAuth().then(result => expect(result).toBeFalsy())
+ })
+
+ test('throws an error if `github-token` field is missing in v2 API', () => {
+ const fields = mockHelpers.getFields()
+ const options = {}
+
+ mockParameters.version = '2'
+
+ const Staticman = require('./../../../lib/Staticman')
+ const staticman = new Staticman(mockParameters)
+
+ staticman.fields = fields
+ staticman.options = options
+ staticman.siteConfig = mockConfig
+
+ return staticman._checkAuth().catch(err => {
+ expect(err).toEqual({
+ _smErrorCode: 'GITHUB_AUTH_TOKEN_MISSING'
+ })
+ })
+ })
+
+ test('throws an error if unable to decrypt the `github-token` option in the v2 API', () => {
+ const fields = mockHelpers.getFields()
+ const options = {
+ 'github-token': 'invalid token'
+ }
+
+ mockParameters.version = '2'
+
+ const Staticman = require('./../../../lib/Staticman')
+ const staticman = new Staticman(mockParameters)
+
+ staticman.fields = fields
+ staticman.options = options
+ staticman.siteConfig = mockConfig
+
+ return staticman._checkAuth().catch(err => {
+ expect(err).toEqual({
+ _smErrorCode: 'GITHUB_AUTH_TOKEN_INVALID'
+ })
+ })
+ })
+
+ test('sets the `gitUser` property to the GitHub user in the v2 API', () => {
+ const mockUser = {
+ login: 'johndoe',
+ name: 'John Doe'
+ }
+ const mockGetCurrentUser = jest.fn(() => Promise.resolve({
+ data: mockUser
+ }))
+
+ jest.mock('../../../lib/GitHub', () => {
+ return function () {
+ return {
+ api: {
+ users: {
+ get: mockGetCurrentUser
+ }
+ }
+ }
+ }
+ })
+
+ const fields = mockHelpers.getFields()
+ const options = {
+ 'github-token': mockHelpers.encrypt('test-token')
+ }
+
+ mockParameters.version = '2'
+
+ const Staticman = require('./../../../lib/Staticman')
+ const staticman = new Staticman(mockParameters)
+
+ staticman.fields = fields
+ staticman.options = options
+ staticman.siteConfig = mockConfig
+
+ return staticman._checkAuth().then((result) => {
+ expect(mockGetCurrentUser).toHaveBeenCalledTimes(1)
+ expect(staticman.gitUser).toEqual(mockUser)
+ expect(result).toBeTruthy()
+ })
+ })
+ })
+
describe('date creator', () => {
const mockDate = new Date('1988-08-31T11:00:00')
+ // eslint-disable-next-line no-global-assign
Date = class extends Date {
- constructor() {
+ constructor () {
return mockDate
}
}
@@ -408,22 +781,25 @@ describe('Staticman interface', () => {
expect(date).toBe(Math.floor(mockDate.getTime() / 1000))
})
- test('creates a ISO-8601 representation of the date if the format is set to `iso8601`, absent, or set to none of the other supported formats', () => {
- const Staticman = require('./../../../lib/Staticman')
- const staticman = new Staticman(mockParameters)
+ test(
+ 'creates a ISO-8601 representation of the date if the format is set to `iso8601`, absent, or set to none of the other supported formats',
+ () => {
+ const Staticman = require('./../../../lib/Staticman')
+ const staticman = new Staticman(mockParameters)
- const date1 = staticman._createDate({
- format: 'iso8601'
- })
- const date2 = staticman._createDate({
- format: 'somethingNotValid'
- })
- const date3 = staticman._createDate()
+ const date1 = staticman._createDate({
+ format: 'iso8601'
+ })
+ const date2 = staticman._createDate({
+ format: 'somethingNotValid'
+ })
+ const date3 = staticman._createDate()
- expect(date1).toBe(mockDate.toISOString())
- expect(date2).toBe(mockDate.toISOString())
- expect(date3).toBe(mockDate.toISOString())
- })
+ expect(date1).toBe(mockDate.toISOString())
+ expect(date2).toBe(mockDate.toISOString())
+ expect(date3).toBe(mockDate.toISOString())
+ }
+ )
})
describe('file formatting', () => {
@@ -484,21 +860,24 @@ describe('Staticman interface', () => {
})
})
- test('throws an error if `format` is set to `frontmatter` but there is no `frontmatterContent` transform defined', () => {
- const fields = mockHelpers.getFields()
- const Staticman = require('./../../../lib/Staticman')
- const staticman = new Staticman(mockParameters)
+ test(
+ 'throws an error if `format` is set to `frontmatter` but there is no `frontmatterContent` transform defined',
+ () => {
+ const fields = mockHelpers.getFields()
+ const Staticman = require('./../../../lib/Staticman')
+ const staticman = new Staticman(mockParameters)
- mockConfig.set('format', 'frontmatter')
- mockConfig.set('transforms', undefined)
- staticman.siteConfig = mockConfig
+ mockConfig.set('format', 'frontmatter')
+ mockConfig.set('transforms', undefined)
+ staticman.siteConfig = mockConfig
- return staticman._createFile(fields).catch(err => {
- expect(err).toEqual({
- _smErrorCode: 'NO_FRONTMATTER_CONTENT_TRANSFORM'
+ return staticman._createFile(fields).catch(err => {
+ expect(err).toEqual({
+ _smErrorCode: 'NO_FRONTMATTER_CONTENT_TRANSFORM'
+ })
})
- })
- })
+ }
+ )
test('throws an error if `format` contains an invalid format', () => {
const fields = mockHelpers.getFields()
@@ -522,11 +901,11 @@ describe('Staticman interface', () => {
const fieldsTable = mockHelpers.getFieldsTable()
const Staticman = require('./../../../lib/Staticman')
const staticman = new Staticman(mockParameters)
-
+
mockConfig.set('notifications.enabled', false)
staticman.siteConfig = mockConfig
- const pullRequestBody = staticman._generatePRBody(fields)
+ const pullRequestBody = staticman._generateReviewBody(fields)
expect(pullRequestBody).toBe(mockConfig.get('pullRequestBody') + fieldsTable)
})
@@ -554,7 +933,7 @@ describe('Staticman interface', () => {
parameters: req.params
}
const notificationsComment = `\n\n`
- const pullRequestBody = staticman._generatePRBody(fields)
+ const pullRequestBody = staticman._generateReviewBody(fields)
expect(pullRequestBody).toBe(
mockConfig.get('pullRequestBody') +
@@ -687,7 +1066,7 @@ describe('Staticman interface', () => {
test('returns the given string unchanged if it does not contain placeholders', () => {
const Staticman = require('./../../../lib/Staticman')
const staticman = new Staticman(mockParameters)
-
+
const subject = 'This is a normal string, nothing to replace here.'
const data = mockHelpers.getParameters()
@@ -697,7 +1076,7 @@ describe('Staticman interface', () => {
test('returns the given string with placeholders replaced with data from the data object provided', () => {
const Staticman = require('./../../../lib/Staticman')
const staticman = new Staticman(mockParameters)
-
+
const subject = 'My name is {name} and I come from {location.city}, {location.country}'
const data = {
name: 'Eduardo',
@@ -717,15 +1096,16 @@ describe('Staticman interface', () => {
test('returns the given string with special placeholders replaced', () => {
const mockDate = new Date('1988-08-31T11:00:00')
+ // eslint-disable-next-line no-global-assign
Date = class extends Date {
- constructor() {
+ constructor () {
return mockDate
}
}
const Staticman = require('./../../../lib/Staticman')
const staticman = new Staticman(mockParameters)
-
+
const data = {
name: 'Eduardo'
}
@@ -741,8 +1121,9 @@ describe('Staticman interface', () => {
test('returns the given string with `date:` placeholders replaced', () => {
const mockDate = new Date('1988-08-31T11:00:00')
+ // eslint-disable-next-line no-global-assign
Date = class extends Date {
- constructor() {
+ constructor () {
return mockDate
}
}
@@ -889,48 +1270,48 @@ describe('Staticman interface', () => {
})
})
- test('fetches the site config from the repository, even if there is one already defined, if `force` is truthy', () => {
- const Staticman = require('./../../../lib/Staticman')
- const staticman = new Staticman(mockParameters)
- const configObject = mockHelpers.getConfigObject()
-
- staticman.setConfigPath(configObject)
- staticman.siteConfig = mockConfig
- staticman.github = {
- readFile: jest.fn(() => {
- const config = Object.assign({}, mockConfig.getProperties())
+ test(
+ 'fetches the site config from the repository, even if there is one already defined, if `force` is truthy',
+ () => {
+ const Staticman = require('./../../../lib/Staticman')
+ const staticman = new Staticman(mockParameters)
+ const configObject = mockHelpers.getConfigObject()
- config.reCaptcha.secret = mockConfig.getRaw('reCaptcha.secret')
+ staticman.setConfigPath(configObject)
+ staticman.siteConfig = mockConfig
+ staticman.git = {
+ readFile: jest.fn(() => {
+ const config = mockHelpers.getParsedConfig()
- return Promise.resolve({
- [configObject.path]: config
+ return Promise.resolve(config)
})
+ }
+
+ return staticman.getSiteConfig(true).then(config => {
+ expect(staticman.git.readFile).toHaveBeenCalledTimes(1)
+ expect(staticman.git.readFile.mock.calls[0][0]).toBe(configObject.file)
})
}
-
- return staticman.getSiteConfig(true).then(config => {
- expect(staticman.github.readFile).toHaveBeenCalledTimes(1)
- expect(staticman.github.readFile.mock.calls[0][0]).toBe(configObject.file)
- })
- })
+ )
test('fetches the site config from the repository and throws an error if it fails validation', () => {
const Staticman = require('./../../../lib/Staticman')
const staticman = new Staticman(mockParameters)
const configObject = mockHelpers.getConfigObject()
- const mockRemoteConfig = Object.assign({}, mockConfig.getProperties())
const validationErrors = {
_smErrorCode: 'MISSING_CONFIG_FIELDS',
data: ['branch', 'path']
}
- mockRemoteConfig.reCaptcha.secret = mockConfig.getRaw('reCaptcha.secret')
-
+ const invalidConfig = {
+ missingFields: true
+ }
+
staticman.setConfigPath(configObject)
- staticman.github = {
+ staticman.git = {
readFile: jest.fn(() => {
return Promise.resolve({
- [configObject.path]: mockRemoteConfig
+ [configObject.path]: invalidConfig
})
})
}
@@ -938,21 +1319,20 @@ describe('Staticman interface', () => {
return staticman.getSiteConfig().catch(err => {
expect(err).toEqual(validationErrors)
- expect(staticman._validateConfig.mock.calls[0][0]).toEqual(mockRemoteConfig)
+ expect(staticman._validateConfig.mock.calls[0][0]).toEqual(invalidConfig)
})
})
- test('fetches the site config from the repository and throws an error if it fails validation', () => {
+ test('fetches the site config from the repository and throws an error if there is a branch mismatch', () => {
const Staticman = require('./../../../lib/Staticman')
const staticman = new Staticman(mockParameters)
const configObject = mockHelpers.getConfigObject()
const mockRemoteConfig = Object.assign({}, mockConfig.getProperties())
mockRemoteConfig.branch = 'some-other-branch'
- mockRemoteConfig.reCaptcha.secret = mockConfig.getRaw('reCaptcha.secret')
-
+
staticman.setConfigPath(configObject)
- staticman.github = {
+ staticman.git = {
readFile: jest.fn(() => {
return Promise.resolve({
[configObject.path]: mockRemoteConfig
@@ -972,16 +1352,13 @@ describe('Staticman interface', () => {
const Staticman = require('./../../../lib/Staticman')
const staticman = new Staticman(mockParameters)
const configObject = mockHelpers.getConfigObject()
- const mockRemoteConfig = Object.assign({}, mockConfig.getProperties())
- mockRemoteConfig.reCaptcha.secret = mockConfig.getRaw('reCaptcha.secret')
-
staticman.setConfigPath(configObject)
- staticman.github = {
+ staticman.git = {
readFile: jest.fn(() => {
- return Promise.resolve({
- [configObject.path]: mockRemoteConfig
- })
+ const mockRemoteConfig = mockHelpers.getParsedConfig()
+
+ return Promise.resolve(mockRemoteConfig)
})
}
@@ -992,7 +1369,7 @@ describe('Staticman interface', () => {
})
describe('`processEntry()`', () => {
- test.only('gets site config and checks for spam, throwing an error if found', () => {
+ test('gets site config and checks for spam, throwing an error if found', () => {
const Staticman = require('./../../../lib/Staticman')
const staticman = new Staticman(mockParameters)
@@ -1036,38 +1413,94 @@ describe('Staticman interface', () => {
_smErrorCode: 'INVALID_FIELDS',
data: ['someField1']
})
- })
+ })
})
- test('creates a file after applying generated fields, transforms and internal fields, throwing an error if file creation fails', () => {
+ test(
+ 'creates a file after applying generated fields, transforms and internal fields, throwing an error if file creation fails',
+ () => {
+ const Staticman = require('./../../../lib/Staticman')
+ const staticman = new Staticman(mockParameters)
+ const fields = mockHelpers.getFields()
+
+ mockConfig.set('allowedFields', Object.keys(fields))
+
+ staticman.siteConfig = mockConfig
+ staticman._checkForSpam = () => Promise.resolve(fields)
+
+ const spyApplyGeneratedFields = jest.spyOn(staticman, '_applyGeneratedFields')
+ const spyApplyTransforms = jest.spyOn(staticman, '_applyTransforms')
+ const spyApplyInternalFields = jest.spyOn(staticman, '_applyInternalFields')
+
+ staticman._createFile = jest.fn(() => {
+ return Promise.reject(errorHandler('INVALID_FORMAT'))
+ })
+
+ return staticman.processEntry(
+ mockHelpers.getFields(),
+ {}
+ ).catch(err => {
+ expect(spyApplyGeneratedFields).toHaveBeenCalled()
+ expect(spyApplyTransforms).toHaveBeenCalled()
+ expect(spyApplyInternalFields).toHaveBeenCalled()
+ expect(err).toEqual({
+ _smErrorCode: 'INVALID_FORMAT'
+ })
+ })
+ }
+ )
+
+ test('authenticates user before creating file', () => {
+ const mockUser = new User('github', 'johndoe', 'johndoe@test.com', 'John Doe')
+ const mockGetCurrentUser = jest.fn(() => Promise.resolve(mockUser))
+
+ jest.mock('../../../lib/GitHub', () => {
+ return function () {
+ return {
+ getCurrentUser: mockGetCurrentUser
+ }
+ }
+ })
+
const Staticman = require('./../../../lib/Staticman')
const staticman = new Staticman(mockParameters)
const fields = mockHelpers.getFields()
+ const options = {
+ 'auth-token': mockHelpers.encrypt('test-token')
+ }
- mockConfig.set('allowedFields', Object.keys(fields))
+ mockConfig.set('auth.required', true)
staticman.siteConfig = mockConfig
staticman._checkForSpam = () => Promise.resolve(fields)
+ staticman.git.writeFile = jest.fn(() => Promise.resolve())
- const spyApplyGeneratedFields = jest.spyOn(staticman, '_applyGeneratedFields')
- const spyApplyTransforms = jest.spyOn(staticman, '_applyTransforms')
- const spyApplyInternalFields = jest.spyOn(staticman, '_applyInternalFields')
-
- staticman._createFile = jest.fn(() => {
- return Promise.reject(errorHandler('INVALID_FORMAT'))
+ const spyCheckAuth = jest.spyOn(staticman, '_checkAuth')
+
+ return staticman.processEntry(fields, options).then(_ => {
+ expect(spyCheckAuth).toHaveBeenCalledTimes(1)
+ expect(mockGetCurrentUser).toHaveBeenCalledTimes(1)
+ expect(staticman.gitUser).toEqual(mockUser)
})
+ })
- return staticman.processEntry(
- mockHelpers.getFields(),
- {}
- ).catch(err => {
- expect(spyApplyGeneratedFields).toHaveBeenCalled()
- expect(spyApplyTransforms).toHaveBeenCalled()
- expect(spyApplyInternalFields).toHaveBeenCalled()
- expect(err).toEqual({
- _smErrorCode: 'INVALID_FORMAT'
- })
- })
+ test('authenticates user before creating file, throwing an error if unable to authenticate', () => {
+ const Staticman = require('./../../../lib/Staticman')
+ const staticman = new Staticman(mockParameters)
+ const fields = mockHelpers.getFields()
+ const options = {
+ 'auth-token': 'invalid token'
+ }
+
+ mockConfig.set('auth.required', true)
+
+ staticman.siteConfig = mockConfig
+ staticman._checkForSpam = () => Promise.resolve(fields)
+ staticman.git.writeFile = jest.fn(() => Promise.resolve())
+
+ return staticman.processEntry(fields, options).catch(err => {
+ err._smErrorCode = 'AUTH_TOKEN_INVALID'
+ })
})
test('subscribes the user to notifications', () => {
@@ -1094,7 +1527,7 @@ describe('Staticman interface', () => {
staticman.siteConfig = mockConfig
staticman._checkForSpam = () => Promise.resolve(fields)
- staticman.github.writeFile = jest.fn(() => {
+ staticman.git.writeFile = jest.fn(() => {
return Promise.resolve()
})
@@ -1118,7 +1551,7 @@ describe('Staticman interface', () => {
staticman.siteConfig = mockConfig
staticman._checkForSpam = () => Promise.resolve(fields)
- staticman.github.writeFileAndSendPR = jest.fn(() => {
+ staticman.git.writeFileAndSendReview = jest.fn(() => {
return Promise.resolve()
})
@@ -1135,16 +1568,16 @@ describe('Staticman interface', () => {
}
)
- expect(staticman.github.writeFileAndSendPR.mock.calls[0][0])
+ expect(staticman.git.writeFileAndSendReview.mock.calls[0][0])
.toBe(staticman._getNewFilePath(fields))
- expect(staticman.github.writeFileAndSendPR.mock.calls[0][1])
+ expect(staticman.git.writeFileAndSendReview.mock.calls[0][1])
.toBe(expectedFile)
- expect(staticman.github.writeFileAndSendPR.mock.calls[0][2])
+ expect(staticman.git.writeFileAndSendReview.mock.calls[0][2])
.toBe(`staticman_${staticman.uid}`)
- expect(staticman.github.writeFileAndSendPR.mock.calls[0][3])
+ expect(staticman.git.writeFileAndSendReview.mock.calls[0][3])
.toBe(expectedCommitMessage)
- expect(staticman.github.writeFileAndSendPR.mock.calls[0][4])
- .toBe(staticman._generatePRBody(fields))
+ expect(staticman.git.writeFileAndSendReview.mock.calls[0][4])
+ .toBe(staticman._generateReviewBody(fields))
})
})
@@ -1172,7 +1605,7 @@ describe('Staticman interface', () => {
staticman.siteConfig = mockConfig
staticman._checkForSpam = () => Promise.resolve(fields)
- staticman.github.writeFile = jest.fn(() => {
+ staticman.git.writeFile = jest.fn(() => {
return Promise.resolve()
})
@@ -1191,50 +1624,49 @@ describe('Staticman interface', () => {
expect(mockSubscriptionSend.mock.calls[0][0]).toBe(options.parent)
expect(mockSubscriptionSend.mock.calls[0][1]).toEqual(fields)
- expect(staticman.github.writeFile.mock.calls[0][0])
+ expect(staticman.git.writeFile.mock.calls[0][0])
.toBe(staticman._getNewFilePath(fields))
- expect(staticman.github.writeFile.mock.calls[0][1])
+ expect(staticman.git.writeFile.mock.calls[0][1])
.toBe(expectedFile)
- expect(staticman.github.writeFile.mock.calls[0][2])
+ expect(staticman.git.writeFile.mock.calls[0][2])
.toBe(mockParameters.branch)
- expect(staticman.github.writeFile.mock.calls[0][3])
+ expect(staticman.git.writeFile.mock.calls[0][3])
.toBe(expectedCommitMessage)
})
})
- })
- describe('`processMerge()`', () => {
- test('subscribes the user to notifications', () => {
- const mockSubscriptionSend = jest.fn()
+ describe('`processMerge()`', () => {
+ test('subscribes the user to notifications', () => {
+ const mockSubscriptionSend = jest.fn()
- jest.mock('./../../../lib/SubscriptionsManager', () => {
- return jest.fn(() => ({
- send: mockSubscriptionSend
- }))
- })
+ jest.mock('./../../../lib/SubscriptionsManager', () => {
+ return jest.fn(() => ({
+ send: mockSubscriptionSend
+ }))
+ })
- const Staticman = require('./../../../lib/Staticman')
- const staticman = new Staticman(mockParameters)
- const fields = mockHelpers.getFields()
- const options = {
- parent: '1a2b3c4d5e6f',
- subscribe: 'email'
- }
+ const Staticman = require('./../../../lib/Staticman')
+ const staticman = new Staticman(mockParameters)
+ const fields = mockHelpers.getFields()
+ const options = {
+ parent: '1a2b3c4d5e6f',
+ subscribe: 'email'
+ }
- mockConfig.set('notifications.enabled', true)
+ mockConfig.set('notifications.enabled', true)
- staticman.siteConfig = mockConfig
+ staticman.siteConfig = mockConfig
- return staticman.processMerge(
- fields,
- options
- ).then(response => {
- expect(mockSubscriptionSend.mock.calls[0][0]).toBe(options.parent)
- expect(mockSubscriptionSend.mock.calls[0][1]).toEqual(fields)
- expect(mockSubscriptionSend.mock.calls[0][2]).toEqual(options)
- expect(mockSubscriptionSend.mock.calls[0][3]).toEqual(mockConfig)
+ return staticman.processMerge(
+ fields,
+ options
+ ).then(response => {
+ expect(mockSubscriptionSend.mock.calls[0][0]).toBe(options.parent)
+ expect(mockSubscriptionSend.mock.calls[0][1]).toEqual(fields)
+ expect(mockSubscriptionSend.mock.calls[0][2]).toEqual(options)
+ expect(mockSubscriptionSend.mock.calls[0][3]).toEqual(mockConfig)
+ })
})
})
- })
+ })
})
-
diff --git a/test/utils/coverage.js b/test/utils/coverage.js
index ce9bc9f3..3f29f8cb 100644
--- a/test/utils/coverage.js
+++ b/test/utils/coverage.js
@@ -7,7 +7,7 @@ const path = require('path')
const opts = {
badgeFileName: 'coverage',
destinationDir: __dirname,
- istanbulReportFile: path.resolve(__dirname + '/../../coverage', 'cobertura-coverage.xml'),
+ istanbulReportFile: path.resolve(__dirname, '../../coverage', 'cobertura-coverage.xml'),
thresholds: {
excellent: 90, // overall percent >= excellent, green badge
good: 60 // overall percent < excellent and >= good, yellow badge
@@ -21,16 +21,18 @@ coberturaBadger(opts, function parsingResults(err, badgeStatus) {
console.log('An error occurred: ' + err.message)
}
- const readme = path.resolve(__dirname + '/../../README.md')
+ const readme = path.resolve(__dirname, '../../README.md')
const badgeUrl = badgeStatus.url // e.g. http://img.shields.io/badge/coverage-60%-yellow.svg
// open the README.md and add this url
- fs.readFile(readme, {encoding: 'utf-8'}, function (err, body) {
- body = body.replace(/(!\[coverage\]\()(.+?)(\))/g, function(whole, a, b, c) {
- return a + badgeUrl
+ fs.readFile(readme, {encoding: 'utf-8'}, (err, body) => {
+ if (err) console.log(err.toString())
+
+ body = body.replace(/(!\[coverage\]\()(.+?)(\))/g, (whole, a, b, c) => {
+ return a + badgeUrl + c
})
- fs.writeFile(readme, body, {encoding: 'utf-8'}, function (err) {
+ fs.writeFile(readme, body, {encoding: 'utf-8'}, (err) => {
if (err) console.log(err.toString())
console.log('Coverage badge successfully added to ' + readme)
diff --git a/test/utils/coverage.svg b/test/utils/coverage.svg
index 15498abd..02d44a70 100644
--- a/test/utils/coverage.svg
+++ b/test/utils/coverage.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file