diff --git a/packages/pubsweet-client/.babelrc b/packages/pubsweet-client/.babelrc new file mode 100644 index 0000000000000000000000000000000000000000..8e05f6ce40a1827aba4a03391e136548a0589e5d --- /dev/null +++ b/packages/pubsweet-client/.babelrc @@ -0,0 +1,7 @@ +{ + "presets": [ + "env", + "react", + "stage-2" + ] +} diff --git a/packages/pubsweet-client/.eslintrc b/packages/pubsweet-client/.eslintrc new file mode 100644 index 0000000000000000000000000000000000000000..2c80442dbcd4471f228a994d6a9321437de8418e --- /dev/null +++ b/packages/pubsweet-client/.eslintrc @@ -0,0 +1,21 @@ +{ + "extends": [ + "standard", + "plugin:react/recommended", + "prettier", + "prettier/standard", + "prettier/react", + ], + "parserOptions": { + "ecmaFeatures": { + "jsx": true + }, + "ecmaVersion": 2017 + }, + "env": { + "browser": true + }, + "globals": { + "PUBSWEET_COMPONENTS": true + } +} diff --git a/packages/pubsweet-client/.gitignore b/packages/pubsweet-client/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..4d1df6e2c7a98808e41d2ef34e5ae71115078371 --- /dev/null +++ b/packages/pubsweet-client/.gitignore @@ -0,0 +1,12 @@ +node_modules/* +npm-debug.log +public/assets/* +public/uploads/* +.happypack +.DS_Store +.idea + +test.log +scratch +coverage +mockapp.json diff --git a/packages/pubsweet-client/.gitlab-ci.yml b/packages/pubsweet-client/.gitlab-ci.yml new file mode 100644 index 0000000000000000000000000000000000000000..d1cd29c5d58949f702dca86467eb75664bc29d28 --- /dev/null +++ b/packages/pubsweet-client/.gitlab-ci.yml @@ -0,0 +1,14 @@ +image: pubsweet/pubsweet-test-base + +before_script: + - yarn + +test: + script: + - npm test + coverage: '/^All files\s+\|\s+(\d+.\d+)\s\|.*$/' + +lint: + script: + - npm run lint + diff --git a/packages/pubsweet-client/.lintstagedrc b/packages/pubsweet-client/.lintstagedrc new file mode 100644 index 0000000000000000000000000000000000000000..f8d909b97a21f1943b144709cdfe21ddcb45e267 --- /dev/null +++ b/packages/pubsweet-client/.lintstagedrc @@ -0,0 +1,3 @@ +{ + "*.{js, jsx}": ["prettier --write", "eslint --fix", "git add"] +} diff --git a/packages/pubsweet-client/.prettierrc b/packages/pubsweet-client/.prettierrc new file mode 100644 index 0000000000000000000000000000000000000000..63b7777aac4961f6217197df86d7e2fcc4f98a5e --- /dev/null +++ b/packages/pubsweet-client/.prettierrc @@ -0,0 +1,6 @@ +{ + "singleQuote": true, + "semi": false, + "printWidth": 80, + "trailingComma": "all" +} diff --git a/packages/pubsweet-client/CONTRIBUTING.md b/packages/pubsweet-client/CONTRIBUTING.md new file mode 100644 index 0000000000000000000000000000000000000000..66b3456044b75cf2f3ea98f79a1a7f3877cb5f9d --- /dev/null +++ b/packages/pubsweet-client/CONTRIBUTING.md @@ -0,0 +1,21 @@ +# CONTRIBUTING + +## Branches +We maintain master as the production branch and tag it with release names. If you wish to contribute to PubSweet then you need to make a branch and then issue a pull request following this procedure: +1. create a user account on Coko GitLab : http://gitlab.coko.foundation +2. Clone master with ```git clone git@gitlab.coko.foundation:pubsweet/core.git``` +3. Create a new branch and work off that. Please name the branch which sensibly identifies the feature you are working on. You can push the branch to Coko Gitlab at anytime. + +## Getting your contributions merged +This is a two part process, first ask for comments, then ask for the changes to be merged. +1. Ask for feedback generate a Merge Request (Pull Request) from the gitlab interface but do not assign this request to anyone. You do this from the Gitlab UI on your branch. +2. Look at the feedback and alter your branch as necessary. +3. To merge with master - generate a merge request (Pull Request) and assign to Jure Triglav. You do this from the Gitlab UI on your branch. + +We encourage feedback and discussion from as many people as possible on Merge Requests! + +## Bug reports, feature requests, support questions +This is all done through GitLab using their native issue tracker +1. Visit the master issue tracker for PubSweet (https://gitlab.coko.foundation/pubsweet/core/issues) +2. Add an issue +3. Tag the issue with 'support', 'bug', or 'feature' to identify the nature of your issue \ No newline at end of file diff --git a/packages/pubsweet-client/LICENSE b/packages/pubsweet-client/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..e218890defd2f464caae083d38bc1b29e0d78a45 --- /dev/null +++ b/packages/pubsweet-client/LICENSE @@ -0,0 +1,7 @@ +Copyright (c) 2015 Adam Hyde + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/pubsweet-client/README.md b/packages/pubsweet-client/README.md new file mode 100644 index 0000000000000000000000000000000000000000..7cd88bff0625cc4f834cbb1300f9085daf40f2e1 --- /dev/null +++ b/packages/pubsweet-client/README.md @@ -0,0 +1,8 @@ +# Build status + +[](https://gitlab.coko.foundation/pubsweet/pubsweet-client/builds) + +# Description + +This is the PubSweet client, to be used as a dependency in PubSweet apps, such as: [Editoria](https://gitlab.coko.foundation/editoria/editoria). + diff --git a/packages/pubsweet-client/config/default.js b/packages/pubsweet-client/config/default.js new file mode 100644 index 0000000000000000000000000000000000000000..3e1cd0b18868e4104b84b65b2f3ab6056b573320 --- /dev/null +++ b/packages/pubsweet-client/config/default.js @@ -0,0 +1,5 @@ +module.exports = { + 'pubsweet-client': { + API_ENDPOINT: 'http://localhost:3000/api', + }, +} diff --git a/packages/pubsweet-client/config/test.js b/packages/pubsweet-client/config/test.js new file mode 100644 index 0000000000000000000000000000000000000000..bf905ac797acea67e836c178eda263d5adf93862 --- /dev/null +++ b/packages/pubsweet-client/config/test.js @@ -0,0 +1,11 @@ +module.exports = { + 'pubsweet-client': { + API_ENDPOINT: 'http://example.com', + 'update-subscriber': { + visible: true, + }, + }, + authsome: { + mode: 'fake-mode' + }, +} diff --git a/packages/pubsweet-client/package.json b/packages/pubsweet-client/package.json new file mode 100644 index 0000000000000000000000000000000000000000..f928c59f11011ddc44fb5c944516d921f07bf121 --- /dev/null +++ b/packages/pubsweet-client/package.json @@ -0,0 +1,82 @@ +{ + "name": "pubsweet-client", + "version": "1.0.0", + "main": "src/index.js", + "scripts": { + "compile": "babel -d lib/ src/", + "lint": "eslint --ext js,jsx src test", + "precommit": "lint-staged", + "test": "jest", + "testci": "gitlab-ci-multi-runner exec docker test" + }, + "engines": { + "node": ">=8.6.0", + "npm": ">=5.0.0" + }, + "author": "Collaborative Knowledge Foundation", + "license": "MIT", + "dependencies": { + "authsome": "0.0.9", + "config": "^1.21.0", + "eslint-config-prettier": "^2.6.0", + "event-source-polyfill": "^0.0.10", + "global": "^4.3.1", + "husky": "^0.14.3", + "isomorphic-fetch": "^2.1.1", + "lint-staged": "^4.2.3", + "lodash": "^4.0.0", + "prettier": "^1.7.4", + "prop-types": "^15.5.8", + "pubsweet-component-login": "^0.5.2", + "react": "^15.4.4", + "react-css-themr": "^2.1.2", + "react-redux": "^5.0.2", + "react-router-dom": "^4.2.2", + "react-router-redux": "next", + "redux": "^3.6.0", + "redux-form": "^7.0.3", + "redux-logger": "^3.0.1", + "redux-thunk": "^2.2.0" + }, + "devDependencies": { + "babel-cli": "^6.26.0", + "babel-preset-env": "^1.6.0", + "babel-preset-react": "^6.24.1", + "babel-preset-stage-2": "^6.24.1", + "enzyme": "^2.9.1", + "eslint": "^4.8.0", + "eslint-config-standard": "^10.2.1", + "eslint-plugin-import": "^2.7.0", + "eslint-plugin-node": "^5.2.0", + "eslint-plugin-promise": "^3.5.0", + "eslint-plugin-react": "^7.4.0", + "eslint-plugin-standard": "^3.0.1", + "eventsourcemock": "^1.0.1", + "isomorphic-form-data": "^1.0.0", + "jest": "^21.2.1", + "nock": "^9.0.14", + "react-dom": "^15.6.1", + "react-test-renderer": "^15.6.1", + "redux-mock-store": "^1.3.0" + }, + "peerDependencies": { + "pubsweet-server": "^1.0.0-beta.2" + }, + "repository": { + "type": "git", + "url": "https://gitlab.coko.foundation/pubsweet/pubsweet-client" + }, + "jest": { + "testRegex": "/test/.+test.jsx?$", + "collectCoverage": true, + "collectCoverageFrom": [ + "src/**/*.{js,jsx}" + ], + "globals": { + "window": {} + }, + "transformIgnorePatterns": [ + "<rootDir>/node_modules/(?!pubsweet)" + ] + } +} diff --git a/packages/pubsweet-client/src/actions/collections.js b/packages/pubsweet-client/src/actions/collections.js new file mode 100644 index 0000000000000000000000000000000000000000..2a06e4044450e9c13a98f082aba1c4c4f08c799c --- /dev/null +++ b/packages/pubsweet-client/src/actions/collections.js @@ -0,0 +1,244 @@ +import * as api from '../helpers/api' +import * as T from './types' + +const collectionUrl = (collection, suffix) => { + let url = '/collections' + + if (collection) url += `/${collection.id}` + + if (suffix) url += `/${suffix}` + + return url +} + +function getCollectionsRequest() { + return { + type: T.GET_COLLECTIONS_REQUEST, + } +} + +function getCollectionsFailure(error) { + return { + type: T.GET_COLLECTIONS_FAILURE, + error: error, + } +} + +function getCollectionsSuccess(collections) { + return { + type: T.GET_COLLECTIONS_SUCCESS, + collections: collections, + receivedAt: Date.now(), + } +} + +export function getCollections(options) { + return dispatch => { + dispatch(getCollectionsRequest()) + + let url = collectionUrl() + + if (options && options.fields) { + url += '?fields=' + encodeURIComponent(options.fields.join(',')) + } + + return api + .get(url) + .then( + collections => dispatch(getCollectionsSuccess(collections)), + err => dispatch(getCollectionsFailure(err)), + ) + } +} + +function getCollectionTeamsRequest() { + return { + type: T.GET_COLLECTION_TEAMS_REQUEST, + } +} + +function getCollectionTeamsFailure(error) { + return { + type: T.GET_COLLECTION_TEAMS_FAILURE, + error: error, + } +} + +function getCollectionTeamsSuccess(teams) { + return { + type: T.GET_COLLECTION_TEAMS_SUCCESS, + teams, + receivedAt: Date.now(), + } +} + +export function getCollectionTeams(collection) { + return dispatch => { + dispatch(getCollectionTeamsRequest()) + + let url = collectionUrl(collection, 'teams') + + return api + .get(url) + .then( + teams => dispatch(getCollectionTeamsSuccess(teams)), + err => dispatch(getCollectionTeamsFailure(err)), + ) + } +} + +function createCollectionRequest(collection) { + return { + type: T.CREATE_COLLECTION_REQUEST, + collection: collection, + } +} + +function createCollectionSuccess(collection) { + return { + type: T.CREATE_COLLECTION_SUCCESS, + collection: collection, + } +} + +function createCollectionFailure(collection, error) { + return { + type: T.CREATE_COLLECTION_FAILURE, + isFetching: false, + collection: collection, + error: error, + } +} + +export function createCollection(collection) { + return dispatch => { + dispatch(createCollectionRequest(collection)) + + const url = collectionUrl() + + return api + .create(url, collection) + .then( + collection => dispatch(createCollectionSuccess(collection)), + err => dispatch(createCollectionFailure(collection, err)), + ) + } +} + +function getCollectionRequest(collection) { + return { + type: T.GET_COLLECTION_REQUEST, + collection: collection, + } +} + +function getCollectionSuccess(collection) { + return { + type: T.GET_COLLECTION_SUCCESS, + collection: collection, + receivedAt: Date.now(), + } +} + +function getCollectionFailure(collection, error) { + return { + type: T.GET_COLLECTION_FAILURE, + isFetching: false, + collection: collection, + error: error, + } +} + +export function getCollection(collection) { + return dispatch => { + dispatch(getCollectionRequest(collection)) + + const url = collectionUrl(collection) + + return api + .get(url) + .then( + collection => dispatch(getCollectionSuccess(collection)), + err => dispatch(getCollectionFailure(collection, err)), + ) + } +} + +function updateCollectionRequest(collection) { + return { + type: T.UPDATE_COLLECTION_REQUEST, + collection: collection, + } +} + +function updateCollectionSuccess(collection, update) { + return { + type: T.UPDATE_COLLECTION_SUCCESS, + collection: collection, + update: update, + receivedAt: Date.now(), + } +} + +function updateCollectionFailure(collection, error) { + return { + type: T.UPDATE_COLLECTION_FAILURE, + isFetching: false, + collection: collection, + error: error, + } +} + +export function updateCollection(collection) { + return dispatch => { + dispatch(updateCollectionRequest(collection)) + + const url = collectionUrl(collection) + + return api + .update(url, collection) + .then( + update => dispatch(updateCollectionSuccess(collection, update)), + err => dispatch(updateCollectionFailure(collection, err)), + ) + } +} + +function deleteCollectionRequest(collection) { + return { + type: T.DELETE_COLLECTION_REQUEST, + collection: collection, + update: { deleted: true }, + } +} + +function deleteCollectionSuccess(collection) { + return { + type: T.DELETE_COLLECTION_SUCCESS, + collection: collection, + } +} + +function deleteCollectionFailure(collection, error) { + return { + type: T.DELETE_COLLECTION_FAILURE, + collection: collection, + update: { deleted: undefined }, + error: error, + } +} + +export function deleteCollection(collection) { + return dispatch => { + dispatch(deleteCollectionRequest(collection)) + + const url = collectionUrl(collection) + + return api + .remove(url) + .then( + () => dispatch(deleteCollectionSuccess(collection)), + err => dispatch(deleteCollectionFailure(collection, err)), + ) + } +} diff --git a/packages/pubsweet-client/src/actions/currentUser.js b/packages/pubsweet-client/src/actions/currentUser.js new file mode 100644 index 0000000000000000000000000000000000000000..a3a08b0a2f30ce926b989b1f976c26bfa4494409 --- /dev/null +++ b/packages/pubsweet-client/src/actions/currentUser.js @@ -0,0 +1,33 @@ +import * as api from '../helpers/api' +import * as T from './types' + +function getCurrentUserRequest() { + return { + type: T.GET_CURRENT_USER_REQUEST, + } +} + +function getCurrentUserSuccess(user) { + return { + type: T.GET_CURRENT_USER_SUCCESS, + user, + } +} + +function getCurrentUserFailure(error) { + return { + type: T.GET_CURRENT_USER_FAILURE, + error, + } +} + +export function getCurrentUser() { + return dispatch => { + dispatch(getCurrentUserRequest()) + + return api + .get('/users/authenticate') + .then(user => dispatch(getCurrentUserSuccess(user))) + .catch(err => dispatch(getCurrentUserFailure(err))) + } +} diff --git a/packages/pubsweet-client/src/actions/fileUpload.js b/packages/pubsweet-client/src/actions/fileUpload.js new file mode 100644 index 0000000000000000000000000000000000000000..ee67814de34d550bb8746867443accd2213defca --- /dev/null +++ b/packages/pubsweet-client/src/actions/fileUpload.js @@ -0,0 +1,48 @@ +import request from '../helpers/api' +import * as T from './types' + +function fileUploadRequest() { + return { + type: T.FILE_UPLOAD_REQUEST, + isFetching: true, + } +} + +function fileUploadSuccess(file) { + return { + type: T.FILE_UPLOAD_SUCCESS, + isFetching: false, + file: file, + } +} + +function fileUploadFailure(message) { + return { + type: T.FILE_UPLOAD_FAILURE, + isFetching: false, + error: message, + } +} + +export function fileUpload(file) { + return dispatch => { + dispatch(fileUploadRequest()) + + const data = new FormData() + data.append('file', file) + + let opts = { + method: 'POST', + headers: { + Accept: 'text/plain', // the response is a URL + // TODO: set the Location header of the response instead + }, + body: data, + } + + return request('/upload', opts).then( + file => dispatch(fileUploadSuccess(file)), + err => dispatch(fileUploadFailure(err)), + ) + } +} diff --git a/packages/pubsweet-client/src/actions/fragments.js b/packages/pubsweet-client/src/actions/fragments.js new file mode 100644 index 0000000000000000000000000000000000000000..0f9197be1c6a1590c50336c3fcd233effe358f11 --- /dev/null +++ b/packages/pubsweet-client/src/actions/fragments.js @@ -0,0 +1,211 @@ +import * as api from '../helpers/api' +import * as T from './types' + +export const fragmentUrl = (collection, fragment) => { + let url = '' + if (collection) url += `/collections/${collection.id}` + url += '/fragments' + if (fragment && fragment.id) url += `/${fragment.id}` + + return url +} + +function getFragmentsRequest(collection) { + return { + type: T.GET_FRAGMENTS_REQUEST, + collection: collection, + } +} + +function getFragmentsSuccess(collection, fragments) { + return { + type: T.GET_FRAGMENTS_SUCCESS, + collection: collection, + fragments: fragments, + receivedAt: Date.now(), + } +} + +function getFragmentsFailure(error) { + return { + type: T.GET_FRAGMENTS_FAILURE, + error: error, + } +} + +export function getFragments(collection, options) { + return dispatch => { + dispatch(getFragmentsRequest(collection)) + + let url = fragmentUrl(collection) + + if (options && options.fields) { + url += '?fields=' + encodeURIComponent(options.fields.join(',')) + } + + return api + .get(url) + .then( + fragments => dispatch(getFragmentsSuccess(collection, fragments)), + err => dispatch(getFragmentsFailure(err)), + ) + } +} + +function createFragmentRequest(fragment) { + return { + type: T.CREATE_FRAGMENT_REQUEST, + fragment: fragment, + } +} + +function createFragmentSuccess(collection, fragment) { + return { + type: T.CREATE_FRAGMENT_SUCCESS, + collection: collection, + fragment: fragment, + } +} + +function createFragmentFailure(fragment, error) { + return { + type: T.CREATE_FRAGMENT_FAILURE, + isFetching: false, + fragment: fragment, + error: error, + } +} + +export function createFragment(collection, fragment) { + return dispatch => { + dispatch(createFragmentRequest(fragment)) + + const url = fragmentUrl(collection, fragment) + + return api + .create(url, fragment) + .then( + fragment => dispatch(createFragmentSuccess(collection, fragment)), + err => dispatch(createFragmentFailure(fragment, err)), + ) + } +} + +function getFragmentRequest(fragment) { + return { + type: T.GET_FRAGMENT_REQUEST, + fragment: fragment, + } +} + +function getFragmentSuccess(fragment) { + return { + type: T.GET_FRAGMENT_SUCCESS, + fragment: fragment, + receivedAt: Date.now(), + } +} + +function getFragmentFailure(fragment, error) { + return { + type: T.GET_FRAGMENT_FAILURE, + isFetching: false, + fragment: fragment, + error: error, + } +} + +export function getFragment(collection, fragment) { + return dispatch => { + dispatch(getFragmentRequest(fragment)) + + const url = fragmentUrl(collection, fragment) + + return api + .get(url) + .then( + fragment => dispatch(getFragmentSuccess(fragment)), + err => dispatch(getFragmentFailure(fragment, err)), + ) + } +} + +function updateFragmentRequest(fragment) { + return { + type: T.UPDATE_FRAGMENT_REQUEST, + fragment: fragment, + } +} + +function updateFragmentSuccess(fragment, update) { + return { + type: T.UPDATE_FRAGMENT_SUCCESS, + fragment: fragment, + update: update, + receivedAt: Date.now(), + } +} + +function updateFragmentFailure(fragment, error) { + return { + type: T.UPDATE_FRAGMENT_FAILURE, + isFetching: false, + fragment: fragment, + error: error, + } +} + +export function updateFragment(collection, fragment) { + return dispatch => { + dispatch(updateFragmentRequest(fragment)) + + const url = fragmentUrl(collection, fragment) + + return api + .update(url, fragment) + .then( + update => dispatch(updateFragmentSuccess(fragment, update)), + err => dispatch(updateFragmentFailure(fragment, err)), + ) + } +} + +function deleteFragmentRequest(fragment) { + return { + type: T.DELETE_FRAGMENT_REQUEST, + fragment: fragment, + update: { deleted: true }, + } +} + +function deleteFragmentSuccess(collection, fragment) { + return { + type: T.DELETE_FRAGMENT_SUCCESS, + collection: collection, + fragment: fragment, + } +} + +function deleteFragmentFailure(fragment, error) { + return { + type: T.DELETE_FRAGMENT_FAILURE, + fragment: fragment, + update: { deleted: undefined }, + error: error, + } +} + +export function deleteFragment(collection, fragment) { + return dispatch => { + dispatch(deleteFragmentRequest(fragment)) + + const url = fragmentUrl(collection, fragment) + + return api + .remove(url) + .then( + json => dispatch(deleteFragmentSuccess(collection, fragment)), + err => dispatch(deleteFragmentFailure(fragment, err)), + ) + } +} diff --git a/packages/pubsweet-client/src/actions/index.js b/packages/pubsweet-client/src/actions/index.js new file mode 100644 index 0000000000000000000000000000000000000000..0ad2f8c2a6f287006007fe015dd4a4957ebce461 --- /dev/null +++ b/packages/pubsweet-client/src/actions/index.js @@ -0,0 +1,35 @@ +import { RESET_ERROR_MESSAGE } from './types' + +import * as collections from './collections' +import * as currentUser from './currentUser' +import * as fileUpload from './fileUpload' +import * as fragments from './fragments' +import * as teams from './teams' +import * as users from './users' + +import componentActions from '../components/actions' + +// Resets the currently visible error message. +const resetErrorMessage = () => ({ + type: RESET_ERROR_MESSAGE, +}) + +// Hydrate hydrates the store from a persistent store, the backend. +// It gets collections, fragments and user data (via token). +const hydrate = () => dispatch => + Promise.all([ + dispatch(currentUser.getCurrentUser()), + dispatch(collections.getCollections()), + ]) + +export default { + ...collections, + ...currentUser, + ...fileUpload, + ...fragments, + ...teams, + ...users, + ...componentActions, + hydrate, + resetErrorMessage, +} diff --git a/packages/pubsweet-client/src/actions/teams.js b/packages/pubsweet-client/src/actions/teams.js new file mode 100644 index 0000000000000000000000000000000000000000..741bf172a26fd230d0ed6614d823889fc6dac988 --- /dev/null +++ b/packages/pubsweet-client/src/actions/teams.js @@ -0,0 +1,159 @@ +import * as api from '../helpers/api' +import * as T from './types' + +const teamUrl = team => { + let url = '/teams' + + if (team) url += `/${team.id}` + + return url +} + +function getTeamsRequest() { + return { + type: T.GET_TEAMS_REQUEST, + isFetching: true, + } +} + +function getTeamsSuccess(teams) { + return { + type: T.GET_TEAMS_SUCCESS, + isFetching: false, + teams: teams, + } +} + +function getTeamsFailure(message) { + return { + type: T.GET_TEAMS_FAILURE, + isFetching: false, + message, + } +} + +export function getTeams() { + return dispatch => { + dispatch(getTeamsRequest()) + + return api + .get(teamUrl()) + .then( + teams => dispatch(getTeamsSuccess(teams)), + err => dispatch(getTeamsFailure(err)), + ) + } +} + +function createTeamRequest(team) { + return { + type: T.CREATE_TEAM_REQUEST, + team: team, + } +} + +function createTeamSuccess(team) { + return { + type: T.CREATE_TEAM_SUCCESS, + team: team, + } +} + +function createTeamFailure(team, error) { + return { + type: T.CREATE_TEAM_FAILURE, + isFetching: false, + team: team, + error: error, + } +} + +export function createTeam(team) { + return dispatch => { + dispatch(createTeamRequest(team)) + + const url = teamUrl() + + return api + .create(url, team) + .then( + team => dispatch(createTeamSuccess(team)), + err => dispatch(createTeamFailure(team, err)), + ) + } +} + +function updateTeamRequest(team) { + return { + type: T.UPDATE_TEAM_REQUEST, + team: team, + } +} + +function updateTeamSuccess(team) { + return { + type: T.UPDATE_TEAM_SUCCESS, + team: team, + } +} + +function updateTeamFailure(team, error) { + return { + type: T.UPDATE_TEAM_FAILURE, + isFetching: false, + team: team, + error: error, + } +} + +export function updateTeam(team) { + return dispatch => { + dispatch(updateTeamRequest(team)) + const url = teamUrl(team) + + return api + .update(url, team) + .then( + team => dispatch(updateTeamSuccess(team)), + err => dispatch(updateTeamFailure(team, err)), + ) + } +} + +function deleteTeamRequest(team) { + return { + type: T.DELETE_TEAM_REQUEST, + team: team, + } +} + +function deleteTeamSuccess(team) { + return { + type: T.DELETE_TEAM_SUCCESS, + team: team, + } +} + +function deleteTeamFailure(team, error) { + return { + type: T.DELETE_TEAM_FAILURE, + isFetching: false, + team: team, + error: error, + } +} + +export function deleteTeam(team) { + return dispatch => { + dispatch(deleteTeamRequest(team)) + + const url = teamUrl(team) + + return api + .remove(url) + .then( + team => dispatch(deleteTeamSuccess(team)), + err => dispatch(deleteTeamFailure(team, err)), + ) + } +} diff --git a/packages/pubsweet-client/src/actions/types.js b/packages/pubsweet-client/src/actions/types.js new file mode 100644 index 0000000000000000000000000000000000000000..0ff0ae9f0389cfdf22b44d58889a43b8b50db8d7 --- /dev/null +++ b/packages/pubsweet-client/src/actions/types.js @@ -0,0 +1,98 @@ +// Action types + +export const GET_COLLECTIONS_REQUEST = 'GET_COLLECTIONS_REQUEST' +export const GET_COLLECTIONS_SUCCESS = 'GET_COLLECTIONS_SUCCESS' +export const GET_COLLECTIONS_FAILURE = 'GET_COLLECTIONS_FAILURE' + +export const CREATE_COLLECTION_REQUEST = 'CREATE_COLLECTION_REQUEST' +export const CREATE_COLLECTION_SUCCESS = 'CREATE_COLLECTION_SUCCESS' +export const CREATE_COLLECTION_FAILURE = 'CREATE_COLLECTION_FAILURE' + +export const GET_COLLECTION_REQUEST = 'GET_COLLECTION_REQUEST' +export const GET_COLLECTION_SUCCESS = 'GET_COLLECTION_SUCCESS' +export const GET_COLLECTION_FAILURE = 'GET_COLLECTION_FAILURE' + +export const GET_COLLECTION_TEAMS_REQUEST = 'GET_COLLECTION_TEAMS_REQUEST' +export const GET_COLLECTION_TEAMS_SUCCESS = 'GET_COLLECTION_TEAMS_SUCCESS' +export const GET_COLLECTION_TEAMS_FAILURE = 'GET_COLLECTION_TEAMS_FAILURE' + +export const UPDATE_COLLECTION_REQUEST = 'UPDATE_COLLECTION_REQUEST' +export const UPDATE_COLLECTION_SUCCESS = 'UPDATE_COLLECTION_SUCCESS' +export const UPDATE_COLLECTION_FAILURE = 'UPDATE_COLLECTION_FAILURE' + +export const PATCH_COLLECTION_REQUEST = 'PATCH_COLLECTION_REQUEST' +export const PATCH_COLLECTION_SUCCESS = 'PATCH_COLLECTION_SUCCESS' +export const PATCH_COLLECTION_FAILURE = 'PATCH_COLLECTION_FAILURE' + +export const DELETE_COLLECTION_REQUEST = 'DELETE_COLLECTION_REQUEST' +export const DELETE_COLLECTION_SUCCESS = 'DELETE_COLLECTION_SUCCESS' +export const DELETE_COLLECTION_FAILURE = 'DELETE_COLLECTION_FAILURE' + +export const GET_FRAGMENTS_REQUEST = 'GET_FRAGMENTS_REQUEST' +export const GET_FRAGMENTS_SUCCESS = 'GET_FRAGMENTS_SUCCESS' +export const GET_FRAGMENTS_FAILURE = 'GET_FRAGMENTS_FAILURE' + +export const CREATE_FRAGMENT_REQUEST = 'CREATE_FRAGMENT_REQUEST' +export const CREATE_FRAGMENT_SUCCESS = 'CREATE_FRAGMENT_SUCCESS' +export const CREATE_FRAGMENT_FAILURE = 'CREATE_FRAGMENT_FAILURE' + +export const GET_FRAGMENT_REQUEST = 'GET_FRAGMENT_REQUEST' +export const GET_FRAGMENT_SUCCESS = 'GET_FRAGMENT_SUCCESS' +export const GET_FRAGMENT_FAILURE = 'GET_FRAGMENT_FAILURE' + +export const UPDATE_FRAGMENT_REQUEST = 'UPDATE_FRAGMENT_REQUEST' +export const UPDATE_FRAGMENT_SUCCESS = 'UPDATE_FRAGMENT_SUCCESS' +export const UPDATE_FRAGMENT_FAILURE = 'UPDATE_FRAGMENT_FAILURE' + +export const DELETE_FRAGMENT_REQUEST = 'DELETE_FRAGMENT_REQUEST' +export const DELETE_FRAGMENT_SUCCESS = 'DELETE_FRAGMENT_SUCCESS' +export const DELETE_FRAGMENT_FAILURE = 'DELETE_FRAGMENT_FAILURE' + +export const GET_CURRENT_USER_REQUEST = 'GET_CURRENT_USER_REQUEST' +export const GET_CURRENT_USER_SUCCESS = 'GET_CURRENT_USER_SUCCESS' +export const GET_CURRENT_USER_FAILURE = 'GET_CURRENT_USER_FAILURE' + +export const GET_USER_REQUEST = 'GET_USER_REQUEST' +export const GET_USER_SUCCESS = 'GET_USER_SUCCESS' +export const GET_USER_FAILURE = 'GET_USER_FAILURE' + +export const GET_USERS_REQUEST = 'GET_USERS_REQUEST' +export const GET_USERS_SUCCESS = 'GET_USERS_SUCCESS' +export const GET_USERS_FAILURE = 'GET_USERS_FAILURE' + +export const UPDATE_USER_REQUEST = 'UPDATE_USER_REQUEST' +export const UPDATE_USER_SUCCESS = 'UPDATE_USER_SUCCESS' +export const UPDATE_USER_FAILURE = 'UPDATE_USER_FAILURE' + +export const GET_TEAMS_REQUEST = 'GET_TEAMS_REQUEST' +export const GET_TEAMS_SUCCESS = 'GET_TEAMS_SUCCESS' +export const GET_TEAMS_FAILURE = 'GET_TEAMS_FAILURE' + +export const CREATE_TEAM_REQUEST = 'CREATE_TEAM_REQUEST' +export const CREATE_TEAM_SUCCESS = 'CREATE_TEAM_SUCCESS' +export const CREATE_TEAM_FAILURE = 'CREATE_TEAM_FAILURE' + +export const UPDATE_TEAM_REQUEST = 'UPDATE_TEAM_REQUEST' +export const UPDATE_TEAM_SUCCESS = 'UPDATE_TEAM_SUCCESS' +export const UPDATE_TEAM_FAILURE = 'UPDATE_TEAM_FAILURE' + +export const DELETE_TEAM_REQUEST = 'DELETE_TEAM_REQUEST' +export const DELETE_TEAM_SUCCESS = 'DELETE_TEAM_SUCCESS' +export const DELETE_TEAM_FAILURE = 'DELETE_TEAM_FAILURE' + +export const FILE_UPLOAD_REQUEST = 'FILE_UPLOAD_REQUEST' +export const FILE_UPLOAD_SUCCESS = 'FILE_UPLOAD_SUCCESS' +export const FILE_UPLOAD_FAILURE = 'FILE_UPLOAD_FAILURE' + +export const RESET_ERROR_MESSAGE = 'RESET_ERROR_MESSAGE' +export const HYDRATE = 'HYDRATE' + +// The following actions are implemented elsewhere in pubsweet components + +export const LOGIN_REQUEST = 'LOGIN_REQUEST' +export const LOGIN_SUCCESS = 'LOGIN_SUCCESS' +export const LOGIN_FAILURE = 'LOGIN_FAILURE' + +export const LOGOUT_REQUEST = 'LOGOUT_REQUEST' +export const LOGOUT_SUCCESS = 'LOGOUT_SUCCESS' +export const LOGOUT_FAILURE = 'LOGOUT_FAILURE' diff --git a/packages/pubsweet-client/src/actions/users.js b/packages/pubsweet-client/src/actions/users.js new file mode 100644 index 0000000000000000000000000000000000000000..1c76c0429949f5649ffd55ba68e44fab19f8ad32 --- /dev/null +++ b/packages/pubsweet-client/src/actions/users.js @@ -0,0 +1,112 @@ +import * as api from '../helpers/api' +import * as T from './types' + +function getUsersRequest() { + return { + type: T.GET_USERS_REQUEST, + isFetching: true, + } +} + +function getUsersSuccess(users) { + return { + type: T.GET_USERS_SUCCESS, + isFetching: false, + users: users, + } +} + +function getUsersFailure(message) { + return { + type: T.GET_USERS_FAILURE, + isFetching: false, + message, + } +} + +export function getUsers() { + return dispatch => { + dispatch(getUsersRequest()) + + return api + .get('/users') + .then( + users => dispatch(getUsersSuccess(users.users)), + err => dispatch(getUsersFailure(err)), + ) + } +} + +function getUserRequest(user) { + return { + type: T.GET_USER_REQUEST, + user, + } +} + +function getUserSuccess(user) { + return { + type: T.GET_USER_SUCCESS, + user, + } +} + +function getUserFailure(user, error) { + return { + type: T.GET_USER_FAILURE, + user, + error, + } +} + +export function getUser(user) { + return dispatch => { + dispatch(getUserRequest(user)) + + return api + .get('/users/' + user.id) + .then( + user => dispatch(getUserSuccess(user)), + err => dispatch(getUserFailure(err)), + ) + } +} + +function updateUserRequest(user) { + return { + type: T.UPDATE_USER_REQUEST, + user: user, + isFetching: true, + } +} + +function updateUserSuccess(users) { + return { + type: T.UPDATE_USER_SUCCESS, + isFetching: false, + users: users, + } +} + +function updateUserFailure(message) { + return { + type: T.UPDATE_USER_FAILURE, + isFetching: false, + error: message, + } +} + +export function updateUser(user) { + return dispatch => { + dispatch(updateUserRequest(user)) + + const url = '/users/' + user.id + + return api + .update(url, user) + .then( + user => dispatch(updateUserSuccess(user)), + err => dispatch(updateUserFailure(err)), + ) + } +} diff --git a/packages/pubsweet-client/src/components/AuthenticatedComponent.jsx b/packages/pubsweet-client/src/components/AuthenticatedComponent.jsx new file mode 100644 index 0000000000000000000000000000000000000000..996014060f574e630f1f5ca1812eafc39dd73d81 --- /dev/null +++ b/packages/pubsweet-client/src/components/AuthenticatedComponent.jsx @@ -0,0 +1,53 @@ +import React from 'react' +import { connect } from 'react-redux' +import { withRouter } from 'react-router' +import { push } from 'react-router-redux' +import PropTypes from 'prop-types' + +import actions from '../actions' + +export class AuthenticatedComponent extends React.Component { + componentWillMount() { + this.props.getCurrentUser().then(() => this.checkAuth(this.props)) + } + + componentWillReceiveProps(nextProps) { + this.checkAuth(nextProps) + } + + checkAuth({ isFetching, isAuthenticated }) { + if (!isFetching && !isAuthenticated) { + const redirectAfterLogin = this.props.location.pathname + this.props.pushState(`/login?next=${redirectAfterLogin}`) + } + } + + render() { + return this.props.isAuthenticated ? this.props.children : null + } +} + +AuthenticatedComponent.propTypes = { + children: PropTypes.node, + location: PropTypes.object, + getCurrentUser: PropTypes.func.isRequired, + isFetching: PropTypes.bool, + isAuthenticated: PropTypes.bool, + pushState: PropTypes.func.isRequired, +} + +function mapState(state) { + return { + isFetching: state.currentUser.isFetching, + isAuthenticated: state.currentUser.isAuthenticated, + } +} + +const ConnectedAuthenticatedComponent = withRouter( + connect(mapState, { + getCurrentUser: actions.getCurrentUser, + pushState: push, + })(AuthenticatedComponent), +) + +export default ConnectedAuthenticatedComponent diff --git a/packages/pubsweet-client/src/components/Root.js b/packages/pubsweet-client/src/components/Root.js new file mode 100644 index 0000000000000000000000000000000000000000..f40aafc770a532d7aa17be50218d3d270826d322 --- /dev/null +++ b/packages/pubsweet-client/src/components/Root.js @@ -0,0 +1,22 @@ +import React from 'react' +import { ConnectedRouter } from 'react-router-redux' +import { Provider } from 'react-redux' +import PropTypes from 'prop-types' +import { ThemeProvider } from 'react-css-themr' + +const Root = ({ store, history, routes, theme }) => ( + <Provider store={store}> + <ConnectedRouter history={history}> + <ThemeProvider theme={theme}>{routes}</ThemeProvider> + </ConnectedRouter> + </Provider> +) + +Root.propTypes = { + routes: PropTypes.node.isRequired, + history: PropTypes.object.isRequired, + store: PropTypes.object.isRequired, + theme: PropTypes.object.isRequired, +} + +export default Root diff --git a/packages/pubsweet-client/src/components/UpdateSubscriber.jsx b/packages/pubsweet-client/src/components/UpdateSubscriber.jsx new file mode 100644 index 0000000000000000000000000000000000000000..9f483e24f67f90331404033947f7ff20bff94d9e --- /dev/null +++ b/packages/pubsweet-client/src/components/UpdateSubscriber.jsx @@ -0,0 +1,179 @@ +import { connect } from 'react-redux' +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import config from 'config' +import _ from 'lodash/fp' + +import * as T from '../actions/types' +import 'event-source-polyfill' +import token from '../helpers/token' + +const actionMap = { + 'collection:create': T.CREATE_COLLECTION_SUCCESS, + 'collection:patch': T.UPDATE_COLLECTION_SUCCESS, + 'collection:delete': T.DELETE_COLLECTION_SUCCESS, + 'fragment:create': T.CREATE_FRAGMENT_SUCCESS, + 'fragment:patch': T.UPDATE_FRAGMENT_SUCCESS, + 'fragment:delete': T.DELETE_FRAGMENT_SUCCESS, +} + +export class UpdateSubscriber extends Component { + constructor(props) { + super(props) + + this.state = { + connected: false, + visible: false, + } + + this.listeners = {} + } + + componentDidMount() { + this.subscribe(this.props) + this.setState({ visible: this.visible() }) + } + + componentWillReceiveProps(nextProps) { + if (!this.eventSource) { + this.subscribe(nextProps) + } + } + + componentWillUnmount() { + if (this.eventSource) { + this.removeAllEventListeners() + this.eventSource.close() + // delete this.eventSource + } + } + + visible() { + return _.get('pubsweet-client.update-subscriber.visible', config, false) + } + + // if haven't received a heartbeat for 30 seconds, try to reconnect + monitor() { + if (this.heartbeat) { + window.clearTimeout(this.heartbeat) + } + + this.heartbeat = window.setTimeout(() => { + // console.log('no heartbeat - reconnecting…') + this.subscribe(this.props) + }, 30000) + } + + subscribe(props) { + const { currentUser, handleUpdate } = props + + if (currentUser) { + // ignore if not supported + if (!window.EventSource) return + + // clear any existing heartbeat monitor + if (this.heartbeat) { + // console.log('clearing timeout') + window.clearTimeout(this.heartbeat) + } + + // close any existing connection + if (this.eventSource) { + // console.log('closing') + this.eventSource.close() + } + + // EventSource can't have Authorization header, so have to use query string + const url = '/updates?access_token=' + encodeURIComponent(token()) + + this.eventSource = new window.EventSource(url) + + this.listeners.error = () => { + // console.log('error', this.eventSource.readyState) + + switch (this.eventSource.readyState) { + case 0: // CONNECTING + this.setState({ connected: false }) + break + + case 2: // CLOSED + this.setState({ connected: false }) + this.monitor() // try again in a while if not connected + break + } + } + + this.listeners.close = () => { + // console.log('close') + + this.setState({ connected: false }) + // this.monitor() // don't try to reconnect, as "close" without error is deliberate + } + + this.listeners.message = event => { + // console.log('message', event) + + if (event.origin !== window.location.origin) { + // console.error('Message from unexpected origin', event.origin) + return + } + + const { action, data } = JSON.parse(event.data) + + const actionType = actionMap[action] + + handleUpdate(actionType, data) + } + + this.listeners.open = () => { + // console.log('open') + this.setState({ connected: true }) + } + + // listen for a heartbeat message + this.listeners.pulse = () => { + // console.log('â¤ï¸') + this.monitor() + } + + Object.keys(this.listeners).forEach(key => { + this.eventSource.addEventListener(key, this.listeners[key]) + }) + } + } + + removeAllEventListeners() { + Object.keys(this.listeners).forEach(key => { + this.eventSource.removeEventListener(key, this.listeners[key]) + }) + } + + render() { + const { connected, visible } = this.state + + if (!visible) return null + + return ( + <i + className="fa fa-wifi" + style={{ + color: connected ? 'green' : 'gray', + }} + /> + ) + } +} + +UpdateSubscriber.propTypes = { + currentUser: PropTypes.object, + handleUpdate: PropTypes.func, +} + +export default connect( + state => ({ + currentUser: state.currentUser, + }), + dispatch => ({ + handleUpdate: (type, body) => dispatch({ type, ...body }), + }), +)(UpdateSubscriber) diff --git a/packages/pubsweet-client/src/components/actions.js b/packages/pubsweet-client/src/components/actions.js new file mode 100644 index 0000000000000000000000000000000000000000..2d4b6fb4f7b6cbf8ed8e4a56a1892c23544dd3f2 --- /dev/null +++ b/packages/pubsweet-client/src/components/actions.js @@ -0,0 +1,19 @@ +// const components = require('./components') +const components = PUBSWEET_COMPONENTS + +module.exports = components + .map(component => { + // handle old style component export + const clientDef = component.client || component.frontend + const actions = clientDef && clientDef.actions + + if (actions && typeof actions === 'function') { + return actions + } else if (actions) { + throw new Error("Component's actions are not exported as a function") + } + }) + // filter out falsy values + .filter(Boolean) + .map(actions => actions()) + .reduce((output, actions) => ({ ...output, ...actions }), {}) diff --git a/packages/pubsweet-client/src/components/index.js b/packages/pubsweet-client/src/components/index.js new file mode 100644 index 0000000000000000000000000000000000000000..dfbded0e63572cba580270301ce3373692552bba --- /dev/null +++ b/packages/pubsweet-client/src/components/index.js @@ -0,0 +1,3 @@ +// NOTE: Webpack replaces the string PUBSWEET_COMPONENTS with an array containing a require statement for each client component + +// module.exports = PUBSWEET_COMPONENTS diff --git a/packages/pubsweet-client/src/components/reducers.js b/packages/pubsweet-client/src/components/reducers.js new file mode 100644 index 0000000000000000000000000000000000000000..e43c49009eb5d9aa1e3ee8dc42c10483607290a2 --- /dev/null +++ b/packages/pubsweet-client/src/components/reducers.js @@ -0,0 +1,28 @@ +// const components = require('./components') +const isPlainObject = require('lodash/isPlainObject') +const components = PUBSWEET_COMPONENTS + +module.exports = components + .map(component => { + // handle old style component export + const clientDef = component.client || component.frontend + return clientDef && clientDef.reducers + }) + // filter out falsy values + .filter(Boolean) + .map(reducers => { + if (typeof reducers === 'function') { + const reducer = reducers() + return { + [reducer.default.name]: reducer.default, + } + } else if (isPlainObject(reducers)) { + // component exports an object where each value is a function + return Object.keys(reducers).reduce((output, key) => { + output[key] = reducers[key]() + return output + }, {}) + } + + throw new Error("Component's reducers are exported incorrectly") + }) diff --git a/packages/pubsweet-client/src/helpers/Authorize.jsx b/packages/pubsweet-client/src/helpers/Authorize.jsx new file mode 100644 index 0000000000000000000000000000000000000000..2d239859786a5dc67cbceb6b3674352c94b59ce7 --- /dev/null +++ b/packages/pubsweet-client/src/helpers/Authorize.jsx @@ -0,0 +1,67 @@ +'use strict' + +import React from 'react' +import PropTypes from 'prop-types' +import { connect } from 'react-redux' +import { compose } from 'redux' + +import withAuthsome from './withAuthsome' + +export class Authorize extends React.Component { + constructor(props) { + super(props) + + this.state = { + authorized: false, + } + } + + componentWillMount() { + this.checkAuth(this.props) + } + + componentWillReceiveProps(nextProps) { + this.checkAuth(nextProps) + } + + async checkAuth({ authsome, currentUser, operation, object }) { + try { + const authorized = await authsome.can( + currentUser && currentUser.id, + operation, + object, + ) + this.setState({ + authorized, + }) + } catch (err) { + console.error(err) + } + } + + render() { + return this.state.authorized + ? this.props.children + : this.props.unauthorized || null + } +} + +Authorize.propTypes = { + currentUser: PropTypes.object, + operation: PropTypes.string, + object: PropTypes.object, + children: PropTypes.element, + unauthorized: PropTypes.node, + authsome: PropTypes.object.isRequired, +} + +function mapState(state) { + return { + teams: state.teams, + collections: state.collections, + fragments: state.fragments, + currentUser: state.currentUser.user, + } +} + +export default compose(withAuthsome(), connect(mapState))(Authorize) diff --git a/packages/pubsweet-client/src/helpers/Utils.js b/packages/pubsweet-client/src/helpers/Utils.js new file mode 100644 index 0000000000000000000000000000000000000000..bb9a20f63458935c5c9dfff5646d1f1de8edc932 --- /dev/null +++ b/packages/pubsweet-client/src/helpers/Utils.js @@ -0,0 +1,5 @@ +// NOTE: deprecated - only retained for backwards compatibility + +import { deprecatedFetch } from './api' + +export const fetch = deprecatedFetch diff --git a/packages/pubsweet-client/src/helpers/api.js b/packages/pubsweet-client/src/helpers/api.js new file mode 100644 index 0000000000000000000000000000000000000000..b3e29c4b2cfd7d2576eeb760737ed9c59a533556 --- /dev/null +++ b/packages/pubsweet-client/src/helpers/api.js @@ -0,0 +1,81 @@ +import fetch from 'isomorphic-fetch' +import endpoint from './endpoint' + +// read the authentication token from LocalStorage +import getToken from './token' + +const parse = response => { + if (response.headers.get('content-type').includes('application/json')) { + return response.json() + } + + return response.text() +} + +const request = (url, options = {}) => { + options.headers = options.headers || {} + options.headers['Accept'] = options.headers['Accept'] || 'application/json' + + const token = getToken() + + if (token) { + options.headers['Authorization'] = 'Bearer ' + token + } + + if (!url.match(/^https?:/)) { + url = endpoint + url + } + + return fetch(url, options).then(response => { + if (!response.ok) { + return response.text().then(errorText => { + const error = new Error(response.statusText || response.status) + error.response = errorText + error.statusCode = response.status + throw error + }) + } + + return options.parse === false ? response : parse(response) + }) + // .catch(error => { + // // TODO: handle network errors + // console.error(error) + // }) +} + +// for backwards compatibility +export const deprecatedFetch = (url, options = {}) => { + options.parse = false + return request(url, options) +} + +export const get = url => + request(url, { + method: 'GET', + }) + +export const create = (url, data) => + request(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(data), + }) + +export const update = (url, data, replace = false) => + request(url, { + method: replace ? 'PUT' : 'PATCH', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(data), + }) + +export const remove = url => + request(url, { + method: 'DELETE', + }) + +export default request diff --git a/packages/pubsweet-client/src/helpers/endpoint.js b/packages/pubsweet-client/src/helpers/endpoint.js new file mode 100644 index 0000000000000000000000000000000000000000..84a7b261f64324a184ea4ec52fbf3a7387719a89 --- /dev/null +++ b/packages/pubsweet-client/src/helpers/endpoint.js @@ -0,0 +1,3 @@ +import config from 'config' + +module.exports = config['pubsweet-client'].API_ENDPOINT diff --git a/packages/pubsweet-client/src/helpers/token.js b/packages/pubsweet-client/src/helpers/token.js new file mode 100644 index 0000000000000000000000000000000000000000..0fb7d80d1a57bfd9fc7f8ad819b2ccecf25491c6 --- /dev/null +++ b/packages/pubsweet-client/src/helpers/token.js @@ -0,0 +1,7 @@ +module.exports = () => { + const localStorage = window.localStorage || global.window.localStorage + + if (!localStorage) throw new Error('localstorage is not available') + + return localStorage.getItem('token') +} diff --git a/packages/pubsweet-client/src/helpers/withAuthsome.js b/packages/pubsweet-client/src/helpers/withAuthsome.js new file mode 100644 index 0000000000000000000000000000000000000000..01ab39ee4f3affd6f201aec3ad078177199952e0 --- /dev/null +++ b/packages/pubsweet-client/src/helpers/withAuthsome.js @@ -0,0 +1,36 @@ +import Authsome from 'authsome' +import { connect } from 'react-redux' +import config from 'config' +const mode = require(config.authsome.mode) + +// higher order component to inject authsome into a component +export default function withAuthsome() { + const authsome = new Authsome({...config.authsome, mode}, {}) + + function mapState(state) { + authsome.context = { + // fetch entities from store instead of database + models: { + Collection: { + find: id => + state.collections.find(collection => collection.id === id), + }, + Fragment: { + find: id => state.fragments[id], + }, + Team: { + find: id => state.teams.find(team => team.id === id), + }, + User: { + find: id => { + return state.users.users.find(user => user.id === id) + }, + }, + }, + } + + return { authsome } + } + + return connect(mapState) +} diff --git a/packages/pubsweet-client/src/images/pubsweet-rgb-small.jpg b/packages/pubsweet-client/src/images/pubsweet-rgb-small.jpg new file mode 100644 index 0000000000000000000000000000000000000000..57efdcb962ffac6c6ce60777af38e62d4f872c87 Binary files /dev/null and b/packages/pubsweet-client/src/images/pubsweet-rgb-small.jpg differ diff --git a/packages/pubsweet-client/src/index.js b/packages/pubsweet-client/src/index.js new file mode 100644 index 0000000000000000000000000000000000000000..029662791397fc15fc5e04ccb8b93d2626465768 --- /dev/null +++ b/packages/pubsweet-client/src/index.js @@ -0,0 +1,6 @@ +export { default as configureStore } from './store/configureStore' +export { default as Root } from './components/Root' +export { requireAuthentication } from './components/AuthenticatedComponent' +export { default as actions } from './actions' +export { default as reducers } from './reducers' +export { default as validations } from './validations' diff --git a/packages/pubsweet-client/src/reducers/collections.js b/packages/pubsweet-client/src/reducers/collections.js new file mode 100644 index 0000000000000000000000000000000000000000..25d4fbb61b20ce841ee440bfce21d19312e0011d --- /dev/null +++ b/packages/pubsweet-client/src/reducers/collections.js @@ -0,0 +1,130 @@ +import { + GET_COLLECTIONS_SUCCESS, + GET_COLLECTIONS_FAILURE, + CREATE_COLLECTION_SUCCESS, + GET_COLLECTION_REQUEST, + GET_COLLECTION_SUCCESS, + UPDATE_COLLECTION_SUCCESS, + PATCH_COLLECTION_SUCCESS, + DELETE_COLLECTION_SUCCESS, + GET_FRAGMENTS_SUCCESS, + CREATE_FRAGMENT_SUCCESS, + DELETE_FRAGMENT_SUCCESS, + LOGOUT_SUCCESS, +} from '../actions/types' + +import find from 'lodash/find' +import union from 'lodash/union' +import difference from 'lodash/difference' +import clone from 'lodash/clone' +import findIndex from 'lodash/findIndex' +import without from 'lodash/without' + +export default function(state = [], action) { + const collections = clone(state) + + // TODO: store entities as an object or immutable Map, with the id as the key + function getCollection() { + return find(collections, { id: action.collection.id }) + } + + function getCollectionIndex() { + return findIndex(collections, { id: action.collection.id }) + } + + function addCollection() { + // only add the collection if it hasn't already been added + if (!getCollection()) { + collections.push(action.collection) + } + + return collections + } + + function setCollection() { + const index = getCollectionIndex() + + // NOTE: this is necessary because the collections state is an array + if (index === -1) { + collections.push(action.collection) + } else { + collections[index] = action.collection + } + + return collections + } + + function updateCollection() { + const index = getCollectionIndex() + + collections[index] = { ...collections[index], ...action.update } + + return collections + } + + function deleteCollection() { + const collection = getCollection() + + return without(collections, collection) + } + + function addFragments() { + const collection = getCollection() + + if (collection) { + collection.fragments = union( + collection.fragments, + (action.fragments || [action.fragment]).map(fragment => fragment.id), + ) + } + + return collections + } + + function removeFragments() { + const collection = getCollection() + + if (collection) { + collection.fragments = difference( + collection.fragments, + (action.fragments || [action.fragment]).map(fragment => fragment.id), + ) + } + + return collections + } + + switch (action.type) { + case GET_COLLECTIONS_SUCCESS: + return clone(action.collections) + + case GET_COLLECTIONS_FAILURE: + return [] + + case CREATE_COLLECTION_SUCCESS: + return addCollection() + + case GET_COLLECTION_SUCCESS: + return setCollection() + + case UPDATE_COLLECTION_SUCCESS: + case PATCH_COLLECTION_SUCCESS: + return updateCollection() + + case GET_COLLECTION_REQUEST: + case DELETE_COLLECTION_SUCCESS: + return deleteCollection() + + case DELETE_FRAGMENT_SUCCESS: + return removeFragments() + + case GET_FRAGMENTS_SUCCESS: + case CREATE_FRAGMENT_SUCCESS: + return addFragments() + + case LOGOUT_SUCCESS: + return [] + } + + return state +} diff --git a/packages/pubsweet-client/src/reducers/currentUser.js b/packages/pubsweet-client/src/reducers/currentUser.js new file mode 100644 index 0000000000000000000000000000000000000000..a14eb84953ef93b62cab41a64474a2d4b13ffa3c --- /dev/null +++ b/packages/pubsweet-client/src/reducers/currentUser.js @@ -0,0 +1,48 @@ +import { + GET_CURRENT_USER_REQUEST, + GET_CURRENT_USER_SUCCESS, + GET_CURRENT_USER_FAILURE, + LOGOUT_SUCCESS, +} from '../actions/types' + +export default function( + state = { + isFetching: false, + isAuthenticated: false, + }, + action, +) { + switch (action.type) { + case GET_CURRENT_USER_REQUEST: + return { + ...state, + isFetching: true, + isAuthenticated: false, + } + + case GET_CURRENT_USER_SUCCESS: + return { + ...state, + isFetching: false, + isAuthenticated: true, + user: action.user, + } + + case GET_CURRENT_USER_FAILURE: + return { + ...state, + isFetching: false, + isAuthenticated: false, + } + + case LOGOUT_SUCCESS: + return { + isFetching: false, + isAuthenticated: false, + user: null, + } + + default: + return state + } +} diff --git a/packages/pubsweet-client/src/reducers/error.js b/packages/pubsweet-client/src/reducers/error.js new file mode 100644 index 0000000000000000000000000000000000000000..df299d1c008d4cfc21318731dcbd25b0a142467d --- /dev/null +++ b/packages/pubsweet-client/src/reducers/error.js @@ -0,0 +1,9 @@ +// Updates error message to notify about the failed fetches. +export default function(state = null, { error }) { + if (error && error.message) { + console.error(error) + return error.message + } + + return null +} diff --git a/packages/pubsweet-client/src/reducers/fileUpload.js b/packages/pubsweet-client/src/reducers/fileUpload.js new file mode 100644 index 0000000000000000000000000000000000000000..d5db71dbf81f921f1f9b1178594ee79665217177 --- /dev/null +++ b/packages/pubsweet-client/src/reducers/fileUpload.js @@ -0,0 +1,24 @@ +import { FILE_UPLOAD_REQUEST, FILE_UPLOAD_SUCCESS } from '../actions/types' + +export default function( + state = { + isFetching: false, + }, + action, +) { + switch (action.type) { + case FILE_UPLOAD_SUCCESS: + return { + ...state, + isFetching: false, + file: action.file, + } + case FILE_UPLOAD_REQUEST: + return { + ...state, + isFetching: true, + } + default: + return state + } +} diff --git a/packages/pubsweet-client/src/reducers/fragments.js b/packages/pubsweet-client/src/reducers/fragments.js new file mode 100644 index 0000000000000000000000000000000000000000..4d5cafe9687ded581e3dcaf99212dc0e55fd6f68 --- /dev/null +++ b/packages/pubsweet-client/src/reducers/fragments.js @@ -0,0 +1,80 @@ +import { + GET_FRAGMENTS_SUCCESS, + CREATE_FRAGMENT_REQUEST, + CREATE_FRAGMENT_SUCCESS, + CREATE_FRAGMENT_FAILURE, + GET_FRAGMENT_REQUEST, + GET_FRAGMENT_SUCCESS, + UPDATE_FRAGMENT_REQUEST, + UPDATE_FRAGMENT_SUCCESS, + // UPDATE_FRAGMENT_FAILURE, + DELETE_FRAGMENT_REQUEST, + DELETE_FRAGMENT_FAILURE, + DELETE_FRAGMENT_SUCCESS, + LOGOUT_SUCCESS, +} from '../actions/types' + +import clone from 'lodash/clone' +import unset from 'lodash/unset' + +export default function(state = {}, action) { + const fragments = clone(state) + + function replaceAll() { + unset(fragments, action.collection.fragments) + action.fragments.forEach(fragment => { + fragments[fragment.id] = fragment + }) + return fragments + } + + function setOne() { + fragments[action.fragment.id] = action.fragment + + return fragments + } + + function updateOne() { + const oldfragment = fragments[action.fragment.id] || {} + const update = action.update || action.fragment + + fragments[action.fragment.id] = { ...oldfragment, ...update } + + return fragments + } + + function removeOne() { + unset(fragments, action.fragment.id) + return fragments + } + + // choose the sword, and you will join me + // choose the ball, and you join your mother... in death + // you don't understand my words, but you must choose + // æ‹ ä¸€åˆ€ | Ogami IttÅ + switch (action.type) { + case UPDATE_FRAGMENT_REQUEST: + case UPDATE_FRAGMENT_SUCCESS: + case DELETE_FRAGMENT_REQUEST: + case DELETE_FRAGMENT_FAILURE: + case CREATE_FRAGMENT_SUCCESS: + case CREATE_FRAGMENT_REQUEST: + return updateOne() + + case GET_FRAGMENT_SUCCESS: + return setOne() + + case GET_FRAGMENT_REQUEST: + case CREATE_FRAGMENT_FAILURE: + case DELETE_FRAGMENT_SUCCESS: + return removeOne() + + case GET_FRAGMENTS_SUCCESS: + return replaceAll() + + case LOGOUT_SUCCESS: + return {} + } + + return state +} diff --git a/packages/pubsweet-client/src/reducers/index.js b/packages/pubsweet-client/src/reducers/index.js new file mode 100644 index 0000000000000000000000000000000000000000..25a28908514b239cdd2b359c3d8c7af7e1985e91 --- /dev/null +++ b/packages/pubsweet-client/src/reducers/index.js @@ -0,0 +1,17 @@ +import collections from './collections' +import currentUser from './currentUser' +import error from './error' +import fileUpload from './fileUpload' +import fragments from './fragments' +import users from './users' +import teams from './teams' + +export default { + collections, + currentUser, + error, + fileUpload, + fragments, + teams, + users, +} diff --git a/packages/pubsweet-client/src/reducers/teams.js b/packages/pubsweet-client/src/reducers/teams.js new file mode 100644 index 0000000000000000000000000000000000000000..4055822be4e206d529324210630a70431504727a --- /dev/null +++ b/packages/pubsweet-client/src/reducers/teams.js @@ -0,0 +1,44 @@ +import { + GET_TEAMS_SUCCESS, + CREATE_TEAM_SUCCESS, + UPDATE_TEAM_SUCCESS, + DELETE_TEAM_SUCCESS, + GET_COLLECTION_TEAMS_SUCCESS, + LOGOUT_SUCCESS, +} from '../actions/types' + +import clone from 'lodash/clone' +import findIndex from 'lodash/findIndex' +import differenceBy from 'lodash/differenceBy' +import unionBy from 'lodash/unionBy' + +export default function(state = [], action) { + const teams = clone(state) + + function updateOne() { + const index = findIndex(teams, { id: action.team.id }) + if (index !== -1) { + teams[index] = { ...teams[index], ...action.team } + } else { + teams.push(action.team) + } + + return teams + } + + switch (action.type) { + case CREATE_TEAM_SUCCESS: + case UPDATE_TEAM_SUCCESS: + return updateOne() + case GET_TEAMS_SUCCESS: + return clone(action.teams) + case DELETE_TEAM_SUCCESS: + return differenceBy(state, [action.team], 'id') + case LOGOUT_SUCCESS: + return [] + case GET_COLLECTION_TEAMS_SUCCESS: + return unionBy(state, action.teams, 'id') + } + + return state +} diff --git a/packages/pubsweet-client/src/reducers/users.js b/packages/pubsweet-client/src/reducers/users.js new file mode 100644 index 0000000000000000000000000000000000000000..80d00fb9cae8056e75877c008186364b568d8d03 --- /dev/null +++ b/packages/pubsweet-client/src/reducers/users.js @@ -0,0 +1,72 @@ +import { unionBy } from 'lodash' + +import { + GET_USERS_REQUEST, + GET_USERS_SUCCESS, + GET_USER_SUCCESS, + UPDATE_USER_REQUEST, + UPDATE_USER_SUCCESS, + GET_CURRENT_USER_SUCCESS, + LOGOUT_SUCCESS, +} from '../actions/types' + +// TODO: store users as an object/map instead of an array + +// The users reducer. +export default ( + state = { + isFetching: false, + users: [], + }, + action, +) => { + switch (action.type) { + case GET_USERS_REQUEST: + return { + ...state, + isFetching: true, + } + + case GET_USERS_SUCCESS: + return { + ...state, + isFetching: false, + users: action.users, + } + + case GET_USER_SUCCESS: + return { + ...state, + isFetching: false, + users: unionBy([action.user], state.users, 'id'), + } + + case UPDATE_USER_REQUEST: + return { + ...state, + isFetching: true, + } + + case UPDATE_USER_SUCCESS: + return { + ...state, + isFetching: false, + users: unionBy([action.user], state.users, 'id'), + } + + case LOGOUT_SUCCESS: + return { + isFetching: false, + users: [], + } + + case GET_CURRENT_USER_SUCCESS: + return { + ...state, + users: unionBy([action.user], state.users, 'id'), + } + + default: + return state + } +} diff --git a/packages/pubsweet-client/src/store/configureStore.js b/packages/pubsweet-client/src/store/configureStore.js new file mode 100644 index 0000000000000000000000000000000000000000..9e65befb6c512dfe7d7e63c737d2ada1b5ad4ae1 --- /dev/null +++ b/packages/pubsweet-client/src/store/configureStore.js @@ -0,0 +1,66 @@ +import { createStore, combineReducers, compose, applyMiddleware } from 'redux' +import { routerReducer, routerMiddleware } from 'react-router-redux' + +import thunk from 'redux-thunk' +import { createLogger } from 'redux-logger' +import { reducer as formReducer } from 'redux-form' +import config from 'config' +import reducers from '../reducers' + +require('../components/reducers').forEach(componentReducers => + Object.assign(reducers, componentReducers), +) + +function createConfigureStore(env) { + return function configureStore( + history, + initialState = {}, + customReducers = {}, + customMiddlewares = [], + ) { + const reducer = combineReducers({ + ...reducers, + form: formReducer, + routing: routerReducer, + ...customReducers, + }) + + let logger + if (config['pubsweet-client']['redux-log'] && env !== 'production') { + logger = applyMiddleware(createLogger()) + } + + const middleware = [ + applyMiddleware(thunk), + logger, + applyMiddleware(routerMiddleware(history)), + ...customMiddlewares.map(mw => applyMiddleware(mw)), + ].filter(value => value) + + // https://github.com/zalmoxisus/redux-devtools-extension#12-advanced-store-setup + const composeEnhancers = + window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose + + const store = createStore( + reducer, + initialState, + composeEnhancers(...middleware), + ) + + if (module.hot) { + // Enable Webpack hot module replacement for reducers + module.hot.accept('../reducers', () => { + const nextRootReducer = require('../reducers') + store.replaceReducer(nextRootReducer) + }) + } + + return store + } +} + +if (process.env.NODE_ENV === 'production') { + module.exports = createConfigureStore('production') +} else { + module.exports = createConfigureStore('development') +} diff --git a/packages/pubsweet-client/src/validations.js b/packages/pubsweet-client/src/validations.js new file mode 100644 index 0000000000000000000000000000000000000000..3aaca1f79c46a911c754d4bec8ded771aa4a45f8 --- /dev/null +++ b/packages/pubsweet-client/src/validations.js @@ -0,0 +1,3 @@ +import config from 'config' + +module.exports = require('pubsweet-server/src/models/validations')(config) diff --git a/packages/pubsweet-client/test/.eslintrc b/packages/pubsweet-client/test/.eslintrc new file mode 100644 index 0000000000000000000000000000000000000000..ba085893fda75b0f8c92738825d42acb312b632f --- /dev/null +++ b/packages/pubsweet-client/test/.eslintrc @@ -0,0 +1,7 @@ +{ + "env": { + "node": true, + "jest": true, + "jasmine": true + } +} diff --git a/packages/pubsweet-client/test/actions/collections.test.js b/packages/pubsweet-client/test/actions/collections.test.js new file mode 100644 index 0000000000000000000000000000000000000000..65ed309f625e67324ed9536f69134aa7b0dbea94 --- /dev/null +++ b/packages/pubsweet-client/test/actions/collections.test.js @@ -0,0 +1,120 @@ +global.PUBSWEET_COMPONENTS = [] + +const actions = require('../../src/actions/collections') +const describeAction = require('../helpers/describeAction')(actions) +const T = require('../../src/actions/types') + +describe('Collection actions', () => { + describeAction('getCollections', { + types: { + request: T.GET_COLLECTIONS_REQUEST, + success: T.GET_COLLECTIONS_SUCCESS, + failure: T.GET_COLLECTIONS_FAILURE, + }, + properties: { + request: ['type'], + success: ['type', 'collections', 'receivedAt'], + failure: ['type', 'error'], + }, + }) + + describeAction('getCollectionTeams', { + firstarg: { id: 123 }, + types: { + request: T.GET_COLLECTION_TEAMS_REQUEST, + success: T.GET_COLLECTION_TEAMS_SUCCESS, + failure: T.GET_COLLECTION_TEAMS_FAILURE, + }, + properties: { + request: ['type'], + success: ['type', 'teams', 'receivedAt'], + failure: ['type', 'error'], + }, + }) + + describeAction('createCollection', { + firstarg: { + type: 'testing', + title: 'this is a test collection', + }, + types: { + request: T.CREATE_COLLECTION_REQUEST, + success: T.CREATE_COLLECTION_SUCCESS, + failure: T.CREATE_COLLECTION_FAILURE, + }, + properties: { + request: ['type', 'collection'], + success: ['type', 'collection'], + failure: ['type', 'isFetching', 'collection', 'error'], + }, + }) + + describeAction('getCollection', { + firstarg: { id: 123 }, + types: { + request: T.GET_COLLECTION_REQUEST, + success: T.GET_COLLECTION_SUCCESS, + failure: T.GET_COLLECTION_FAILURE, + }, + properties: { + request: ['type', 'collection'], + success: ['type', 'collection', 'receivedAt'], + failure: ['type', 'isFetching', 'collection', 'error'], + }, + }) + + describeAction('updateCollection', { + firstarg: { id: 123 }, + secondarg: { + type: 'testing', + title: 'this is an updated collection', + }, + types: { + request: T.UPDATE_COLLECTION_REQUEST, + success: T.UPDATE_COLLECTION_SUCCESS, + failure: T.UPDATE_COLLECTION_FAILURE, + }, + properties: { + request: ['type', 'collection'], + success: ['type', 'collection'], + failure: ['type', 'isFetching', 'collection', 'error'], + }, + }) + + // NOTE: enable this once PATCH method is implemented on the server + // describeAction('patchCollection', { + // firstarg: newcol, + // secondarg: { + // type: 'testing', + // title: 'this is a patched collection' + // }, + // types: { + // request: T.PATCH_COLLECTION_REQUEST, + // success: T.PATCH_COLLECTION_SUCCESS, + // failure: T.PATCH_COLLECTION_FAILURE + // }, + // properties: { + // request: ['type', 'collection'], + // success: ['type', 'collection'], + // failure: ['type', 'isFetching', 'collection', 'error'] + // } + // }, (action, data) => { + // expect( + // data.PATCH_COLLECTION_SUCCESS.collection.title + // ).toBe('this is a patched collection') + // }) + + describeAction('deleteCollection', { + firstarg: { id: 123 }, + types: { + request: T.DELETE_COLLECTION_REQUEST, + success: T.DELETE_COLLECTION_SUCCESS, + failure: T.DELETE_COLLECTION_FAILURE, + }, + properties: { + request: ['type', 'collection', 'update'], + success: ['type', 'collection'], + failure: ['type', 'collection', 'update', 'error'], + }, + }) +}) diff --git a/packages/pubsweet-client/test/actions/currentUser.test.js b/packages/pubsweet-client/test/actions/currentUser.test.js new file mode 100644 index 0000000000000000000000000000000000000000..4bfd727a596382b25851eabd42c4fedeaeeee7dc --- /dev/null +++ b/packages/pubsweet-client/test/actions/currentUser.test.js @@ -0,0 +1,20 @@ +global.PUBSWEET_COMPONENTS = [] + +const actions = require('../../src/actions/currentUser') +const describeAction = require('../helpers/describeAction')(actions) +const T = require('../../src/actions/types') + +describe('currentUser actions', () => { + describeAction('getCurrentUser', { + types: { + request: T.GET_CURRENT_USER_REQUEST, + success: T.GET_CURRENT_USER_SUCCESS, + failure: T.GET_CURRENT_USER_FAILURE, + }, + properties: { + request: [], + success: ['user'], + failure: ['error'], + }, + }) +}) diff --git a/packages/pubsweet-client/test/actions/fileUpload.test.js b/packages/pubsweet-client/test/actions/fileUpload.test.js new file mode 100644 index 0000000000000000000000000000000000000000..33b3eaaba8a0dea5d53250cc8ff603fdf6d06828 --- /dev/null +++ b/packages/pubsweet-client/test/actions/fileUpload.test.js @@ -0,0 +1,32 @@ +global.PUBSWEET_COMPONENTS = [] + +require('isomorphic-form-data') +global.FormData.prototype.oldAppend = global.FormData.prototype.append +global.FormData.prototype.append = function(field, value, options) { + // File upload testing hack + if (typeof value === 'string') { + value = fs.createReadStream(value) + } + this.oldAppend(field, value, options) +} + +const fs = require('fs') +const actions = require('../../src/actions/fileUpload') +const describeAction = require('../helpers/describeAction')(actions) +const T = require('../../src/actions/types') + +describe('fileUpload actions', () => { + describeAction('fileUpload', { + firstarg: './test/helpers/mockapp.js', + types: { + request: T.FILE_UPLOAD_REQUEST, + success: T.FILE_UPLOAD_SUCCESS, + failure: T.FILE_UPLOAD_FAILURE, + }, + properties: { + request: ['isFetching'], + success: ['isFetching', 'file'], + failure: ['isFetching', 'error'], + }, + }) +}) diff --git a/packages/pubsweet-client/test/actions/fragments.test.js b/packages/pubsweet-client/test/actions/fragments.test.js new file mode 100644 index 0000000000000000000000000000000000000000..97c50fb914c1e0c96643f5b141130ca7549da857 --- /dev/null +++ b/packages/pubsweet-client/test/actions/fragments.test.js @@ -0,0 +1,105 @@ +global.PUBSWEET_COMPONENTS = [] + +const actions = require('../../src/actions/fragments') +const describeAction = require('../helpers/describeAction')(actions) +const T = require('../../src/actions/types') + +describe('fragments actions', () => { + const mockcol = { id: '123' } + const mockfragment = { id: '1234' } + + describeAction('getFragments', { + firstarg: mockcol, + types: { + request: T.GET_FRAGMENTS_REQUEST, + success: T.GET_FRAGMENTS_SUCCESS, + }, + properties: { + success: ['fragments'], + }, + }) + + // get a list of collections, with the specified fields + describeAction('getFragments', { + firstarg: mockcol, + secondarg: { + fields: ['type', 'presentation'], + }, + types: { + request: T.GET_FRAGMENTS_REQUEST, + success: T.GET_FRAGMENTS_SUCCESS, + failure: T.GET_FRAGMENTS_FAILURE, + }, + properties: { + success: ['fragments'], + }, + }) + + describeAction('createFragment', { + // no collection routes to top level fragment endpoint + firstarg: null, + secondarg: { + title: 'mock fragment', + type: 'some_fragment', + owners: [], + }, + types: { + request: T.CREATE_FRAGMENT_REQUEST, + success: T.CREATE_FRAGMENT_SUCCESS, + failure: T.CREATE_FRAGMENT_FAILURE, + }, + properties: { + success: ['collection', 'fragment'], + failure: ['fragment', 'error'], + }, + }) + + describeAction('getFragment', { + firstarg: mockcol, + secondarg: mockfragment, + types: { + request: T.GET_FRAGMENT_REQUEST, + success: T.GET_FRAGMENT_SUCCESS, + failure: T.GET_FRAGMENT_FAILURE, + }, + properties: { + request: ['fragment'], + success: ['fragment', 'receivedAt'], + failure: ['isFetching', 'fragment', 'error'], + }, + }) + + describeAction('updateFragment', { + firstarg: mockcol, + secondarg: { + id: '1234', + title: 'modded fragment', + type: 'some_fragment', + owners: [], + }, + types: { + request: T.UPDATE_FRAGMENT_REQUEST, + success: T.UPDATE_FRAGMENT_SUCCESS, + failure: T.UPDATE_FRAGMENT_FAILURE, + }, + properties: { + success: ['fragment', 'receivedAt'], + failure: ['fragment', 'error'], + }, + }) + + describeAction('deleteFragment', { + firstarg: mockcol, + secondarg: mockfragment, + types: { + request: T.DELETE_FRAGMENT_REQUEST, + success: T.DELETE_FRAGMENT_SUCCESS, + failure: T.DELETE_FRAGMENT_FAILURE, + }, + properties: { + request: ['fragment', 'update'], + success: ['fragment', 'collection'], + failure: ['fragment', 'error', 'update'], + }, + }) +}) diff --git a/packages/pubsweet-client/test/actions/index.test.js b/packages/pubsweet-client/test/actions/index.test.js new file mode 100644 index 0000000000000000000000000000000000000000..7f0012843384e351bf0d2e30f1c16c4a7de7f02f --- /dev/null +++ b/packages/pubsweet-client/test/actions/index.test.js @@ -0,0 +1,14 @@ +global.PUBSWEET_COMPONENTS = [] + +const { hydrate } = require('../../src/actions').default + +describe('actions index', () => { + describe('hydrate', () => { + it('dispatches two actions', async () => { + const mockDispatch = jest.fn() + await hydrate()(mockDispatch) + + expect(mockDispatch.mock.calls).toHaveLength(2) + }) + }) +}) diff --git a/packages/pubsweet-client/test/actions/teams.test.js b/packages/pubsweet-client/test/actions/teams.test.js new file mode 100644 index 0000000000000000000000000000000000000000..e0206a22ab5a9fea3978916ce885922f871ecc51 --- /dev/null +++ b/packages/pubsweet-client/test/actions/teams.test.js @@ -0,0 +1,85 @@ +global.PUBSWEET_COMPONENTS = [] + +const actions = require('../../src/actions/teams') +const describeAction = require('../helpers/describeAction')(actions) +const T = require('../../src/actions/types') + +describe('teams actions', () => { + describeAction('getTeams', { + types: { + request: T.GET_TEAMS_REQUEST, + success: T.GET_TEAMS_SUCCESS, + failure: T.GET_TEAMS_FAILURE, + }, + properties: { + request: ['isFetching'], + success: ['isFetching', 'teams'], + failure: ['isFetching', 'message'], + }, + }) + + describeAction('createTeam', { + firstarg: { + name: 'My readers', + teamType: { + name: 'Readers', + permissions: 'read', + }, + object: { + kind: 'blogpost', + source: '<blog></blog>', + presentation: '<p></p>', + }, + }, + types: { + request: T.CREATE_TEAM_REQUEST, + success: T.CREATE_TEAM_SUCCESS, + failure: T.CREATE_TEAM_FAILURE, + }, + properties: { + request: ['team'], + success: ['team'], + failure: ['isFetching', 'team', 'error'], + }, + }) + + describeAction('updateTeam', { + firstarg: { id: 234 }, + secondard: { + name: 'My readers', + teamType: { + name: 'Readers', + permissions: 'read', + }, + object: { + kind: 'blogpost', + source: '<blog></blog>', + presentation: '<p></p>', + }, + }, + types: { + request: T.UPDATE_TEAM_REQUEST, + success: T.UPDATE_TEAM_SUCCESS, + failure: T.UPDATE_TEAM_FAILURE, + }, + properties: { + request: ['team'], + success: ['team'], + failure: ['isFetching', 'team', 'error'], + }, + }) + + describeAction('deleteTeam', { + firstarg: { id: 234 }, + types: { + request: T.DELETE_TEAM_REQUEST, + success: T.DELETE_TEAM_SUCCESS, + failure: T.DELETE_TEAM_FAILURE, + }, + properties: { + request: ['team'], + success: ['team'], + failure: ['isFetching', 'team', 'error'], + }, + }) +}) diff --git a/packages/pubsweet-client/test/actions/users.test.js b/packages/pubsweet-client/test/actions/users.test.js new file mode 100644 index 0000000000000000000000000000000000000000..e65136f00971810412cca58c4e0a9e490f45daf5 --- /dev/null +++ b/packages/pubsweet-client/test/actions/users.test.js @@ -0,0 +1,54 @@ +global.PUBSWEET_COMPONENTS = [] + +const actions = require('../../src/actions/users') +const describeAction = require('../helpers/describeAction')(actions) +const T = require('../../src/actions/types') + +describe('users actions', () => { + const user = { + username: 'fakeymcfake', + password: 'correct battery horse staple', + email: 'fakey_mcfake@pseudonymous.com', + id: '57d0fc8e-ece9-47bf-87d3-7935326b0128', + } + + describeAction('getUsers', { + types: { + request: T.GET_USERS_REQUEST, + success: T.GET_USERS_SUCCESS, + failure: T.GET_USERS_FAILURE, + }, + properties: { + success: ['users'], + failure: ['isFetching', 'message'], + }, + }) + + describeAction('getUser', { + firstarg: { id: user.id }, + types: { + request: T.GET_USER_REQUEST, + success: T.GET_USER_SUCCESS, + failure: T.GET_USER_FAILURE, + }, + properties: { + request: ['user'], + success: ['user'], + failure: ['user', 'error'], + }, + }) + + describeAction('updateUser', { + firstarg: user, + secondarg: user, + types: { + request: T.UPDATE_USER_REQUEST, + success: T.UPDATE_USER_SUCCESS, + failure: T.UPDATE_USER_FAILURE, + }, + properties: { + success: ['users'], + failure: ['isFetching', 'error'], + }, + }) +}) diff --git a/packages/pubsweet-client/test/components/AuthenticatedComponent.test.jsx b/packages/pubsweet-client/test/components/AuthenticatedComponent.test.jsx new file mode 100644 index 0000000000000000000000000000000000000000..13bf2a122d0ad9ae0e24551347b111ddf18c9355 --- /dev/null +++ b/packages/pubsweet-client/test/components/AuthenticatedComponent.test.jsx @@ -0,0 +1,58 @@ +import React from 'react' +import { shallow } from 'enzyme' + +global.PUBSWEET_COMPONENTS = [] + +jest.mock('fake-mode', () => false, {virtual: true}) +const { + AuthenticatedComponent, +} = require('../../src/components/AuthenticatedComponent') + +function makeWrapper(props = {}) { + return shallow( + <AuthenticatedComponent + getCurrentUser={() => Promise.resolve()} + pushState={jest.fn()} + location={{}} + {...props} + > + <button /> + </AuthenticatedComponent>, + ) +} + +describe('<AuthenticatedComponent/>', () => { + it('does nothing when fetching', async () => { + const pushState = jest.fn() + const wrapper = makeWrapper({ pushState }) + wrapper.instance().checkAuth({ isFetching: true }) + + expect(wrapper.find('button').length).toBe(0) + expect(pushState).not.toHaveBeenCalled() + }) + + it('redirects to login if not authenticated', async () => { + const pushState = jest.fn() + const wrapper = makeWrapper({ pushState, location: { pathname: 'blah' } }) + wrapper.instance().checkAuth({ isAuthenticated: false }) + + expect(pushState).toHaveBeenCalledWith('/login?next=blah') + }) + + it('calls checkAuth() when props change', () => { + const pushState = jest.fn() + const wrapper = makeWrapper({ pushState, location: { pathname: 'blah' } }) + + expect(pushState).not.toHaveBeenCalled() + + wrapper.setProps({ isAuthenticated: false }) + expect(pushState).toHaveBeenCalledWith('/login?next=blah') + }) + + it('renders children components when authenticated', async () => { + const pushState = jest.fn() + const wrapper = makeWrapper({ pushState, location: { pathname: 'blah' }, isFetching: false, isAuthenticated: true }) + + expect(wrapper.find('button').length).toBe(1) + }) +}) diff --git a/packages/pubsweet-client/test/components/Root.test.jsx b/packages/pubsweet-client/test/components/Root.test.jsx new file mode 100644 index 0000000000000000000000000000000000000000..d53aa3cf91f2ad66ea92e9d00fcca7905e24a679 --- /dev/null +++ b/packages/pubsweet-client/test/components/Root.test.jsx @@ -0,0 +1,37 @@ +import React from 'react' +import { shallow } from 'enzyme' +import { themr } from 'react-css-themr' +import createHistory from 'history/createBrowserHistory' + +global.PUBSWEET_COMPONENTS = [] + +const Root = require('../../src/components/Root').default +const configureStore = require('../../src/store/configureStore') + +const history = createHistory() +const store = configureStore(history, {}) + +const theme = { ThemedComponent: {testClass: 'mappedClassName'} } + +const ThemedComponent = themr('ThemedComponent')(({ theme }) => ( + <div className={theme.testClass}></div> +)) + +function makeWrapper(props = {}) { + return shallow( + <Root + store={store} + history={history} + routes={<ThemedComponent />} + theme={theme} + {...props} + /> + ) +} + +describe('<Root/>', () => { + it('Adds a theme to context', async () => { + const wrapper = makeWrapper({ theme }) + expect(wrapper.html()).toBe('<div class="mappedClassName"></div>') + }) +}) diff --git a/packages/pubsweet-client/test/components/UpdateSubscriber.test.jsx b/packages/pubsweet-client/test/components/UpdateSubscriber.test.jsx new file mode 100644 index 0000000000000000000000000000000000000000..3df25f06c4b10bc2639143846917c10f403be128 --- /dev/null +++ b/packages/pubsweet-client/test/components/UpdateSubscriber.test.jsx @@ -0,0 +1,122 @@ +import React from 'react' +import { shallow } from 'enzyme' +import EventSourceMock, { sources } from 'eventsourcemock' + +import { UpdateSubscriber } from '../../src/components/UpdateSubscriber' + +global.PUBSWEET_COMPONENTS = [] + +function makeWrapper(props = {}) { + const wrapper = shallow( + <UpdateSubscriber currentUser={{}} handleUpdate={jest.fn()} {...props} />, + ) + // did* lifecycle methods don't get automatically called on shallow render + wrapper.instance().componentDidMount() + return wrapper +} + +describe('<UpdateSubscriber/>', () => { + beforeAll(() => { + global.window.localStorage = { + getItem: jest.fn(() => 'tok'), + } + global.window.EventSource = EventSourceMock + }) + + it('is disconnected by default', () => { + const wrapper = makeWrapper() + + expect(wrapper.html()).toContain('color:gray') + }) + + it('is connected after open event', () => { + const wrapper = makeWrapper() + sources['/updates?access_token=tok'].emit('open') + + expect(wrapper.html()).toContain('color:green') + }) + + it('is disconnected after error event', () => { + const wrapper = makeWrapper() + + sources['/updates?access_token=tok'].emit('open') + expect(wrapper.html()).toContain('color:green') + + sources['/updates?access_token=tok'].readyState = 0 + sources['/updates?access_token=tok'].emit('error') + wrapper.update() + expect(wrapper.html()).toContain('color:gray') + }) + + it('is disconnected after close event', () => { + const wrapper = makeWrapper() + + sources['/updates?access_token=tok'].emit('open') + expect(wrapper.html()).toContain('color:green') + + sources['/updates?access_token=tok'].emit('close') + wrapper.update() + expect(wrapper.html()).toContain('color:gray') + }) + + it('calls handleUpdate on message event', () => { + const handleUpdate = jest.fn() + makeWrapper({ handleUpdate }) + + sources['/updates?access_token=tok'].emit('message', { + origin: 'null', + data: '{"action":"collection:create", "data":{"stuff":42}}', + }) + expect(handleUpdate).toHaveBeenCalledWith('CREATE_COLLECTION_SUCCESS', { + stuff: 42, + }) + }) + + // TODO enable this test once PR is merged + // https://github.com/gcedo/eventsourcemock/pull/1 + it.skip('unregisters listeners on unmount', () => { + const handleUpdate = jest.fn() + const wrapper = makeWrapper({ handleUpdate }) + wrapper.instance().componentWillUnmount() + + sources['/updates?access_token=tok'].emit('message', { + origin: 'null', + data: '{}', + }) + expect(handleUpdate).not.toHaveBeenCalled() + }) + + it('connects on prop change once user is provided', () => { + const wrapper = makeWrapper({ currentUser: null }) + + sources['/updates?access_token=tok'].emit('open') + expect(wrapper.html()).toContain('color:gray') + + wrapper.setProps({ currentUser: {} }).update() + sources['/updates?access_token=tok'].emit('open') + expect(wrapper.html()).toContain('color:green') + }) + + it('reconnects after timeout if no pulse', () => { + jest.useFakeTimers() + + const wrapper = makeWrapper() + sources['/updates?access_token=tok'].emit('open') + + const instance = wrapper.instance() + jest.spyOn(instance, 'subscribe') + + sources['/updates?access_token=tok'].emit('pulse') + jest.runTimersToTime(20000) + expect(instance.subscribe).not.toHaveBeenCalled() + + sources['/updates?access_token=tok'].emit('pulse') + jest.runTimersToTime(20000) + expect(instance.subscribe).not.toHaveBeenCalled() + + jest.runTimersToTime(20000) + expect(instance.subscribe).toHaveBeenCalled() + + jest.useRealTimers() + }) +}) diff --git a/packages/pubsweet-client/test/components/actions.test.js b/packages/pubsweet-client/test/components/actions.test.js new file mode 100644 index 0000000000000000000000000000000000000000..97640d5ddc79e7a1bf3525824a534c986f0a3f9c --- /dev/null +++ b/packages/pubsweet-client/test/components/actions.test.js @@ -0,0 +1,41 @@ +describe('component actions combiner', () => { + afterEach(() => jest.resetModules()) + + it('merges actions into one object', () => { + global.PUBSWEET_COMPONENTS = [ + { + client: { + actions: () => ({ cowSay: 'moo', dogSay: 'woof' }), + }, + }, + { + frontend: { + actions: () => ({ squirrelEat: 'nuts' }), + }, + }, + { + backend: "don't care", + }, + ] + const actions = require('../../src/components/actions') + expect(actions).toEqual({ + cowSay: 'moo', + dogSay: 'woof', + squirrelEat: 'nuts', + }) + }) + + it('throws if actions is exported incorrectly', () => { + global.PUBSWEET_COMPONENTS = [ + { + client: { + actions: [() => 'wrong', () => 'export'], + }, + }, + ] + + expect(() => { + require('../../src/components/actions') + }).toThrow() + }) +}) diff --git a/packages/pubsweet-client/test/components/reducers.test.js b/packages/pubsweet-client/test/components/reducers.test.js new file mode 100644 index 0000000000000000000000000000000000000000..a5c27a9323126d070b3a04f831dcc35f5233fddb --- /dev/null +++ b/packages/pubsweet-client/test/components/reducers.test.js @@ -0,0 +1,47 @@ +describe('component actions combiner', () => { + afterEach(() => jest.resetModules()) + + it('merges actions into one object', () => { + global.PUBSWEET_COMPONENTS = [ + { + client: { + reducers: () => ({ default: { name: 'handleCows' } }), + }, + }, + { + frontend: { + reducers: () => ({ default: { name: 'handleDogs' } }), + }, + }, + { + client: { + reducers: { + handleDoors: () => 'I am reducer', + }, + }, + }, + { + backend: "don't care", + }, + ] + const reducers = require('../../src/components/reducers') + expect(reducers).toEqual([ + { handleCows: { name: 'handleCows' } }, + { handleDogs: { name: 'handleDogs' } }, + { handleDoors: 'I am reducer' }, + ]) + }) + + it('throws if reducers exported incorrectly', () => { + global.PUBSWEET_COMPONENTS = [ + { + client: { + reducers: [() => 'wrong', () => 'export'], + }, + }, + ] + expect(() => { + require('../../src/components/reducers') + }).toThrow() + }) +}) diff --git a/packages/pubsweet-client/test/helpers/Authorize.test.jsx b/packages/pubsweet-client/test/helpers/Authorize.test.jsx new file mode 100644 index 0000000000000000000000000000000000000000..e02eacee80985916fb8937b0beda995a0dee738d --- /dev/null +++ b/packages/pubsweet-client/test/helpers/Authorize.test.jsx @@ -0,0 +1,87 @@ +import React from 'react' +import { shallow } from 'enzyme' +import { Authorize } from '../../src/helpers/Authorize' +jest.mock('fake-mode', () => false, {virtual: true}) + +global.PUBSWEET_COMPONENTS = [] + +function makeWrapper(props = {}) { + return shallow( + <Authorize currentUser={{ id: 'user1' }} {...props}> + <div /> + </Authorize>, + ) +} + +describe('<Authorize/>', () => { + let resolveMode + let rejectMode + let modePromise + let mode + let authsome + + beforeEach(() => { + modePromise = new Promise((resolve, reject) => { + resolveMode = resolve + rejectMode = reject + }) + mode = jest.fn(() => modePromise) + authsome = { can: mode } + }) + + it('is empty when not authorized', async () => { + const wrapper = makeWrapper({ authsome }) + + // mode is called synchronously but returns asynchronously + expect(mode).toHaveBeenCalled() + + resolveMode(false) + + // wait for mode promise to resolve before asserting on content + await modePromise + + expect(wrapper.type()).toBe(null) + }) + + it('optionally shows alternative content when not authorized', async () => { + const wrapper = makeWrapper({ authsome, unauthorized: <span /> }) + + resolveMode(false) + await modePromise + expect(wrapper.type()).toBe('span') + }) + + it('is empty when authsome throws', async () => { + const wrapper = makeWrapper({ authsome }) + jest.spyOn(console, 'error').mockImplementation(jest.fn()) + + rejectMode(new Error('Authorize test error')) + + try { + await modePromise + } catch (err) { + expect(wrapper.type()).toBe(null) + expect(console.error).toHaveBeenCalled() + } + + expect.hasAssertions() + }) + + it('renders children when authorized', async () => { + const wrapper = makeWrapper({ authsome }) + + resolveMode(true) + await modePromise + expect(wrapper.type()).toBe('div') + }) + + it('rechecks auth when props change', () => { + const wrapper = makeWrapper({ authsome }) + + expect(mode).toHaveBeenCalled() + mode.mockClear() + + wrapper.setProps({ authsome, currentUser: { id: 'user2' } }) + expect(mode).toHaveBeenCalled() + }) +}) diff --git a/packages/pubsweet-client/test/helpers/api.test.js b/packages/pubsweet-client/test/helpers/api.test.js new file mode 100644 index 0000000000000000000000000000000000000000..dd1d4ed6576f4894df784bdf57d8de1db6bf22ec --- /dev/null +++ b/packages/pubsweet-client/test/helpers/api.test.js @@ -0,0 +1,118 @@ +import nock from 'nock' +import endpoint from '../../src/helpers/endpoint' + +// must be require, not import, due to mocking global above +const api = require('../../src/helpers/api') + +describe('API helper', () => { + beforeAll(() => { + global.window.localStorage = { + getItem: jest.fn(() => 'tok123'), + } + }) + + it('makes a GET request', async () => { + nock(endpoint) + .get('/thing') + .reply(200, 'A thing', { 'content-type': 'text/plain' }) + + const actual = await api.get('/thing') + expect(actual).toBe('A thing') + }) + + it('makes a POST request', async () => { + nock(endpoint) + .post('/thing', { + some: 'data', + }) + .reply(200, 'A new thing', { 'content-type': 'text/plain' }) + + const actual = await api.create('/thing', { some: 'data' }) + expect(actual).toBe('A new thing') + }) + + it('makes a PATCH request', async () => { + nock(endpoint) + .patch('/thing/1', { + some: 'data', + }) + .reply(200, 'A partially updated thing', { 'content-type': 'text/plain' }) + + const actual = await api.update('/thing/1', { some: 'data' }) + expect(actual).toBe('A partially updated thing') + }) + + it('makes a PUT request', async () => { + nock(endpoint) + .put('/thing/1', { + some: 'data', + }) + .reply(200, 'An updated thing', { 'content-type': 'text/plain' }) + + const actual = await api.update('/thing/1', { some: 'data' }, true) + expect(actual).toBe('An updated thing') + }) + + it('makes a DELETE request', async () => { + nock(endpoint) + .delete('/thing/1') + .reply(200, 'No thing', { 'content-type': 'text/plain' }) + + const actual = await api.remove('/thing/1') + expect(actual).toBe('No thing') + }) + + it('automatically parses JSON response', async () => { + const expected = { oh: 'yeah' } + nock(endpoint) + .get('/thing') + .reply(200, expected, { 'content-type': 'application/json' }) + + const actual = await api.get('/thing') + expect(actual).toEqual(expected) + }) + + it('includes token in header', async () => { + nock(endpoint, { + reqheaders: { + authorization: 'Bearer tok123', + }, + }) + .get('/thing') + .reply(200, 'OK', { 'content-type': '' }) + + const actual = await api.get('/thing') + expect(actual).toEqual('OK') + }) + + it('wraps HTTP errors', async () => { + nock(endpoint) + .get('/thing') + .reply(500, 'Yikes!', { 'content-type': '' }) + + try { + await api.get('/thing') + } catch (e) { + expect(e.message).toBe('Internal Server Error') + expect(e.response).toBe('Yikes!') + expect(e.statusCode).toBe(500) + } + expect.hasAssertions() + }) + + it('optionally returns raw response', async () => { + nock(endpoint) + .get('/thing') + .reply(204) + + const response = await api.default('/thing', { + method: 'GET', + parse: false, + }) + + expect(response).toMatchObject({ + ok: true, + statusText: 'No Content', + }) + }) +}) diff --git a/packages/pubsweet-client/test/helpers/describeAction.js b/packages/pubsweet-client/test/helpers/describeAction.js new file mode 100644 index 0000000000000000000000000000000000000000..4d6222d18f3291de6eb0788ad7b2f0e9650e12c3 --- /dev/null +++ b/packages/pubsweet-client/test/helpers/describeAction.js @@ -0,0 +1,128 @@ +const allactions = require('../../src/actions').default +const api = require('../../src/helpers/api') + +const mockGetState = () => { + return { + currentUser: {}, + } +} + +function mockApi(succeed = true) { + const implementation = () => + succeed ? Promise.resolve({}) : Promise.reject(new Error({})) + Object.keys(api) + .filter(method => typeof api[method] === 'function') + .forEach(method => + jest.spyOn(api, method).mockImplementation(implementation), + ) +} + +// custom Jest matcher +expect.extend({ + toHaveProperties(object, expectedKeys) { + const actualKeys = Object.keys(object) + const pass = expectedKeys.every(key => actualKeys.includes(key)) + return { + message: `Expected object ${pass + ? 'not to' + : 'to'} have properties: ${expectedKeys.join(', ')}`, + pass, + } + }, +}) + +const describeAction = actions => (key, opts) => { + describe(key, () => { + const actionCreator = actions[key] + + beforeEach(mockApi) + + afterEach(() => jest.restoreAllMocks()) + + it('is exported from the file', () => { + expect(actions).toHaveProperty(key) + }) + + it('is exported in the all actions object', () => { + expect(allactions).toHaveProperty(key) + }) + + it('returns a fetcher function', () => { + const thunk = actionCreator(() => {}, mockGetState) + expect(typeof thunk).toBe('function') + }) + + it('returns a promise from the fetcher function', () => { + const thunk = actionCreator(opts.firstarg, opts.secondarg) + const returned = thunk(() => {}, mockGetState) + expect(typeof returned.then).toBe('function') + }) + + it('dispatches an action object with a type property', () => { + const actions = [] + const thunk = actionCreator(opts.firstarg, opts.secondarg) + thunk(action => actions.push(action), mockGetState) + expect(actions).toHaveLength(1) + expect(actions[0]).toHaveProperty('type') + }) + + if (opts.types.request) { + const properties = opts.properties.request + const propmsg = properties ? `with [${properties.join(', ')}] ` : '' + + it(`dispatches ${key}Request ${propmsg}immediately`, () => { + const actions = [] + const thunk = actionCreator(opts.firstarg, opts.secondarg) + thunk(action => actions.push(action), mockGetState) + + const firstAction = actions[0] + expect(firstAction).toBeTruthy() + expect(firstAction.type).toBe(opts.types.request) + if (properties) { + expect(firstAction).toHaveProperties(properties) + } + }) + } + + if (opts.types.success) { + const properties = opts.properties.success + const propmsg = properties ? `with [${properties.join(', ')}] ` : '' + + it(`dispatches ${key}Success ${propmsg}on successful response`, async () => { + const actions = [] + const thunk = actionCreator(opts.firstarg, opts.secondarg) + await thunk(action => actions.push(action), mockGetState) + + const secondAction = actions[1] + expect(secondAction).toBeTruthy() + expect(secondAction.type).toBe(opts.types.success) + if (properties) { + expect(secondAction).toHaveProperties(properties) + } + }) + } + + if (opts.types.failure) { + const properties = opts.properties.failure + const propmsg = properties ? `with [${properties.join(', ')}] ` : '' + + it(`dispatches ${key}Failure ${propmsg}on failed response`, async () => { + // make API reject every request + mockApi(false) + + const actions = [] + const thunk = actionCreator(opts.firstarg, opts.secondarg) + await thunk(action => actions.push(action), mockGetState) + + const secondAction = actions[1] + expect(secondAction).toBeTruthy() + expect(secondAction.type).toBe(opts.types.failure) + if (properties) { + expect(secondAction).toHaveProperties(properties) + } + }) + } + }) +} + +module.exports = describeAction diff --git a/packages/pubsweet-client/test/helpers/withAuthsome.test.js b/packages/pubsweet-client/test/helpers/withAuthsome.test.js new file mode 100644 index 0000000000000000000000000000000000000000..ade5c259180f166f4fa66a5aff620a1b94607f3f --- /dev/null +++ b/packages/pubsweet-client/test/helpers/withAuthsome.test.js @@ -0,0 +1,37 @@ +import React from 'react' +import { shallow } from 'enzyme' +import configureStore from 'redux-mock-store' +import Authsome from 'authsome' + +import withAuthsome from '../../src/helpers/withAuthsome' +jest.mock('fake-mode', () => false, {virtual: true}) + +describe('withAuthsome higher order component', () => { + const createStore = configureStore() + + it('injects authsome instance as prop', () => { + const store = createStore() + const Component = withAuthsome()(() => null) + const wrapper = shallow(<Component store={store} />) + + const authsome = wrapper.prop('authsome') + expect(authsome).toBeInstanceOf(Authsome) + }) + + it('reads values from store', () => { + const user1 = { id: 1, admin: true } + const user2 = { id: 2 } + const store = createStore({ + users: { + users: [user1, user2], + }, + }) + const Component = withAuthsome()(() => null) + const wrapper = shallow(<Component store={store} />) + + const { context } = wrapper.prop('authsome') + expect(context.models.User.find(1)).toEqual(user1) + expect(context.models.User.find(2)).toEqual(user2) + expect(context.models.User.find(3)).toBeUndefined() + }) +}) diff --git a/packages/pubsweet-client/test/reducers/collections.test.js b/packages/pubsweet-client/test/reducers/collections.test.js new file mode 100644 index 0000000000000000000000000000000000000000..0ff025c93b75bc726e37be2102e0e8c236d2fdfb --- /dev/null +++ b/packages/pubsweet-client/test/reducers/collections.test.js @@ -0,0 +1,116 @@ +const allReducers = require('../../src/reducers').default +const reducer = require('../../src/reducers/collections').default + +const T = require('../../src/actions/types') + +describe('collections reducers', () => { + it('is exported in the all reducers object', () => { + expect(allReducers.collections).toBe(reducer) + }) + + const mockCollection = { id: '123' } + const mockFragment = { name: 'mock fragment', id: '1234' } + const mockCollectionWithFragment = { + ...mockCollection, + fragments: [mockFragment.id], + } + + it('getCollections success', () => { + const actual = reducer([mockCollection], { + type: T.GET_COLLECTIONS_SUCCESS, + collections: [mockCollection], + }) + expect(actual).toEqual([mockCollection]) + }) + + it('getCollections failure', () => { + const actual = reducer(undefined, { + type: T.GET_COLLECTIONS_FAILURE, + }) + expect(actual).toEqual([]) + }) + + it('getCollection request', () => { + const actual = reducer([mockCollection], { + type: T.GET_COLLECTION_REQUEST, + collection: mockCollection, + }) + expect(actual).toEqual([]) + }) + + it('getCollection success adds collection to store', () => { + const actual = reducer([], { + type: T.GET_COLLECTION_SUCCESS, + collection: mockCollection, + }) + expect(actual).toEqual([mockCollection]) + }) + + it('getCollection success updates collection in store', () => { + const actual = reducer([mockCollection], { + type: T.GET_COLLECTION_SUCCESS, + collection: mockCollectionWithFragment, + }) + expect(actual).toEqual([mockCollectionWithFragment]) + }) + + it('createCollection success', () => { + const actual = reducer(['dummy'], { + type: T.CREATE_COLLECTION_SUCCESS, + collection: mockCollection, + }) + expect(actual).toEqual(['dummy', mockCollection]) + }) + + it('createCollection success ignores duplicate', () => { + const actual = reducer([mockCollection], { + type: T.CREATE_COLLECTION_SUCCESS, + collection: { ...mockCollection, same: 'but different' }, + }) + expect(actual).toEqual([mockCollection]) + }) + + it('updateCollection success', () => { + const actual = reducer(['dummy', mockCollection], { + type: T.UPDATE_COLLECTION_SUCCESS, + collection: mockCollection, + update: { + some: 'value', + }, + }) + expect(actual).toEqual(['dummy', { ...mockCollection, some: 'value' }]) + }) + + it('addFragments success', () => { + const actual = reducer([mockCollection], { + type: T.CREATE_FRAGMENT_SUCCESS, + collection: mockCollection, + fragment: mockFragment, + }) + expect(actual).toEqual([mockCollectionWithFragment]) + }) + + it('removeFragments success', () => { + const actual = reducer([mockCollectionWithFragment], { + type: T.DELETE_FRAGMENT_SUCCESS, + collection: mockCollectionWithFragment, + fragment: mockFragment, + }) + expect(actual).toEqual([mockCollectionWithFragment]) + }) + + it('logout success', () => { + const actual = reducer([mockCollectionWithFragment], { + type: T.LOGOUT_SUCCESS, + }) + expect(actual).toEqual([]) + }) + + it('returns same state for unrecognised action', () => { + const state = [] + const actual = reducer(state, { + type: 'something else', + }) + expect(actual).toBe(state) + }) +}) diff --git a/packages/pubsweet-client/test/reducers/currentUser.test.js b/packages/pubsweet-client/test/reducers/currentUser.test.js new file mode 100644 index 0000000000000000000000000000000000000000..de55c028c7faf919ebc2a7ee6b3d95d7a82845bc --- /dev/null +++ b/packages/pubsweet-client/test/reducers/currentUser.test.js @@ -0,0 +1,73 @@ +const allReducers = require('../../src/reducers').default +const reducer = require('../../src/reducers/currentUser').default + +const T = require('../../src/actions/types') + +describe('currentUser reducers', () => { + it('is exported in the all reducers object', () => { + expect(allReducers.currentUser).toBe(reducer) + }) + + const mockuser = { + name: 'jo johnson', + } + + it('currentUser success', () => { + const actual = reducer( + {}, + { + type: T.GET_CURRENT_USER_SUCCESS, + user: mockuser, + }, + ) + expect(actual).toEqual({ + isFetching: false, + isAuthenticated: true, + user: mockuser, + }) + }) + + it('currentUser failure', () => { + const actual = reducer( + {}, + { + type: T.GET_CURRENT_USER_FAILURE, + }, + ) + expect(actual).toEqual({ isFetching: false, isAuthenticated: false }) + }) + + it('currentUser request', () => { + const actual = reducer( + {}, + { + type: T.GET_CURRENT_USER_REQUEST, + }, + ) + expect(actual).toEqual({ isFetching: true, isAuthenticated: false }) + }) + + it('logout success', () => { + const actual = reducer( + { + user: mockuser, + }, + { + type: T.LOGOUT_SUCCESS, + }, + ) + expect(actual).toEqual({ + isFetching: false, + isAuthenticated: false, + user: null, + }) + }) + + it('returns same state for unrecognised action', () => { + const state = {} + const actual = reducer(state, { + type: 'something else', + }) + expect(actual).toBe(state) + }) +}) diff --git a/packages/pubsweet-client/test/reducers/error.test.js b/packages/pubsweet-client/test/reducers/error.test.js new file mode 100644 index 0000000000000000000000000000000000000000..ad2fc75f496f0ba936928fdbb6ae15eaed2a63a4 --- /dev/null +++ b/packages/pubsweet-client/test/reducers/error.test.js @@ -0,0 +1,22 @@ +const allReducers = require('../../src/reducers').default +const reducer = require('../../src/reducers/error').default + +describe('error reducers', () => { + it('is exported in the all reducers object', () => { + expect(allReducers.error).toBe(reducer) + }) + + describe('reducer error handler', () => { + it("doesn't do anything if there's no error", () => { + expect(reducer(null, { error: null })).toBeNull() + }) + + it("returns the error message if there's an error", () => { + jest.spyOn(console, 'error').mockImplementation(jest.fn()) + const error = new Error('this is a fake error') + const action = { error } + expect(reducer(null, action)).toBe(error.message) + expect(console.error.mock.calls[0][0]).toBe(error) + }) + }) +}) diff --git a/packages/pubsweet-client/test/reducers/fileUpload.test.js b/packages/pubsweet-client/test/reducers/fileUpload.test.js new file mode 100644 index 0000000000000000000000000000000000000000..4e0a014fe82e3a7b6c35580fe828332e2386f6a0 --- /dev/null +++ b/packages/pubsweet-client/test/reducers/fileUpload.test.js @@ -0,0 +1,36 @@ +const allReducers = require('../../src/reducers').default +const reducer = require('../../src/reducers/fileUpload').default + +const T = require('../../src/actions/types') + +describe('fileUpload reducers', () => { + it('is exported in the all reducers object', () => { + expect(allReducers.fileUpload).toBe(reducer) + }) + + it('fileUpload success', () => { + const actual = reducer(undefined, { + type: T.FILE_UPLOAD_SUCCESS, + file: 'somefile', + }) + expect(actual).toEqual({ + isFetching: false, + file: 'somefile', + }) + }) + + it('fileUpload request', () => { + const actual = reducer(undefined, { + type: T.FILE_UPLOAD_REQUEST, + }) + expect(actual).toEqual({ isFetching: true }) + }) + + it('returns same state for unrecognised action', () => { + const state = {} + const actual = reducer(state, { + type: 'something else', + }) + expect(actual).toBe(state) + }) +}) diff --git a/packages/pubsweet-client/test/reducers/fragments.test.js b/packages/pubsweet-client/test/reducers/fragments.test.js new file mode 100644 index 0000000000000000000000000000000000000000..6a51433adf76b231cb5eba7c1337c0a93ca0a03e --- /dev/null +++ b/packages/pubsweet-client/test/reducers/fragments.test.js @@ -0,0 +1,97 @@ +const allReducers = require('../../src/reducers').default +const reducer = require('../../src/reducers/fragments').default + +const T = require('../../src/actions/types') + +const clone = require('lodash/clone') + +describe('fragments reducers', () => { + it('is exported in the all reducers object', () => { + expect(allReducers.fragments).toBe(reducer) + }) + + const mockcol = { id: '123' } + mockcol.fragments = [] + + const mockfrag = { + title: 'mock fragment', + type: 'some_fragment', + owners: [], + } + const mockstate = {} + mockstate[mockfrag.id] = mockfrag + + const mockfragmod = { + title: 'modded fragment', + type: 'some_fragment', + owners: [], + } + const mockstatemod = {} + mockstatemod[mockfrag.id] = mockfragmod + + const colwithfrag = clone(mockcol) + colwithfrag.fragments = [mockfrag] + + it('getOne request', () => { + const actual = reducer(mockstate, { + type: T.GET_FRAGMENT_REQUEST, + collection: colwithfrag, + fragment: mockfragmod, + }) + expect(actual).toEqual({}) + }) + + it('getOne success', () => { + const actual = reducer( + {}, + { + type: T.GET_FRAGMENT_SUCCESS, + collection: colwithfrag, + fragment: mockfragmod, + }, + ) + expect(actual).toEqual(mockstatemod) + }) + + it('updateOne success', () => { + const actual = reducer(mockstate, { + type: T.UPDATE_FRAGMENT_SUCCESS, + collection: colwithfrag, + fragment: mockfragmod, + }) + expect(actual).toEqual(mockstatemod) + }) + + it('removeOne success', () => { + const actual = reducer(mockstate, { + type: T.DELETE_FRAGMENT_SUCCESS, + collection: colwithfrag, + fragment: mockfrag, + }) + expect(actual).toEqual({}) + }) + + it('replaceAll success', () => { + const actual = reducer(mockstate, { + type: T.GET_FRAGMENTS_SUCCESS, + collection: colwithfrag, + fragments: [mockfragmod], + }) + expect(actual).toEqual(mockstatemod) + }) + + it('logout success', () => { + const actual = reducer(mockstate, { + type: T.LOGOUT_SUCCESS, + }) + expect(actual).toEqual({}) + }) + + it('returns same state for unrecognised action', () => { + const state = {} + const actual = reducer(state, { + type: 'something else', + }) + expect(actual).toBe(state) + }) +}) diff --git a/packages/pubsweet-client/test/reducers/teams.test.js b/packages/pubsweet-client/test/reducers/teams.test.js new file mode 100644 index 0000000000000000000000000000000000000000..49160d689d64f63bad90205aa03450330f9f8c24 --- /dev/null +++ b/packages/pubsweet-client/test/reducers/teams.test.js @@ -0,0 +1,70 @@ +const allReducers = require('../../src/reducers').default +const reducer = require('../../src/reducers/teams').default + +const T = require('../../src/actions/types') + +describe('teams reducers', () => { + it('is exported in the all reducers object', () => { + expect(allReducers.teams).toBe(reducer) + }) + + const mockteam = { name: 'someteam', id: '1234' } + const mockstate = [mockteam] + + it('createTeam success', () => { + const actual = reducer([], { + type: T.CREATE_TEAM_SUCCESS, + team: mockteam, + }) + expect(actual).toEqual(mockstate) + }) + + it('updateTeam success', () => { + const updatedTeam = { ...mockteam, foo: 'bar' } + const actual = reducer(mockstate, { + type: T.CREATE_TEAM_SUCCESS, + team: updatedTeam, + }) + expect(actual).toEqual([updatedTeam]) + }) + + it('getTeams success', () => { + const actual = reducer(mockstate, { + type: T.GET_TEAMS_SUCCESS, + teams: mockstate, + }) + expect(actual).toEqual(mockstate) + }) + + it('deleteTeam success', () => { + const actual = reducer(mockstate, { + type: T.DELETE_TEAM_SUCCESS, + team: { ...mockteam }, + }) + expect(actual).toEqual([]) + }) + + it('logout success', () => { + const actual = reducer(mockstate, { + type: T.LOGOUT_SUCCESS, + }) + expect(actual).toEqual([]) + }) + + it('getCollectionTeam success', () => { + const extraTeam = { id: '4321', name: 'Another team' } + const actual = reducer(mockstate, { + type: T.GET_COLLECTION_TEAMS_SUCCESS, + teams: [extraTeam, mockteam], + }) + expect(actual).toEqual([mockteam, extraTeam]) + }) + + it('returns same state for unrecognised action', () => { + const state = [] + const actual = reducer(state, { + type: 'something else', + }) + expect(actual).toBe(state) + }) +}) diff --git a/packages/pubsweet-client/test/reducers/users.test.js b/packages/pubsweet-client/test/reducers/users.test.js new file mode 100644 index 0000000000000000000000000000000000000000..33e2c1726caff14ba7617da63cfa53d533b13ed6 --- /dev/null +++ b/packages/pubsweet-client/test/reducers/users.test.js @@ -0,0 +1,109 @@ +import { GET_CURRENT_USER_SUCCESS } from '../../src/actions/types' + +const allReducers = require('../../src/reducers').default +const reducer = require('../../src/reducers/users').default + +const T = require('../../src/actions/types') + +describe('users reducers', () => { + it('is exported in the all reducers object', () => { + expect(allReducers.users).toBe(reducer) + }) + + const user = { + username: 'fakeymcfake', + password: 'correct battery horse staple', + email: 'fakey_mcfake@pseudonymous.com', + id: '57d0fc8e-ece9-47bf-87d3-7935326b0128', + } + + const usermod = { ...user, email: 'new@email.com' } + + const mockstate = { users: [user] } + + it('getUsers success', () => { + const actual = reducer(undefined, { + type: T.GET_USERS_SUCCESS, + users: [user], + }) + expect(actual).toEqual({ + isFetching: false, + users: [user], + }) + }) + + it('getUsers request', () => { + const actual = reducer(undefined, { + type: T.GET_USERS_REQUEST, + }) + expect(actual).toEqual({ + isFetching: true, + users: [], + }) + }) + + it('getUser success', () => { + const actual = reducer( + { users: [] }, + { + type: T.GET_USER_SUCCESS, + user: user, + }, + ) + expect(actual).toEqual({ + users: [user], + isFetching: false, + }) + }) + + it('updateUser request', () => { + const actual = reducer(mockstate, { + type: T.UPDATE_USER_REQUEST, + user: usermod, + }) + expect(actual).toEqual({ + users: [user], + isFetching: true, + }) + }) + + it('updateUser success', () => { + const actual = reducer(mockstate, { + type: T.UPDATE_USER_SUCCESS, + user: usermod, + }) + expect(actual).toEqual({ + users: [usermod], + isFetching: false, + }) + }) + + it('logout success', () => { + const actual = reducer(mockstate, { + type: T.LOGOUT_SUCCESS, + user: usermod, + }) + expect(actual).toEqual({ + users: [], + isFetching: false, + }) + }) + + it('getCurrentUser success adds user to users array', () => { + const actual = reducer(mockstate, { + type: GET_CURRENT_USER_SUCCESS, + user, + }) + expect(actual).toEqual({ + users: [user], + }) + }) + + it('returns same state for unrecognised action', () => { + const state = {} + const actual = reducer(state, { + type: 'something else', + }) + expect(actual).toBe(state) + }) +}) diff --git a/packages/pubsweet-client/test/store/configureStore.test.js b/packages/pubsweet-client/test/store/configureStore.test.js new file mode 100644 index 0000000000000000000000000000000000000000..ccf70ba2066a29503c48e3123dd59096de266650 --- /dev/null +++ b/packages/pubsweet-client/test/store/configureStore.test.js @@ -0,0 +1,41 @@ +describe('configureStore', () => { + afterEach(() => jest.resetModules()) + + it('allows initialization of store with custom initialState, reducers and middleware', () => { + global.PUBSWEET_COMPONENTS = [] + + const configureStore = require('../../src/store/configureStore') + + const customHistory = {} + const customInitialState = { collections: ['initial'] } + + const customReducers = { + test: (state, action) => { + return { + ...state, + fired: action.fired, + } + }, + } + + const customMiddlewares = [ + () => next => action => { + action.fired = true + return next(action) + }, + ] + + const store = configureStore( + customHistory, + customInitialState, + customReducers, + customMiddlewares, + ) + + expect(store.getState().collections[0]).toBe( + customInitialState.collections[0], + ) + store.dispatch({ type: 'TEST', fired: false }) + expect(store.getState().test.fired).toBe(true) + }) +}) diff --git a/packages/pubsweet-client/yarn.lock b/packages/pubsweet-client/yarn.lock new file mode 100644 index 0000000000000000000000000000000000000000..2860c32ad9120581836b3365919e9540073b4357 --- /dev/null +++ b/packages/pubsweet-client/yarn.lock @@ -0,0 +1,4578 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +abab@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.4.tgz#5faad9c2c07f60dd76770f71cf025b62a63cfd4e" + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + +acorn-globals@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-3.1.0.tgz#fd8270f71fbb4996b004fa880ee5d46573a731bf" + dependencies: + acorn "^4.0.4" + +acorn-jsx@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" + dependencies: + acorn "^3.0.4" + +acorn@^3.0.4: + version "3.3.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" + +acorn@^4.0.4: + version "4.0.13" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" + +acorn@^5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.1.2.tgz#911cb53e036807cf0fa778dc5d370fbd864246d7" + +ajv-keywords@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.0.tgz#a296e17f7bfae7c1ce4f7e0de53d29cb32162df0" + +ajv@^4.9.1: + version "4.11.8" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" + dependencies: + co "^4.6.0" + json-stable-stringify "^1.0.1" + +ajv@^5.1.0, ajv@^5.2.0, ajv@^5.2.3: + version "5.2.3" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.2.3.tgz#c06f598778c44c6b161abafe3466b81ad1814ed2" + dependencies: + co "^4.6.0" + fast-deep-equal "^1.0.0" + json-schema-traverse "^0.3.0" + json-stable-stringify "^1.0.1" + +align-text@^0.1.1, align-text@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" + dependencies: + kind-of "^3.0.2" + longest "^1.0.1" + repeat-string "^1.5.2" + +amdefine@>=0.0.4: + version "1.0.1" + resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + +ansi-escapes@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" + +ansi-escapes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.0.0.tgz#ec3e8b4e9f8064fc02c3ac9b65f1c275bda8ef92" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + +ansi-styles@^3.1.0, ansi-styles@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88" + dependencies: + color-convert "^1.9.0" + +anymatch@^1.3.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" + dependencies: + micromatch "^2.1.5" + normalize-path "^2.0.0" + +app-root-path@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-2.0.1.tgz#cd62dcf8e4fd5a417efc664d2e5b10653c651b46" + +append-transform@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-0.4.0.tgz#d76ebf8ca94d276e247a36bad44a4b74ab611991" + dependencies: + default-require-extensions "^1.0.0" + +aproba@^1.0.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + +are-we-there-yet@~1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +argparse@^1.0.7: + version "1.0.9" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + dependencies: + arr-flatten "^1.0.1" + +arr-flatten@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + +array-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" + +array-includes@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.0.3.tgz#184b48f62d92d7452bb31b323165c7f8bd02266d" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.7.0" + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + +array-unique@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + +arrify@^1.0.0, arrify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + +asap@~2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + +asn1@~0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + +assert-plus@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" + +assertion-error@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c" + +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" + +async-each@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + +async@^1.4.0: + version "1.5.2" + resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + +async@^2.0.1, async@^2.1.4: + version "2.5.0" + resolved "https://registry.yarnpkg.com/async/-/async-2.5.0.tgz#843190fd6b7357a0b9e1c956edddd5ec8462b54d" + dependencies: + lodash "^4.14.0" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + +authsome@0.0.9: + version "0.0.9" + resolved "https://registry.yarnpkg.com/authsome/-/authsome-0.0.9.tgz#08b34f1797b3539e6a362f0fb11a01ae0613f928" + +aws-sign2@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + +aws4@^1.2.1, aws4@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" + +babel-cli@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-cli/-/babel-cli-6.26.0.tgz#502ab54874d7db88ad00b887a06383ce03d002f1" + dependencies: + babel-core "^6.26.0" + babel-polyfill "^6.26.0" + babel-register "^6.26.0" + babel-runtime "^6.26.0" + commander "^2.11.0" + convert-source-map "^1.5.0" + fs-readdir-recursive "^1.0.0" + glob "^7.1.2" + lodash "^4.17.4" + output-file-sync "^1.1.2" + path-is-absolute "^1.0.1" + slash "^1.0.0" + source-map "^0.5.6" + v8flags "^2.1.1" + optionalDependencies: + chokidar "^1.6.1" + +babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + dependencies: + chalk "^1.1.3" + esutils "^2.0.2" + js-tokens "^3.0.2" + +babel-core@^6.0.0, babel-core@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.0.tgz#af32f78b31a6fcef119c87b0fd8d9753f03a0bb8" + dependencies: + babel-code-frame "^6.26.0" + babel-generator "^6.26.0" + 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.0" + debug "^2.6.8" + json5 "^0.5.1" + lodash "^4.17.4" + minimatch "^3.0.4" + path-is-absolute "^1.0.1" + private "^0.1.7" + slash "^1.0.0" + source-map "^0.5.6" + +babel-generator@^6.18.0, babel-generator@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.0.tgz#ac1ae20070b79f6e3ca1d3269613053774f20dc5" + dependencies: + 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.4" + source-map "^0.5.6" + trim-right "^1.0.1" + +babel-helper-bindify-decorators@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.24.1.tgz#14c19e5f142d7b47f19a52431e52b1ccbc40a330" + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" + dependencies: + babel-helper-explode-assignable-expression "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-builder-react-jsx@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz#39ff8313b75c8b65dceff1f31d383e0ff2a408a0" + dependencies: + babel-runtime "^6.26.0" + babel-types "^6.26.0" + esutils "^2.0.2" + +babel-helper-call-delegate@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-define-map@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-helper-explode-assignable-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-explode-class@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz#7dc2a3910dee007056e1e31d640ced3d54eaa9eb" + dependencies: + babel-helper-bindify-decorators "^6.24.1" + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-function-name@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" + dependencies: + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-get-function-arity@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-hoist-variables@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-optimise-call-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-regex@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" + dependencies: + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-helper-remap-async-to-generator@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-replace-supers@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" + dependencies: + babel-helper-optimise-call-expression "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helpers@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-jest@^21.2.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-21.2.0.tgz#2ce059519a9374a2c46f2455b6fbef5ad75d863e" + dependencies: + babel-plugin-istanbul "^4.0.0" + babel-preset-jest "^21.2.0" + +babel-messages@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-check-es2015-constants@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-istanbul@^4.0.0: + version "4.1.5" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.5.tgz#6760cdd977f411d3e175bb064f2bc327d99b2b6e" + dependencies: + find-up "^2.1.0" + istanbul-lib-instrument "^1.7.5" + test-exclude "^4.1.1" + +babel-plugin-jest-hoist@^21.2.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-21.2.0.tgz#2cef637259bd4b628a6cace039de5fcd14dbb006" + +babel-plugin-syntax-async-functions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" + +babel-plugin-syntax-async-generators@^6.5.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz#6bc963ebb16eccbae6b92b596eb7f35c342a8b9a" + +babel-plugin-syntax-class-properties@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" + +babel-plugin-syntax-decorators@^6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz#312563b4dbde3cc806cee3e416cceeaddd11ac0b" + +babel-plugin-syntax-dynamic-import@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da" + +babel-plugin-syntax-exponentiation-operator@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" + +babel-plugin-syntax-flow@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d" + +babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" + +babel-plugin-syntax-object-rest-spread@^6.13.0, babel-plugin-syntax-object-rest-spread@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" + +babel-plugin-syntax-trailing-function-commas@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" + +babel-plugin-transform-async-generator-functions@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz#f058900145fd3e9907a6ddf28da59f215258a5db" + dependencies: + babel-helper-remap-async-to-generator "^6.24.1" + babel-plugin-syntax-async-generators "^6.5.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-async-to-generator@^6.22.0, babel-plugin-transform-async-to-generator@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" + dependencies: + babel-helper-remap-async-to-generator "^6.24.1" + babel-plugin-syntax-async-functions "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-class-properties@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac" + dependencies: + babel-helper-function-name "^6.24.1" + babel-plugin-syntax-class-properties "^6.8.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-decorators@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.24.1.tgz#788013d8f8c6b5222bdf7b344390dfd77569e24d" + dependencies: + babel-helper-explode-class "^6.24.1" + babel-plugin-syntax-decorators "^6.13.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-arrow-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoping@^6.23.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" + dependencies: + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-plugin-transform-es2015-classes@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" + dependencies: + babel-helper-define-map "^6.24.1" + babel-helper-function-name "^6.24.1" + babel-helper-optimise-call-expression "^6.24.1" + babel-helper-replace-supers "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-computed-properties@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-destructuring@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-duplicate-keys@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-for-of@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-function-name@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" + dependencies: + babel-plugin-transform-es2015-modules-commonjs "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz#0d8394029b7dc6abe1a97ef181e00758dd2e5d8a" + dependencies: + babel-plugin-transform-strict-mode "^6.24.1" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-types "^6.26.0" + +babel-plugin-transform-es2015-modules-systemjs@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-modules-umd@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" + dependencies: + babel-plugin-transform-es2015-modules-amd "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-object-super@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" + dependencies: + babel-helper-replace-supers "^6.24.1" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-parameters@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" + dependencies: + babel-helper-call-delegate "^6.24.1" + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-shorthand-properties@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-spread@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-sticky-regex@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-template-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-typeof-symbol@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-unicode-regex@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + regexpu-core "^2.0.0" + +babel-plugin-transform-exponentiation-operator@^6.22.0, babel-plugin-transform-exponentiation-operator@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" + dependencies: + babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" + babel-plugin-syntax-exponentiation-operator "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-flow-strip-types@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz#84cb672935d43714fdc32bce84568d87441cf7cf" + dependencies: + babel-plugin-syntax-flow "^6.18.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-object-rest-spread@^6.22.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz#0f36692d50fef6b7e2d4b3ac1478137a963b7b06" + dependencies: + babel-plugin-syntax-object-rest-spread "^6.8.0" + babel-runtime "^6.26.0" + +babel-plugin-transform-react-display-name@^6.23.0: + version "6.25.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.25.0.tgz#67e2bf1f1e9c93ab08db96792e05392bf2cc28d1" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-react-jsx-self@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.22.0.tgz#df6d80a9da2612a121e6ddd7558bcbecf06e636e" + dependencies: + babel-plugin-syntax-jsx "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-react-jsx-source@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.22.0.tgz#66ac12153f5cd2d17b3c19268f4bf0197f44ecd6" + dependencies: + babel-plugin-syntax-jsx "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-react-jsx@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz#840a028e7df460dfc3a2d29f0c0d91f6376e66a3" + dependencies: + babel-helper-builder-react-jsx "^6.24.1" + babel-plugin-syntax-jsx "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-regenerator@^6.22.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" + dependencies: + regenerator-transform "^0.10.0" + +babel-plugin-transform-strict-mode@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-polyfill@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" + dependencies: + babel-runtime "^6.26.0" + core-js "^2.5.0" + regenerator-runtime "^0.10.5" + +babel-preset-env@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.6.0.tgz#2de1c782a780a0a5d605d199c957596da43c44e4" + dependencies: + babel-plugin-check-es2015-constants "^6.22.0" + babel-plugin-syntax-trailing-function-commas "^6.22.0" + babel-plugin-transform-async-to-generator "^6.22.0" + babel-plugin-transform-es2015-arrow-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoping "^6.23.0" + babel-plugin-transform-es2015-classes "^6.23.0" + babel-plugin-transform-es2015-computed-properties "^6.22.0" + babel-plugin-transform-es2015-destructuring "^6.23.0" + babel-plugin-transform-es2015-duplicate-keys "^6.22.0" + babel-plugin-transform-es2015-for-of "^6.23.0" + babel-plugin-transform-es2015-function-name "^6.22.0" + babel-plugin-transform-es2015-literals "^6.22.0" + babel-plugin-transform-es2015-modules-amd "^6.22.0" + babel-plugin-transform-es2015-modules-commonjs "^6.23.0" + babel-plugin-transform-es2015-modules-systemjs "^6.23.0" + babel-plugin-transform-es2015-modules-umd "^6.23.0" + babel-plugin-transform-es2015-object-super "^6.22.0" + babel-plugin-transform-es2015-parameters "^6.23.0" + babel-plugin-transform-es2015-shorthand-properties "^6.22.0" + babel-plugin-transform-es2015-spread "^6.22.0" + babel-plugin-transform-es2015-sticky-regex "^6.22.0" + babel-plugin-transform-es2015-template-literals "^6.22.0" + babel-plugin-transform-es2015-typeof-symbol "^6.23.0" + babel-plugin-transform-es2015-unicode-regex "^6.22.0" + babel-plugin-transform-exponentiation-operator "^6.22.0" + babel-plugin-transform-regenerator "^6.22.0" + browserslist "^2.1.2" + invariant "^2.2.2" + semver "^5.3.0" + +babel-preset-flow@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz#e71218887085ae9a24b5be4169affb599816c49d" + dependencies: + babel-plugin-transform-flow-strip-types "^6.22.0" + +babel-preset-jest@^21.2.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-21.2.0.tgz#ff9d2bce08abd98e8a36d9a8a5189b9173b85638" + dependencies: + babel-plugin-jest-hoist "^21.2.0" + babel-plugin-syntax-object-rest-spread "^6.13.0" + +babel-preset-react@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-react/-/babel-preset-react-6.24.1.tgz#ba69dfaea45fc3ec639b6a4ecea6e17702c91380" + dependencies: + babel-plugin-syntax-jsx "^6.3.13" + babel-plugin-transform-react-display-name "^6.23.0" + babel-plugin-transform-react-jsx "^6.24.1" + babel-plugin-transform-react-jsx-self "^6.22.0" + babel-plugin-transform-react-jsx-source "^6.22.0" + babel-preset-flow "^6.23.0" + +babel-preset-stage-2@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz#d9e2960fb3d71187f0e64eec62bc07767219bdc1" + dependencies: + babel-plugin-syntax-dynamic-import "^6.18.0" + babel-plugin-transform-class-properties "^6.24.1" + babel-plugin-transform-decorators "^6.24.1" + babel-preset-stage-3 "^6.24.1" + +babel-preset-stage-3@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz#836ada0a9e7a7fa37cb138fb9326f87934a48395" + dependencies: + babel-plugin-syntax-trailing-function-commas "^6.22.0" + babel-plugin-transform-async-generator-functions "^6.24.1" + babel-plugin-transform-async-to-generator "^6.24.1" + babel-plugin-transform-exponentiation-operator "^6.24.1" + babel-plugin-transform-object-rest-spread "^6.22.0" + +babel-register@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" + dependencies: + babel-core "^6.26.0" + babel-runtime "^6.26.0" + core-js "^2.5.0" + home-or-tmp "^2.0.0" + lodash "^4.17.4" + mkdirp "^0.5.1" + source-map-support "^0.4.15" + +babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + +babel-template@^6.16.0, babel-template@^6.24.1, babel-template@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" + dependencies: + babel-runtime "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + lodash "^4.17.4" + +babel-traverse@^6.18.0, babel-traverse@^6.24.1, babel-traverse@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" + dependencies: + 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.8" + globals "^9.18.0" + invariant "^2.2.2" + lodash "^4.17.4" + +babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" + dependencies: + babel-runtime "^6.26.0" + esutils "^2.0.2" + lodash "^4.17.4" + to-fast-properties "^1.0.3" + +babylon@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + +bcrypt-pbkdf@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" + dependencies: + tweetnacl "^0.14.3" + +binary-extensions@^1.0.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.10.0.tgz#9aeb9a6c5e88638aad171e167f5900abe24835d0" + +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + dependencies: + inherits "~2.0.0" + +boolbase@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + +boom@2.x.x: + version "2.10.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" + dependencies: + hoek "2.x.x" + +boom@4.x.x: + version "4.3.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-4.3.1.tgz#4f8a3005cb4a7e3889f749030fd25b96e01d2e31" + dependencies: + hoek "4.x.x" + +boom@5.x.x: + version "5.2.0" + resolved "https://registry.yarnpkg.com/boom/-/boom-5.2.0.tgz#5dd9da6ee3a5f302077436290cb717d3f4a54e02" + dependencies: + hoek "4.x.x" + +brace-expansion@^1.1.7: + version "1.1.8" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^1.8.2: + version "1.8.5" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + dependencies: + expand-range "^1.8.1" + preserve "^0.2.0" + repeat-element "^1.1.2" + +browser-resolve@^1.11.2: + version "1.11.2" + resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.2.tgz#8ff09b0a2c421718a1051c260b32e48f442938ce" + dependencies: + resolve "1.1.7" + +browserslist@^2.1.2: + version "2.5.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.5.1.tgz#68e4bc536bbcc6086d62843a2ffccea8396821c6" + dependencies: + caniuse-lite "^1.0.30000744" + electron-to-chromium "^1.3.24" + +bser@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" + dependencies: + node-int64 "^0.4.0" + +builtin-modules@^1.0.0, builtin-modules@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + +caller-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" + dependencies: + callsites "^0.2.0" + +callsites@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" + +callsites@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" + +camelcase@^1.0.2: + version "1.2.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" + +camelcase@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" + +caniuse-lite@^1.0.30000744: + version "1.0.30000746" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000746.tgz#c64f95a3925cfd30207a308ed76c1ae96ea09ea0" + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + +center-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" + dependencies: + align-text "^0.1.3" + lazy-cache "^1.0.3" + +"chai@>=1.9.2 <4.0.0": + version "3.5.0" + resolved "https://registry.yarnpkg.com/chai/-/chai-3.5.0.tgz#4d02637b067fe958bdbfdd3a40ec56fef7373247" + dependencies: + assertion-error "^1.0.1" + deep-eql "^0.1.3" + type-detect "^1.0.0" + +chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.1.0.tgz#ac5becf14fa21b99c6c92ca7a7d7cfd5b17e743e" + dependencies: + ansi-styles "^3.1.0" + escape-string-regexp "^1.0.5" + supports-color "^4.0.0" + +cheerio@^0.22.0: + version "0.22.0" + resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-0.22.0.tgz#a9baa860a3f9b595a6b81b1a86873121ed3a269e" + dependencies: + css-select "~1.2.0" + dom-serializer "~0.1.0" + entities "~1.1.1" + htmlparser2 "^3.9.1" + lodash.assignin "^4.0.9" + lodash.bind "^4.1.4" + lodash.defaults "^4.0.1" + lodash.filter "^4.4.0" + lodash.flatten "^4.2.0" + lodash.foreach "^4.3.0" + lodash.map "^4.4.0" + lodash.merge "^4.4.0" + lodash.pick "^4.2.1" + lodash.reduce "^4.4.0" + lodash.reject "^4.4.0" + lodash.some "^4.4.0" + +chokidar@^1.6.1: + version "1.7.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" + dependencies: + anymatch "^1.3.0" + async-each "^1.0.0" + glob-parent "^2.0.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^2.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + optionalDependencies: + fsevents "^1.0.0" + +ci-info@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.1.tgz#47b44df118c48d2597b56d342e7e25791060171a" + +circular-json@^0.3.1: + version "0.3.3" + resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" + +classnames@^2.2.5: + version "2.2.5" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d" + +cli-cursor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" + dependencies: + restore-cursor "^1.0.1" + +cli-cursor@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + dependencies: + restore-cursor "^2.0.0" + +cli-spinners@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-0.1.2.tgz#bb764d88e185fb9e1e6a2a1f19772318f605e31c" + +cli-truncate@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-0.2.1.tgz#9f15cfbb0705005369216c626ac7d05ab90dd574" + dependencies: + slice-ansi "0.0.4" + string-width "^1.0.1" + +cli-width@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" + +cliui@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" + dependencies: + center-align "^0.1.1" + right-align "^0.1.1" + wordwrap "0.0.2" + +cliui@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrap-ansi "^2.0.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + +color-convert@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a" + dependencies: + color-name "^1.1.1" + +color-name@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + +combined-stream@^1.0.5, combined-stream@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" + dependencies: + delayed-stream "~1.0.0" + +commander@^2.11.0, commander@^2.9.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +concat-stream@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" + dependencies: + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +config@^1.21.0: + version "1.26.2" + resolved "https://registry.yarnpkg.com/config/-/config-1.26.2.tgz#2466291168d8afae0aae8ab99ea4d4272f520cae" + dependencies: + json5 "0.4.0" + os-homedir "1.0.2" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + +contains-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" + +content-type-parser@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/content-type-parser/-/content-type-parser-1.0.1.tgz#c3e56988c53c65127fb46d4032a3a900246fdc94" + +convert-source-map@^1.4.0, convert-source-map@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5" + +core-js@^1.0.0: + version "1.2.7" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" + +core-js@^2.4.0, core-js@^2.5.0: + version "2.5.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.1.tgz#ae6874dc66937789b80754ff5428df66819ca50b" + +core-util-is@1.0.2, core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +cosmiconfig@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-1.1.0.tgz#0dea0f9804efdfb929fbb1b188e25553ea053d37" + dependencies: + graceful-fs "^4.1.2" + js-yaml "^3.4.3" + minimist "^1.2.0" + object-assign "^4.0.1" + os-homedir "^1.0.1" + parse-json "^2.2.0" + pinkie-promise "^2.0.0" + require-from-string "^1.1.0" + +create-react-class@^15.6.0: + version "15.6.2" + resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.6.2.tgz#cf1ed15f12aad7f14ef5f2dfe05e6c42f91ef02a" + dependencies: + fbjs "^0.8.9" + loose-envify "^1.3.1" + object-assign "^4.1.1" + +cross-spawn@^5.0.1, cross-spawn@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + +cryptiles@2.x.x: + version "2.0.5" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" + dependencies: + boom "2.x.x" + +cryptiles@3.x.x: + version "3.1.2" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-3.1.2.tgz#a89fbb220f5ce25ec56e8c4aa8a4fd7b5b0d29fe" + dependencies: + boom "5.x.x" + +css-select@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" + dependencies: + boolbase "~1.0.0" + css-what "2.1" + domutils "1.5.1" + nth-check "~1.0.1" + +css-what@2.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.0.tgz#9467d032c38cfaefb9f2d79501253062f87fa1bd" + +cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0": + version "0.3.2" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.2.tgz#b8036170c79f07a90ff2f16e22284027a243848b" + +"cssstyle@>= 0.2.37 < 0.3.0": + version "0.2.37" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-0.2.37.tgz#541097234cb2513c83ceed3acddc27ff27987d54" + dependencies: + cssom "0.3.x" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + dependencies: + assert-plus "^1.0.0" + +date-fns@^1.27.2: + version "1.29.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.29.0.tgz#12e609cdcb935127311d04d33334e2960a2a54e6" + +debug@^2.2.0, debug@^2.6.3, debug@^2.6.8: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + dependencies: + ms "2.0.0" + +debug@^3.0.1: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + dependencies: + ms "2.0.0" + +decamelize@^1.0.0, decamelize@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + +deep-diff@^0.3.5: + version "0.3.8" + resolved "https://registry.yarnpkg.com/deep-diff/-/deep-diff-0.3.8.tgz#c01de63efb0eec9798801d40c7e0dae25b582c84" + +deep-eql@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2" + dependencies: + type-detect "0.1.1" + +deep-equal@^1.0.0, deep-equal@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" + +deep-extend@~0.4.0: + version "0.4.2" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" + +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + +default-require-extensions@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8" + dependencies: + strip-bom "^2.0.0" + +define-properties@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" + dependencies: + foreach "^2.0.5" + object-keys "^1.0.8" + +del@^2.0.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" + dependencies: + globby "^5.0.0" + is-path-cwd "^1.0.0" + is-path-in-cwd "^1.0.0" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + rimraf "^2.2.8" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + +detect-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + dependencies: + repeating "^2.0.0" + +diff@^3.2.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.4.0.tgz#b1d85507daf3964828de54b37d0d73ba67dda56c" + +doctrine@1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" + dependencies: + esutils "^2.0.2" + isarray "^1.0.0" + +doctrine@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.0.0.tgz#c73d8d2909d22291e1a007a395804da8b665fe63" + dependencies: + esutils "^2.0.2" + isarray "^1.0.0" + +dom-helpers@^3.2.0, dom-helpers@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.2.1.tgz#3203e07fed217bd1f424b019735582fc37b2825a" + +dom-serializer@0, dom-serializer@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82" + dependencies: + domelementtype "~1.1.1" + entities "~1.1.1" + +dom-walk@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018" + +domelementtype@1, domelementtype@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.0.tgz#b17aed82e8ab59e52dd9c19b1756e0fc187204c2" + +domelementtype@~1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.1.3.tgz#bd28773e2642881aec51544924299c5cd822185b" + +domhandler@^2.3.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.1.tgz#892e47000a99be55bbf3774ffea0561d8879c259" + dependencies: + domelementtype "1" + +domutils@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" + dependencies: + dom-serializer "0" + domelementtype "1" + +domutils@^1.5.1: + version "1.6.2" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.6.2.tgz#1958cc0b4c9426e9ed367fb1c8e854891b0fa3ff" + dependencies: + dom-serializer "0" + domelementtype "1" + +ecc-jsbn@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" + dependencies: + jsbn "~0.1.0" + +electron-to-chromium@^1.3.24: + version "1.3.26" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.26.tgz#996427294861a74d9c7c82b9260ea301e8c02d66" + +elegant-spinner@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e" + +encoding@^0.1.11: + version "0.1.12" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + dependencies: + iconv-lite "~0.4.13" + +entities@^1.1.1, entities@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" + +enzyme@^2.9.1: + version "2.9.1" + resolved "https://registry.yarnpkg.com/enzyme/-/enzyme-2.9.1.tgz#07d5ce691241240fb817bf2c4b18d6e530240df6" + dependencies: + cheerio "^0.22.0" + function.prototype.name "^1.0.0" + is-subset "^0.1.1" + lodash "^4.17.4" + object-is "^1.0.1" + object.assign "^4.0.4" + object.entries "^1.0.4" + object.values "^1.0.4" + prop-types "^15.5.10" + uuid "^3.0.1" + +errno@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d" + dependencies: + prr "~0.0.0" + +error-ex@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.6.1, es-abstract@^1.7.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.9.0.tgz#690829a07cae36b222e7fd9b75c0d0573eb25227" + dependencies: + es-to-primitive "^1.1.1" + function-bind "^1.1.1" + has "^1.0.1" + is-callable "^1.1.3" + is-regex "^1.0.4" + +es-to-primitive@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" + dependencies: + is-callable "^1.1.1" + is-date-object "^1.0.1" + is-symbol "^1.0.1" + +es6-error@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.0.2.tgz#eec5c726eacef51b7f6b73c20db6e1b13b069c98" + +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +escodegen@^1.6.1: + version "1.9.0" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.9.0.tgz#9811a2f265dc1cd3894420ee3717064b632b8852" + dependencies: + esprima "^3.1.3" + estraverse "^4.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.5.6" + +eslint-config-prettier@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-2.6.0.tgz#f21db0ebb438ad678fb98946097c4bb198befccc" + dependencies: + get-stdin "^5.0.1" + +eslint-config-standard@^10.2.1: + version "10.2.1" + resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-10.2.1.tgz#c061e4d066f379dc17cd562c64e819b4dd454591" + +eslint-import-resolver-node@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.1.tgz#4422574cde66a9a7b099938ee4d508a199e0e3cc" + dependencies: + debug "^2.6.8" + resolve "^1.2.0" + +eslint-module-utils@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.1.1.tgz#abaec824177613b8a95b299639e1b6facf473449" + dependencies: + debug "^2.6.8" + pkg-dir "^1.0.0" + +eslint-plugin-import@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.7.0.tgz#21de33380b9efb55f5ef6d2e210ec0e07e7fa69f" + dependencies: + builtin-modules "^1.1.1" + contains-path "^0.1.0" + debug "^2.6.8" + doctrine "1.5.0" + eslint-import-resolver-node "^0.3.1" + eslint-module-utils "^2.1.1" + has "^1.0.1" + lodash.cond "^4.3.0" + minimatch "^3.0.3" + read-pkg-up "^2.0.0" + +eslint-plugin-node@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-5.2.0.tgz#e1efca04a385516cff3f2f04027ce8c5ae6db749" + dependencies: + ignore "^3.3.3" + minimatch "^3.0.4" + resolve "^1.3.3" + semver "5.3.0" + +eslint-plugin-promise@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-3.5.0.tgz#78fbb6ffe047201627569e85a6c5373af2a68fca" + +eslint-plugin-react@^7.4.0: + version "7.4.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.4.0.tgz#300a95861b9729c087d362dd64abcc351a74364a" + dependencies: + doctrine "^2.0.0" + has "^1.0.1" + jsx-ast-utils "^2.0.0" + prop-types "^15.5.10" + +eslint-plugin-standard@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-3.0.1.tgz#34d0c915b45edc6f010393c7eef3823b08565cf2" + +eslint-scope@^3.7.1: + version "3.7.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint@^4.8.0: + version "4.8.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.8.0.tgz#229ef0e354e0e61d837c7a80fdfba825e199815e" + dependencies: + ajv "^5.2.0" + babel-code-frame "^6.22.0" + chalk "^2.1.0" + concat-stream "^1.6.0" + cross-spawn "^5.1.0" + debug "^3.0.1" + doctrine "^2.0.0" + eslint-scope "^3.7.1" + espree "^3.5.1" + esquery "^1.0.0" + estraverse "^4.2.0" + esutils "^2.0.2" + file-entry-cache "^2.0.0" + functional-red-black-tree "^1.0.1" + glob "^7.1.2" + globals "^9.17.0" + ignore "^3.3.3" + imurmurhash "^0.1.4" + inquirer "^3.0.6" + is-resolvable "^1.0.0" + js-yaml "^3.9.1" + json-stable-stringify "^1.0.1" + levn "^0.3.0" + lodash "^4.17.4" + minimatch "^3.0.2" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.2" + path-is-inside "^1.0.2" + pluralize "^7.0.0" + progress "^2.0.0" + require-uncached "^1.0.3" + semver "^5.3.0" + strip-ansi "^4.0.0" + strip-json-comments "~2.0.1" + table "^4.0.1" + text-table "~0.2.0" + +espree@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.1.tgz#0c988b8ab46db53100a1954ae4ba995ddd27d87e" + dependencies: + acorn "^5.1.1" + acorn-jsx "^3.0.0" + +esprima@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" + +esprima@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" + +esquery@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.0.tgz#cfba8b57d7fba93f17298a8a006a04cda13d80fa" + dependencies: + estraverse "^4.0.0" + +esrecurse@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.0.tgz#fa9568d98d3823f9a41d91e902dcab9ea6e5b163" + dependencies: + estraverse "^4.1.0" + object-assign "^4.0.1" + +estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + +esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + +event-source-polyfill@^0.0.10: + version "0.0.10" + resolved "https://registry.yarnpkg.com/event-source-polyfill/-/event-source-polyfill-0.0.10.tgz#e7e81863c333f5a842e3bf0a3b570bedaf042e09" + +eventsourcemock@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/eventsourcemock/-/eventsourcemock-1.0.1.tgz#1bcd88f602097c33d4e95f85923bbba7bd847a86" + +exec-sh@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.1.tgz#163b98a6e89e6b65b47c2a28d215bc1f63989c38" + dependencies: + merge "^1.1.3" + +execa@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +execa@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.8.0.tgz#d8d76bbc1b55217ed190fd6dd49d3c774ecfc8da" + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +exit-hook@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" + +expand-brackets@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + dependencies: + is-posix-bracket "^0.1.0" + +expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + dependencies: + fill-range "^2.1.0" + +expect@^21.2.1: + version "21.2.1" + resolved "https://registry.yarnpkg.com/expect/-/expect-21.2.1.tgz#003ac2ac7005c3c29e73b38a272d4afadd6d1d7b" + dependencies: + ansi-styles "^3.2.0" + jest-diff "^21.2.1" + jest-get-type "^21.2.0" + jest-matcher-utils "^21.2.1" + jest-message-util "^21.2.1" + jest-regex-util "^21.2.0" + +extend@~3.0.0, extend@~3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" + +external-editor@^2.0.4: + version "2.0.5" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.0.5.tgz#52c249a3981b9ba187c7cacf5beb50bf1d91a6bc" + dependencies: + iconv-lite "^0.4.17" + jschardet "^1.4.2" + tmp "^0.0.33" + +extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + dependencies: + is-extglob "^1.0.0" + +extsprintf@1.3.0, extsprintf@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + +fast-deep-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff" + +fast-levenshtein@~2.0.4: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + +fb-watchman@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58" + dependencies: + bser "^2.0.0" + +fbjs@^0.8.16, fbjs@^0.8.9: + version "0.8.16" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db" + dependencies: + core-js "^1.0.0" + isomorphic-fetch "^2.1.1" + loose-envify "^1.0.0" + object-assign "^4.1.0" + promise "^7.1.1" + setimmediate "^1.0.5" + ua-parser-js "^0.7.9" + +figures@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" + dependencies: + escape-string-regexp "^1.0.5" + object-assign "^4.1.0" + +figures@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + dependencies: + escape-string-regexp "^1.0.5" + +file-entry-cache@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" + dependencies: + flat-cache "^1.2.1" + object-assign "^4.0.1" + +filename-regex@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" + +fileset@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/fileset/-/fileset-2.0.3.tgz#8e7548a96d3cc2327ee5e674168723a333bba2a0" + dependencies: + glob "^7.0.3" + minimatch "^3.0.3" + +fill-range@^2.1.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^1.1.3" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + +find-up@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + dependencies: + path-exists "^2.0.0" + pinkie-promise "^2.0.0" + +find-up@^2.0.0, find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + dependencies: + locate-path "^2.0.0" + +flat-cache@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.0.tgz#d3030b32b38154f4e3b7e9c709f490f7ef97c481" + dependencies: + circular-json "^0.3.1" + del "^2.0.2" + graceful-fs "^4.1.2" + write "^0.2.1" + +for-in@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + +for-own@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" + dependencies: + for-in "^1.0.1" + +foreach@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + +form-data@^1.0.0-rc3: + version "1.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-1.0.1.tgz#ae315db9a4907fa065502304a66d7733475ee37c" + dependencies: + async "^2.0.1" + combined-stream "^1.0.5" + mime-types "^2.1.11" + +form-data@~2.1.1: + version "2.1.4" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.12" + +form-data@~2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.1.tgz#6fb94fbd71885306d73d15cc497fe4cc4ecd44bf" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.12" + +fs-readdir-recursive@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.0.0.tgz#8cd1745c8b4f8a29c8caec392476921ba195f560" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +fsevents@^1.0.0, fsevents@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.2.tgz#3282b713fb3ad80ede0e9fcf4611b5aa6fc033f4" + dependencies: + nan "^2.3.0" + node-pre-gyp "^0.6.36" + +fstream-ignore@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" + dependencies: + fstream "^1.0.0" + inherits "2" + minimatch "^3.0.0" + +fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: + version "1.0.11" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +function-bind@^1.0.2, function-bind@^1.1.0, function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + +function.prototype.name@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.0.3.tgz#0099ae5572e9dd6f03c97d023fd92bcc5e639eac" + dependencies: + define-properties "^1.1.2" + function-bind "^1.1.0" + is-callable "^1.1.3" + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +get-caller-file@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" + +get-own-enumerable-property-symbols@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-2.0.1.tgz#5c4ad87f2834c4b9b4e84549dc1e0650fb38c24b" + +get-stdin@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398" + +get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + dependencies: + assert-plus "^1.0.0" + +glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + +glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + dependencies: + is-glob "^2.0.0" + +glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global@^4.3.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f" + dependencies: + min-document "^2.19.0" + process "~0.5.1" + +globals@^9.17.0, globals@^9.18.0: + version "9.18.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" + +globby@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" + dependencies: + array-union "^1.0.1" + arrify "^1.0.0" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.4: + version "4.1.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + +growly@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" + +handlebars@^4.0.3: + version "4.0.10" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.10.tgz#3d30c718b09a3d96f23ea4cc1f403c4d3ba9ff4f" + dependencies: + async "^1.4.0" + optimist "^0.6.1" + source-map "^0.4.4" + optionalDependencies: + uglify-js "^2.6" + +har-schema@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + +har-validator@~4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" + dependencies: + ajv "^4.9.1" + har-schema "^1.0.5" + +har-validator@~5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" + dependencies: + ajv "^5.1.0" + har-schema "^2.0.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + dependencies: + ansi-regex "^2.0.0" + +has-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" + +has-flag@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + +has@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" + dependencies: + function-bind "^1.0.2" + +hawk@3.1.3, hawk@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" + dependencies: + boom "2.x.x" + cryptiles "2.x.x" + hoek "2.x.x" + sntp "1.x.x" + +hawk@~6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-6.0.2.tgz#af4d914eb065f9b5ce4d9d11c1cb2126eecc3038" + dependencies: + boom "4.x.x" + cryptiles "3.x.x" + hoek "4.x.x" + sntp "2.x.x" + +history@^4.5.1, history@^4.7.2: + version "4.7.2" + resolved "https://registry.yarnpkg.com/history/-/history-4.7.2.tgz#22b5c7f31633c5b8021c7f4a8a954ac139ee8d5b" + dependencies: + invariant "^2.2.1" + loose-envify "^1.2.0" + resolve-pathname "^2.2.0" + value-equal "^0.4.0" + warning "^3.0.0" + +hoek@2.x.x: + version "2.16.3" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" + +hoek@4.x.x: + version "4.2.0" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.0.tgz#72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d" + +hoist-non-react-statics@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz#aa448cf0986d55cc40773b17174b7dd066cb7cfb" + +hoist-non-react-statics@^2.2.1, hoist-non-react-statics@^2.3.0, hoist-non-react-statics@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.3.1.tgz#343db84c6018c650778898240135a1420ee22ce0" + +home-or-tmp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.1" + +hosted-git-info@^2.1.4: + version "2.5.0" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" + +html-encoding-sniffer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.1.tgz#79bf7a785ea495fe66165e734153f363ff5437da" + dependencies: + whatwg-encoding "^1.0.1" + +htmlparser2@^3.9.1: + version "3.9.2" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.9.2.tgz#1bdf87acca0f3f9e53fa4fcceb0f4b4cbb00b338" + dependencies: + domelementtype "^1.3.0" + domhandler "^2.3.0" + domutils "^1.5.1" + entities "^1.1.1" + inherits "^2.0.1" + readable-stream "^2.0.2" + +http-signature@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" + dependencies: + assert-plus "^0.2.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +husky@^0.14.3: + version "0.14.3" + resolved "https://registry.yarnpkg.com/husky/-/husky-0.14.3.tgz#c69ed74e2d2779769a17ba8399b54ce0b63c12c3" + dependencies: + is-ci "^1.0.10" + normalize-path "^1.0.0" + strip-indent "^2.0.0" + +iconv-lite@0.4.13: + version "0.4.13" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2" + +iconv-lite@^0.4.17, iconv-lite@~0.4.13: + version "0.4.19" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" + +ignore@^3.3.3: + version "3.3.5" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.5.tgz#c4e715455f6073a8d7e5dae72d2fc9d71663dba6" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + +indent-string@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" + dependencies: + repeating "^2.0.0" + +indent-string@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +ini@~1.3.0: + version "1.3.4" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" + +inquirer@^3.0.6: + version "3.3.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.0" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^2.0.4" + figures "^2.0.0" + lodash "^4.3.0" + mute-stream "0.0.7" + run-async "^2.2.0" + rx-lite "^4.0.8" + rx-lite-aggregates "^4.0.8" + string-width "^2.1.0" + strip-ansi "^4.0.0" + through "^2.3.6" + +invariant@^2.0.0, invariant@^2.1.0, invariant@^2.2.1, invariant@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" + dependencies: + loose-envify "^1.0.0" + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc" + +is-builtin-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + dependencies: + builtin-modules "^1.0.0" + +is-callable@^1.1.1, is-callable@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.3.tgz#86eb75392805ddc33af71c92a0eedf74ee7604b2" + +is-ci@^1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.0.10.tgz#f739336b2632365061a9d48270cd56ae3369318e" + dependencies: + ci-info "^1.0.0" + +is-date-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" + +is-dotfile@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" + +is-equal-shallow@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + dependencies: + is-primitive "^2.0.0" + +is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + +is-finite@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + +is-glob@^2.0.0, is-glob@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + dependencies: + is-extglob "^1.0.0" + +is-glob@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0" + dependencies: + is-extglob "^2.1.1" + +is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + dependencies: + kind-of "^3.0.2" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + dependencies: + kind-of "^3.0.2" + +is-obj@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + +is-path-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + +is-path-in-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" + dependencies: + is-path-inside "^1.0.0" + +is-path-inside@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" + dependencies: + path-is-inside "^1.0.1" + +is-posix-bracket@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + +is-primitive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + +is-promise@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" + +is-regex@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" + dependencies: + has "^1.0.1" + +is-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" + +is-resolvable@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" + dependencies: + tryit "^1.0.1" + +is-stream@^1.0.1, is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + +is-subset@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-subset/-/is-subset-0.1.1.tgz#8a59117d932de1de00f245fcdd39ce43f1e939a6" + +is-symbol@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + +isomorphic-fetch@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" + dependencies: + node-fetch "^1.0.1" + whatwg-fetch ">=0.10.0" + +isomorphic-form-data@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isomorphic-form-data/-/isomorphic-form-data-1.0.0.tgz#0447be7e0f6b86def3d393036cf7664a98919100" + dependencies: + form-data "^1.0.0-rc3" + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + +istanbul-api@^1.1.1: + version "1.1.14" + resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-1.1.14.tgz#25bc5701f7c680c0ffff913de46e3619a3a6e680" + dependencies: + async "^2.1.4" + fileset "^2.0.2" + istanbul-lib-coverage "^1.1.1" + istanbul-lib-hook "^1.0.7" + istanbul-lib-instrument "^1.8.0" + istanbul-lib-report "^1.1.1" + istanbul-lib-source-maps "^1.2.1" + istanbul-reports "^1.1.2" + js-yaml "^3.7.0" + mkdirp "^0.5.1" + once "^1.4.0" + +istanbul-lib-coverage@^1.0.1, istanbul-lib-coverage@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.1.tgz#73bfb998885299415c93d38a3e9adf784a77a9da" + +istanbul-lib-hook@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.0.7.tgz#dd6607f03076578fe7d6f2a630cf143b49bacddc" + dependencies: + append-transform "^0.4.0" + +istanbul-lib-instrument@^1.4.2, istanbul-lib-instrument@^1.7.5, istanbul-lib-instrument@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.8.0.tgz#66f6c9421cc9ec4704f76f2db084ba9078a2b532" + dependencies: + babel-generator "^6.18.0" + babel-template "^6.16.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + babylon "^6.18.0" + istanbul-lib-coverage "^1.1.1" + semver "^5.3.0" + +istanbul-lib-report@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz#f0e55f56655ffa34222080b7a0cd4760e1405fc9" + dependencies: + istanbul-lib-coverage "^1.1.1" + mkdirp "^0.5.1" + path-parse "^1.0.5" + supports-color "^3.1.2" + +istanbul-lib-source-maps@^1.1.0, istanbul-lib-source-maps@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.1.tgz#a6fe1acba8ce08eebc638e572e294d267008aa0c" + dependencies: + debug "^2.6.3" + istanbul-lib-coverage "^1.1.1" + mkdirp "^0.5.1" + rimraf "^2.6.1" + source-map "^0.5.3" + +istanbul-reports@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.1.2.tgz#0fb2e3f6aa9922bd3ce45d05d8ab4d5e8e07bd4f" + dependencies: + handlebars "^4.0.3" + +jest-changed-files@^21.2.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-21.2.0.tgz#5dbeecad42f5d88b482334902ce1cba6d9798d29" + dependencies: + throat "^4.0.0" + +jest-cli@^21.2.1: + version "21.2.1" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-21.2.1.tgz#9c528b6629d651911138d228bdb033c157ec8c00" + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.1" + glob "^7.1.2" + graceful-fs "^4.1.11" + is-ci "^1.0.10" + istanbul-api "^1.1.1" + istanbul-lib-coverage "^1.0.1" + istanbul-lib-instrument "^1.4.2" + istanbul-lib-source-maps "^1.1.0" + jest-changed-files "^21.2.0" + jest-config "^21.2.1" + jest-environment-jsdom "^21.2.1" + jest-haste-map "^21.2.0" + jest-message-util "^21.2.1" + jest-regex-util "^21.2.0" + jest-resolve-dependencies "^21.2.0" + jest-runner "^21.2.1" + jest-runtime "^21.2.1" + jest-snapshot "^21.2.1" + jest-util "^21.2.1" + micromatch "^2.3.11" + node-notifier "^5.0.2" + pify "^3.0.0" + slash "^1.0.0" + string-length "^2.0.0" + strip-ansi "^4.0.0" + which "^1.2.12" + worker-farm "^1.3.1" + yargs "^9.0.0" + +jest-config@^21.2.1: + version "21.2.1" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-21.2.1.tgz#c7586c79ead0bcc1f38c401e55f964f13bf2a480" + dependencies: + chalk "^2.0.1" + glob "^7.1.1" + jest-environment-jsdom "^21.2.1" + jest-environment-node "^21.2.1" + jest-get-type "^21.2.0" + jest-jasmine2 "^21.2.1" + jest-regex-util "^21.2.0" + jest-resolve "^21.2.0" + jest-util "^21.2.1" + jest-validate "^21.2.1" + pretty-format "^21.2.1" + +jest-diff@^21.2.1: + version "21.2.1" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-21.2.1.tgz#46cccb6cab2d02ce98bc314011764bb95b065b4f" + dependencies: + chalk "^2.0.1" + diff "^3.2.0" + jest-get-type "^21.2.0" + pretty-format "^21.2.1" + +jest-docblock@^21.2.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-21.2.0.tgz#51529c3b30d5fd159da60c27ceedc195faf8d414" + +jest-environment-jsdom@^21.2.1: + version "21.2.1" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-21.2.1.tgz#38d9980c8259b2a608ec232deee6289a60d9d5b4" + dependencies: + jest-mock "^21.2.0" + jest-util "^21.2.1" + jsdom "^9.12.0" + +jest-environment-node@^21.2.1: + version "21.2.1" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-21.2.1.tgz#98c67df5663c7fbe20f6e792ac2272c740d3b8c8" + dependencies: + jest-mock "^21.2.0" + jest-util "^21.2.1" + +jest-get-type@^21.2.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-21.2.0.tgz#f6376ab9db4b60d81e39f30749c6c466f40d4a23" + +jest-haste-map@^21.2.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-21.2.0.tgz#1363f0a8bb4338f24f001806571eff7a4b2ff3d8" + dependencies: + fb-watchman "^2.0.0" + graceful-fs "^4.1.11" + jest-docblock "^21.2.0" + micromatch "^2.3.11" + sane "^2.0.0" + worker-farm "^1.3.1" + +jest-jasmine2@^21.2.1: + version "21.2.1" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-21.2.1.tgz#9cc6fc108accfa97efebce10c4308548a4ea7592" + dependencies: + chalk "^2.0.1" + expect "^21.2.1" + graceful-fs "^4.1.11" + jest-diff "^21.2.1" + jest-matcher-utils "^21.2.1" + jest-message-util "^21.2.1" + jest-snapshot "^21.2.1" + p-cancelable "^0.3.0" + +jest-matcher-utils@^21.2.1: + version "21.2.1" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-21.2.1.tgz#72c826eaba41a093ac2b4565f865eb8475de0f64" + dependencies: + chalk "^2.0.1" + jest-get-type "^21.2.0" + pretty-format "^21.2.1" + +jest-message-util@^21.2.1: + version "21.2.1" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-21.2.1.tgz#bfe5d4692c84c827d1dcf41823795558f0a1acbe" + dependencies: + chalk "^2.0.1" + micromatch "^2.3.11" + slash "^1.0.0" + +jest-mock@^21.2.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-21.2.0.tgz#7eb0770e7317968165f61ea2a7281131534b3c0f" + +jest-regex-util@^21.2.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-21.2.0.tgz#1b1e33e63143babc3e0f2e6c9b5ba1eb34b2d530" + +jest-resolve-dependencies@^21.2.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-21.2.0.tgz#9e231e371e1a736a1ad4e4b9a843bc72bfe03d09" + dependencies: + jest-regex-util "^21.2.0" + +jest-resolve@^21.2.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-21.2.0.tgz#068913ad2ba6a20218e5fd32471f3874005de3a6" + dependencies: + browser-resolve "^1.11.2" + chalk "^2.0.1" + is-builtin-module "^1.0.0" + +jest-runner@^21.2.1: + version "21.2.1" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-21.2.1.tgz#194732e3e518bfb3d7cbfc0fd5871246c7e1a467" + dependencies: + jest-config "^21.2.1" + jest-docblock "^21.2.0" + jest-haste-map "^21.2.0" + jest-jasmine2 "^21.2.1" + jest-message-util "^21.2.1" + jest-runtime "^21.2.1" + jest-util "^21.2.1" + pify "^3.0.0" + throat "^4.0.0" + worker-farm "^1.3.1" + +jest-runtime@^21.2.1: + version "21.2.1" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-21.2.1.tgz#99dce15309c670442eee2ebe1ff53a3cbdbbb73e" + dependencies: + babel-core "^6.0.0" + babel-jest "^21.2.0" + babel-plugin-istanbul "^4.0.0" + chalk "^2.0.1" + convert-source-map "^1.4.0" + graceful-fs "^4.1.11" + jest-config "^21.2.1" + jest-haste-map "^21.2.0" + jest-regex-util "^21.2.0" + jest-resolve "^21.2.0" + jest-util "^21.2.1" + json-stable-stringify "^1.0.1" + micromatch "^2.3.11" + slash "^1.0.0" + strip-bom "3.0.0" + write-file-atomic "^2.1.0" + yargs "^9.0.0" + +jest-snapshot@^21.2.1: + version "21.2.1" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-21.2.1.tgz#29e49f16202416e47343e757e5eff948c07fd7b0" + dependencies: + chalk "^2.0.1" + jest-diff "^21.2.1" + jest-matcher-utils "^21.2.1" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + pretty-format "^21.2.1" + +jest-util@^21.2.1: + version "21.2.1" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-21.2.1.tgz#a274b2f726b0897494d694a6c3d6a61ab819bb78" + dependencies: + callsites "^2.0.0" + chalk "^2.0.1" + graceful-fs "^4.1.11" + jest-message-util "^21.2.1" + jest-mock "^21.2.0" + jest-validate "^21.2.1" + mkdirp "^0.5.1" + +jest-validate@^21.1.0, jest-validate@^21.2.1: + version "21.2.1" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-21.2.1.tgz#cc0cbca653cd54937ba4f2a111796774530dd3c7" + dependencies: + chalk "^2.0.1" + jest-get-type "^21.2.0" + leven "^2.1.0" + pretty-format "^21.2.1" + +jest@^21.2.1: + version "21.2.1" + resolved "https://registry.yarnpkg.com/jest/-/jest-21.2.1.tgz#c964e0b47383768a1438e3ccf3c3d470327604e1" + dependencies: + jest-cli "^21.2.1" + +js-tokens@^3.0.0, js-tokens@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + +js-yaml@^3.4.3, js-yaml@^3.7.0, js-yaml@^3.9.1: + version "3.10.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc" + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + +jschardet@^1.4.2: + version "1.5.1" + resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-1.5.1.tgz#c519f629f86b3a5bedba58a88d311309eec097f9" + +jsdom@^9.12.0: + version "9.12.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-9.12.0.tgz#e8c546fffcb06c00d4833ca84410fed7f8a097d4" + dependencies: + abab "^1.0.3" + acorn "^4.0.4" + acorn-globals "^3.1.0" + array-equal "^1.0.0" + content-type-parser "^1.0.1" + cssom ">= 0.3.2 < 0.4.0" + cssstyle ">= 0.2.37 < 0.3.0" + escodegen "^1.6.1" + html-encoding-sniffer "^1.0.1" + nwmatcher ">= 1.3.9 < 2.0.0" + parse5 "^1.5.1" + request "^2.79.0" + sax "^1.2.1" + symbol-tree "^3.2.1" + tough-cookie "^2.3.2" + webidl-conversions "^4.0.0" + whatwg-encoding "^1.0.1" + whatwg-url "^4.3.0" + xml-name-validator "^2.0.1" + +jsesc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + +json-schema-traverse@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + +json-stable-stringify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + dependencies: + jsonify "~0.0.0" + +json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + +json5@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.4.0.tgz#054352e4c4c80c86c0923877d449de176a732c8d" + +json5@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +jsx-ast-utils@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz#e801b1b39985e20fffc87b40e3748080e2dcac7f" + dependencies: + array-includes "^3.0.3" + +keycode@^2.1.2: + version "2.1.9" + resolved "https://registry.yarnpkg.com/keycode/-/keycode-2.1.9.tgz#964a23c54e4889405b4861a5c9f0480d45141dfa" + +kind-of@^3.0.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + dependencies: + is-buffer "^1.1.5" + +lazy-cache@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" + +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + dependencies: + invert-kv "^1.0.0" + +leven@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580" + +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +lint-staged@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-4.2.3.tgz#5a1f12256af06110b96225f109dbf215009a37a9" + dependencies: + app-root-path "^2.0.0" + chalk "^2.1.0" + cosmiconfig "^1.1.0" + execa "^0.8.0" + is-glob "^4.0.0" + jest-validate "^21.1.0" + listr "^0.12.0" + lodash "^4.17.4" + log-symbols "^2.0.0" + minimatch "^3.0.0" + npm-which "^3.0.1" + p-map "^1.1.1" + staged-git-files "0.0.4" + stringify-object "^3.2.0" + +listr-silent-renderer@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz#924b5a3757153770bf1a8e3fbf74b8bbf3f9242e" + +listr-update-renderer@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/listr-update-renderer/-/listr-update-renderer-0.2.0.tgz#ca80e1779b4e70266807e8eed1ad6abe398550f9" + dependencies: + chalk "^1.1.3" + cli-truncate "^0.2.1" + elegant-spinner "^1.0.1" + figures "^1.7.0" + indent-string "^3.0.0" + log-symbols "^1.0.2" + log-update "^1.0.2" + strip-ansi "^3.0.1" + +listr-verbose-renderer@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/listr-verbose-renderer/-/listr-verbose-renderer-0.4.0.tgz#44dc01bb0c34a03c572154d4d08cde9b1dc5620f" + dependencies: + chalk "^1.1.3" + cli-cursor "^1.0.2" + date-fns "^1.27.2" + figures "^1.7.0" + +listr@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/listr/-/listr-0.12.0.tgz#6bce2c0f5603fa49580ea17cd6a00cc0e5fa451a" + dependencies: + chalk "^1.1.3" + cli-truncate "^0.2.1" + figures "^1.7.0" + indent-string "^2.1.0" + is-promise "^2.1.0" + is-stream "^1.1.0" + listr-silent-renderer "^1.1.1" + listr-update-renderer "^0.2.0" + listr-verbose-renderer "^0.4.0" + log-symbols "^1.0.2" + log-update "^1.0.2" + ora "^0.2.3" + p-map "^1.1.1" + rxjs "^5.0.0-beta.11" + stream-to-observable "^0.1.0" + strip-ansi "^3.0.1" + +load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + +load-json-file@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + strip-bom "^3.0.0" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +lodash-es@^4.17.3, lodash-es@^4.2.0, lodash-es@^4.2.1: + version "4.17.4" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.4.tgz#dcc1d7552e150a0640073ba9cb31d70f032950e7" + +lodash.assignin@^4.0.9: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" + +lodash.bind@^4.1.4: + version "4.2.1" + resolved "https://registry.yarnpkg.com/lodash.bind/-/lodash.bind-4.2.1.tgz#7ae3017e939622ac31b7d7d7dcb1b34db1690d35" + +lodash.cond@^4.3.0: + version "4.5.2" + resolved "https://registry.yarnpkg.com/lodash.cond/-/lodash.cond-4.5.2.tgz#f471a1da486be60f6ab955d17115523dd1d255d5" + +lodash.defaults@^4.0.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + +lodash.filter@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.filter/-/lodash.filter-4.6.0.tgz#668b1d4981603ae1cc5a6fa760143e480b4c4ace" + +lodash.flatten@^4.2.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" + +lodash.foreach@^4.3.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53" + +lodash.map@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3" + +lodash.merge@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.0.tgz#69884ba144ac33fe699737a6086deffadd0f89c5" + +lodash.pick@^4.2.1: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" + +lodash.reduce@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.reduce/-/lodash.reduce-4.6.0.tgz#f1ab6b839299ad48f784abbf476596f03b914d3b" + +lodash.reject@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.reject/-/lodash.reject-4.6.0.tgz#80d6492dc1470864bbf583533b651f42a9f52415" + +lodash.some@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d" + +lodash@^4.0.0, lodash@^4.14.0, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@~4.17.2: + version "4.17.4" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" + +log-symbols@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18" + dependencies: + chalk "^1.0.0" + +log-symbols@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.1.0.tgz#f35fa60e278832b538dc4dddcbb478a45d3e3be6" + dependencies: + chalk "^2.0.1" + +log-update@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/log-update/-/log-update-1.0.2.tgz#19929f64c4093d2d2e7075a1dad8af59c296b8d1" + dependencies: + ansi-escapes "^1.0.0" + cli-cursor "^1.0.2" + +longest@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" + +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" + dependencies: + js-tokens "^3.0.0" + +lru-cache@^4.0.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.1.tgz#622e32e82488b49279114a4f9ecf45e7cd6bba55" + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +makeerror@1.0.x: + version "1.0.11" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + dependencies: + tmpl "1.0.x" + +mem@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" + dependencies: + mimic-fn "^1.0.0" + +merge@^1.1.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" + +micromatch@^2.1.5, micromatch@^2.3.11: + version "2.3.11" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + dependencies: + arr-diff "^2.0.0" + array-unique "^0.2.1" + braces "^1.8.2" + expand-brackets "^0.1.4" + extglob "^0.3.1" + filename-regex "^2.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.1" + kind-of "^3.0.2" + normalize-path "^2.0.1" + object.omit "^2.0.0" + parse-glob "^3.0.4" + regex-cache "^0.4.2" + +mime-db@~1.30.0: + version "1.30.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" + +mime-types@^2.1.11, mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.7: + version "2.1.17" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a" + dependencies: + mime-db "~1.30.0" + +mimic-fn@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18" + +min-document@^2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" + dependencies: + dom-walk "^0.1.0" + +minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + +minimist@^1.1.1, minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +minimist@~0.0.1: + version "0.0.10" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" + +"mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + +mute-stream@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + +nan@^2.3.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.7.0.tgz#d95bf721ec877e08db276ed3fc6eb78f9083ad46" + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + +nock@^9.0.14: + version "9.0.22" + resolved "https://registry.yarnpkg.com/nock/-/nock-9.0.22.tgz#f6eb8ea58c6232dead857484370c2e46f010a087" + dependencies: + chai ">=1.9.2 <4.0.0" + debug "^2.2.0" + deep-equal "^1.0.0" + json-stringify-safe "^5.0.1" + lodash "~4.17.2" + mkdirp "^0.5.0" + propagate "0.4.0" + qs "^6.0.2" + semver "^5.3.0" + +node-fetch@^1.0.1: + version "1.7.3" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" + dependencies: + encoding "^0.1.11" + is-stream "^1.0.1" + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + +node-notifier@^5.0.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.1.2.tgz#2fa9e12605fa10009d44549d6fcd8a63dde0e4ff" + dependencies: + growly "^1.3.0" + semver "^5.3.0" + shellwords "^0.1.0" + which "^1.2.12" + +node-pre-gyp@^0.6.36: + version "0.6.38" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.38.tgz#e92a20f83416415bb4086f6d1fb78b3da73d113d" + dependencies: + hawk "3.1.3" + mkdirp "^0.5.1" + nopt "^4.0.1" + npmlog "^4.0.2" + rc "^1.1.7" + request "2.81.0" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^2.2.1" + tar-pack "^3.4.0" + +nopt@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + dependencies: + abbrev "1" + osenv "^0.1.4" + +normalize-package-data@^2.3.2: + version "2.4.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" + dependencies: + hosted-git-info "^2.1.4" + is-builtin-module "^1.0.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-1.0.0.tgz#32d0e472f91ff345701c15a8311018d3b0a90379" + +normalize-path@^2.0.0, normalize-path@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + dependencies: + remove-trailing-separator "^1.0.1" + +npm-path@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/npm-path/-/npm-path-2.0.3.tgz#15cff4e1c89a38da77f56f6055b24f975dfb2bbe" + dependencies: + which "^1.2.10" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + dependencies: + path-key "^2.0.0" + +npm-which@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/npm-which/-/npm-which-3.0.1.tgz#9225f26ec3a285c209cae67c3b11a6b4ab7140aa" + dependencies: + commander "^2.9.0" + npm-path "^2.0.2" + which "^1.2.10" + +npmlog@^4.0.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +nth-check@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.1.tgz#9929acdf628fc2c41098deab82ac580cf149aae4" + dependencies: + boolbase "~1.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + +"nwmatcher@>= 1.3.9 < 2.0.0": + version "1.4.3" + resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.4.3.tgz#64348e3b3d80f035b40ac11563d278f8b72db89c" + +oauth-sign@~0.8.1, oauth-sign@~0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + +object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + +object-is@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.0.1.tgz#0aa60ec9989a0b3ed795cf4d06f62cf1ad6539b6" + +object-keys@^1.0.10, object-keys@^1.0.8: + version "1.0.11" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" + +object.assign@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.0.4.tgz#b1c9cc044ef1b9fe63606fc141abbb32e14730cc" + dependencies: + define-properties "^1.1.2" + function-bind "^1.1.0" + object-keys "^1.0.10" + +object.entries@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.0.4.tgz#1bf9a4dd2288f5b33f3a993d257661f05d161a5f" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.6.1" + function-bind "^1.1.0" + has "^1.0.1" + +object.omit@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + dependencies: + for-own "^0.1.4" + is-extendable "^0.1.1" + +object.values@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.0.4.tgz#e524da09b4f66ff05df457546ec72ac99f13069a" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.6.1" + function-bind "^1.1.0" + has "^1.0.1" + +once@^1.3.0, once@^1.3.3, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +onetime@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" + +onetime@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + dependencies: + mimic-fn "^1.0.0" + +optimist@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + dependencies: + minimist "~0.0.1" + wordwrap "~0.0.2" + +optionator@^0.8.1, optionator@^0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.4" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + wordwrap "~1.0.0" + +ora@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/ora/-/ora-0.2.3.tgz#37527d220adcd53c39b73571d754156d5db657a4" + dependencies: + chalk "^1.1.1" + cli-cursor "^1.0.2" + cli-spinners "^0.1.2" + object-assign "^4.0.1" + +os-homedir@1.0.2, os-homedir@^1.0.0, os-homedir@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +os-locale@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" + dependencies: + execa "^0.7.0" + lcid "^1.0.0" + mem "^1.1.0" + +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + +osenv@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +output-file-sync@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76" + dependencies: + graceful-fs "^4.1.4" + mkdirp "^0.5.1" + object-assign "^4.1.0" + +p-cancelable@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa" + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + +p-limit@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.1.0.tgz#b07ff2d9a5d88bec806035895a2bab66a27988bc" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + dependencies: + p-limit "^1.1.0" + +p-map@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b" + +parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + dependencies: + error-ex "^1.2.0" + +parse5@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94" + +path-exists@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + dependencies: + pinkie-promise "^2.0.0" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + +path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +path-is-inside@^1.0.1, path-is-inside@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + +path-key@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + +path-parse@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" + +path-to-regexp@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d" + dependencies: + isarray "0.0.1" + +path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + dependencies: + graceful-fs "^4.1.2" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +path-type@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" + dependencies: + pify "^2.0.0" + +performance-now@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + +pkg-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" + dependencies: + find-up "^1.0.0" + +pluralize@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + +preserve@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + +prettier@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.7.4.tgz#5e8624ae9363c80f95ec644584ecdf55d74f93fa" + +pretty-format@^21.2.1: + version "21.2.1" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-21.2.1.tgz#ae5407f3cf21066cd011aa1ba5fce7b6a2eddb36" + dependencies: + ansi-regex "^3.0.0" + ansi-styles "^3.2.0" + +private@^0.1.6, private@^0.1.7: + version "0.1.8" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" + +process-nextick-args@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + +process@~0.5.1: + version "0.5.2" + resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" + +progress@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" + +promise@^7.1.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" + dependencies: + asap "~2.0.3" + +prop-types-extra@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prop-types-extra/-/prop-types-extra-1.0.1.tgz#a57bd4810e82d27a3ff4317ecc1b4ad005f79a82" + dependencies: + warning "^3.0.0" + +prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.8, prop-types@^15.5.9: + version "15.6.0" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.0.tgz#ceaf083022fc46b4a35f69e13ef75aed0d639856" + dependencies: + fbjs "^0.8.16" + loose-envify "^1.3.1" + object-assign "^4.1.1" + +propagate@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/propagate/-/propagate-0.4.0.tgz#f3fcca0a6fe06736a7ba572966069617c130b481" + +prr@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a" + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + +pubsweet-component-login@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/pubsweet-component-login/-/pubsweet-component-login-0.5.2.tgz#ff942838be4c64607020f67c777d6e1da9197115" + dependencies: + prop-types "^15.5.10" + react-bootstrap "^0.31.3" + react-redux "^5.0.6" + react-router-dom "^4.2.2" + react-router-redux "^4.0.8" + redux "^3.7.2" + +punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + +qs@^6.0.2, qs@~6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" + +qs@~6.4.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" + +randomatic@^1.1.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +rc@^1.1.7: + version "1.2.1" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.1.tgz#2e03e8e42ee450b8cb3dce65be1bf8974e1dfd95" + dependencies: + deep-extend "~0.4.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +react-bootstrap@^0.31.3: + version "0.31.3" + resolved "https://registry.yarnpkg.com/react-bootstrap/-/react-bootstrap-0.31.3.tgz#db2b7d45b00b5dac1ab8b6de3dd97feb3091b849" + dependencies: + babel-runtime "^6.11.6" + classnames "^2.2.5" + dom-helpers "^3.2.0" + invariant "^2.2.1" + keycode "^2.1.2" + prop-types "^15.5.10" + prop-types-extra "^1.0.1" + react-overlays "^0.7.0" + react-prop-types "^0.4.0" + uncontrollable "^4.1.0" + warning "^3.0.0" + +react-css-themr@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/react-css-themr/-/react-css-themr-2.1.2.tgz#e017514e471c232f43a754a55b49d81faf5dafb8" + dependencies: + hoist-non-react-statics "^1.2.0" + invariant "^2.2.1" + +react-dom@^15.6.1: + version "15.6.2" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.6.2.tgz#41cfadf693b757faf2708443a1d1fd5a02bef730" + dependencies: + fbjs "^0.8.9" + loose-envify "^1.1.0" + object-assign "^4.1.0" + prop-types "^15.5.10" + +react-overlays@^0.7.0: + version "0.7.2" + resolved "https://registry.yarnpkg.com/react-overlays/-/react-overlays-0.7.2.tgz#03808f80d99dfadd93d67438c619aa55d07b3f80" + dependencies: + classnames "^2.2.5" + dom-helpers "^3.2.1" + prop-types "^15.5.10" + prop-types-extra "^1.0.1" + warning "^3.0.0" + +react-prop-types@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/react-prop-types/-/react-prop-types-0.4.0.tgz#f99b0bfb4006929c9af2051e7c1414a5c75b93d0" + dependencies: + warning "^3.0.0" + +react-redux@^5.0.2, react-redux@^5.0.6: + version "5.0.6" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.0.6.tgz#23ed3a4f986359d68b5212eaaa681e60d6574946" + dependencies: + hoist-non-react-statics "^2.2.1" + invariant "^2.0.0" + lodash "^4.2.0" + lodash-es "^4.2.0" + loose-envify "^1.1.0" + prop-types "^15.5.10" + +react-router-dom@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-4.2.2.tgz#c8a81df3adc58bba8a76782e946cbd4eae649b8d" + dependencies: + history "^4.7.2" + invariant "^2.2.2" + loose-envify "^1.3.1" + prop-types "^15.5.4" + react-router "^4.2.0" + warning "^3.0.0" + +react-router-redux@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/react-router-redux/-/react-router-redux-4.0.8.tgz#227403596b5151e182377dab835b5d45f0f8054e" + +react-router-redux@next: + version "5.0.0-alpha.6" + resolved "https://registry.yarnpkg.com/react-router-redux/-/react-router-redux-5.0.0-alpha.6.tgz#7418663c2ecd3c51be856fcf28f3d1deecc1a576" + dependencies: + history "^4.5.1" + prop-types "^15.5.4" + react-router "^4.1.1" + +react-router@^4.1.1, react-router@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-4.2.0.tgz#61f7b3e3770daeb24062dae3eedef1b054155986" + dependencies: + history "^4.7.2" + hoist-non-react-statics "^2.3.0" + invariant "^2.2.2" + loose-envify "^1.3.1" + path-to-regexp "^1.7.0" + prop-types "^15.5.4" + warning "^3.0.0" + +react-test-renderer@^15.6.1: + version "15.6.2" + resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-15.6.2.tgz#d0333434fc2c438092696ca770da5ed48037efa8" + dependencies: + fbjs "^0.8.9" + object-assign "^4.1.0" + +react@^15.4.4: + version "15.6.2" + resolved "https://registry.yarnpkg.com/react/-/react-15.6.2.tgz#dba0434ab439cfe82f108f0f511663908179aa72" + dependencies: + create-react-class "^15.6.0" + fbjs "^0.8.9" + loose-envify "^1.1.0" + object-assign "^4.1.0" + prop-types "^15.5.10" + +read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + dependencies: + find-up "^1.0.0" + read-pkg "^1.0.0" + +read-pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" + dependencies: + find-up "^2.0.0" + read-pkg "^2.0.0" + +read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + dependencies: + load-json-file "^1.0.0" + normalize-package-data "^2.3.2" + path-type "^1.0.0" + +read-pkg@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" + dependencies: + load-json-file "^2.0.0" + normalize-package-data "^2.3.2" + path-type "^2.0.0" + +readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.2.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + safe-buffer "~5.1.1" + string_decoder "~1.0.3" + util-deprecate "~1.0.1" + +readdirp@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" + dependencies: + graceful-fs "^4.1.2" + minimatch "^3.0.2" + readable-stream "^2.0.2" + set-immediate-shim "^1.0.1" + +redux-form@^7.0.3: + version "7.1.1" + resolved "https://registry.yarnpkg.com/redux-form/-/redux-form-7.1.1.tgz#4d9ab1d9c03beb3a8b5f8e5d0f398cff4209081f" + dependencies: + babel-jest "^21.2.0" + deep-equal "^1.0.1" + es6-error "^4.0.0" + hoist-non-react-statics "^2.3.1" + invariant "^2.2.2" + is-promise "^2.1.0" + lodash "^4.17.3" + lodash-es "^4.17.3" + prop-types "^15.5.9" + +redux-logger@^3.0.1: + version "3.0.6" + resolved "https://registry.yarnpkg.com/redux-logger/-/redux-logger-3.0.6.tgz#f7555966f3098f3c88604c449cf0baf5778274bf" + dependencies: + deep-diff "^0.3.5" + +redux-mock-store@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/redux-mock-store/-/redux-mock-store-1.3.0.tgz#6edfef0d2332f20576381069d6d889a6d0a4451c" + +redux-thunk@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.2.0.tgz#e615a16e16b47a19a515766133d1e3e99b7852e5" + +redux@^3.6.0, redux@^3.7.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/redux/-/redux-3.7.2.tgz#06b73123215901d25d065be342eb026bc1c8537b" + dependencies: + lodash "^4.2.1" + lodash-es "^4.2.1" + loose-envify "^1.1.0" + symbol-observable "^1.0.3" + +regenerate@^1.2.1: + version "1.3.3" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.3.tgz#0c336d3980553d755c39b586ae3b20aa49c82b7f" + +regenerator-runtime@^0.10.5: + version "0.10.5" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" + +regenerator-runtime@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz#7e54fe5b5ccd5d6624ea6255c3473be090b802e1" + +regenerator-transform@^0.10.0: + version "0.10.1" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" + dependencies: + babel-runtime "^6.18.0" + babel-types "^6.19.0" + private "^0.1.6" + +regex-cache@^0.4.2: + version "0.4.4" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" + dependencies: + is-equal-shallow "^0.1.3" + +regexpu-core@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + +regjsgen@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + +regjsparser@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + dependencies: + jsesc "~0.5.0" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + +repeat-element@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + +repeat-string@^1.5.2: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + dependencies: + is-finite "^1.0.0" + +request@2.81.0: + version "2.81.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~2.1.1" + har-validator "~4.2.1" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + oauth-sign "~0.8.1" + performance-now "^0.2.0" + qs "~6.4.0" + safe-buffer "^5.0.1" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "^0.6.0" + uuid "^3.0.0" + +request@^2.79.0: + version "2.83.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356" + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.6.0" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.1" + forever-agent "~0.6.1" + form-data "~2.3.1" + 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.17" + oauth-sign "~0.8.2" + performance-now "^2.1.0" + qs "~6.5.1" + safe-buffer "^5.1.1" + stringstream "~0.0.5" + tough-cookie "~2.3.3" + tunnel-agent "^0.6.0" + uuid "^3.1.0" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + +require-from-string@^1.1.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-1.2.1.tgz#529c9ccef27380adfec9a2f965b649bbee636418" + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + +require-uncached@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" + dependencies: + caller-path "^0.1.0" + resolve-from "^1.0.0" + +resolve-from@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" + +resolve-pathname@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-2.2.0.tgz#7e9ae21ed815fd63ab189adeee64dc831eefa879" + +resolve@1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" + +resolve@^1.2.0, resolve@^1.3.3: + version "1.4.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.4.0.tgz#a75be01c53da25d934a98ebd0e4c4a7312f92a86" + dependencies: + path-parse "^1.0.5" + +restore-cursor@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" + dependencies: + exit-hook "^1.0.0" + onetime "^1.0.0" + +restore-cursor@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + dependencies: + onetime "^2.0.0" + signal-exit "^3.0.2" + +right-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" + dependencies: + align-text "^0.1.1" + +rimraf@2, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.6.1: + version "2.6.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" + dependencies: + glob "^7.0.5" + +run-async@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" + dependencies: + is-promise "^2.1.0" + +rx-lite-aggregates@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" + dependencies: + rx-lite "*" + +rx-lite@*, rx-lite@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" + +rxjs@^5.0.0-beta.11: + version "5.4.3" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.4.3.tgz#0758cddee6033d68e0fd53676f0f3596ce3d483f" + dependencies: + symbol-observable "^1.0.1" + +safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" + +sane@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/sane/-/sane-2.2.0.tgz#d6d2e2fcab00e3d283c93b912b7c3a20846f1d56" + dependencies: + anymatch "^1.3.0" + exec-sh "^0.2.0" + fb-watchman "^2.0.0" + minimatch "^3.0.2" + minimist "^1.1.1" + walker "~1.0.5" + watch "~0.18.0" + optionalDependencies: + fsevents "^1.1.1" + +sax@^1.2.1: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + +"semver@2 || 3 || 4 || 5", semver@^5.3.0: + version "5.4.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" + +semver@5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + +set-blocking@^2.0.0, set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +set-immediate-shim@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + +shellwords@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + +slice-ansi@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" + +slice-ansi@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" + dependencies: + is-fullwidth-code-point "^2.0.0" + +sntp@1.x.x: + version "1.0.9" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" + dependencies: + hoek "2.x.x" + +sntp@2.x.x: + version "2.0.2" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-2.0.2.tgz#5064110f0af85f7cfdb7d6b67a40028ce52b4b2b" + dependencies: + hoek "4.x.x" + +source-map-support@^0.4.15: + version "0.4.18" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" + dependencies: + source-map "^0.5.6" + +source-map@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + dependencies: + amdefine ">=0.0.4" + +source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.6: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + +spdx-correct@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" + dependencies: + spdx-license-ids "^1.0.2" + +spdx-expression-parse@~1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" + +spdx-license-ids@^1.0.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + +sshpk@^1.7.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3" + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + dashdash "^1.12.0" + getpass "^0.1.1" + optionalDependencies: + bcrypt-pbkdf "^1.0.0" + ecc-jsbn "~0.1.1" + jsbn "~0.1.0" + tweetnacl "~0.14.0" + +staged-git-files@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/staged-git-files/-/staged-git-files-0.0.4.tgz#d797e1b551ca7a639dec0237dc6eb4bb9be17d35" + +stream-to-observable@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/stream-to-observable/-/stream-to-observable-0.1.0.tgz#45bf1d9f2d7dc09bed81f1c307c430e68b84cffe" + +string-length@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-2.0.0.tgz#d40dbb686a3ace960c1cffca562bf2c45f8363ed" + dependencies: + astral-regex "^1.0.0" + strip-ansi "^4.0.0" + +string-width@^1.0.1, string-width@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string_decoder@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" + dependencies: + safe-buffer "~5.1.0" + +stringify-object@^3.2.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.2.1.tgz#2720c2eff940854c819f6ee252aaeb581f30624d" + dependencies: + get-own-enumerable-property-symbols "^2.0.1" + is-obj "^1.0.1" + is-regexp "^1.0.0" + +stringstream@~0.0.4, stringstream@~0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + dependencies: + ansi-regex "^3.0.0" + +strip-bom@3.0.0, strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + dependencies: + is-utf8 "^0.2.0" + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + +strip-indent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68" + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + +supports-color@^3.1.2: + version "3.2.3" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" + dependencies: + has-flag "^1.0.0" + +supports-color@^4.0.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.4.0.tgz#883f7ddabc165142b2a61427f3352ded195d1a3e" + dependencies: + has-flag "^2.0.0" + +symbol-observable@^1.0.1, symbol-observable@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.4.tgz#29bf615d4aa7121bdd898b22d4b3f9bc4e2aa03d" + +symbol-tree@^3.2.1: + version "3.2.2" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6" + +table@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36" + dependencies: + ajv "^5.2.3" + ajv-keywords "^2.1.0" + chalk "^2.1.0" + lodash "^4.17.4" + slice-ansi "1.0.0" + string-width "^2.1.1" + +tar-pack@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.0.tgz#23be2d7f671a8339376cbdb0b8fe3fdebf317984" + dependencies: + debug "^2.2.0" + fstream "^1.0.10" + fstream-ignore "^1.0.5" + once "^1.3.3" + readable-stream "^2.1.4" + rimraf "^2.5.1" + tar "^2.2.1" + uid-number "^0.0.6" + +tar@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + dependencies: + block-stream "*" + fstream "^1.0.2" + inherits "2" + +test-exclude@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-4.1.1.tgz#4d84964b0966b0087ecc334a2ce002d3d9341e26" + dependencies: + arrify "^1.0.1" + micromatch "^2.3.11" + object-assign "^4.1.0" + read-pkg-up "^1.0.1" + require-main-filename "^1.0.1" + +text-table@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + +throat@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a" + +through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + dependencies: + os-tmpdir "~1.0.2" + +tmpl@1.0.x: + version "1.0.4" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" + +to-fast-properties@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" + +tough-cookie@^2.3.2, tough-cookie@~2.3.0, tough-cookie@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561" + dependencies: + punycode "^1.4.1" + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + +trim-right@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + +tryit@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + dependencies: + prelude-ls "~1.1.2" + +type-detect@0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822" + +type-detect@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + +ua-parser-js@^0.7.9: + version "0.7.17" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.17.tgz#e9ec5f9498b9ec910e7ae3ac626a805c4d09ecac" + +uglify-js@^2.6: + version "2.8.29" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" + dependencies: + source-map "~0.5.1" + yargs "~3.10.0" + optionalDependencies: + uglify-to-browserify "~1.0.0" + +uglify-to-browserify@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" + +uid-number@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" + +uncontrollable@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/uncontrollable/-/uncontrollable-4.1.0.tgz#e0358291252e1865222d90939b19f2f49f81c1a9" + dependencies: + invariant "^2.1.0" + +user-home@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +uuid@^3.0.0, uuid@^3.0.1, uuid@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" + +v8flags@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.1.1.tgz#aab1a1fa30d45f88dd321148875ac02c0b55e5b4" + dependencies: + user-home "^1.1.1" + +validate-npm-package-license@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" + dependencies: + spdx-correct "~1.0.0" + spdx-expression-parse "~1.0.0" + +value-equal@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-0.4.0.tgz#c5bdd2f54ee093c04839d71ce2e4758a6890abc7" + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +walker@~1.0.5: + version "1.0.7" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + dependencies: + makeerror "1.0.x" + +warning@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/warning/-/warning-3.0.0.tgz#32e5377cb572de4ab04753bdf8821c01ed605b7c" + dependencies: + loose-envify "^1.0.0" + +watch@~0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/watch/-/watch-0.18.0.tgz#28095476c6df7c90c963138990c0a5423eb4b986" + dependencies: + exec-sh "^0.2.0" + minimist "^1.2.0" + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + +webidl-conversions@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" + +whatwg-encoding@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.1.tgz#3c6c451a198ee7aec55b1ec61d0920c67801a5f4" + dependencies: + iconv-lite "0.4.13" + +whatwg-fetch@>=0.10.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84" + +whatwg-url@^4.3.0: + version "4.8.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-4.8.0.tgz#d2981aa9148c1e00a41c5a6131166ab4683bbcc0" + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + +which@^1.2.10, which@^1.2.12, which@^1.2.9: + version "1.3.0" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" + dependencies: + string-width "^1.0.2" + +window-size@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" + +wordwrap@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" + +wordwrap@~0.0.2: + version "0.0.3" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + +wordwrap@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + +worker-farm@^1.3.1: + version "1.5.0" + resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.5.0.tgz#adfdf0cd40581465ed0a1f648f9735722afd5c8d" + dependencies: + errno "^0.1.4" + xtend "^4.0.1" + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +write-file-atomic@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.3.0.tgz#1ff61575c2e2a4e8e510d6fa4e243cce183999ab" + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + signal-exit "^3.0.2" + +write@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" + dependencies: + mkdirp "^0.5.1" + +xml-name-validator@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635" + +xtend@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + +y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + +yargs-parser@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9" + dependencies: + camelcase "^4.1.0" + +yargs@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-9.0.1.tgz#52acc23feecac34042078ee78c0c007f5085db4c" + dependencies: + camelcase "^4.1.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + read-pkg-up "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^7.0.0" + +yargs@~3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" + dependencies: + camelcase "^1.0.2" + cliui "^2.1.0" + decamelize "^1.0.0" + window-size "0.1.0"