Adding option to switch deployment pipeline

This commit is contained in:
Anthony Laibe 2018-10-16 10:35:15 +01:00 committed by Pascal Precht
parent 83a9fd4ed0
commit a4d4278dc9
No known key found for this signature in database
GPG Key ID: 0EE28D8D6FD85D7D
11 changed files with 1700 additions and 120 deletions

File diff suppressed because it is too large Load Diff

View File

@ -71,6 +71,7 @@
"sw-precache-webpack-plugin": "0.11.4",
"tabler-react": "^1.18.0",
"url-loader": "0.6.2",
"web3": "^1.0.0-beta.36",
"webpack": "3.8.1",
"webpack-dev-server": "2.9.4",
"webpack-manifest-plugin": "1.3.2",

View File

@ -323,11 +323,33 @@ export const gasOracle = {
failure: (error) => action(GAS_ORACLE[FAILURE], {error})
};
<<<<<<< HEAD
export const EXPLORER_SEARCH = createRequestTypes('EXPLORER_SEARCH');
export const explorerSearch = {
request: (searchValue) => action(EXPLORER_SEARCH[REQUEST], {searchValue}),
success: (searchResult) => action(EXPLORER_SEARCH[SUCCESS], {searchResult}),
failure: (error) => action(EXPLORER_SEARCH[FAILURE], {error})
=======
export const WEB3_CONNECT = createRequestTypes('WEB3_CONNECT');
export const web3Connect = {
request: () => action(WEB3_CONNECT[REQUEST]),
success: (web3) => action(WEB3_CONNECT[SUCCESS], {web3}),
failure: (error) => action(WEB3_CONNECT[FAILURE], {web3Error: error})
};
export const WEB3_DEPLOY = createRequestTypes('WEB3_DEPLOY');
export const web3Deploy = {
request: (contract, args) => action(WEB3_DEPLOY[REQUEST], {contract, args}),
success: (receipt, payload) => action(WEB3_DEPLOY[SUCCESS], {contract: payload.contract, receipt}),
failure: (error, payload) => action(WEB3_DEPLOY[FAILURE], {web3Error: error, contract: payload.contract})
};
export const WEB3_ESTIMAGE_GAS = createRequestTypes('WEB3_ESTIMAGE_GAS');
export const web3EstimateGas = {
request: (contract, args) => action(WEB3_ESTIMAGE_GAS[REQUEST], {contract, args}),
success: (gas, payload) => action(WEB3_ESTIMAGE_GAS[SUCCESS], {contract: payload.contract, gas}),
failure: (error, payload) => action(WEB3_ESTIMAGE_GAS[FAILURE], {web3Error: error, contract: payload.contract})
>>>>>>> Adding option to switch deployment pipeline
};
// Web Socket
@ -407,4 +429,10 @@ export function toggleBreakpoint(filename, lineNumber) {
};
}
export const UPDATE_DEPLOYMENT_PIPELINE = 'UPDATE_DEPLOYMENT_PIPELINE';
export function updateDeploymentPipeline(value) {
return {
type: UPDATE_DEPLOYMENT_PIPELINE,
payload: value
};
}

View File

