diff --git a/.gitignore b/.gitignore index 53ffa91..be0f9f0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ .DS_Store env +shows.db -yarn.lock -*/yarn.lock */package-lock.json diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..6f664eb --- /dev/null +++ b/.travis.yml @@ -0,0 +1,14 @@ +{ + 'dist': 'trusty', + 'language': 'node_js', + 'node_js': '8.7.0', + 'cache': 'yarn', + 'scripts': [ + 'npm run test' + ], + 'before_install': [ + 'cd seasoned_api', + ], + 'before_script': 'yarn', + 'os': 'linux', +} diff --git a/README.md b/README.md index 8b34d0b..cde5c89 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,18 @@ # 🌶 seasonedShows -Your customly seasoned movie and show requester, downloader and organizer +[![Build Status](https://travis-ci.org/KevinMidboe/seasonedShows.svg?branch=testing)](https://travis-ci.org/KevinMidboe/seasonedShows) +[![DUB](https://img.shields.io/dub/l/vibe-d.svg)]() + +Your customly *seasoned* movie and show requester, downloader and organizer. ## About +The goal of this project is to create a full custom stack that can to everything surround downloading, organizing and notifiyng of new media. From the top down we have a website using [tmdb](https://www.themoviedb.com) api to search for from over 350k movies and 70k tv shows. Using [hjone72](https://github.com/hjone72/PlexAuth) great PHP reverse proxy we can have a secure way of allowing users to login with their plex credentials which limits request capabilites to only users that are authenticated to use your plex library. seasonedShows is a intelligent organizer for your tv show episodes. It is made to automate and simplify to process of renaming and moving newly downloaded tv show episodes following Plex file naming and placement. +So this is a multipart system that lets your plex users request movies, and then from the admin page the owner can. + +## Installation +There are two main ways of + ## Architecture The flow of the system will first check for new folders in your tv shows directory, if a new file is found it's contents are analyzed, stored and tweets suggested changes to it's contents to use_admin. @@ -27,4 +36,4 @@ After approval by user the files are modified and moved to folders in resptected + Parse directories for new content. + Extract and save in db information about stray item. + Move a confirmed stray item. - + (+) Search for torrents matching new content. \ No newline at end of file + + (+) Search for torrents matching new content. diff --git a/app/torrent_search b/app/torrent_search new file mode 160000 index 0000000..3deaed4 --- /dev/null +++ b/app/torrent_search @@ -0,0 +1 @@ +Subproject commit 3deaed48b71adf97172e7bf899af87972cc7f4e2 diff --git a/client/app/components/MovieObject.jsx b/client/app/components/MovieObject.jsx deleted file mode 100644 index 64ea04c..0000000 --- a/client/app/components/MovieObject.jsx +++ /dev/null @@ -1,124 +0,0 @@ -import React from 'react'; - -import Notifications, {notify} from 'react-notify-toast'; - -// StyleComponents -import movieStyle from './styles/movieObjectStyle.jsx'; - -var MediaQuery = require('react-responsive'); - -import RequestButton from './buttons/request_button.jsx'; - -import { fetchJSON } from './http.jsx'; - -class MovieObject { - constructor(object) { - this.id = object.id; - this.title = object.title; - this.year = object.year; - this.type = object.type; - // Check if object.poster != undefined - this.rating = object.rating; - this.poster = object.poster; - this.background = object.background; - this.matchedInPlex = object.matchedInPlex; - this.summary = object.summary; - } - - requestExisting(movie) { - console.log('Exists', movie); - } - - requestMovie() { - // fetch('http://localhost:31459/api/v1/plex/request/' + this.id + '?type='+this.type, { - // fetch('https://apollo.kevinmidboe.com/api/v1/plex/request/' + this.id + '?type='+this.type, { - // method: 'POST' - // }); - fetchJSON('https://apollo.kevinmidboe.com/api/v1/plex/request/' + this.id + '?type='+this.type, 'POST') - .then((response) => { - console.log(response); - }) - - notify.show(this.title + ' requested!', 'success', 3000); - } - - getElement(index) { - const element_key = index + this.id; - - // TODO set the poster image async by updating the dom after this is returned - if (this.poster == null || this.poster == undefined) { - var posterPath = 'https://openclipart.org/image/2400px/svg_to_png/211479/Simple-Image-Not-Found-Icon.png' - } else { - var posterPath = 'https://image.tmdb.org/t/p/w300' + this.poster; - } - var backgroundPath = 'https://image.tmdb.org/t/p/w640_and_h360_bestv2/' + this.background; - - var foundInPlex; - if (this.matchedInPlex) { - foundInPlex = ; - } else { - foundInPlex = ; - } - - if (this.type === 'movie') - var themoviedbLink = 'https://www.themoviedb.org/movie/' + this.id - else if (this.type === 'show') - var themoviedbLink = 'https://www.themoviedb.org/tv/' + this.id - - - - // TODO add request button class - return ( -
- -
- -
- -
-
-
- - {this.title} -

- Released: { this.year } | Rating: {this.rating} -

- {this.summary} -

-
- - - - - {this.title} -

- Released: {this.year} | Rating: {this.rating} -
- - - - - - -
- {foundInPlex} - - - -
-
-
- -

-
-
-
-
-
) - - } -} - -export default MovieObject; \ No newline at end of file diff --git a/client/app/components/SearchObject.jsx b/client/app/components/SearchObject.jsx new file mode 100644 index 0000000..b61f4ea --- /dev/null +++ b/client/app/components/SearchObject.jsx @@ -0,0 +1,126 @@ +import React from 'react'; + +import Notifications, {notify} from 'react-notify-toast'; + +// StyleComponents +import searchObjectCSS from './styles/searchObject.jsx'; +import buttonsCSS from './styles/buttons.jsx'; +import InfoButton from './buttons/InfoButton.jsx'; + +var MediaQuery = require('react-responsive'); + +import { fetchJSON } from './http.jsx'; + +import Interactive from 'react-interactive'; + + +class SearchObject { + constructor(object) { + this.id = object.id; + this.title = object.title; + this.year = object.year; + this.type = object.type; + this.rating = object.rating; + this.poster = object.poster; + this.background = object.background; + this.matchedInPlex = object.matchedInPlex; + this.summary = object.summary; + } + + requestExisting(movie) { + console.log('Exists', movie); + } + + requestMovie() { + fetchJSON('https://apollo.kevinmidboe.com/api/v1/plex/request/' + this.id + '?type='+this.type, 'POST') + .then((response) => { + console.log(response); + notify.show(this.title + ' requested!', 'success', 3000); + }) + .catch((e) => { + console.error('Request movie fetch went wrong: '+ e); + }) + + } + + getElement(index) { + const element_key = index + this.id; + + if (this.poster == null || this.poster == undefined) { + var posterPath = 'https://openclipart.org/image/2400px/svg_to_png/211479/Simple-Image-Not-Found-Icon.png' + } else { + var posterPath = 'https://image.tmdb.org/t/p/w185' + this.poster; + } + var backgroundPath = 'https://image.tmdb.org/t/p/w640_and_h360_bestv2/' + this.background; + + var foundInPlex; + if (this.matchedInPlex) { + foundInPlex = {this.requestExisting(this)}} + style={buttonsCSS.submit} + focus={buttonsCSS.submit_hover} + hover={buttonsCSS.submit_hover}> + + Request Anyway + ; + } else { + foundInPlex = {this.requestMovie()}} + style={buttonsCSS.submit} + focus={buttonsCSS.submit_hover} + hover={buttonsCSS.submit_hover}> + + + Request + ; + } + + // TODO go away from using mediaQuery, and create custom resizer + return ( +
+ + +
+ +
+ +
+ {this.title} +

+ + Released: { this.year } | Rating: {this.rating} | Type: {this.type} + +

+ {this.summary} +

+
+ + + + {this.title} +

+ Released: {this.year} | Rating: {this.rating} +
+ +
+ {foundInPlex} + + +
+
+ + +
+
+ +
+
+
+
+ ) + + } +} + +export default SearchObject; \ No newline at end of file diff --git a/client/app/components/SearchRequest.jsx b/client/app/components/SearchRequest.jsx index dcd1cdd..bdb5098 100644 --- a/client/app/components/SearchRequest.jsx +++ b/client/app/components/SearchRequest.jsx @@ -1,14 +1,14 @@ import React from 'react'; -import MovieObject from './MovieObject.jsx'; - -// StyleComponents -import searchStyle from './styles/searchRequestStyle.jsx'; -import movieStyle from './styles/movieObjectStyle.jsx'; - import URI from 'urijs'; import InfiniteScroll from 'react-infinite-scroller'; +// StyleComponents +import searchRequestCSS from './styles/searchRequestStyle.jsx'; + +import SearchObject from './SearchObject.jsx'; +import Loading from './images/loading.jsx' + import { fetchJSON } from './http.jsx'; import { getCookie } from './Cookie.jsx'; @@ -29,7 +29,8 @@ class SearchRequest extends React.Component { page: 1, resultHeader: '', loadResults: false, - scrollHasMore: true + scrollHasMore: true, + loading: false, } this.allowedListTypes = ['discover', 'popular', 'nowplaying', 'upcoming'] @@ -46,7 +47,7 @@ class SearchRequest extends React.Component { // this.setState({responseMovieList: null}) this.resetPageNumber(); this.state.loadResults = true; - this.fetchTmdbList('upcoming'); + this.fetchTmdbList('discover'); } // Handles all errors of the response of a fetch call @@ -88,9 +89,9 @@ class SearchRequest extends React.Component { this.state.page = 1; } - writeLoading() { + setLoading(value) { this.setState({ - responseMovieList: 'Loading...' + loading: value }); } @@ -122,10 +123,7 @@ class SearchRequest extends React.Component { // Here we first call api for a search with the input uri, handle any errors // and fill the reponseData from api into the state of reponseMovieList as movieObjects - callSearchFillMovieList(uri) { - // Write loading animation - // this.writeLoading(); - + callSearchFillMovieList(uri) { Promise.resolve() .then(() => this.callURI(uri, 'GET')) .then(response => { @@ -152,7 +150,7 @@ class SearchRequest extends React.Component { } // Convert to json and update the state of responseMovieList with the results of the api call - // mapped as a movieObject. + // mapped as a SearchObject. response.json() .then(responseData => { if (this.state.page === 1) { @@ -180,7 +178,6 @@ class SearchRequest extends React.Component { callListFillMovieList(uri) { // Write loading animation - // this.writeLoading(); Promise.resolve() .then(() => this.callURI(uri, 'GET', undefined)) @@ -198,7 +195,7 @@ class SearchRequest extends React.Component { } // Convert to json and update the state of responseMovieList with the results of the api call - // mapped as a movieObject. + // mapped as a SearchObject. response.json() .then(responseData => { if (this.state.page === 1) { @@ -218,6 +215,7 @@ class SearchRequest extends React.Component { }) .catch((error) => { console.log('Something went wrong when fetching query.', error) + }) } @@ -287,10 +285,10 @@ class SearchRequest extends React.Component { } } - // When called passes the variable to MovieObject and calls it's interal function for + // When called passes the variable to SearchObject and calls it's interal function for // generating the wanted HTML createMovieObjects(item, index) { - let movie = new MovieObject(item); + let movie = new SearchObject(item); return movie.getElement(index); } @@ -345,12 +343,12 @@ class SearchRequest extends React.Component { movieToggle() { if (this.state.movieFilter) - return {this.toggleFilter('movies')}} id="category_active">Movies else - return {this.toggleFilter('movies')}} id="category_active">Movies @@ -358,12 +356,12 @@ class SearchRequest extends React.Component { showToggle() { if (this.state.showFilter) - return {this.toggleFilter('shows')}} id="category_active">TV Shows else - return {this.toggleFilter('shows')}} id="category_active">TV Shows @@ -379,50 +377,53 @@ class SearchRequest extends React.Component { pageStart={0} loadMore={this.pageForwards.bind(this)} hasMore={this.state.scrollHasMore} - loader={loader} + loader={} initialLoad={this.state.loadResults}> -
-
-
- Request new content +
+
+
+ Request new content for plex
-
-
- +
+ - this._handleQueryKeyPress(event)} - onChange={event => this.updateQueryState(event)} - value={this.state.searchQuery}/> + this._handleQueryKeyPress(event)} + onChange={event => this.updateQueryState(event)} + value={this.state.searchQuery}/> -
-
- {this.state.resultHeader} -



+
+
+
{this.state.resultHeader}
+ - {this.state.responseMovieList} +
+ +