@ -2,9 +2,18 @@ import PropTypes from "prop-types";
import React from 'react';
import {
Row,
Col
Col,
FormGroup,
Input,
Label,
UncontrolledTooltip,
Button,
Card,
CardHeader,
CardBody
} from 'reactstrap';
import classNames from 'classnames';
import {DEPLOYMENT_PIPELINES} from '../constants';
const orderClassName = (address) => {
return classNames({
@ -14,50 +23,240 @@ const orderClassName = (address) => {
});
}
const Contract = ({contract}) => (
// TODO add an ABI parser
const findConstructor = (abiDefinition) => abiDefinition.find(method => method.type === 'constructor');
const NoWeb3 = () => (
<Row>
<Col>
<h3>You are not connected to web3 yet</h3>
</Col>
</Row>
)
const LayoutContract = ({contract, children}) => (
<Row className="border-bottom border-primary pb-3 mt-4">
<Col xs={1} className="text-center">
<h4><span className={orderClassName(contract.address)}>{contract.index + 1}</span></h4>
</Col>
<Col xs={11}>
{contract.address &&
<React.Fragment>
<h5>{contract.className} deployed at {contract.address}</h5>
<p><strong>Arguments:</strong> {JSON.stringify(contract.args)}</p>
</React.Fragment>
}
{!contract.address &&
<h5>{contract.className} not deployed</h5>
}
{contract.transactionHash &&
<React.Fragment>
<p><strong>Transaction Hash:</strong> {contract.transactionHash}</p>
<p><strong>{contract.gas}</strong> gas at <strong>{contract.gasPrice}</strong> Wei, estimated cost: <strong>{contract.gas * contract.gasPrice}</strong> Wei</p>
</React.Fragment>
}
{contract.address && !contract.transactionHash &&
<p><strong>Contract already deployed</strong></p>
}
{children}
</Col>
</Row>
)
const DeploymentResult = ({deployment}) => {
if (deployment.running) {
return <p>Deployment is in progress <i className="fa fa-spinner fa-spin fa-fw"/></p>
}
if (deployment.error) {
return <p className="text-danger">Deployment failed: {deployment.error}</p>
}
return (
<React.Fragment>
<p className="text-success">Deployment succeed:</p>
<dl class="row">
<dt class="col-sm-3">Transaction</dt>
<dd class="col-sm-9">{deployment.transactionHash}</dd>
<dt class="col-sm-3">Gas used</dt>
<dd class="col-sm-9">{deployment.gasUsed}</dd>
<dt class="col-sm-3">Address</dt>
<dd class="col-sm-9">{deployment.contractAddress}</dd>
</dl>
</React.Fragment>
)
}
const GasEstimateResult = ({gasEstimate}) => {
if (gasEstimate.running) {
return <p>Gas Estimation is in progresss <i className="fa fa-spinner fa-spin fa-fw"/></p>
}
if (gasEstimate.error) {
return <p className="text-danger">Gas Estimation failed: {gasEstimate.error}</p>
}
return <p className="text-success">Gas Estimation succeed: {gasEstimate.gas}</p>
}
class Web3Contract extends React.Component {
constructor(props) {
super(props);
this.state = {inputs: {}};
}
handleOnChange(event, name) {
let newInputs = this.state.inputs;
newInputs[name] = event.target.value;
this.setState({inputs: newInputs});
}
inputsAsArray() {
return findConstructor(this.props.contract.abiDefinition).inputs
.map(input => this.state.inputs[input.name])
.filter(value => value);
}
actionDisabled() {
return this.inputsAsArray().length !== findConstructor(this.props.contract.abiDefinition).inputs.length;
}
render() {
const constructor = findConstructor(this.props.contract.abiDefinition);
const isInterface = !constructor;
const argumentsRequired = constructor && constructor.inputs.length > 0;
return (
<LayoutContract contract={this.props.contract}>
<Row>
<Col md={6}>
{isInterface && <h5>{this.props.contract.className} is an interface</h5>}
{!isInterface && <h5>{this.props.contract.className}</h5>}
{argumentsRequired &&
<Card>
<CardHeader>
<strong>Arguments:</strong>
</CardHeader>
<CardBody>
{constructor.inputs.map(input => (
<FormGroup key={input.name}>
<Label htmlFor={input.name}>{input.name}</Label>
<Input id={input.name} placeholder={input.name} onChange={e => this.handleOnChange(e, input.name)} />
</FormGroup>
))}
</CardBody>
</Card>
}
{!this.props.web3 && <NoWeb3 />}
{this.props.web3 && !isInterface &&
<React.Fragment>
<Button className="mr-2"
color="primary"
disabled={this.actionDisabled()}
onClick={() => this.props.web3EstimateGas(this.props.contract, this.inputsAsArray())}>
Estimate
</Button>
<Button color="primary" disabled={this.actionDisabled()} onClick={() => this.props.web3Deploy(this.props.contract, this.inputsAsArray())}>Deploy</Button>
</React.Fragment>
}
</Col>
<Col md={5}>
{this.props.gasEstimate && <GasEstimateResult gasEstimate={this.props.gasEstimate}/>}
<hr />
{this.props.deployment && <DeploymentResult deployment={this.props.deployment}/>}
</Col>
</Row>
</LayoutContract>
)
}
}
const EmbarkContract = ({contract}) => (
<LayoutContract contract={contract}>
{contract.address &&
<React.Fragment>
<h5>{contract.className} deployed at {contract.address}</h5>
<p><strong>Arguments:</strong> {JSON.stringify(contract.args)}</p>
</React.Fragment>
}
{!contract.address &&
<h5>{contract.className} not deployed</h5>
}
{contract.transactionHash &&
<React.Fragment>
<p><strong>Transaction Hash:</strong> {contract.transactionHash}</p>
<p><strong>{contract.gas}</strong> gas at <strong>{contract.gasPrice}</strong> Wei, estimated cost: <strong>{contract.gas * contract.gasPrice}</strong> Wei</p>
</React.Fragment>
}
{contract.address && !contract.transactionHash &&
<p><strong>Contract already deployed</strong></p>
}
</LayoutContract>
);
const Contracts = ({contracts}) => (
<React.Fragment>
<Row className="mt-3">
<Col xs={1} className="text-center">
<strong>Order</strong>
</Col>
<Col xs={11}>
const ContractsHeader = ({deploymentPipeline, updateDeploymentPipeline}) => (
<Row className="mt-3">
<Col xs={1} className="text-center">
<strong>Order</strong>
</Col>
<Col xs={11}>
<Row>
<strong>Contract</strong>
</Col>
</Row>
{contracts.sort((a, b) => a.index - b.index).map(contract => <Contract key={contract.index} contract={contract} />)}
<div className="ml-auto mr-5">
<FormGroup row>
<span className="mr-2">Deploy using</span>
<FormGroup check inline>
<Label className="form-check-label" check>
<Input className="form-check-input"
type="radio"
onChange={() => updateDeploymentPipeline(DEPLOYMENT_PIPELINES.embark)}
checked={deploymentPipeline === DEPLOYMENT_PIPELINES.embark} />
Embark
<i className="ml-1 fa fa-question" id="embark-tooltip" />
<UncontrolledTooltip placement="bottom" target="embark-tooltip">
Embark will deploy the contracts automatically for you each time there is a change in one of them.
</UncontrolledTooltip>
</Label>
</FormGroup>
<FormGroup check inline>
<Label className="form-check-label" check>
<Input className="form-check-input"
type="radio"
onChange={() => updateDeploymentPipeline(DEPLOYMENT_PIPELINES.injectedWeb3)}
checked={deploymentPipeline === DEPLOYMENT_PIPELINES.injectedWeb3} />
Injected Web3
<i className="ml-1 fa fa-question" id="web3-tooltip" />
<UncontrolledTooltip placement="bottom" target="web3-tooltip">
You will have full control on your deployment
</UncontrolledTooltip>
</Label>
</FormGroup>
</FormGroup>
</div>
</Row>
</Col>
</Row>
)
const Contract = ({web3, contract, deploymentPipeline, web3Deploy, web3EstimateGas, web3Deployments, web3GasEstimates}) => {
const deployment = web3Deployments[contract.className];
const gasEstimate = web3GasEstimates[contract.className];
switch(deploymentPipeline) {
case 'embark':
return <EmbarkContract contract={contract} />;
case 'injectedWeb3':
return <Web3Contract web3={web3}
deployment={deployment}
gasEstimate={gasEstimate}
contract={contract}
web3Deploy={web3Deploy}
web3EstimateGas={web3EstimateGas} />;
default:
return <React.Fragment></React.Fragment>;
}
}
const Contracts = (props) => (
<React.Fragment>
<ContractsHeader deploymentPipeline={props.deploymentPipeline} updateDeploymentPipeline={props.updateDeploymentPipeline} />
{props.contracts.sort((a, b) => a.index - b.index).map(contract => <Contract key={contract.index} contract={contract} {...props} />)}
</React.Fragment>
);
Contracts.propTypes = {
contracts: PropTypes.array,
deploymentPipeline: PropTypes.string,
updateDeploymentPipeline: PropTypes.func,
web3Deployments: PropTypes.object,
web3GasEstimates: PropTypes.object,
web3: PropTypes.object,
web3Deploy: PropTypes.func,
web3EstimateGas: PropTypes.func
};
export default Contracts;

View File

@ -2,3 +2,7 @@ export const EMBARK_PROCESS_NAME = 'embark';
export const LOG_LIMIT = 50;
export const DARK_THEME = 'dark';
export const LIGHT_THEME = 'light';
export const DEPLOYMENT_PIPELINES = {
injectedWeb3: 'injectedWeb3',
embark: 'embark'
}

View File

@ -1,11 +1,15 @@
import React, {Component} from 'react';
import {connect} from 'react-redux';
import PropTypes from 'prop-types';
import {contracts as contractsAction} from "../actions";
import {
contracts as contractsAction,
web3Deploy as web3DeployAction,
web3EstimateGas as web3EstimateGasAction,
updateDeploymentPipeline} from "../actions";
import ContractsDeployment from '../components/ContractsDeployment';
import DataWrapper from "../components/DataWrapper";
import {getContracts} from "../reducers/selectors";
import {getContracts, getDeploymentPipeline, getWeb3, getWeb3GasEstimates, getWeb3Deployments} from "../reducers/selectors";
class DeploymentContainer extends Component {
componentDidMount() {
@ -14,8 +18,15 @@ class DeploymentContainer extends Component {
render() {
return (
<DataWrapper shouldRender={this.props.contracts.length > 0} {...this.props} render={({contracts}) => (
<ContractsDeployment contracts={contracts} />
<DataWrapper shouldRender={this.props.contracts.length > 0} {...this.props} render={() => (
<ContractsDeployment contracts={this.props.contracts}
deploymentPipeline={this.props.deploymentPipeline}
web3={this.props.web3}
web3Deploy={this.props.web3Deploy}
web3EstimateGas={this.props.web3EstimateGas}
web3Deployments={this.props.web3Deployments}
web3GasEstimates={this.props.web3GasEstimates}
updateDeploymentPipeline={this.props.updateDeploymentPipeline} />
)} />
);
}
@ -23,18 +34,31 @@ class DeploymentContainer extends Component {
function mapStateToProps(state) {
return {
contracts: getContracts(state),
contracts: getContracts(state),
deploymentPipeline: getDeploymentPipeline(state),
web3: getWeb3(state),
web3Deployments: getWeb3Deployments(state),
web3GasEstimates: getWeb3GasEstimates(state),
error: state.errorMessage,
loading: state.loading};
loading: state.loading
};
}
DeploymentContainer.propTypes = {
web3: PropTypes.object,
web3Deployments: PropTypes.object,
web3GasEstimates: PropTypes.object,
contracts: PropTypes.array,
fetchContracts: PropTypes.func
fetchContracts: PropTypes.func,
web3Deploy: PropTypes.func,
web3EstimateGas: PropTypes.func,
};
export default connect(
mapStateToProps,{
fetchContracts: contractsAction.request
mapStateToProps, {
fetchContracts: contractsAction.request,
web3Deploy: web3DeployAction.request,
web3EstimateGas: web3EstimateGasAction.request,
updateDeploymentPipeline: updateDeploymentPipeline
}
)(DeploymentContainer);

View File

@ -1,8 +1,14 @@
import {combineReducers} from 'redux';
<<<<<<< HEAD
import {REQUEST, SUCCESS, FAILURE, CONTRACT_COMPILE, FILES, LOGOUT, AUTHENTICATE,
FETCH_CREDENTIALS, UPDATE_BASE_ETHER, CHANGE_THEME, FETCH_THEME, EXPLORER_SEARCH,
SIGN_MESSAGE, VERIFY_MESSAGE, TOGGLE_BREAKPOINT} from "../actions";
import {EMBARK_PROCESS_NAME, DARK_THEME} from '../constants';
=======
import {REQUEST, SUCCESS, FAILURE, CONTRACT_COMPILE, FILES, LOGOUT, AUTHENTICATE, CHANGE_THEME, FETCH_THEME,
FETCH_CREDENTIALS, UPDATE_BASE_ETHER, UPDATE_DEPLOYMENT_PIPELINE, WEB3_CONNECT, WEB3_DEPLOY, WEB3_ESTIMAGE_GAS} from "../actions";
import {EMBARK_PROCESS_NAME, DARK_THEME, DEPLOYMENT_PIPELINES} from '../constants';
>>>>>>> Adding option to switch deployment pipeline
const BN_FACTOR = 10000;
const VOID_ADDRESS = '0x0000000000000000000000000000000000000000';
@ -234,6 +240,13 @@ function theme(state=DARK_THEME, action) {
if (action.type === CHANGE_THEME[REQUEST] || (action.type === FETCH_THEME[SUCCESS] && action.theme)) {
return action.theme;
}
return state
}
function deploymentPipeline(state = DEPLOYMENT_PIPELINES.embark, action) {
if (action.type === UPDATE_DEPLOYMENT_PIPELINE) {
return action.payload;
}
return state;
}
@ -320,6 +333,26 @@ function breakpoints(state = {}, action) {
return state;
}
function web3(state = {deployments: {}, gasEstimates: {}}, action) {
if (action.type === WEB3_CONNECT[SUCCESS]) {
return {...state, instance: action.web3};
} else if (action.type === WEB3_DEPLOY[REQUEST]) {
return {...state, deployments: {...state['deployments'], [action.contract.className]: {running: true, error: null}}};
} else if (action.type === WEB3_DEPLOY[SUCCESS]){
return {...state, deployments: {...state['deployments'], [action.contract.className]: {...action.receipt, running: false, error: null}}};
} else if (action.type === WEB3_DEPLOY[FAILURE]){
return {...state, deployments: {...state['deployments'], [action.contract.className]: {error: action.web3Error, running: false}}};
} else if (action.type === WEB3_ESTIMAGE_GAS[REQUEST]){
return {...state, gasEstimates: {...state['gasEstimates'], [action.contract.className]: {running: true, error: null}}};
} else if (action.type === WEB3_ESTIMAGE_GAS[SUCCESS]){
return {...state, gasEstimates: {...state['gasEstimates'], [action.contract.className]: {gas: action.gas, running: false, error: null}}};
} else if (action.type === WEB3_ESTIMAGE_GAS[FAILURE]){
return {...state, gasEstimates: {...state['gasEstimates'], [action.contract.className]: {error: action.web3Error, running: false}}};
}
return state
}
const rootReducer = combineReducers({
entities,
loading,
@ -332,7 +365,9 @@ const rootReducer = combineReducers({
searchResult,
messageSignature,
messageVerification,
breakpoints
breakpoints,
deploymentPipeline,
web3
});
export default rootReducer;

View File

@ -208,3 +208,19 @@ export function getVerificationError(state) {
export function getBreakpointsByFilename(state, filename) {
return state.breakpoints[filename] || [];
}
export function getDeploymentPipeline(state) {
return state.deploymentPipeline;
}
export function getWeb3(state) {
return state.web3.instance;
}
export function getWeb3GasEstimates(state) {
return state.web3.gasEstimates;
}
export function getWeb3Deployments(state) {
return state.web3.deployments;
}

View File

@ -1,9 +1,11 @@
import * as actions from '../actions';
import * as api from '../services/api';
import * as storage from '../services/storage';
import * as web3Service from '../services/web3';
import {eventChannel} from 'redux-saga';
import {all, call, fork, put, takeLatest, takeEvery, take, select, race} from 'redux-saga/effects';
import {getCredentials} from '../reducers/selectors';
import {getCredentials, getWeb3} from '../reducers/selectors';
import { DEPLOYMENT_PIPELINES } from '../constants';
import {searchExplorer} from './searchSaga';
function *doRequest(entity, serviceFn, payload) {
@ -12,7 +14,29 @@ function *doRequest(entity, serviceFn, payload) {
if(response) {
yield put(entity.success(response.data, payload));
} else if (error) {
yield put(entity.failure(error));
yield put(entity.failure(error.message));
}
}
function *doWeb3Request(entity, serviceFn, payload) {
payload.web3 = yield select(getWeb3);
try {
const result = yield call(serviceFn, payload);
yield put(entity.success(result, payload));
} catch (error) {
yield put(entity.failure(error.message, payload));
}
}
function *web3Connect(action) {
if (action.payload !== DEPLOYMENT_PIPELINES.injectedWeb3) return;
if (yield select(getWeb3)) return;
try {
const web3 = yield call(web3Service.connect);
yield put(actions.web3Connect.success(web3));
} catch(error) {
yield put(actions.web3Connect.failure(error));
}
}
@ -60,6 +84,9 @@ export const verifyMessage = doRequest.bind(null, actions.verifyMessage, api.ver
export const explorerSearch = searchExplorer.bind(null, actions.explorerSearch);
export const web3Deploy = doWeb3Request.bind(null, actions.web3Deploy, web3Service.deploy);
export const web3EstimateGas = doWeb3Request.bind(null, actions.web3EstimateGas, web3Service.estimateGas);
export function *watchFetchTransaction() {
yield takeEvery(actions.TRANSACTION[actions.REQUEST], fetchTransaction);
@ -234,6 +261,18 @@ export function *watchVerifyMessage() {
yield takeEvery(actions.VERIFY_MESSAGE[actions.REQUEST], verifyMessage);
}
export function *watchWeb3Deploy() {
yield takeEvery(actions.WEB3_DEPLOY[actions.REQUEST], web3Deploy);
}
export function *watchWeb3EstimateGas() {
yield takeEvery(actions.WEB3_ESTIMAGE_GAS[actions.REQUEST], web3EstimateGas);
}
export function *watchUpdateDeploymentPipeline() {
yield takeEvery(actions.UPDATE_DEPLOYMENT_PIPELINE, web3Connect);
}
function createChannel(socket) {
return eventChannel(emit => {
socket.onmessage = ((message) => {
@ -405,6 +444,9 @@ export default function *root() {
fork(watchChangeTheme),
fork(watchListenGasOracle),
fork(watchSignMessage),
fork(watchVerifyMessage)
fork(watchVerifyMessage),
fork(watchWeb3EstimateGas),
fork(watchWeb3Deploy),
fork(watchUpdateDeploymentPipeline)
]);
}

View File

@ -0,0 +1,37 @@
import Web3 from 'web3';
export const connect = () => {
return new Promise(async (resolve,reject) => {
if (window.ethereum) {
const web3 = new Web3(window.ethereum);
try {
const accounts = await window.ethereum.enable();
web3.eth.defaultAccount = accounts[0];
resolve(web3);
} catch (error) {
reject(error);
}
} else if (window.web3) {
const web3 = new Web3(window.web3.currentProvider);
resolve(web3);
} else {
reject(Error('Non-Ethereum browser detected. You should use MetaMask!'));
}
});
}
export const estimateGas = ({web3, contract, args}) => {
return new web3.eth.Contract(contract.abiDefinition)
.deploy({data: `0x${contract.code}`, arguments: args})
.estimateGas({from: web3.eth.defaultAccount});
}
export const deploy = ({web3, contract, args}) => {
return new Promise((resolve, reject) => {
new web3.eth.Contract(contract.abiDefinition)
.deploy({data: `0x${contract.code}`, arguments: args})
.send({from: web3.eth.defaultAccount})
.on('error', reject)
.on('receipt', resolve)
});
}

74
npm-shrinkwrap.json generated
View File

@ -1738,7 +1738,7 @@
},
"babel-plugin-istanbul": {
"version": "4.1.6",
"resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz",
"resolved": "http://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz",
"integrity": "sha512-PWP9FQ1AhZhS01T/4qLSKoHGY/xvkZdVBGlKM/HuxxS3+sC66HhTNR7+MpbO/so/cz/wY94MeSWJuP1hXIPfwQ==",
"requires": {
"babel-plugin-syntax-object-rest-spread": "^6.13.0",
@ -1766,37 +1766,37 @@
},
"babel-plugin-syntax-async-functions": {
"version": "6.13.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz",
"resolved": "http://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz",
"integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU="
},
"babel-plugin-syntax-class-properties": {
"version": "6.13.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz",
"resolved": "http://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz",
"integrity": "sha1-1+sjt5oxf4VDlixQW4J8fWysJ94="
},
"babel-plugin-syntax-dynamic-import": {
"version": "6.18.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz",
"resolved": "http://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz",
"integrity": "sha1-jWomIpyDdFqZgqRBBRVyyqF5sdo="
},
"babel-plugin-syntax-exponentiation-operator": {
"version": "6.13.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz",
"resolved": "http://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz",
"integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4="
},
"babel-plugin-syntax-flow": {
"version": "6.18.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz",
"resolved": "http://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz",
"integrity": "sha1-TDqyCiryaqIM0lmVw5jE63AxDI0="
},
"babel-plugin-syntax-jsx": {
"version": "6.18.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz",
"resolved": "http://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz",
"integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY="
},
"babel-plugin-syntax-object-rest-spread": {
"version": "6.13.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz",
"resolved": "http://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz",
"integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U="
},
"babel-plugin-syntax-trailing-function-commas": {
@ -3320,7 +3320,7 @@
},
"get-stream": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
"resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
}
}
@ -3653,7 +3653,7 @@
"dependencies": {
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
},
"parse-json": {
@ -4304,7 +4304,7 @@
},
"dom-converter": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.1.4.tgz",
"resolved": "http://registry.npmjs.org/dom-converter/-/dom-converter-0.1.4.tgz",
"integrity": "sha1-pF71cnuJDJv/5tfIduexnLDhfzs=",
"requires": {
"utila": "~0.3"
@ -4388,7 +4388,7 @@
},
"dotenv": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-4.0.0.tgz",
"resolved": "http://registry.npmjs.org/dotenv/-/dotenv-4.0.0.tgz",
"integrity": "sha1-hk7xN5rO1Vzm+V3r7NzhefegzR0="
},
"dotenv-expand": {
@ -4933,7 +4933,7 @@
},
"load-json-file": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
"resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
"integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=",
"requires": {
"graceful-fs": "^4.1.2",
@ -7321,7 +7321,7 @@
},
"readable-stream": {
"version": "1.0.34",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
"integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
"requires": {
"core-util-is": "~1.0.0",
@ -8071,7 +8071,7 @@
},
"is-obj": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
"resolved": "http://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
"integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8="
},
"is-object": {
@ -8435,7 +8435,7 @@
},
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"requires": {
"ansi-styles": "^2.2.1",
@ -8541,7 +8541,7 @@
},
"os-locale": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
"resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
"integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
"requires": {
"lcid": "^1.0.0"
@ -8621,7 +8621,7 @@
},
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"requires": {
"ansi-styles": "^2.2.1",
@ -8656,7 +8656,7 @@
},
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"requires": {
"ansi-styles": "^2.2.1",
@ -8815,7 +8815,7 @@
},
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"requires": {
"ansi-styles": "^2.2.1",
@ -8848,7 +8848,7 @@
},
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"requires": {
"ansi-styles": "^2.2.1",
@ -8916,7 +8916,7 @@
},
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"requires": {
"ansi-styles": "^2.2.1",
@ -9070,7 +9070,7 @@
},
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"requires": {
"ansi-styles": "^2.2.1",
@ -9139,7 +9139,7 @@
},
"os-locale": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
"resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
"integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
"requires": {
"lcid": "^1.0.0"
@ -9210,7 +9210,7 @@
},
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"requires": {
"ansi-styles": "^2.2.1",
@ -9248,7 +9248,7 @@
},
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"requires": {
"ansi-styles": "^2.2.1",
@ -9283,7 +9283,7 @@
},
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"requires": {
"ansi-styles": "^2.2.1",
@ -10071,7 +10071,7 @@
"dependencies": {
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
}
}
@ -11278,7 +11278,7 @@
},
"got": {
"version": "6.7.1",
"resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz",
"resolved": "http://registry.npmjs.org/got/-/got-6.7.1.tgz",
"integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=",
"requires": {
"create-error-class": "^3.0.0",
@ -12468,7 +12468,7 @@
"dependencies": {
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
}
}
@ -12505,7 +12505,7 @@
},
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"requires": {
"ansi-styles": "^2.2.1",
@ -12669,7 +12669,7 @@
},
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"requires": {
"ansi-styles": "^2.2.1",
@ -12895,7 +12895,7 @@
},
"load-json-file": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
"resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
"integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=",
"requires": {
"graceful-fs": "^4.1.2",
@ -13055,7 +13055,7 @@
},
"yargs": {
"version": "3.10.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
"resolved": "http://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
"integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
"requires": {
"camelcase": "^1.0.2",
@ -13871,7 +13871,7 @@
},
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
}
}
@ -16769,7 +16769,7 @@
},
"os-locale": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
"resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
"integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
"requires": {
"lcid": "^1.0.0"
@ -16782,7 +16782,7 @@
},
"yargs": {
"version": "6.6.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz",
"resolved": "http://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz",
"integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=",
"requires": {
"camelcase": "^3.0.0",