+ + {this.state.responseMovieList}
-
-
-
- Request new content +
+
+
+ Request new content
-
-
- +
+
+ - this._handleQueryKeyPress(event)} onChange={event => this.updateQueryState(event)} value={this.state.searchQuery}/> @@ -431,11 +432,11 @@ class SearchRequest extends React.Component {
-
- {this.state.resultHeader} +
+ {this.state.resultHeader}



- {this.state.responseMovieList} + {this.state.responseMovieList}
@@ -443,7 +444,21 @@ class SearchRequest extends React.Component { ) } - + //
+ // + //
+ + //
+ // + //
} -export default SearchRequest; \ No newline at end of file +export default SearchRequest; diff --git a/client/app/components/admin/Admin.jsx b/client/app/components/admin/Admin.jsx index 47d941a..d2faeef 100644 --- a/client/app/components/admin/Admin.jsx +++ b/client/app/components/admin/Admin.jsx @@ -1,10 +1,5 @@ -/* - ./app/components/App.jsx - - -*/ + import React from 'react'; -import { HashRouter as Router, Route, Switch, IndexRoute } from 'react-router-dom'; import LoginForm from './LoginForm/LoginForm.jsx'; import { Provider } from 'react-redux'; @@ -16,6 +11,8 @@ import { fetchJSON } from '../http.jsx'; import Sidebar from './Sidebar.jsx'; import AdminRequestInfo from './AdminRequestInfo.jsx'; +import adminCSS from '../styles/adminComponent.jsx' + class AdminComponent extends React.Component { constructor(props) { @@ -23,9 +20,16 @@ class AdminComponent extends React.Component { this.state = { requested_objects: '', } + + this.updateHandler = this.updateHandler.bind(this) } + // Fetches all requested elements and updates the state with response componentWillMount() { + this.fetchRequestedItems() + } + + fetchRequestedItems() { fetchJSON('https://apollo.kevinmidboe.com/api/v1/plex/requests/all', 'GET') .then(result => { this.setState({ @@ -34,16 +38,13 @@ class AdminComponent extends React.Component { }) } - verifyLoggedIn() { - let adminComponentStyle = { - sidebar: { - float: 'left', - }, - selectedObjectPanel: { - float: 'left', - } - } + updateHandler() { + this.fetchRequestedItems() + } + // Displays loginform if not logged in and passes response from + // api call to sidebar and infoPanel through props + verifyLoggedIn() { const logged_in = getCookie('logged_in'); if (!logged_in) { return @@ -53,25 +54,27 @@ class AdminComponent extends React.Component { let listItemSelected = undefined; const requestParam = this.props.match.params.request; + if (requestParam && this.state.requested_objects !== '') { selectedRequest = this.state.requested_objects[requestParam] - listItemSelected = requestParam + listItemSelected = requestParam; } return (
-
- -
-
+
+
+ +
) } diff --git a/client/app/components/admin/AdminRequestInfo.jsx b/client/app/components/admin/AdminRequestInfo.jsx index a3a89f4..a67e7e1 100644 --- a/client/app/components/admin/AdminRequestInfo.jsx +++ b/client/app/components/admin/AdminRequestInfo.jsx @@ -1,16 +1,46 @@ import React, { Component } from 'react'; + +import { fetchJSON } from '../http.jsx'; + import PirateSearch from './PirateSearch.jsx' +// No in use! +import InfoButton from '../buttons/InfoButton.jsx'; + +// Stylesheets +import requestInfoCSS from '../styles/adminRequestInfo.jsx' +import buttonsCSS from '../styles/buttons.jsx'; + + +String.prototype.capitalize = function() { + return this.charAt(0).toUpperCase() + this.slice(1); +} + class AdminRequestInfo extends Component { constructor() { super(); + + this.state = { + statusValue: '', + movieInfo: undefined, + expandedSummary: false, + } + + this.requestInfo = ''; + } + + componentWillReceiveProps(props) { + this.requestInfo = props.selectedRequest; + this.state.statusValue = this.requestInfo.status; + this.state.expandedSummary = false; + this.fetchIteminfo() } userAgent(agent) { if (agent) { try { - return agent.split(" ")[1].replace(/[\(\;]/g, ''); + return agent.split(" ")[1].replace(/[\(\;]/g, ''); } catch(e) { return agent; @@ -19,66 +49,170 @@ class AdminRequestInfo extends Component { return ''; } + generateStatusDropdown() { + return ( + + ) + } + + updateRequestStatus(event) { + const eventValue = event.target.value; + const itemID = this.requestInfo.id; + + const apiData = { + type: this.requestInfo.type, + status: eventValue, + } + + fetchJSON('https://apollo.kevinmidboe.com/api/v1/plex/request/' + itemID, 'PUT', apiData) + .then((response) => { + console.log('Response, updateRequestStatus: ', response) + this.props.updateHandler() + }) + } + + generateStatusIndicator(status) { + switch (status) { + case 'requested': + // Yellow + return 'linear-gradient(to right, rgb(63, 195, 243) 0, rgb(63, 195, 243) 10px, #fff 4px, #fff 100%) no-repeat' + case 'downloading': + // Blue + return 'linear-gradient(to right, rgb(255, 225, 77) 0, rgb(255, 225, 77) 10px, #fff 4px, #fff 100%) no-repeat' + case 'downloaded': + // Green + return 'linear-gradient(to right, #39aa56 0, #39aa56 10px, #fff 4px, #fff 100%) no-repeat' + default: + return 'linear-gradient(to right, grey 0, grey 10px, #fff 4px, #fff 100%) no-repeat' + } + } + + generateTypeIcon(type) { + if (type === 'show') + return ( + + ) + else if (type === 'movie') + return ( + + ) + else + return ( + + ) + } + + toggleSummmaryLength() { + this.setState({ + expandedSummary: !this.state.expandedSummary + }) + } + + generateSummary() { + // { this.state.movieInfo != undefined ? this.state.movieInfo.summary : 'Loading...' } + const info = this.state.movieInfo; + if (info !== undefined) { + const summary = this.state.movieInfo.summary + const summary_short = summary.slice(0, 180); + + return ( +
+ Matched: {String(info.matchedInPlex)}
+ Rating: {info.rating}
+ Popularity: {info.popularity}
+ { + (summary.length > 180 && this.state.expandedSummary === false) ? + Summary: { summary_short } this.toggleSummmaryLength()}>... Show more + : + Summary: { summary } this.toggleSummmaryLength()}> Show less + + } +
+ ) + } else { + return Loading... + } + } + requested_by_user(request_user) { if (request_user === 'NULL') return undefined return ( - Requested by: {request_user} + Requested by: {request_user} ) } - displayInfo() { - let adminIndexStyle = { - wrapper: { - width: '100%', - }, - headerWrapper: { - width: '100%', - }, - poster: { - float: 'left', - minHeight: '450px', - }, - info: { - float: 'left', - minHeight: '450px', - } - } - const request = this.props.selectedRequest; + fetchIteminfo() { + const itemID = this.requestInfo.id; + const type = this.requestInfo.type; - if (request) { - return ( -
-
- {request.name} - {request.year} -
-
- -
-
- type: {request.type}
- status: {request.status}
- ip: {request.ip}
- user_agent: {this.userAgent(request.user_agent)}
- request_date: {request.requested_date}
- { this.requested_by_user(request.requested_by) } -
- - - -
- ) - } - } + fetchJSON('https://apollo.kevinmidboe.com/api/v1/tmdb/' + itemID +'&type='+type, 'GET') + .then((response) => { + console.log('Response, getInfo:', response) + this.setState({ + movieInfo: response + }); + console.log(this.state.movieInfo) + }) + } - render() { - return ( -
{this.displayInfo()}
- ); - } + displayInfo() { + const request = this.props.selectedRequest; + + if (request) { + requestInfoCSS.info.background = this.generateStatusIndicator(request.status); + + return ( +
+ +
+ {request.name} {request.year} + + {this.generateTypeIcon(request.type)} + {/*{request.type.capitalize()}
*/} +
+
+ +
+
+ Movie poster image +
+ +
+

Request info

+ + status:{ request.status }
+ ip:{ request.ip }
+ user_agent:{ this.userAgent(request.user_agent) }
+ request_date:{ request.requested_date}
+ { this.requested_by_user(request.requested_by) }
+ { this.generateStatusDropdown() }
+
+ +
+

Movie info

+ + { this.generateSummary() } +
+
+ + + +
+ ) + } + } + + render() { + return ( +
{this.displayInfo()}
+ ); + } } export default AdminRequestInfo; \ No newline at end of file diff --git a/client/app/components/admin/PirateSearch.jsx b/client/app/components/admin/PirateSearch.jsx index b1d5191..c60e7c2 100644 --- a/client/app/components/admin/PirateSearch.jsx +++ b/client/app/components/admin/PirateSearch.jsx @@ -1,57 +1,89 @@ import React, { Component } from 'react'; import { fetchJSON } from '../http.jsx'; +// Components +import TorrentTable from './TorrentTable.jsx' + +// Stylesheets +import btnStylesheet from '../styles/buttons.jsx'; + +// Interactive button +import Interactive from 'react-interactive'; + +import Loading from '../images/loading.jsx' + class PirateSearch extends Component { - constructor() { - super(); - this.state = { - response: [], - name: '', - } - } + constructor() { + super(); + this.state = { + torrentResponse: undefined, + name: '', + loading: null, + showButton: true, + } + } - sendToDownload(torrent) { - console.log(torrent.magnet) + componentWillReceiveProps(props) { + if (props.name != this.state.name) { + this.setState({ + torrentResponse: undefined, + showButton: true, + }) + } + } - let data = {magnet: torrent.magnet} - fetchJSON('https://apollo.kevinmidboe.com/api/v1/pirate/add', 'POST', data) - .then((response) => { - console.log(response) - }) - } + searchTheBay() { + const query = this.props.name; + const type = this.props.type; - searchTheBay() { - const query = this.props.name; - const type = this.props.type; + this.setState({ + showButton: false, + loading: , + }) - fetchJSON('https://apollo.kevinmidboe.com/api/v1/pirate/search?query='+query+'&type='+type, 'GET') - .then((response) => { - console.log(response.torrents) - this.setState({ - response: response.torrents.map((torrent, index) => { - return ( -
- {torrent.name}
- {torrent.size}
- {torrent.seed}
- -

-
- ) - }) - }) - }) - } + fetchJSON('https://apollo.kevinmidboe.com/api/v1/pirate/search?query='+query+'&type='+type, 'GET') + // fetchJSON('http://localhost:31459/api/v1/pirate/search?query='+query+'&type='+type, 'GET') + .then((response) => { + this.setState({ + torrentResponse: response.torrents, + loading: null, + }) + }) + .catch((error) => { + console.error(error); + this.setState({ + showButton: true, + }) + }) + } - render() { - return ( -
- {this.props.name} - - {this.state.response} -
- ) - } + render() { + btnStylesheet.submit.top = '50%' + btnStylesheet.submit.position = 'absolute' + btnStylesheet.submit.marginLeft = '-75px' + + return ( +
+ { this.state.showButton ? +
+ {this.searchTheBay()}} + style={btnStylesheet.submit} + focus={btnStylesheet.submit_hover} + hover={btnStylesheet.submit_hover}> + + Search for torrents + +
+ : null } + + { this.state.loading } + + +
+ ) + } } -export default PirateSearch \ No newline at end of file +export default PirateSearch diff --git a/client/app/components/admin/Sidebar.jsx b/client/app/components/admin/Sidebar.jsx index 5d001b0..187e72c 100644 --- a/client/app/components/admin/Sidebar.jsx +++ b/client/app/components/admin/Sidebar.jsx @@ -1,57 +1,248 @@ import React, { Component } from 'react'; import { Link } from 'react-router-dom'; +import Interactive from 'react-interactive'; + +import sidebarCSS from '../styles/adminSidebar.jsx' + class SidebarComponent extends Component { - generateListElements(index, item) { - if (index == this.props.listItemSelected) - return ( - {item.name} - ) - else - return ( - {item.name} - ) - } + constructor(props){ + super(props) + // Constructor with states holding the search query and the element of reponse. + this.state = { + filterValue: '', + filterQuery: '', + requestItemsToBeDisplayed: [], + listItemSelected: '', + height: '0', + } - displayRequestedElementsInfo() { - if (this.props.requested_objects) { - let requestedElement = this.props.requested_objects.map((item, index) => { - return ( - - { this.generateListElements(index, item) } - {item.status} - {item.requested_date} - - ) - }) + this.updateWindowDimensions = this.updateWindowDimensions.bind(this); + } - return ( - - - - - - - - - - {requestedElement} - -
NameStatusDate
- ) - } - } + // Where we wait for api response to be delivered from parent through props + componentWillReceiveProps(props) { + this.state.listItemSelected = props.listItemSelected; + this.displayRequestedElementsInfo(props.requested_objects); + } - render() { - console.log('sidebar: ', this.props.requested_objects) - return ( -
-

Hello from the sidebar:

- { this.displayRequestedElementsInfo() } -
- ); - } + componentDidMount() { + this.updateWindowDimensions(); + window.addEventListener('resize', this.updateWindowDimensions); + } + + componentWillUnmount() { + window.removeEventListener('resize', this.updateWindowDimensions); + } + + updateWindowDimensions() { + this.setState({ height: window.innerHeight }); + } + + // Inputs a date and returns a text string that matches how long it was since + convertDateToDaysSince(date) { + var oneDay = 24*60*60*1000; + var firstDate = new Date(date); + var secondDate = new Date(); + + var diffDays = Math.round(Math.abs((firstDate.getTime() - secondDate.getTime()) / oneDay)); + + switch (diffDays) { + case 0: + return 'Today'; + case 1: + return '1 day ago' + default: + return diffDays + ' days ago' + } + } + + // Called from our dropdown, receives a filter string and checks it with status field + // of our request objects. + filterItems(filterValue) { + let filteredRequestElements = this.props.requested_objects.map((item, index) => { + if (item.status === filterValue || filterValue === 'all') + return this.generateListElements(index, item); + }) + + this.setState({ + requestItemsToBeDisplayed: filteredRequestElements, + filterValue: filterValue, + }) + } + + + // Updates the internal state of the query filter and updates the list to only + // display names matching the query. This is real-time filtering. + updateFilterQuery(event) { + const query = event.target.value; + + let filteredByQuery = this.props.requested_objects.map((item, index) => { + if (item.name.toLowerCase().indexOf(query.toLowerCase()) != -1) + return this.generateListElements(index, item); + }) + + console.log(filteredByQuery) + this.setState({ + requestItemsToBeDisplayed: filteredByQuery, + filterQuery: query, + }); + } + + + generateFilterSearch() { + return ( +
+
+ this.updateFilterQuery(event)} + value={this.state.filterQuery}/> + + + + + + + + +
+
+ ) + } + + generateNav() { + let filterValue = this.state.filterValue; + + return ( + + ) + } + + generateBody(cards) { + let style = sidebarCSS.ulCard; + style.maxHeight = this.state.height - 160; + + return ( +
    + { cards } +
+ ) + } + + + generateListElements(index, item) { + let statusBar; + + switch (item.status) { + case 'requested': + // Yellow + statusBar = { background: 'linear-gradient(to right, rgb(63, 195, 243) 0, rgb(63, 195, 243) 4px, #fff 4px, #fff 100%) no-repeat' } + break; + case 'downloading': + // Blue + statusBar = { background: 'linear-gradient(to right, rgb(255, 225, 77) 0, rgb(255, 225, 77) 4px, #fff 4px, #fff 100%) no-repeat' } + break; + case 'downloaded': + // Green + statusBar = { background: 'linear-gradient(to right, #39aa56 0, #39aa56 4px, #fff 4px, #fff 100%) no-repeat' } + break; + default: + statusBar = { background: 'linear-gradient(to right, grey 0, grey 4px, #fff 4px, #fff 100%) no-repeat' } + } + + statusBar.listStyleType = 'none'; + + return ( + +
  • + + +

    + { item.name } +

    + +

    + Requested: + + +

    +
    +
  • + + ) + } + + // This is our main loader that gets called when we receive api response through props from parent + displayRequestedElementsInfo(requested_objects) { + let requestedElement = requested_objects.map((item, index) => { + if (['requested', 'downloading', 'downloaded'].indexOf(this.state.filterValue) != -1) { + if (item.status === this.state.filterValue){ + return this.generateListElements(index, item); + } + } + else if (this.state.filterQuery !== '') { + if (item.name.toLowerCase().indexOf(this.state.filterQuery.toLowerCase()) != -1) + return this.generateListElements(index, item); + } + else + return this.generateListElements(index, item); + }) + + this.setState({ + requestItemsToBeDisplayed: this.generateBody(requestedElement) + }) + } + + render() { + // if (typeof InstallTrigger !== 'undefined') + // bodyCSS.width = '-moz-min-content'; + + return ( +
    +

    Requested items

    + { this.generateFilterSearch() } + { this.generateNav() } + +
    + { this.state.requestItemsToBeDisplayed } +
    +
    + ); + } } export default SidebarComponent; \ No newline at end of file diff --git a/client/app/components/buttons/InfoButton.jsx b/client/app/components/buttons/InfoButton.jsx new file mode 100644 index 0000000..fa8f4f4 --- /dev/null +++ b/client/app/components/buttons/InfoButton.jsx @@ -0,0 +1,52 @@ +import React, { Component } from 'react'; +import Interactive from 'react-interactive'; + +import buttonsCSS from '../styles/buttons.jsx'; + + +class InfoButton extends Component { + constructor(props) { + super(props); + + if (props) { + this.state = { + id: props.id, + type: props.type, + } + } + } + + componentWillReceiveProps(props) { + this.setState({ + id: props.id, + type: props.type, + }) + } + + getTMDBLink() { + const id = this.state.id; + const type = this.state.type; + + if (type === 'movie') + return 'https://www.themoviedb.org/movie/' + id + else if (type === 'show') + return 'https://www.themoviedb.org/tv/' + id + } + + render() { + return ( + + + + More info + + + ); + } +} + +export default InfoButton; \ No newline at end of file diff --git a/client/app/components/images/loading.jsx b/client/app/components/images/loading.jsx new file mode 100644 index 0000000..455e39c --- /dev/null +++ b/client/app/components/images/loading.jsx @@ -0,0 +1,34 @@ +import React from 'react'; + +function Loading() { + return ( +
    + + + + + + +
    + + ) +} + +export default Loading; \ No newline at end of file diff --git a/client/app/components/styles/adminComponent.jsx b/client/app/components/styles/adminComponent.jsx new file mode 100644 index 0000000..721a740 --- /dev/null +++ b/client/app/components/styles/adminComponent.jsx @@ -0,0 +1,16 @@ +export default { + sidebar: { + float: 'left', + width: '18%', + minWidth: '250px', + fontFamily: '"Open Sans", sans-serif', + fontSize: '14px', + borderRight: '2px solid #f2f2f2', + }, + selectedObjectPanel: { + width: '80%', + float: 'right', + fontFamily: '"Open Sans", sans-serif', + marginTop: '1em', + } +} \ No newline at end of file diff --git a/client/app/components/styles/adminRequestInfo.jsx b/client/app/components/styles/adminRequestInfo.jsx new file mode 100644 index 0000000..d3a525f --- /dev/null +++ b/client/app/components/styles/adminRequestInfo.jsx @@ -0,0 +1,58 @@ +export default { + wrapper: { + width: '100%', + }, + stick: { + marginBottom: '1em', + }, + + title: { + fontSize: '2em', + }, + image: { + width: '105px', + borderRadius: '4px', + }, + + info: { + paddingTop: '1em', + paddingBottom: '0.5em', + marginRight: '2em', + backgroundColor: 'white', + border: '1px solid #d0d0d0', + borderRadius: '2px', + display: 'flex', + }, + + type_icon: { + marginLeft: '-1.9em', + marginRight: '0.7em', + }, + type_text: { + verticalAlign: 'super', + }, + + + info_poster: { + marginLeft: '2em', + flex: '0 1 10%' + }, + + info_request: { + flex: '0 1 auto' + }, + info_request_header: { + margin: '0', + marginBottom: '0.5em', + }, + + info_movie: { + maxWidth: '70%', + marginLeft: '1em', + flex: '0 1 auto', + }, + info_movie_header: { + margin: '0', + marginBottom: '0.5em', + } +} \ No newline at end of file diff --git a/client/app/components/styles/adminSidebar.jsx b/client/app/components/styles/adminSidebar.jsx new file mode 100644 index 0000000..16f2371 --- /dev/null +++ b/client/app/components/styles/adminSidebar.jsx @@ -0,0 +1,153 @@ +export default { + header: { + textAlign: 'center', + }, + body: { + backgroundColor: 'white', + }, + + parentElement: { + display: 'inline-block', + width: '100%', + border: '1px solid grey', + borderRadius: '2px', + padding: '4px', + margin: '4px', + marginLeft: '4px', + backgroundColor: 'white', + }, + + parentElement_hover: { + backgroundColor: '#f8f8f8', + pointer: 'hand', + }, + + parentElement_active: { + textDecoration: 'none', + }, + + parentElement_selected: { + display: 'inline-block', + width: '100%', + border: '1px solid grey', + borderRadius: '2px', + padding: '4px', + margin: '4px 0px 4px 4px', + marginLeft: '10px', + backgroundColor: 'white', + }, + + title: { + maxWidth: '65%', + display: 'inline-flex', + }, + + link: { + color: 'black', + textDecoration: 'none', + }, + + rightContainer: { + float: 'right', + }, + + + + searchSidebar: { + height: '4em', + }, + searchInner: { + top: '0', + right: '0', + left: '0', + bottom: '0', + margin: 'auto', + width: '90%', + minWidth: '280px', + height: '30px', + border: '1px solid #d0d0d0', + borderRadius: '4px', + overflow: 'hidden' + }, + searchTextField: { + display: 'inline-block', + width: '90%', + padding: '.3em', + verticalAlign: 'middle', + border: 'none', + background: '#fff', + fontSize: '14px', + marginTop: '-7px', + }, + searchIcon: { + width: '15px', + height: '16px', + marginRight: '4px', + marginTop: '7px', + }, + searchSVGIcon: { + fill: 'none', + stroke: '#9d9d9d', + strokeLinecap: 'round', + strokeLinejoin: 'round', + strokeMiterlimit: '10', + }, + + + ulFilterSelectors: { + borderBottom: '2px solid #f1f1f1', + display: 'flex', + padding: '0', + margin: '0', + listStyle: 'none', + justifyContent: 'space-evenly', + }, + aFilterSelectors: { + color: '#3eaaaf', + fontSize: '16px', + cursor: 'pointer', + }, + spanFilterSelectors: { + content: '""', + bottom: '-2px', + display: 'block', + width: '100%', + height: '2px', + backgroundColor: '#3eaaaa', + }, + + + ulCard: { + margin: '1em 0 0 0', + padding: '0', + listStyle: 'none', + borderBottom: '.46rem solid #f1f1f', + backgroundColor: '#f1f1f1', + overflow: 'scroll', + }, + + + card: { + padding: '.1em .5em .8em 1.5em', + marginBottom: '.26rem', + height: 'auto', + cursor: 'pointer', + }, + cardSelected: { + padding: '.1em .5em .8em 1.5em', + marginBottom: '.26rem', + height: 'auto', + cursor: 'pointer', + + backgroundColor: '#f9f9f9', + }, + titleCard: { + fontSize: '15px', + fontWeight: '400', + whiteSpace: 'no-wrap', + textDecoration: 'none', + }, + pCard: { + margin: '0', + }, +} \ No newline at end of file diff --git a/client/app/components/styles/adminTorrentTable.jsx b/client/app/components/styles/adminTorrentTable.jsx new file mode 100644 index 0000000..f6098bd --- /dev/null +++ b/client/app/components/styles/adminTorrentTable.jsx @@ -0,0 +1,48 @@ +export default { + table: { + width: '80%', + marginRight: 'auto', + marginLeft: 'auto', + }, + + searchSidebar: { + height: '4em', + marginTop: '1em', + }, + searchInner: { + top: '0', + right: '0', + left: '0', + bottom: '0', + margin: 'auto', + width: '50%', + minWidth: '280px', + height: '30px', + border: '1px solid #d0d0d0', + borderRadius: '4px', + overflow: 'hidden' + }, + searchTextField: { + display: 'inline-block', + width: '95%', + padding: '.3em', + verticalAlign: 'middle', + border: 'none', + background: '#fff', + fontSize: '14px', + marginTop: '-7px', + }, + searchIcon: { + width: '15px', + height: '16px', + marginRight: '4px', + marginTop: '7px', + }, + searchSVGIcon: { + fill: 'none', + stroke: '#9d9d9d', + strokeLinecap: 'round', + strokeLinejoin: 'round', + strokeMiterlimit: '10', + }, +} \ No newline at end of file diff --git a/client/app/components/styles/buttons.jsx b/client/app/components/styles/buttons.jsx new file mode 100644 index 0000000..a27fdba --- /dev/null +++ b/client/app/components/styles/buttons.jsx @@ -0,0 +1,80 @@ + +export default { + + submit: { + color: '#e9a131', + marginRight: '10px', + backgroundColor: 'white', + border: '#e9a131 2px solid', + borderColor: '#e9a131', + borderRadius: '4px', + textAlign: 'center', + padding: '10px', + minWidth: '100px', + float: 'left', + fontSize: '13px', + fontWeight: '800', + cursor: 'pointer', + }, + + submit_hover: { + backgroundColor: '#e9a131', + color: 'white', + }, + + info: { + color: '#00d17c', + marginRight: '10px', + backgroundColor: 'white', + border: '#00d17c 2px solid', + borderRadius: '4px', + textAlign: 'center', + padding: '10px', + minWidth: '100px', + float: 'left', + fontSize: '13px', + fontWeight: '800', + cursor: 'pointer', + }, + + info_hover: { + backgroundColor: '#00d17c', + color: 'white', + }, + + edit: { + color: '#4a95da', + marginRight: '10px', + backgroundColor: 'white', + border: '#4a95da 2px solid', + borderRadius: '4px', + textAlign: 'center', + padding: '10px', + minWidth: '100px', + float: 'left', + fontSize: '13px', + fontWeight: '800', + cursor: 'pointer', + }, + + edit_small: { + color: '#4a95da', + marginRight: '10px', + backgroundColor: 'white', + border: '#4a95da 2px solid', + borderRadius: '4px', + textAlign: 'center', + padding: '4px', + minWidth: '50px', + float: 'left', + fontSize: '13px', + fontWeight: '800', + cursor: 'pointer', + }, + + edit_hover: { + backgroundColor: '#4a95da', + color: 'white', + }, + +} \ No newline at end of file diff --git a/client/app/components/styles/movieObjectStyle.jsx b/client/app/components/styles/movieObjectStyle.jsx deleted file mode 100644 index 627d7dd..0000000 --- a/client/app/components/styles/movieObjectStyle.jsx +++ /dev/null @@ -1,101 +0,0 @@ - -export default { - resultItem: { - maxWidth: '95%', - margin: '0 auto', - minHeight: '230px' - }, - - movie_content: { - marginLeft: '15px' - }, - - resultTitleLarge: { - color: 'black', - fontSize: '2em', - }, - - resultTitleSmall: { - color: 'black', - fontSize: '22px', - }, - - yearRatingLarge: { - fontSize: '0.8em' - }, - - resultPoster: { - float: 'left', - zIndex: '3', - position: 'relative', - marginRight: '30px' - }, - - background: { - width: '100%' - }, - - yearRatingSmall: { - marginTop: '5px', - fontSize: '0.8em' - }, - - resultPosterImg: { - border: '2px none', - borderRadius: '2px', - width: '150px' - }, - - cornerRibbon: { - position: 'absolute', - width: '450px', - }, - - summary: { - fontSize: '15px', - }, - - buttons: { - paddingTop: '20px' - }, - - requestButton: { - color: '#e9a131', - marginRight: '10px', - background: 'white', - border: '#e9a131 2px solid', - borderRadius: '4px', - textAlign: 'center', - padding: '10px', - minWidth: '100px', - float: 'left', - fontSize: '13px', - fontWeight: '800', - cursor: 'pointer' - }, - - tmdbButton: { - color: '#00d17c', - marginRight: '10px', - background: 'white', - border: '#00d17c 2px solid', - borderRadius: '4px', - textAlign: 'center', - padding: '10px', - minWidth: '100px', - float: 'left', - fontSize: '13px', - fontWeight: '800', - cursor: 'pointer' - }, - - row: { - width: '100%' - }, - - itemDivider: { - width: '90%', - borderBottom: '1px solid grey', - margin: '2rem auto' - } -} \ No newline at end of file diff --git a/client/app/components/styles/searchObject.jsx b/client/app/components/styles/searchObject.jsx new file mode 100644 index 0000000..a1dc4d0 --- /dev/null +++ b/client/app/components/styles/searchObject.jsx @@ -0,0 +1,62 @@ + +export default { + container: { + maxWidth: '95%', + margin: '0 auto', + minHeight: '230px' + }, + + title_large: { + color: 'black', + fontSize: '2em', + }, + + title_small: { + color: 'black', + fontSize: '22px', + }, + + stats_large: { + fontSize: '0.8em' + }, + + stats_small: { + marginTop: '5px', + fontSize: '0.8em' + }, + + posterContainer: { + float: 'left', + zIndex: '3', + position: 'relative', + marginRight: '30px' + }, + + posterImage: { + border: '2px none', + borderRadius: '2px', + width: '150px' + }, + + backgroundImage: { + width: '100%' + }, + + buttons: { + paddingTop: '20px', + }, + + summary: { + fontSize: '15px', + }, + + dividerRow: { + width: '100%' + }, + + itemDivider: { + width: '90%', + borderBottom: '1px solid grey', + margin: '2rem auto' + } +} \ No newline at end of file diff --git a/client/app/components/styles/searchRequestStyle.jsx b/client/app/components/styles/searchRequestStyle.jsx index 45d5cff..0700a4e 100644 --- a/client/app/components/styles/searchRequestStyle.jsx +++ b/client/app/components/styles/searchRequestStyle.jsx @@ -10,18 +10,19 @@ export default { backgroundLargeHeader: { width: '100%', - minHeight: '400px', - backgroundColor: '#011c23', + minHeight: '180px', + backgroundColor: 'rgb(1, 28, 35)', + // backgroundImage: 'radial-gradient(circle, #004c67 0, #005771 120%)', zIndex: 1, - marginBottom: '-100px' + marginBottom: '80px' }, - backgroundSmallHeader: { + backgroundSmallHeader: { width: '100%', - minHeight: '300px', + minHeight: '120px', backgroundColor: '#011c23', zIndex: 1, - marginBottom: '-100px' + marginBottom: '40px' }, requestWrapper: { @@ -31,7 +32,7 @@ export default { backgroundColor: 'white', position: 'relative', zIndex: '10', - boxShadow: '0 4px 2px black' + boxShadow: '0 1px 2px grey', }, pageTitle: { @@ -53,39 +54,35 @@ export default { fontSize: '2em', marginTop: '3vh', marginBottom: '3vh' - }, - - box: { - height: '50px', }, searchLargeContainer: { - margin: '0 25%', + height: '52px', + width: '77%', + paddingLeft: '23%', + backgroundColor: 'white', }, searchSmallContainer: { - margin: '0 10%', }, searchIcon: { position: 'absolute', - fontSize: '1.2em', - marginTop: '12px', - marginLeft: '-13px', - color: '#4f5b66' + fontSize: '1.6em', + marginTop: '7px', + color: '#4f5b66', + display: 'block', }, searchLargeBar: { - width: '100%', + width: '50%', height: '50px', background: '#ffffff', border: 'none', - fontSize: '10pt', + fontSize: '12pt', float: 'left', color: '#63717f', - paddingLeft: '45px', - marginLeft: '-25px', - borderRadius: '5px', + paddingLeft: '40px', }, searchSmallBar: { @@ -93,14 +90,58 @@ export default { height: '50px', background: '#ffffff', border: 'none', - fontSize: '13pt', + fontSize: '11pt', float: 'left', color: '#63717f', - paddingLeft: '45px', + paddingLeft: '65px', marginLeft: '-25px', borderRadius: '5px', }, + + // Dropdown for selecting tmdb lists + controls: { + textAlign: 'left', + paddingTop: '8px', + width: '33.3333%', + marginLeft: '0', + marginRight: '0', + }, + + withData: { + boxSizing: 'border-box', + marginBottom: '0', + display: 'block', + padding: '0', + verticalAlign: 'baseline', + font: 'inherit', + textAlign: 'left', + boxSizing: 'border-box', + }, + + sortOptions: { + border: '1px solid #000', + maxWidth: '100%', + overflow: 'hidden', + lineHeight: 'normal', + textAlign: 'left', + padding: '4px 12px', + paddingRight: '2rem', + backgroundImage: 'url("data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxOCAxOCI+CiAgPHRpdGxlPmFycm93LWRvd24tbWljcm88L3RpdGxlPgogIDxwb2x5bGluZSBwb2ludHM9IjE0IDQuNjcgOSAxMy4zMyA0IDQuNjciIHN0eWxlPSJmaWxsOiBub25lO3N0cm9rZTogIzAwMDtzdHJva2UtbWl0ZXJsaW1pdDogMTA7c3Ryb2tlLXdpZHRoOiAycHgiLz4KPC9zdmc+Cg==")', + backgroundSize: '18px 18px', + backgroundPosition: 'right 8px center', + backgroundRepeat: 'no-repeat', + width: 'auto', + display: 'inline-block', + outline: 'none', + boxSizing: 'border-box', + fontSize: '15px', + WebkitAppearance: 'none', + MozAppearance: 'none', + appearance: 'none', + }, + + searchFilterActive: { color: '#00d17c', fontSize: '1em', @@ -115,7 +156,6 @@ export default { cursor: 'pointer' }, - filter: { color: 'white', paddingLeft: '40px', @@ -123,9 +163,9 @@ export default { }, resultLargeHeader: { - paddingLeft: '30px', color: 'black', fontSize: '1.6em', + width: '20%', }, resultSmallHeader: { @@ -133,70 +173,4 @@ export default { color: 'black', fontSize: '1.4em', }, - - row: { - width: '100%' - }, - - itemDivider: { - width: '90%', - borderBottom: '1px solid grey', - margin: '1rem auto' - }, - - - pageNavigationBar: { - width: '100%', - display: 'flex', - alignItems: 'center', - justifyContent: 'center' - }, - - pageNavigationButton: { - margin: '0 auto', - }, - - hvrUnderlineFromCenter: { - color: 'white', - fontSize: '1em', - paddingTop: '12px', - marginBottom: '12px', - marginLeft: '10px', - cursor: 'pointer', - display: 'inline-block', - verticalAlign: 'middle', - WebkitTransform: 'perspective(1px) translateZ(0)', - transform: 'perspective(1px) translateZ(0)', - boxShadow: '0 0 1px transparent', - position: 'relative', - overflow: 'hidden', - ':before': { - content: "", - position: 'absolute', - zIndex: '-1', - left: '50%', - right: '50%', - bottom: '0', - background: '#00d17c', - height: '2px', - WebkitTransitionProperty: 'left, right', - transitionProperty: 'left, right', - WebkitTransitionDuration: '0.3s', - transitionDuration: '0.3s', - WebkitTransitionTimingFunction: 'ease-out', - transitionTimingFunction: 'ease-out' - }, - ':hover:before': { - left: 0, - right: 0 - }, - 'focus:before': { - left: 0, - right: 0 - }, - 'active:before': { - left: 0, - right: 0 - } - } } \ No newline at end of file diff --git a/client/app/index.html b/client/app/index.html index 3ab7f3f..3ec9c02 100644 --- a/client/app/index.html +++ b/client/app/index.html @@ -4,7 +4,7 @@ - + seasoned Shows diff --git a/client/package.json b/client/package.json index 7d36795..3529ce3 100644 --- a/client/package.json +++ b/client/package.json @@ -7,7 +7,7 @@ "license": "MIT", "scripts": { "start": "webpack-dev-server --open --config webpack.dev.js", - "build": "webpack --config webpack.prod.js", + "build": "NODE_ENV=production webpack --config webpack.prod.js", "build_dev": "webpack --config webpack.dev.js" }, "dependencies": { @@ -19,6 +19,7 @@ "react-burger-menu": "^2.1.6", "react-dom": "^15.5.4", "react-infinite-scroller": "^1.0.15", + "react-interactive": "^0.8.1", "react-notify-toast": "^0.3.2", "react-redux": "^5.0.6", "react-responsive": "^1.3.4", diff --git a/client/webpack.common.js b/client/webpack.common.js index 114c775..0fd9a5f 100644 --- a/client/webpack.common.js +++ b/client/webpack.common.js @@ -21,8 +21,7 @@ module.exports = { ], module: { loaders: [ - { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }, - { test: /\.jsx$/, loader: 'babel-loader', exclude: /node_modules/ }, + { test: /\.(js|jsx)$/, loader: 'babel-loader', exclude: /node_modules/ }, ] }, diff --git a/seasoned_api/conf/development.json b/seasoned_api/conf/development.json new file mode 100644 index 0000000..abf8399 --- /dev/null +++ b/seasoned_api/conf/development.json @@ -0,0 +1,24 @@ +{ + "database": { + "host": "../shows.db" + }, + "webserver": { + "port": 31459 + }, + "tmdb": { + "apiKey": "" + }, + "raven": { + "DSN": "" + }, + "mail": { + "host": "", + "user": "", + "password": "", + "user_pi": "", + "password_pi": "" + }, + "authentication": { + "secret": "secret" + } +} diff --git a/seasoned_api/package.json b/seasoned_api/package.json index 2f2309a..7814f28 100644 --- a/seasoned_api/package.json +++ b/seasoned_api/package.json @@ -3,6 +3,8 @@ "main": "webserver/server.js", "scripts": { "start": "cross-env SEASONED_CONFIG=conf/development.json NODE_PATH=. node src/webserver/server.js", + "test": "cross-env SEASONED_CONFIG=conf/development.json NODE_PATH=. mocha --recursive test/system", + "coverage": "cross-env PLANFLIX_CONFIG=conf/test.json NODE_PATH=. istanbul cover -x script/autogenerate-documentation.js --include-all-sources --dir test/.coverage node_modules/mocha/bin/_mocha --recursive test/**/* -- --report lcovonly && cat test/.coverage/lcov.info | coveralls && rm -rf test/.coverage", "lint": "./node_modules/.bin/eslint src/webserver/" }, "dependencies": { @@ -10,7 +12,7 @@ "body-parser": "~1.0.1", "cross-env": "^3.1.3", "express": "~4.11.0", - "jsonwebtoken": "^8.0.1", + "jsonwebtoken": "^8.0.1", "mongoose": "^3.6.13", "moviedb": "^0.2.10", "node-cache": "^4.1.1", @@ -19,12 +21,17 @@ "raven": "^2.2.1", "request": "^2.81.0", "request-promise": "^4.2", - "sqlite": "^2.2.1", - "sqlite3": "^2.5.0" + "sqlite": "^2.9.0" }, "devDependencies": { "eslint": "^4.9.0", "eslint-config-airbnb-base": "^12.1.0", - "eslint-plugin-import": "^2.8.0" + "eslint-plugin-import": "^2.8.0", + "eslint": "^4.9.0", + "istanbul": "^0.4.5", + "mocha": "^3.1.0", + "supertest": "^2.0.1", + "supertest-as-promised": "^4.0.1" + } } diff --git a/seasoned_api/src/config/configuration.js b/seasoned_api/src/config/configuration.js index c8aa9a2..bd9d4c3 100644 --- a/seasoned_api/src/config/configuration.js +++ b/seasoned_api/src/config/configuration.js @@ -27,6 +27,11 @@ class Config { const field = new Field(this.fields[section][option]) + if (field.value === '') { + const envField = process.env[[section.toUpperCase(), option.toUpperCase()].join('_')] + if (envField !== undefined && envField.length !== 0) { return envField } + } + if (field.value === undefined) { throw new Error(`${section} => ${option} is empty.`); } diff --git a/seasoned_api/src/config/field.js b/seasoned_api/src/config/field.js index 2dbfc58..1a8b79a 100644 --- a/seasoned_api/src/config/field.js +++ b/seasoned_api/src/config/field.js @@ -4,7 +4,7 @@ const EnvironmentVariables = require('./environmentVariables.js'); class Field { constructor(rawValue, environmentVariables) { - this.rawValue, rawValue; + this.rawValue = rawValue; this.filters = new Filters(rawValue); this.valueWithoutFilters = this.filters.removeFiltersFromValue(); this.environmentVariables = new EnvironmentVariables(environmentVariables); diff --git a/seasoned_api/src/config/filters.js b/seasoned_api/src/config/filters.js index ebd813d..fbeab07 100644 --- a/seasoned_api/src/config/filters.js +++ b/seasoned_api/src/config/filters.js @@ -10,7 +10,7 @@ class Filters { } isEmpty() { - return !this.hasValidType() || this.filters.length === 0; + return !this.hasValidType() || this.value.length === 0; } has(filter) { diff --git a/seasoned_api/src/database/database.js b/seasoned_api/src/database/database.js index 00c9d98..8e509df 100644 --- a/seasoned_api/src/database/database.js +++ b/seasoned_api/src/database/database.js @@ -10,6 +10,6 @@ const database = new SqliteDatabase(configuration.get('database', 'host')); */ Promise.resolve() .then(() => database.connect()) -// .then(() => database.setUp()); +.then(() => database.setUp()); module.exports = database; diff --git a/seasoned_api/src/database/schemas/setup.sql b/seasoned_api/src/database/schemas/setup.sql new file mode 100644 index 0000000..5d9d8fd --- /dev/null +++ b/seasoned_api/src/database/schemas/setup.sql @@ -0,0 +1,57 @@ +CREATE TABLE IF NOT EXISTS user ( + user_name varchar(127) UNIQUE, + password varchar(127), + email varchar(127) UNIQUE, + primary key (user_name) +); + +CREATE TABLE IF NOT EXISTS cache ( + key varchar(255), + value blob, + time_to_live INTEGER DEFAULT 60, + created_at DATE DEFAULT (datetime('now','localtime')), + primary key(key) +); + +CREATE TABLE IF NOT EXISTS search_history ( + id integer, + user_name varchar(127), + search_query varchar(255), + primary key (id), + foreign key(user_name) REFERENCES user(user_name) ON DELETE CASCADE +); + +CREATE TABLE IF NOT EXISTS requests( + id TEXT, + name TEXT, + year NUMBER, + poster_path TEXT DEFAULT NULL, + background_path TEXT DEFAULT NULL, + requested_by TEXT, + ip TEXT, + requested_date DATE DEFAULT CURRENT_DATE NOT NULL, + status CHAR(25) DEFAULT 'requested' NOT NULL, + user_agent CHAR(255) DEFAULT NULL, + type CHAR(50) DEFAULT 'movie' +); + + +CREATE TABLE IF NOT EXISTS stray_eps( + id TEXT UNIQUE, + parent TEXT, + path TEXT, + name TEXT, + season NUMBER, + episode NUMBER, + video_files TEXT, + subtitles TEXT, + trash TEXT, + verified BOOLEAN DEFAULT 0, + primary key(id) +); + +CREATE TABLE IF NOT EXISTS shows( + show_names TEXT, + date_added DATE, + date_modified DATE DEFUALT CURRENT_DATE NOT NULL +); \ No newline at end of file diff --git a/seasoned_api/src/database/schemas/teardown.sql b/seasoned_api/src/database/schemas/teardown.sql new file mode 100644 index 0000000..750cbab --- /dev/null +++ b/seasoned_api/src/database/schemas/teardown.sql @@ -0,0 +1,3 @@ +DROP TABLE IF EXISTS user; +DROP TABLE IF EXISTS search_history; +DROP TABLE IF EXISTS requests; diff --git a/seasoned_api/src/database/sqliteDatabase.js b/seasoned_api/src/database/sqliteDatabase.js index 3d0c5a4..a68e207 100644 --- a/seasoned_api/src/database/sqliteDatabase.js +++ b/seasoned_api/src/database/sqliteDatabase.js @@ -4,30 +4,89 @@ const sqlite = require('sqlite'); class SqliteDatabase { - constructor(host) { - this.host = host; - this.connection = sqlite; + constructor(host) { + this.host = host; + this.connection = sqlite; + this.schemaDirectory = path.join(__dirname, 'schemas'); + } - // this.schemaDirectory = path.join(__dirname, 'schemas'); - } + /** + * Connect to the database. + * @returns {Promise} succeeds if connection was established + */ + connect() { + return Promise.resolve() + .then(() => sqlite.open(this.host)) + .then(() => sqlite.exec('pragma foreign_keys = on;')); + } - connect() { - return Promise.resolve() - .then(() => sqlite.open(this.host)) - .then(() => sqlite.exec('pragma foreign_keys = on;')); - } + /** + * Run a SQL query against the database. + * @param {String} sql SQL query + * @param {Array} parameters in the SQL query + * @returns {Promise} + */ + run(sql, parameters) { + return this.connection.run(sql, parameters); + } - all(sql, parameters) { - return this.connection.all(sql, parameters); - } + /** + * Run a SQL query against the database and retrieve all the rows. + * @param {String} sql SQL query + * @param {Array} parameters in the SQL query + * @returns {Promise} + */ + all(sql, parameters) { + return this.connection.all(sql, parameters); + } - get(sql, parameters) { - return this.connection.get(sql, parameters); - } + /** + * Run a SQL query against the database and retrieve one row. + * @param {String} sql SQL query + * @param {Array} parameters in the SQL query + * @returns {Promise} + */ + get(sql, parameters) { + return this.connection.get(sql, parameters); + } - run(sql, parameters) { - return this.connection.run(sql, parameters); - } + /** + * Run a SQL query against the database and retrieve the status. + * @param {String} sql SQL query + * @param {Array} parameters in the SQL query + * @returns {Promise} + */ + execute(sql) { + return this.connection.exec(sql); + } + + /** + * Setup the database by running setup.sql file in schemas/. + * @returns {Promise} + */ + setUp() { + const setupSchema = this.readSqlFile('setup.sql'); + return this.execute(setupSchema); + } + + /** + * Tears down the database by running tearDown.sql file in schemas/. + * @returns {Promise} + */ + tearDown() { + const tearDownSchema = this.readSqlFile('tearDown.sql'); + return this.execute(tearDownSchema); + } + + /** + * Returns the file contents of a SQL file in schemas/. + * @returns {String} + */ + readSqlFile(filename) { + const schemaPath = path.join(this.schemaDirectory, filename); + const schema = fs.readFileSync(schemaPath).toString('utf-8'); + return schema; + } } module.exports = SqliteDatabase; diff --git a/seasoned_api/src/pirate/pirateRepository.js b/seasoned_api/src/pirate/pirateRepository.js index 97bb77c..ab4ca3c 100644 --- a/seasoned_api/src/pirate/pirateRepository.js +++ b/seasoned_api/src/pirate/pirateRepository.js @@ -6,12 +6,12 @@ var PythonShell = require('python-shell'); async function find(searchterm, callback) { var options = { - pythonPath: '/usr/bin/python3', - // pythonPath: '/Library/Frameworks/Python.framework/Versions/3.6/bin/python3', - args: [searchterm] + // pythonPath: '/usr/bin/python3', + pythonPath: '/Library/Frameworks/Python.framework/Versions/3.6/bin/python3', + args: [searchterm, '-s', 'jackett', '--print'] } - PythonShell.run('../app/pirateSearch.py', options, callback); + PythonShell.run('../app/torrent_search/torrentSearch/search.py', options, callback); // PythonShell does not support return }; @@ -29,6 +29,7 @@ async function callPythonAddMagnet(magnet, callback) { async function SearchPiratebay(query) { return await new Promise((resolve) => { return find(query, function(err, results) { + console.log('err', err, '. result', results); resolve(JSON.parse(results, null, '\t')); }) }) diff --git a/seasoned_api/src/plex/requestRepository.js b/seasoned_api/src/plex/requestRepository.js index 94bfdc8..ffddd12 100644 --- a/seasoned_api/src/plex/requestRepository.js +++ b/seasoned_api/src/plex/requestRepository.js @@ -22,7 +22,7 @@ class RequestRepository { constructor(cache, database) { this.database = database || establishedDatabase; this.queries = { - 'insertRequest': "INSERT INTO requests VALUES (?, ?, ?, ?, ?, ?, CURRENT_DATE, 'requested', ?, ?)", + 'insertRequest': "INSERT INTO requests VALUES (?, ?, ?, ?, ?, ?, ?, CURRENT_DATE, 'requested', ?, ?)", 'fetchRequstedItems': "SELECT * FROM requests", 'updateRequestedById': "UPDATE requests SET status = ? WHERE id is ? AND type is ?", } @@ -117,7 +117,7 @@ class RequestRepository { user = 'NULL'; console.log(user) // Add request to database - this.database.run(this.queries.insertRequest, [movie.id, movie.title, movie.year, movie.poster, user, ip, user_agent, movie.type]) + this.database.run(this.queries.insertRequest, [movie.id, movie.title, movie.year, movie.poster, movie.background, user, ip, user_agent, movie.type]) // create reusable transporter object using the default SMTP transport diff --git a/seasoned_api/test/fixtures/interstellar-query-success-response.json b/seasoned_api/test/fixtures/interstellar-query-success-response.json new file mode 100644 index 0000000..b56f1f2 --- /dev/null +++ b/seasoned_api/test/fixtures/interstellar-query-success-response.json @@ -0,0 +1,89 @@ +{ + "number_of_items_on_page": 5, + "page": 1, + "results": [ + { + "background": "/xu9zaAevzQ5nnrsXN6JcahLnG4i.jpg", + "genre": [ + 12, + 18, + 878 + ], + "id": 157336, + "matchedInPlex": false, + "popularity": 50.262329, + "poster": "/nBNZadXqJSdt05SHLqgT0HuC5Gm.jpg", + "rating": 8.1, + "summary": "Interstellar chronicles the adventures of a group of explorers who make use of a newly discovered wormhole to surpass the limitations on human space travel and conquer the vast distances involved in an interstellar voyage.", + "title": "Interstellar", + "type": "movie", + "vote_count": 12095, + "year": 2014 + }, + { + "background": "/bT5jpIZE50MI0COE8pOeq0kMpQo.jpg", + "genre": [ + 99 + ], + "id": 301959, + "matchedInPlex": false, + "popularity": 6.174326, + "poster": "/xZwUIPqBHyJ2QIfMPANOZ1mAld6.jpg", + "rating": 7.9, + "summary": "Behind the scenes of Christopher Nolan's sci-fi drama, which stars Matthew McConaughey and Anne Hathaway", + "title": "Interstellar: Nolan's Odyssey", + "type": "movie", + "vote_count": 102, + "year": 2014 + }, + { + "background": "/yTnHa6lgIv8rNneSNBDkBe8MnZe.jpg", + "genre": [ + 878 + ], + "id": 398188, + "matchedInPlex": false, + "popularity": 3.847981, + "poster": "/cjvTebuqD8wmhchHE286ltVcbX6.jpg", + "rating": 4.7, + "summary": "For Millennia the Aliien force has watched and waited, a brooding menace that has now at last decided to take over the Earth. Communications systems worldwide are sent into chaos by a strange atmospheric interference and this has turned into a global phenomenon. A massive spaceship headed towards Earth and smaller spaceships began to cover entire cities around the world. Suddenly, the wonder turns into horror as the spaceships destroy the cities with energy weapons. When the world counterattacks, the alien ships are invincible to military weapons. The survivors have to use their wits to kill the aliens, or die.", + "title": "Interstellar Wars", + "type": "movie", + "vote_count": 5, + "year": 2016 + }, + { + "background": "/mgb6tVEieDYLpQt666ACzGz5cyE.jpg", + "genre": [ + 35 + ], + "id": 287954, + "matchedInPlex": false, + "popularity": 2.778622, + "poster": "/buoq7zYO4J3ttkEAqEMWelPDC0G.jpg", + "rating": 7, + "summary": "An undeniably beautiful alien is sent to Earth to study the complex mating rituals of human beings, which leads to the young interstellar traveler experiencing the passion that surrounds the centuries-old ritual of the species.", + "title": "Lolita from Interstellar Space", + "type": "movie", + "vote_count": 1, + "year": 2014 + }, + { + "background": null, + "genre": [ + 99 + ], + "id": 336592, + "matchedInPlex": false, + "popularity": 2.147155, + "poster": "/6KBD7YSBjCfgBgHwpsQo3G3GGdx.jpg", + "rating": 7.8, + "summary": "The science of Christopher Nolan's sci-fi, Interstellar.", + "title": "The Science of Interstellar", + "type": "movie", + "vote_count": 6, + "year": 2014 + } + ], + "total_pages": 1 +} \ No newline at end of file diff --git a/seasoned_api/test/fixtures/popular-movies-success-response.json b/seasoned_api/test/fixtures/popular-movies-success-response.json new file mode 100644 index 0000000..3a906d4 --- /dev/null +++ b/seasoned_api/test/fixtures/popular-movies-success-response.json @@ -0,0 +1,375 @@ +{ + "page": 1, + "results": [ + { + "background": "/tcheoA2nPATCm2vvXw2hVQoaEFD.jpg", + "genre": [ + 18, + 14, + 27, + 53 + ], + "id": 346364, + "matchedInPlex": false, + "popularity": 847.49142, + "poster": "/9E2y5Q7WlCVNEhP5GiVTjhEhx1o.jpg", + "rating": 7.2, + "summary": "In a small town in Maine, seven children known as The Losers Club come face to face with life problems, bullies and a monster that takes the shape of a clown called Pennywise.", + "title": "It", + "type": "movie", + "vote_count": 4647, + "year": 2017 + }, + { + "background": "/askg3SMvhqEl4OL52YuvdtY40Yb.jpg", + "genre": [ + 12, + 16, + 10751 + ], + "id": 354912, + "matchedInPlex": false, + "popularity": 545.354595, + "poster": "/eKi8dIrr8voobbaGzDpe8w0PVbC.jpg", + "rating": 7.5, + "summary": "Despite his family’s baffling generations-old ban on music, Miguel dreams of becoming an accomplished musician like his idol, Ernesto de la Cruz. Desperate to prove his talent, Miguel finds himself in the stunning and colorful Land of the Dead following a mysterious chain of events. Along the way, he meets charming trickster Hector, and together, they set off on an extraordinary journey to unlock the real story behind Miguel's family history.", + "title": "Coco", + "type": "movie", + "vote_count": 532, + "year": 2017 + }, + { + "background": "/5Iw7zQTHVRBOYpA0V6z0yypOPZh.jpg", + "genre": [ + 28, + 12, + 14, + 878 + ], + "id": 181808, + "matchedInPlex": false, + "popularity": 510.708216, + "poster": "/xGWVjewoXnJhvxKW619cMzppJDQ.jpg", + "rating": 7.5, + "summary": "Rey develops her newly discovered abilities with the guidance of Luke Skywalker, who is unsettled by the strength of her powers. Meanwhile, the Resistance prepares to do battle with the First Order.", + "title": "Star Wars: The Last Jedi", + "type": "movie", + "vote_count": 1054, + "year": 2017 + }, + { + "background": "/o5T8rZxoWSBMYwjsUFUqTt6uMQB.jpg", + "genre": [ + 28, + 12, + 14, + 878 + ], + "id": 141052, + "matchedInPlex": false, + "popularity": 423.487801, + "poster": "/9rtrRGeRnL0JKtu9IMBWsmlmmZz.jpg", + "rating": 6.6, + "summary": "Fueled by his restored faith in humanity and inspired by Superman's selfless act, Bruce Wayne and Diana Prince assemble a team of metahumans consisting of Barry Allen, Arthur Curry, and Victor Stone to face the catastrophic threat of Steppenwolf and the Parademons who are on the hunt for three Mother Boxes on Earth.", + "title": "Justice League", + "type": "movie", + "vote_count": 1805, + "year": 2017 + }, + { + "background": "/52lVqTDhIeNTjT7EiJuovXgw6iE.jpg", + "genre": [ + 12, + 14, + 10751 + ], + "id": 8844, + "matchedInPlex": false, + "popularity": 372.129434, + "poster": "/8wBKXZNod4frLZjAKSDuAcQ2dEU.jpg", + "rating": 6.9, + "summary": "When siblings Judy and Peter discover an enchanted board game that opens the door to a magical world, they unwittingly invite Alan -- an adult who's been trapped inside the game for 26 years -- into their living room. Alan's only hope for freedom is to finish the game, which proves risky as all three find themselves running from giant rhinoceroses, evil monkeys and other terrifying creatures.", + "title": "Jumanji", + "type": "movie", + "vote_count": 2907, + "year": 1995 + }, + { + "background": "/qLmdjn2fv0FV2Mh4NBzMArdA0Uu.jpg", + "genre": [ + 10751, + 16, + 12, + 35 + ], + "id": 211672, + "matchedInPlex": false, + "popularity": 345.173187, + "poster": "/q0R4crx2SehcEEQEkYObktdeFy.jpg", + "rating": 6.4, + "summary": "Minions Stuart, Kevin and Bob are recruited by Scarlet Overkill, a super-villain who, alongside her inventor husband Herb, hatches a plot to take over the world.", + "title": "Minions", + "type": "movie", + "vote_count": 5237, + "year": 2015 + }, + { + "background": "/6aUWe0GSl69wMTSWWexsorMIvwU.jpg", + "genre": [ + 10751, + 14, + 10749 + ], + "id": 321612, + "matchedInPlex": false, + "popularity": 297.124109, + "poster": "/tWqifoYuwLETmmasnGHO7xBjEtt.jpg", + "rating": 6.8, + "summary": "A live-action adaptation of Disney's version of the classic tale of a cursed prince and a beautiful young woman who helps him break the spell.", + "title": "Beauty and the Beast", + "type": "movie", + "vote_count": 6318, + "year": 2017 + }, + { + "background": "/lMDyuHzBhx3zNAv48vYzmgcJCCD.jpg", + "genre": [ + 18, + 35 + ], + "id": 419680, + "matchedInPlex": false, + "popularity": 278.025258, + "poster": "/rF2IoKL0IFmumEXQFUuB8LajTYP.jpg", + "rating": 5.7, + "summary": "Brad and Dusty must deal with their intrusive fathers during the holidays.", + "title": "Daddy's Home 2", + "type": "movie", + "vote_count": 408, + "year": 2017 + }, + { + "background": "/tvKcA4OFUiZkNeTJmmTkNqKHMMg.jpg", + "genre": [ + 80, + 18, + 9648 + ], + "id": 392044, + "matchedInPlex": false, + "popularity": 259.276687, + "poster": "/iBlfxlw8qwtUS0R8YjIU7JtM6LM.jpg", + "rating": 6.8, + "summary": "Genius Belgian detective Hercule Poirot investigates the murder of an American tycoon aboard the Orient Express train.", + "title": "Murder on the Orient Express", + "type": "movie", + "vote_count": 878, + "year": 2017 + }, + { + "background": "/ulMscezy9YX0bhknvJbZoUgQxO5.jpg", + "genre": [ + 18, + 878, + 10752 + ], + "id": 281338, + "matchedInPlex": false, + "popularity": 252.304349, + "poster": "/3vYhLLxrTtZLysXtIWktmd57Snv.jpg", + "rating": 6.7, + "summary": "Caesar and his apes are forced into a deadly conflict with an army of humans led by a ruthless Colonel. After the apes suffer unimaginable losses, Caesar wrestles with his darker instincts and begins his own mythic quest to avenge his kind. As the journey finally brings them face to face, Caesar and the Colonel are pitted against each other in an epic battle that will determine the fate of both their species and the future of the planet.", + "title": "War for the Planet of the Apes", + "type": "movie", + "vote_count": 2692, + "year": 2017 + }, + { + "background": "/rz3TAyd5kmiJmozp3GUbYeB5Kep.jpg", + "genre": [ + 28, + 12, + 35, + 10751 + ], + "id": 353486, + "matchedInPlex": false, + "popularity": 250.35028, + "poster": "/bXrZ5iHBEjH7WMidbUDQ0U2xbmr.jpg", + "rating": 5.6, + "summary": "The tables are turned as four teenagers are sucked into Jumanji's world - pitted against rhinos, black mambas and an endless variety of jungle traps and puzzles. To survive, they'll play as characters from the game.", + "title": "Jumanji: Welcome to the Jungle", + "type": "movie", + "vote_count": 128, + "year": 2017 + }, + { + "background": "/iJ5dkwIHQnq8dfmwSLh7dpETNhi.jpg", + "genre": [ + 35, + 16, + 12 + ], + "id": 355547, + "matchedInPlex": false, + "popularity": 250.28269, + "poster": "/zms2RpkqjAtCsbjndTG9gAGWvnx.jpg", + "rating": 4.6, + "summary": "A small but brave donkey and his animal friends become the unsung heroes of the greatest story ever told, the first Christmas.", + "title": "The Star", + "type": "movie", + "vote_count": 78, + "year": 2017 + }, + { + "background": "/2SEgJ0mHJ7TSdVDbkGU061tR33K.jpg", + "genre": [ + 18, + 53, + 28, + 878 + ], + "id": 347882, + "matchedInPlex": false, + "popularity": 210.896389, + "poster": "/wridRvGxDqGldhzAIh3IcZhHT5F.jpg", + "rating": 5.4, + "summary": "A young street magician is left to take care of his little sister after his mother's passing and turns to drug dealing in the Los Angeles party scene to keep a roof over their heads. When he gets into trouble with his supplier, his sister is kidnapped and he is forced to rely on both his sleight of hand and brilliant mind to save her.", + "title": "Sleight", + "type": "movie", + "vote_count": 156, + "year": 2017 + }, + { + "background": "/5wNUJs23rT5rTBacNyf5h83AynM.jpg", + "genre": [ + 28, + 12, + 35, + 14, + 878 + ], + "id": 284053, + "matchedInPlex": false, + "popularity": 210.575092, + "poster": "/oSLd5GYGsiGgzDPKTwQh7wamO8t.jpg", + "rating": 7.5, + "summary": "Thor is imprisoned on the other side of the universe and finds himself in a race against time to get back to Asgard to stop Ragnarok, the prophecy of destruction to his homeworld and the end of Asgardian civilization, at the hands of an all-powerful new threat, the ruthless Hela.", + "title": "Thor: Ragnarok", + "type": "movie", + "vote_count": 2598, + "year": 2017 + }, + { + "background": "/uExPmkOHJySrbJyJDJylHDqaT58.jpg", + "genre": [ + 28, + 12, + 35 + ], + "id": 343668, + "matchedInPlex": false, + "popularity": 190.179283, + "poster": "/34xBL6BXNYFqtHO9zhcgoakS4aP.jpg", + "rating": 7.1, + "summary": "When an attack on the Kingsman headquarters takes place and a new villain rises, Eggsy and Merlin are forced to work together with the American agency known as the Statesman to save the world.", + "title": "Kingsman: The Golden Circle", + "type": "movie", + "vote_count": 1714, + "year": 2017 + }, + { + "background": "/bAI7aPHQcvSZXvt7L11kMJdS0Gm.jpg", + "genre": [ + 18, + 35, + 36 + ], + "id": 371638, + "matchedInPlex": false, + "popularity": 187.757689, + "poster": "/uCH6FOFsDW6pfvbbmIIswuvuNtM.jpg", + "rating": 7.2, + "summary": "An aspiring actor in Hollywood meets an enigmatic stranger by the name of Tommy Wiseau, the meeting leads the actor down a path nobody could have predicted; creating the worst movie ever made.", + "title": "The Disaster Artist", + "type": "movie", + "vote_count": 87, + "year": 2017 + }, + { + "background": "/2BXd0t9JdVqCp9sKf6kzMkr7QjB.jpg", + "genre": [ + 12, + 10751, + 16, + 28, + 35 + ], + "id": 177572, + "matchedInPlex": false, + "popularity": 180.209866, + "poster": "/9gLu47Zw5ertuFTZaxXOvNfy78T.jpg", + "rating": 7.7, + "summary": "The special bond that develops between plus-sized inflatable robot Baymax, and prodigy Hiro Hamada, who team up with a group of friends to form a band of high-tech heroes.", + "title": "Big Hero 6", + "type": "movie", + "vote_count": 6872, + "year": 2014 + }, + { + "background": "/6iUNJZymJBMXXriQyFZfLAKnjO6.jpg", + "genre": [ + 28, + 12, + 14 + ], + "id": 297762, + "matchedInPlex": false, + "popularity": 176.828995, + "poster": "/imekS7f1OuHyUP2LAiTEM0zBzUz.jpg", + "rating": 7.2, + "summary": "An Amazon princess comes to the world of Man to become the greatest of the female superheroes.", + "title": "Wonder Woman", + "type": "movie", + "vote_count": 6535, + "year": 2017 + }, + { + "background": "/umC04Cozevu8nn3JTDJ1pc7PVTn.jpg", + "genre": [ + 28, + 53 + ], + "id": 245891, + "matchedInPlex": false, + "popularity": 171.364116, + "poster": "/5vHssUeVe25bMrof1HyaPyWgaP.jpg", + "rating": 7, + "summary": "Ex-hitman John Wick comes out of retirement to track down the gangsters that took everything from him.", + "title": "John Wick", + "type": "movie", + "vote_count": 6117, + "year": 2014 + }, + { + "background": "/vc8bCGjdVp0UbMNLzHnHSLRbBWQ.jpg", + "genre": [ + 28, + 12, + 35, + 878 + ], + "id": 315635, + "matchedInPlex": false, + "popularity": 157.789584, + "poster": "/ApYhuwBWzl29Oxe9JJsgL7qILbD.jpg", + "rating": 7.3, + "summary": "Following the events of Captain America: Civil War, Peter Parker, with the help of his mentor Tony Stark, tries to balance his life as an ordinary high school student in Queens, New York City, with fighting crime as his superhero alter ego Spider-Man as a new threat, the Vulture, emerges.", + "title": "Spider-Man: Homecoming", + "type": "movie", + "vote_count": 5218, + "year": 2017 + } + ], + "total_pages": 992 +} \ No newline at end of file diff --git a/seasoned_api/test/helpers/createCacheEntry.js b/seasoned_api/test/helpers/createCacheEntry.js new file mode 100644 index 0000000..afc7889 --- /dev/null +++ b/seasoned_api/test/helpers/createCacheEntry.js @@ -0,0 +1,10 @@ +const Cache = require('src/tmdb/cache'); +const SqliteDatabase = require('src/database/sqliteDatabase'); + +function createCacheEntry(key, value) { + const database = new SqliteDatabase(':memory:'); + const cache = new Cache(database); + return cache.set(key, value); +} + +module.exports = createCacheEntry; diff --git a/seasoned_api/test/helpers/createToken.js b/seasoned_api/test/helpers/createToken.js new file mode 100644 index 0000000..0435968 --- /dev/null +++ b/seasoned_api/test/helpers/createToken.js @@ -0,0 +1,10 @@ +const User = require('src/user/user'); +const Token = require('src/user/token'); + +function createToken(username, secret) { + const user = new User(username); + const token = new Token(user); + return token.toString(secret); +} + +module.exports = createToken; diff --git a/seasoned_api/test/helpers/createUser.js b/seasoned_api/test/helpers/createUser.js new file mode 100644 index 0000000..417d71d --- /dev/null +++ b/seasoned_api/test/helpers/createUser.js @@ -0,0 +1,12 @@ +const User = require('src/user/user'); +const UserSecurity = require('src/user/userSecurity'); +const SqliteDatabase = require('src/database/sqliteDatabase'); + +function createUser(username, email, password) { + const database = new SqliteDatabase(':memory:'); + const userSecurity = new UserSecurity(database); + const user = new User(username, email); + return userSecurity.createNewUser(user, password); +} + +module.exports = createUser; \ No newline at end of file diff --git a/seasoned_api/test/helpers/resetDatabase.js b/seasoned_api/test/helpers/resetDatabase.js new file mode 100644 index 0000000..fdb5c0b --- /dev/null +++ b/seasoned_api/test/helpers/resetDatabase.js @@ -0,0 +1,11 @@ +const SqliteDatabase = require('src/database/sqliteDatabase'); + +function resetDatabase() { + const database = new SqliteDatabase(':memory:'); + return Promise.resolve() + .then(() => database.connect()) + // .then(() => database.tearDown()) + .then(() => database.setUp()); +} + +module.exports = resetDatabase; diff --git a/seasoned_api/test/system/asADeveloperIWantTheServerToRegister.js b/seasoned_api/test/system/asADeveloperIWantTheServerToRegister.js new file mode 100644 index 0000000..6b0a60a --- /dev/null +++ b/seasoned_api/test/system/asADeveloperIWantTheServerToRegister.js @@ -0,0 +1,16 @@ +const assert = require('assert'); +const request = require('supertest-as-promised'); +const app = require('src/webserver/app'); +const resetDatabase = require('test/helpers/resetDatabase'); + +describe('As a user I want to register', () => { + before(() => resetDatabase()); + + it('should return 200 and a message indicating success', () => + request(app) + .post('/api/v1/user') + .send({ username: 'test', email: 'test@gmail.com', password: 'password' }) + .expect(200) + .then(response => assert.equal(response.body.message, 'Welcome to Seasoned!')) + ); +}); diff --git a/seasoned_api/test/system/asADeveloperIWantTheServerToStart.js b/seasoned_api/test/system/asADeveloperIWantTheServerToStart.js new file mode 100644 index 0000000..aa2d7ee --- /dev/null +++ b/seasoned_api/test/system/asADeveloperIWantTheServerToStart.js @@ -0,0 +1,14 @@ +/* eslint-disable no-return-assign */ +const net = require('net'); + +xdescribe('As a developer I want the server to start', () => { + beforeEach(() => + this.server = require('src/webserver/server')); + + it('should listen on port 31459', (done) => { + net.createConnection(31459, done); + }); + + afterEach(() => + this.server.close()); +}); diff --git a/seasoned_api/test/system/asADeveloperIWantToLogin.js b/seasoned_api/test/system/asADeveloperIWantToLogin.js new file mode 100644 index 0000000..3a48e7a --- /dev/null +++ b/seasoned_api/test/system/asADeveloperIWantToLogin.js @@ -0,0 +1,25 @@ +const assert = require('assert'); +const request = require('supertest-as-promised'); +const app = require('src/webserver/app'); +const createUser = require('test/helpers/createUser'); +const resetDatabase = require('test/helpers/resetDatabase'); + +describe('As a user I want to log in', () => { + before(() => resetDatabase()); + before(() => createUser('test_user', 'test@gmail.com', 'password')); + + it('should return 200 with a token if correct credentials are given', () => + request(app) + .post('/api/v1/user/login') + .send({ username: 'test_user', password: 'password' }) + .expect(200) + .then(response => assert.equal(typeof response.body.token, 'string')) + ); + + it('should return 401 if incorrect credentials are given', () => + request(app) + .post('/api/v1/user/login') + .send({ username: 'test_user', password: 'anti-password' }) + .expect(401) + ); +}); diff --git a/seasoned_api/test/system/asAUserIWantAForbiddenErrorIfTheTokenIsMalformed.js b/seasoned_api/test/system/asAUserIWantAForbiddenErrorIfTheTokenIsMalformed.js new file mode 100644 index 0000000..73811b2 --- /dev/null +++ b/seasoned_api/test/system/asAUserIWantAForbiddenErrorIfTheTokenIsMalformed.js @@ -0,0 +1,16 @@ +const assert = require('assert'); +const resetDatabase = require('test/helpers/resetDatabase'); +const app = require('src/webserver/app'); +const request = require('supertest-as-promised'); + +describe('As a user I want a forbidden error if the token is malformed', () => { + before(() => resetDatabase()); + + it('should return 401', () => + request(app) + .get('/api/v1/plex/requests/all') + .set('Authorization', 'maLfOrMed TOKEN') + .expect(401) + .then(response => assert.equal(response.body.error, 'You must be logged in.')) + ); +}); diff --git a/seasoned_api/test/system/asAUserIWantToGetPopularMovies.js b/seasoned_api/test/system/asAUserIWantToGetPopularMovies.js new file mode 100644 index 0000000..642a84f --- /dev/null +++ b/seasoned_api/test/system/asAUserIWantToGetPopularMovies.js @@ -0,0 +1,18 @@ +const assert = require('assert'); +const createCacheEntry = require('test/helpers/createCacheEntry'); +const resetDatabase = require('test/helpers/resetDatabase'); +const request = require('supertest-as-promised'); +const app = require('src/webserver/app'); +const popularMoviesSuccess = require('test/fixtures/popular-movies-success-response.json'); + +describe('As a user I want to get popular movies', () => { + before(() => resetDatabase()); + before(() => createCacheEntry('p:movie::1', popularMoviesSuccess)); + + it('should return 200 with the information', () => + request(app) + .get('/api/v1/tmdb/list/popular') + .expect(200) + .then(response => assert.equal(response.body.results.length, 20)) + ); +}); \ No newline at end of file diff --git a/seasoned_api/test/system/asAUserIWantToRequestAMovie.js b/seasoned_api/test/system/asAUserIWantToRequestAMovie.js new file mode 100644 index 0000000..fda5f0a --- /dev/null +++ b/seasoned_api/test/system/asAUserIWantToRequestAMovie.js @@ -0,0 +1,17 @@ +const resetDatabase = require('test/helpers/resetDatabase'); +const app = require('src/webserver/app'); +const request = require('supertest-as-promised'); +const createUser = require('test/helpers/createUser'); +const createToken = require('test/helpers/createToken'); + +describe('As a user I want to request a movie', () => { + before(() => resetDatabase()); + before(() => createUser('test_user', 'test@gmail.com', 'password')); + + it('should return 200 when item is requested', () => + request(app) + .post('/api/v1/plex/request/31749') + .set('Authorization', createToken('test_user', 'secret')) + .expect(200) + ); +}); diff --git a/seasoned_api/test/system/asAnAnonymousUserIWantToSearchForAMovie.js b/seasoned_api/test/system/asAnAnonymousUserIWantToSearchForAMovie.js new file mode 100644 index 0000000..360adab --- /dev/null +++ b/seasoned_api/test/system/asAnAnonymousUserIWantToSearchForAMovie.js @@ -0,0 +1,16 @@ +const createCacheEntry = require('test/helpers/createCacheEntry'); +const resetDatabase = require('test/helpers/resetDatabase'); +const request = require('supertest-as-promised'); +const app = require('src/webserver/app'); +const interstellarQuerySuccess = require('test/fixtures/interstellar-query-success-response.json'); + +describe('As an anonymous user I want to search for a movie', () => { + before(() => resetDatabase()); + before(() => createCacheEntry('s:1:movie:interstellar', interstellarQuerySuccess)); + + it('should return 200 with the search results even if user is not logged in', () => + request(app) + .get('/api/v1/tmdb/search?query=interstellar&page=1') + .expect(200) + ); +}); diff --git a/seasoned_api/yarn.lock b/seasoned_api/yarn.lock new file mode 100644 index 0000000..f1d3980 --- /dev/null +++ b/seasoned_api/yarn.lock @@ -0,0 +1,2403 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + +abbrev@1.0.x: + version "1.0.9" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" + +accepts@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.0.0.tgz#3604c765586c3b9cf7877b6937cdbd4587f947dc" + dependencies: + mime "~1.2.11" + negotiator "~0.3.0" + +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@^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: + 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" + +ajv@^5.2.0, ajv@^5.2.3: + version "5.3.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.3.0.tgz#4414ff74a50879c208ee5fdc826e32c303549eda" + dependencies: + co "^4.6.0" + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" + +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@^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: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88" + dependencies: + color-convert "^1.9.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" + +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" + +arrify@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + +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" + +async@0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/async/-/async-0.9.0.tgz#ac3613b1da9bed1b47510bb4651b8931e47146c7" + +async@1.x, async@^1.4.0, async@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + +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-code-frame@^6.22.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" + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + +base64url@2.0.0, base64url@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/base64url/-/base64url-2.0.0.tgz#eac16e03ea1438eff9423d69baa36262ed1f70bb" + +bcrypt-nodejs@^0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/bcrypt-nodejs/-/bcrypt-nodejs-0.0.3.tgz#c60917f26dc235661566c681061c303c2b28842b" + +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" + +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" + +bluebird@^3.3.1, bluebird@^3.5.0: + version "3.5.1" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" + +body-parser@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.0.2.tgz#3461479a3278fe00fcaebec3314bb54fc4f7b47c" + dependencies: + qs "~0.6.6" + raw-body "~1.1.2" + type-is "~1.1.0" + +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" + +browser-stdout@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.0.tgz#f351d32969d32fa5d7a5567154263d928ae3bd1f" + +bson@~0.2: + version "0.2.22" + resolved "https://registry.yarnpkg.com/bson/-/bson-0.2.22.tgz#fcda103f26d0c074d5a52d50927db80fd02b4b39" + dependencies: + nan "~1.8" + +buffer-crc32@0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.1.tgz#be3e5382fc02b6d6324956ac1af98aa98b08534c" + +buffer-equal-constant-time@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" + +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" + +bytes@1: + version "1.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8" + +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" + +camelcase@^1.0.2: + version "1.2.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" + +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" + +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.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.0.tgz#b5ea48efc9c1793dccc9b4767c93914d3f2d52ba" + dependencies: + ansi-styles "^3.1.0" + escape-string-regexp "^1.0.5" + supports-color "^4.0.0" + +circular-json@^0.3.1: + version "0.3.3" + resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" + +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-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" + +clone@2.x: + version "2.1.1" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb" + +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.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" + dependencies: + graceful-readlink ">= 1.0.0" + +component-emitter@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + +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" + +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" + +cookie-signature@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.3.tgz#91cd997cc51fb641595738c69cda020328f50ff9" + +cookie@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.1.0.tgz#90eb469ddce905c866de687efc43131d8801f9d0" + +cookie@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + +cookiejar@^2.0.6: + version "2.1.1" + resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.1.tgz#41ad57b1b555951ec171412a81942b1e8200d34a" + +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" + +cross-env@^3.1.3: + version "3.2.4" + resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-3.2.4.tgz#9e0585f277864ed421ce756f81a980ff0d698aba" + dependencies: + cross-spawn "^5.1.0" + is-windows "^1.0.0" + +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" + +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" + +debug@*, 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" + +debug@0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-0.7.4.tgz#06e1ea8082c2cb14e39806e22e2f6f757f92af39" + +debug@2.6.8: + version "2.6.8" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" + dependencies: + ms "2.0.0" + +"debug@>= 0.7.3 < 1": + version "0.8.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-0.8.1.tgz#20ff4d26f5e422cb68a1bacbbb61039ad8c1c130" + +debug@^2.2.0, 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" + +decamelize@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + +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" + +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" + +diff@3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9" + +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" + +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" + +ecdsa-sig-formatter@1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.9.tgz#4bc926274ec3b5abb5016e7e1d60921ac262b2a1" + dependencies: + base64url "^2.0.0" + safe-buffer "^5.0.1" + +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" + +escape-html@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.1.tgz#181a286ead397a39a92857cfb1d43052e356bff0" + +escape-string-regexp@1.0.5, 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.8.x: + version "1.8.1" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018" + dependencies: + esprima "^2.7.1" + estraverse "^1.9.1" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.2.0" + +eslint-config-airbnb-base@^12.1.0: + version "12.1.0" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-12.1.0.tgz#386441e54a12ccd957b0a92564a4bafebd747944" + dependencies: + eslint-restricted-globals "^0.1.1" + +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.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.8.0.tgz#fa1b6ef31fcb3c501c09859c1b86f1fc5b986894" + 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-restricted-globals@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz#35f0d5cbc64c2e3ed62e93b4b1a7af05ba7ed4d7" + +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.9.0: + version "4.9.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.9.0.tgz#76879d274068261b191fe0f2f56c74c2f4208e8b" + 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@2.7.x, esprima@^2.7.1: + version "2.7.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" + +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@^1.9.1: + version "1.9.3" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44" + +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" + +express@~4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/express/-/express-4.0.0.tgz#274dc82933c9f574cc38a0ce5ea8172be9c6b094" + dependencies: + accepts "1.0.0" + buffer-crc32 "0.2.1" + cookie "0.1.0" + cookie-signature "1.0.3" + debug ">= 0.7.3 < 1" + escape-html "1.0.1" + fresh "0.2.2" + merge-descriptors "0.0.2" + methods "0.1.0" + parseurl "1.0.1" + path-to-regexp "0.1.2" + qs "0.6.6" + range-parser "1.0.0" + send "0.2.0" + serve-static "1.0.1" + type-is "1.0.0" + utils-merge "1.0.0" + +extend@^3.0.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" + +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-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + +fast-levenshtein@~2.0.4: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + +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" + +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: + 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" + +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-rc4: + version "1.0.0-rc4" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-1.0.0-rc4.tgz#05ac6bc22227b43e4461f488161554699d4f8b5e" + dependencies: + async "^1.5.2" + combined-stream "^1.0.5" + mime-types "^2.1.10" + +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" + +formidable@^1.0.17: + version "1.1.1" + resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.1.1.tgz#96b8886f7c3c3508b932d6bd70c4d3a88f35f1a9" + +fresh@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.2.0.tgz#bfd9402cf3df12c4a4c310c79f99a3dde13d34a7" + +fresh@0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.2.2.tgz#9731dcf5678c7faeb44fb903c4f72df55187fa77" + +fresh@~0.2.1: + version "0.2.4" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.2.4.tgz#3582499206c9723714190edd74b4604feb4a614c" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +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: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + +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" + +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@7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.2" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^5.0.15: + version "5.0.15" + resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.0.3, glob@^7.0.5, 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" + +globals@^9.17.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.2: + version "4.1.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + +"graceful-readlink@>= 1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + +growl@1.9.2: + version "1.9.2" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f" + +handlebars@^4.0.1: + version "4.0.11" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc" + 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" + +he@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" + +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" + +hooks@0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/hooks/-/hooks-0.3.2.tgz#a31f060c2026cea6cf1ca3eb178430e718e1c4a3" + +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" + +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" + +iconv-lite@^0.4.17: + 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.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.6.tgz#b6f3196b38ed92f0c86e52f6f79b7fc4c8266c8d" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + +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.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" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + +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-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-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-promise@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" + +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-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + +is-windows@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.1.tgz#310db70f742d259a16a369202b51af84233310d9" + +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" + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + +istanbul@^0.4.5: + version "0.4.5" + resolved "https://registry.yarnpkg.com/istanbul/-/istanbul-0.4.5.tgz#65c7d73d4c4da84d4f3ac310b918fb0b8033733b" + dependencies: + abbrev "1.0.x" + async "1.x" + escodegen "1.8.x" + esprima "2.7.x" + glob "^5.0.15" + handlebars "^4.0.1" + js-yaml "3.x" + mkdirp "0.5.x" + nopt "3.x" + once "1.x" + resolve "1.1.x" + supports-color "^3.1.0" + which "^1.1.1" + wordwrap "^1.0.0" + +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.x, 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" + +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: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + +json3@3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" + +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + +jsonwebtoken@^8.0.1: + version "8.1.0" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.1.0.tgz#c6397cd2e5fd583d65c007a83dc7bb78e6982b83" + dependencies: + jws "^3.1.4" + lodash.includes "^4.3.0" + lodash.isboolean "^3.0.3" + lodash.isinteger "^4.0.4" + lodash.isnumber "^3.0.3" + lodash.isplainobject "^4.0.6" + lodash.isstring "^4.0.1" + lodash.once "^4.0.0" + ms "^2.0.0" + xtend "^4.0.1" + +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" + +jwa@^1.1.4: + version "1.1.5" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.1.5.tgz#a0552ce0220742cd52e153774a32905c30e756e5" + dependencies: + base64url "2.0.0" + buffer-equal-constant-time "1.0.1" + ecdsa-sig-formatter "1.0.9" + safe-buffer "^5.0.1" + +jws@^3.1.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/jws/-/jws-3.1.4.tgz#f9e8b9338e8a847277d6444b1464f61880e050a2" + dependencies: + base64url "^2.0.0" + jwa "^1.1.4" + safe-buffer "^5.0.1" + +kareem@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/kareem/-/kareem-0.0.4.tgz#a8475defd74cf829b0071d20e6971bf15d911d2b" + +kerberos@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/kerberos/-/kerberos-0.0.4.tgz#11836638f729a2f6c5bae056a7d7a15898c9ba7c" + +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" + +lazy-cache@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" + +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" + +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._baseassign@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" + dependencies: + lodash._basecopy "^3.0.0" + lodash.keys "^3.0.0" + +lodash._basecopy@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" + +lodash._basecreate@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz#1bc661614daa7fc311b7d03bf16806a0213cf821" + +lodash._getnative@^3.0.0: + version "3.9.1" + resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" + +lodash._isiterateecall@^3.0.0: + version "3.0.9" + resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" + +lodash.cond@^4.3.0: + version "4.5.2" + resolved "https://registry.yarnpkg.com/lodash.cond/-/lodash.cond-4.5.2.tgz#f471a1da486be60f6ab955d17115523dd1d255d5" + +lodash.create@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lodash.create/-/lodash.create-3.1.1.tgz#d7f2849f0dbda7e04682bb8cd72ab022461debe7" + dependencies: + lodash._baseassign "^3.0.0" + lodash._basecreate "^3.0.0" + lodash._isiterateecall "^3.0.0" + +lodash.includes@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" + +lodash.isarguments@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + +lodash.isarray@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" + +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" + +lodash.isinteger@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" + +lodash.isnumber@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + +lodash.keys@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" + dependencies: + lodash._getnative "^3.0.0" + lodash.isarguments "^3.0.0" + lodash.isarray "^3.0.0" + +lodash.once@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + +lodash@4.x, lodash@^4.13.1, lodash@^4.17.4, lodash@^4.3.0: + version "4.17.4" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" + +longest@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" + +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" + +lsmod@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lsmod/-/lsmod-1.0.0.tgz#9a00f76dca36eb23fa05350afe1b585d4299e64b" + +merge-descriptors@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-0.0.2.tgz#c36a52a781437513c57275f39dd9d317514ac8c7" + +methods@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/methods/-/methods-0.1.0.tgz#335d429eefd21b7bacf2e9c922a8d2bd14a30e4f" + +methods@1.x, methods@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + +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.10, 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" + +mime@^1.3.4: + version "1.4.1" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" + +mime@~1.2.11, mime@~1.2.9: + version "1.2.11" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" + +mimic-fn@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18" + +"minimatch@2 || 3", 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.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.1, mkdirp@0.5.x, "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" + +mocha@^3.1.0: + version "3.5.3" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-3.5.3.tgz#1e0480fe36d2da5858d1eb6acc38418b26eaa20d" + dependencies: + browser-stdout "1.3.0" + commander "2.9.0" + debug "2.6.8" + diff "3.2.0" + escape-string-regexp "1.0.5" + glob "7.1.1" + growl "1.9.2" + he "1.1.1" + json3 "3.3.2" + lodash.create "3.1.1" + mkdirp "0.5.1" + supports-color "3.1.2" + +mongodb@1.4.12: + version "1.4.12" + resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-1.4.12.tgz#65cdd46ec127861e941168fdccf82bf17ad71c4d" + dependencies: + bson "~0.2" + optionalDependencies: + kerberos "0.0.4" + readable-stream latest + +mongoose@^3.6.13: + version "3.9.7" + resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-3.9.7.tgz#b315e6ebe5cefcce3843504b791f038828048da6" + dependencies: + async "0.9.0" + hooks "0.3.2" + kareem "0.0.4" + mongodb "1.4.12" + mpath "0.1.1" + mpromise "0.5.4" + mquery "1.0.0" + ms "0.1.0" + muri "0.3.1" + regexp-clone "0.0.1" + sliced "0.0.5" + +moviedb@^0.2.10: + version "0.2.10" + resolved "https://registry.yarnpkg.com/moviedb/-/moviedb-0.2.10.tgz#53238d403608478b8ba69e8d8dad19e3f0af78e8" + dependencies: + superagent "^2.3.0" + +mpath@0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/mpath/-/mpath-0.1.1.tgz#23da852b7c232ee097f4759d29c0ee9cd22d5e46" + +mpromise@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/mpromise/-/mpromise-0.5.4.tgz#b610613ec6de37419f944b35f0783b4de9f5dc75" + +mquery@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/mquery/-/mquery-1.0.0.tgz#6940a46d643368fe8e5abddeb94bd8dd32013f5b" + dependencies: + debug "0.7.4" + regexp-clone "0.0.1" + sliced "0.0.5" + +ms@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.1.0.tgz#f21fac490daf1d7667fd180fe9077389cc9442b2" + +ms@2.0.0, ms@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + +muri@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/muri/-/muri-0.3.1.tgz#861889c5c857f1a43700bee85d50731f61727c9a" + +mute-stream@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + +nan@~1.8: + version "1.8.4" + resolved "https://registry.yarnpkg.com/nan/-/nan-1.8.4.tgz#3c76b5382eab33e44b758d2813ca9d92e9342f34" + +nan@~2.7.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" + +negotiator@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.3.0.tgz#706d692efeddf574d57ea9fb1ab89a4fa7ee8f60" + +node-cache@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/node-cache/-/node-cache-4.1.1.tgz#08524645ee4039dedc3dcc1dd7c6b979e0619e44" + dependencies: + clone "2.x" + lodash "4.x" + +node-pre-gyp@~0.6.38: + 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" + +nodemailer@^4.0.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-4.2.0.tgz#310781d30130bc5b7bf756bb626ec27564c5079b" + +nopt@3.x: + version "3.0.6" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + dependencies: + abbrev "1" + +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" + +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" + +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" + +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: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + +once@1.x, once@^1.3.0, once@^1.3.3: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +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" + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +os-tmpdir@^1.0.0, 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" + +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" + +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" + +parseurl@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.0.1.tgz#2e57dce6efdd37c3518701030944c22bf388b7b4" + +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: + 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-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@0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.2.tgz#9b2b151f9cc3018c9eea50ca95729e05781712b4" + +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" + +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" + +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" + +progress@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + +punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + +python-shell@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/python-shell/-/python-shell-0.4.0.tgz#259c5470d885292b22e906a57b085f651752f956" + +qs@0.6.6, qs@~0.6.6: + version "0.6.6" + resolved "https://registry.yarnpkg.com/qs/-/qs-0.6.6.tgz#6e015098ff51968b8a3c819001d5f2c89bc4b107" + +qs@^6.1.0, 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" + +range-parser@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-0.0.4.tgz#c0427ffef51c10acba0782a46c9602e744ff620b" + +range-parser@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.0.0.tgz#a4b264cfe0be5ce36abe3765ac9c2a248746dbc0" + +range-parser@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.0.3.tgz#6872823535c692e2c2a0103826afd82c2e0ff175" + +raven@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/raven/-/raven-2.2.1.tgz#57c7fbe68a80147ec527def3d7c01575cf948fe3" + dependencies: + cookie "0.3.1" + lsmod "1.0.0" + stack-trace "0.0.9" + timed-out "4.0.1" + uuid "3.0.0" + +raw-body@~1.1.2: + version "1.1.7" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-1.1.7.tgz#1d027c2bfa116acc6623bca8f00016572a87d425" + dependencies: + bytes "1" + string_decoder "0.10" + +rc@^1.1.7: + version "1.2.2" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.2.tgz#d8ce9cb57e8d64d9c7badd9876c7c34cbe3c7077" + dependencies: + deep-extend "~0.4.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +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@^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.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.2.2, readable-stream@latest: + 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" + +regexp-clone@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/regexp-clone/-/regexp-clone-0.0.1.tgz#a7c2e09891fdbf38fbb10d376fb73003e68ac589" + +repeat-string@^1.5.2: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + +request-promise-core@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.1.tgz#3eee00b2c5aa83239cfb04c5700da36f81cd08b6" + dependencies: + lodash "^4.13.1" + +request-promise@^4.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/request-promise/-/request-promise-4.2.2.tgz#d1ea46d654a6ee4f8ee6a4fea1018c22911904b4" + dependencies: + bluebird "^3.5.0" + request-promise-core "1.1.1" + stealthy-require "^1.1.0" + tough-cookie ">=2.3.3" + +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.81.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-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@1.1.x: + version "1.1.7" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" + +resolve@^1.2.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" + dependencies: + path-parse "^1.0.5" + +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" + +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" + +"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" + +send@0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/send/-/send-0.1.4.tgz#be70d8d1be01de61821af13780b50345a4f71abd" + dependencies: + debug "*" + fresh "0.2.0" + mime "~1.2.9" + range-parser "0.0.4" + +send@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.2.0.tgz#067abf45cff8bffb29cbdb7439725b32388a2c58" + dependencies: + debug "*" + fresh "~0.2.1" + mime "~1.2.9" + range-parser "~1.0.0" + +serve-static@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.0.1.tgz#10dcbfd44b3e0291a131fc9ab4ab25a9f5a78a42" + dependencies: + send "0.1.4" + +set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +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" + +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" + +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" + +sliced@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/sliced/-/sliced-0.0.5.tgz#5edc044ca4eb6f7816d50ba2fc63e25d8fe4707f" + +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@^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.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d" + dependencies: + amdefine ">=0.0.4" + +source-map@~0.5.1: + 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" + +sqlite3@3.1.13: + version "3.1.13" + resolved "https://registry.yarnpkg.com/sqlite3/-/sqlite3-3.1.13.tgz#d990a05627392768de6278bafd1a31fdfe907dd9" + dependencies: + nan "~2.7.0" + node-pre-gyp "~0.6.38" + +sqlite@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/sqlite/-/sqlite-2.9.0.tgz#33f03c646ea0f7a5d506e645a19b9c5352dd9fa4" + dependencies: + sqlite3 "3.1.13" + +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" + +stack-trace@0.0.9: + version "0.0.9" + resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.9.tgz#a8f6eaeca90674c333e7c43953f275b451510695" + +stealthy-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" + +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.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@0.10: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + +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" + +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: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + +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" + +superagent@^2.0.0, superagent@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/superagent/-/superagent-2.3.0.tgz#703529a0714e57e123959ddefbce193b2e50d115" + dependencies: + component-emitter "^1.2.0" + cookiejar "^2.0.6" + debug "^2.2.0" + extend "^3.0.0" + form-data "1.0.0-rc4" + formidable "^1.0.17" + methods "^1.1.1" + mime "^1.3.4" + qs "^6.1.0" + readable-stream "^2.0.5" + +supertest-as-promised@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/supertest-as-promised/-/supertest-as-promised-4.0.2.tgz#0464f2bd256568d4a59bce84269c0548f6879f1a" + dependencies: + bluebird "^3.3.1" + methods "^1.1.1" + +supertest@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/supertest/-/supertest-2.0.1.tgz#a058081d788f1515d4700d7502881e6b759e44cd" + dependencies: + methods "1.x" + superagent "^2.0.0" + +supports-color@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.1.2.tgz#72a262894d9d408b956ca05ff37b2ed8a6e2a2d5" + dependencies: + has-flag "^1.0.0" + +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.0: + 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.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.5.0.tgz#be7a0de484dec5c5cddf8b3d59125044912f635b" + dependencies: + has-flag "^2.0.0" + +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" + +text-table@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + +through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + +timed-out@4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" + +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" + +tough-cookie@>=2.3.3, 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" + +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-is@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.0.0.tgz#4ff424e97349a1ee1910b4bfc488595ecdc443fc" + dependencies: + mime "~1.2.11" + +type-is@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.1.0.tgz#d0245ec8b2676668d59dd0cf3255060676a57db6" + dependencies: + mime "~1.2.11" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + +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" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +utils-merge@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" + +uuid@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.0.tgz#6728fc0459c450d796a99c31837569bdf672d728" + +uuid@^3.0.0, uuid@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" + +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" + +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" + +which@^1.1.1, 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@^1.0.0, wordwrap@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + +wordwrap@~0.0.2: + version "0.0.3" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +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" + +xtend@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + +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"