add initial status api

This commit is contained in:
Barry Gitarts 2020-06-29 12:16:28 -04:00
commit 39ed00b915
32 changed files with 2647 additions and 0 deletions

8
.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
.embark
chains.json
config/livenet/password
config/production/password
coverage
dist
embarkArtifacts
node_modules

0
.npmrc Normal file
View File

155
CHANGELOG.md Normal file
View File

@ -0,0 +1,155 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [4.2.0](https://github.com/embark-framework/embark/compare/v4.1.1...v4.2.0) (2019-12-18)
### Build System
* **deps:** bump web3[-*] from 1.2.1 to 1.2.4 ([e7ed552](https://github.com/embark-framework/embark/commit/e7ed552))
### BREAKING CHANGES
* **deps:** bump embark's minimum supported version of geth from
`>=1.8.14` to `>=1.9.0` and its minimum supported version of parity from
`>=2.0.0` to `>=2.2.1`. This is necessary since web3 1.2.4 makes use of the
`eth_chainId` RPC method (EIP 695) and those client versions are the earliest
ones to implement it.
## [4.1.1](https://github.com/embark-framework/embark/compare/v4.1.0...v4.1.1) (2019-08-28)
### Bug Fixes
* **@embark/demo:** add back lights ([dd07f67](https://github.com/embark-framework/embark/commit/dd07f67))
# [4.1.0](https://github.com/embark-framework/embark/compare/v4.1.0-beta.6...v4.1.0) (2019-08-12)
**Note:** Version bump only for package embark-dapp-template-demo
# [4.1.0-beta.6](https://github.com/embark-framework/embark/compare/v4.1.0-beta.5...v4.1.0-beta.6) (2019-08-09)
### Features
* **@embark/pipeline:** add minimalContractSize to remove bytecode ([b0cccae](https://github.com/embark-framework/embark/commit/b0cccae))
* **@embark/pipeline:** enable choosing which fields to filter out ([b5c81bd](https://github.com/embark-framework/embark/commit/b5c81bd))
# [4.1.0-beta.5](https://github.com/embark-framework/embark/compare/v4.1.0-beta.4...v4.1.0-beta.5) (2019-07-10)
### Bug Fixes
* **@embark/embarkjs-whisper:** Messages.isAvailable() should always return a promise ([93ca3ad](https://github.com/embark-framework/embark/commit/93ca3ad))
# [4.1.0-beta.4](https://github.com/embark-framework/embark/compare/v4.1.0-beta.3...v4.1.0-beta.4) (2019-06-27)
### Bug Fixes
* **@dapps/demo:** don't allow subscription to whisper channels with less than 4 chars ([322397f](https://github.com/embark-framework/embark/commit/322397f)), closes [#1666](https://github.com/embark-framework/embark/issues/1666)
* **@dapps/templates/demo:** ensure whisper channel state is set correctly ([1b6987e](https://github.com/embark-framework/embark/commit/1b6987e))
# [4.1.0-beta.3](https://github.com/embark-framework/embark/compare/v4.1.0-beta.2...v4.1.0-beta.3) (2019-06-07)
**Note:** Version bump only for package embark-dapp-template-demo
# [4.1.0-beta.2](https://github.com/embark-framework/embark/compare/v4.1.0-beta.1...v4.1.0-beta.2) (2019-05-22)
**Note:** Version bump only for package embark-dapp-template-demo
# [4.1.0-beta.1](https://github.com/embark-framework/embark/compare/v4.1.0-beta.0...v4.1.0-beta.1) (2019-05-15)
### Bug Fixes
* **@embark/demo:** link css from dependency ([438e917](https://github.com/embark-framework/embark/commit/438e917))
* **@embark/demo:** render whisper error messages not error objects ([925ed06](https://github.com/embark-framework/embark/commit/925ed06))
# [4.1.0-beta.0](https://github.com/embark-framework/embark/compare/v4.0.0...v4.1.0-beta.0) (2019-04-17)
**Note:** Version bump only for package embark-dapp-template-demo
## [4.0.2](https://github.com/embark-framework/embark/compare/v4.0.1...v4.0.2) (2019-04-11)
**Note:** Version bump only for package embark-dapp-template-demo
## [4.0.1](https://github.com/embark-framework/embark/compare/v4.0.0...v4.0.1) (2019-03-26)
**Note:** Version bump only for package embark-dapp-template-demo
# [4.0.0](https://github.com/embark-framework/embark/compare/v4.0.0-beta.2...v4.0.0) (2019-03-18)
**Note:** Version bump only for package embark-dapp-template-demo
# [4.0.0-beta.2](https://github.com/embark-framework/embark/compare/v4.0.0-beta.1...v4.0.0-beta.2) (2019-03-18)
**Note:** Version bump only for package embark-dapp-template-demo
# [4.0.0-beta.1](https://github.com/embark-framework/embark/compare/v4.0.0-beta.0...v4.0.0-beta.1) (2019-03-18)
### Features
* add repository.directory field to package.json ([a9c5e1a](https://github.com/embark-framework/embark/commit/a9c5e1a))
* **@embark/pipeline:** Add `enabled` property to pipeline config ([5ea4807](https://github.com/embark-framework/embark/commit/5ea4807))
* normalize README and package.json bugs, homepage, description ([5418f16](https://github.com/embark-framework/embark/commit/5418f16))

22
LICENSE Normal file
View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 iuri matias
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

7
README.md Normal file
View File

@ -0,0 +1,7 @@
# `embark-dapp-template-demo`
> Demo DApp for Embark
Visit [embark.status.im](https://embark.status.im/) to get started with
[Embark](https://github.com/embark-framework/embark).
# status-api-tester

View File

@ -0,0 +1,88 @@
import EmbarkJS from 'Embark/EmbarkJS';
import SimpleStorage from '../../embarkArtifacts/contracts/SimpleStorage';
import React from 'react';
import {Form, FormGroup, Input, HelpBlock, Button, FormText} from 'reactstrap';
class Blockchain extends React.Component {
constructor(props) {
super(props);
this.state = {
valueSet: 10,
valueGet: "",
logs: []
};
}
handleChange(e) {
this.setState({ valueSet: e.target.value });
}
checkEnter(e, func) {
if (e.key !== 'Enter') {
return;
}
e.preventDefault();
func.apply(this, [e]);
}
async setValue(e) {
e.preventDefault();
await EmbarkJS.enableEthereum();
var value = parseInt(this.state.valueSet, 10);
SimpleStorage.methods.set(value).send();
this._addToLog("SimpleStorage.methods.set(value).send()");
}
getValue(e) {
e.preventDefault();
SimpleStorage.methods.get().call().then(_value => this.setState({ valueGet: _value }));
this._addToLog("SimpleStorage.methods.get(console.log)");
}
_addToLog(txt) {
this.state.logs.push(txt);
this.setState({ logs: this.state.logs });
}
render() {
return (<React.Fragment>
<h3> 1. Set the value in the blockchain</h3>
<Form onKeyDown={(e) => this.checkEnter(e, this.setValue)}>
<FormGroup className="inline-input-btn">
<Input
type="text"
defaultValue={this.state.valueSet}
onChange={(e) => this.handleChange(e)}/>
<Button color="primary" onClick={(e) => this.setValue(e)}>Set Value</Button>
<FormText color="muted">Once you set the value, the transaction will need to be mined and then the value will be updated
on the blockchain.</FormText>
</FormGroup>
</Form>
<h3> 2. Get the current value</h3>
<Form>
<FormGroup>
<Button color="primary" onClick={(e) => this.getValue(e)}>Get Value</Button>
<FormText color="muted">Click the button to get the current value. The initial value is 100.</FormText>
{this.state.valueGet && this.state.valueGet !== 0 &&
<p>Current value is <span className="value font-weight-bold">{this.state.valueGet}</span></p>}
</FormGroup>
</Form>
<h3> 3. Contract Calls </h3>
<p>Javascript calls being made: </p>
<div className="logs">
{
this.state.logs.map((item, i) => <p key={i}>{item}</p>)
}
</div>
</React.Fragment>
);
}
}
export default Blockchain;

179
app/components/ens.js Normal file
View File

@ -0,0 +1,179 @@
/*global web3*/
import EmbarkJS from 'Embark/EmbarkJS';
import React from 'react';
import { Alert, Form, FormGroup, Input, Button } from 'reactstrap';
class ENS extends React.Component {
constructor(props) {
super(props);
this.state = {
valueResolve: 'eth',
responseResolve: null,
isResolveError: false,
valueLookup: '',
responseLookup: null,
isLookupError: false,
valueRegister: '',
addressRegister: '',
responseRegister: null,
isRegisterError: false,
embarkLogs: []
};
}
componentDidMount() {
EmbarkJS.onReady(() => {
if (!web3.eth.defaultAccount) {
this.setState({
globalError: 'There is currently no default account. If Metamask is active, please sign in or deactivate it.'
});
}
this.setState({
addressRegister: web3.eth.defaultAccount,
valueLookup: web3.eth.defaultAccount
});
});
}
handleChange(stateName, e) {
this.setState({ [stateName]: e.target.value });
}
checkEnter(e, func) {
if (e.key !== 'Enter') {
return;
}
e.preventDefault();
func.apply(this, [e]);
}
registerSubDomain(e) {
e.preventDefault();
const self = this;
const embarkLogs = this.state.embarkLogs;
embarkLogs.push(`EmbarkJS.Names.registerSubDomain('${this.state.valueRegister}', '${this.state.addressRegister}', console.log)`);
this.setState({
embarkLogs: embarkLogs
});
EmbarkJS.Names.registerSubDomain(this.state.valueRegister, this.state.addressRegister, (err, transaction) => {
const message = err ? err : `Successfully registered "${this.state.valueRegister}" with ${transaction.gasUsed} gas`;
self.setState({
responseRegister: message,
isRegisterError: !!err
});
});
}
resolveName(e) {
e.preventDefault();
const embarkLogs = this.state.embarkLogs;
embarkLogs.push(`EmbarkJS.Names.resolve('${this.state.valueResolve}', console.log)`);
this.setState({
embarkLogs: embarkLogs
});
EmbarkJS.Names.resolve(this.state.valueResolve, (err, result) => {
if (err) {
return this.setState({
responseResolve: err.message || err,
isResolveError: true
});
}
this.setState({
responseResolve: result,
isResolveError: false
});
});
}
lookupAddress(e) {
e.preventDefault();
const embarkLogs = this.state.embarkLogs;
embarkLogs.push(`EmbarkJS.Names.resolve('${this.state.valueLookup}', console.log)`);
this.setState({
embarkLogs: embarkLogs
});
EmbarkJS.Names.lookup(this.state.valueLookup, (err, result) => {
if (err) {
return this.setState({
responseLookup: err.message || err,
isLookupError: true
});
}
this.setState({
responseLookup: result,
isLookupError: false
});
});
}
render() {
return (<React.Fragment>
{this.state.globalError && <Alert color="danger">{this.state.globalError}</Alert>}
<h3>Resolve a name</h3>
<Form onKeyDown={(e) => this.checkEnter(e, this.resolveName)}>
<FormGroup className="inline-input-btn">
{this.state.responseResolve &&
<Alert className="alert-result" color={this.state.isResolveError ? 'danger' : 'success'}>
Resolved address: <span className="value">{this.state.responseResolve}</span>
</Alert>}
<Input
type="text"
defaultValue={this.state.valueResolve}
onChange={(e) => this.handleChange('valueResolve', e)}/>
<Button color="primary" onClick={(e) => this.resolveName(e)}>Resolve name</Button>
</FormGroup>
</Form>
<h3>Lookup an address</h3>
<Form onKeyDown={(e) => this.checkEnter(e, this.lookupAddress)}>
<FormGroup className="inline-input-btn">
{this.state.responseLookup &&
<Alert className="alert-result" color={this.state.isLookupError ? 'danger' : 'success'}>
Looked up domain: <span className="value">{this.state.responseLookup}</span>
</Alert>}
<Input
type="text"
defaultValue={this.state.valueLookup}
onChange={(e) => this.handleChange('valueLookup', e)}/>
<Button color="primary" onClick={(e) => this.lookupAddress(e)}>Lookup address</Button>
</FormGroup>
</Form>
<h3>Register subdomain</h3>
<Form onKeyDown={(e) => this.checkEnter(e, this.registerSubDomain)}>
<FormGroup>
{this.state.responseRegister &&
<Alert className="alert-result" color={this.state.isRegisterError ? 'danger' : 'success'}>
<span className="value">{this.state.responseRegister}</span>
</Alert>}
<Input
defaultValue={this.state.valueRegister} className="small-input float-left"
onChange={(e) => this.handleChange('valueRegister', e)}/>
<div className="inline-input-btn m-0">
<Input
type="text"
defaultValue={this.state.addressRegister}
onChange={(e) => this.handleChange('addressRegister', e)}/>
<Button color="primary" onClick={(e) => this.registerSubDomain(e)}>Register subdomain</Button>
</div>
</FormGroup>
</Form>
<h3>Embark Calls </h3>
<p>Javascript calls being made: </p>
<div className="logs">
{
this.state.embarkLogs.map((item, i) => <p key={i}>{item}</p>)
}
</div>
</React.Fragment>
);
}
}
export default ENS;

92
app/components/status.js Normal file
View File

@ -0,0 +1,92 @@
import React, { Fragment, useState, useEffect } from 'react';
import { Button } from 'reactstrap';
import { Formik, Form, Field, ErrorMessage } from 'formik';
async function sendToPublicChat(topic, message) {
try {
const res = await window.ethereum.status.sendToPublicChat(topic, message)
return res
} catch (e) {
console.error('send to public chat', {e})
}
}
const SendMessage = () => (
<div>
<h2>Send to public chat</h2>
<Formik
initialValues={{ topic: 'test-room', message: 'test message' }}
onSubmit={async (values, { setSubmitting }) => {
const { topic, message } = values;
const res = sendToPublicChat(topic, message)
console.log({res})
}}
>
{({ isSubmitting }) => (
<Form>
<Field type="text" name="topic" />
<ErrorMessage name="topic" component="div" />
<Field type="text" name="message" />
<ErrorMessage name="message" component="div" />
<Button type="submit" disabled={isSubmitting}>
Send
</Button>
</Form>
)}
</Formik>
</div>
);
function StatusApi() {
const [account, setAccount] = useState()
const [isStatus, setIsStatus] = useState(false)
const [contactCode, setContactCode] = useState()
useEffect(() => {
setIsStatus(!!window.ethereum.isStatus)
}, [account])
async function enableEthereum() {
try {
const res = await window.ethereum.enable()
const account = res[0]
setAccount(account)
} catch (e) {
console.error('Enable Ethereum :', {e})
}
}
async function getContactCode() {
try {
const code = await window.ethereum.status.getContactCode()
setContactCode(code)
} catch (e) {
console.error('Contct code :', {e})
}
}
async function sendToPublicChat(topic = 'testroom', message = 'test') {
try {
const res = await window.ethereum.status.sendToPublicChat('testroom', 'testing')
console.log({res})
} catch (e) {
console.error('send to public chat', {e})
}
}
return (
<Fragment>
<div>{isStatus ? 'Status API Detected' : 'Status API not found'}</div>
<h3>Enable ethereum</h3>
<Button onClick={enableEthereum}>Enable ethereum</Button>
{account && <div>{account}</div>}
<h3>Get contact code</h3>
<Button onClick={getContactCode}>Get Contact Code</Button>
{contactCode && <div>{contactCode}</div>}
<SendMessage />
</Fragment>
)
}
export default StatusApi;

273
app/components/storage.js Normal file
View File

@ -0,0 +1,273 @@
import EmbarkJS from 'Embark/EmbarkJS';
import React, {Fragment} from 'react';
import {Alert, Form, FormGroup, Input, FormText, Button} from 'reactstrap';
class Storage extends React.Component {
constructor(props) {
super(props);
this.state = {
textToSave: 'hello world!',
generatedHash: '',
loadText: '',
storedText: '',
fileToUpload: null,
fileHash: '',
imageToDownload: '',
url: '',
logs: [],
storageError: '',
valueRegister: '',
valueResolver: ''
};
}
handleChange(e, name) {
this.state[name] = e.target.value;
this.setState(this.state);
}
checkEnter(e, func) {
if (e.key !== 'Enter') {
return;
}
e.preventDefault();
func.apply(this, [e]);
}
handleFileUpload(e) {
this.setState({fileToUpload: [e.target]});
}
addToLog(txt) {
this.state.logs.push(txt);
this.setState({logs: this.state.logs});
}
setText(e) {
e.preventDefault();
EmbarkJS.Storage.saveText(this.state.textToSave)
.then((hash) => {
this.setState({
generatedHash: hash,
loadText: hash,
storageError: ''
});
this.addToLog("EmbarkJS.Storage.saveText('" + this.state.textToSave + "').then(function(hash) { })");
})
.catch((err) => {
if (err) {
this.setState({storageError: err.message});
console.log("Storage saveText Error => " + err.message);
}
});
}
loadHash(e) {
e.preventDefault();
EmbarkJS.Storage.get(this.state.loadText)
.then((content) => {
this.setState({storedText: content, storageError: ''});
this.addToLog("EmbarkJS.Storage.get('" + this.state.loadText + "').then(function(content) { })");
})
.catch((err) => {
if (err) {
this.setState({storageError: err.message});
console.log("Storage get Error => " + err.message);
}
});
}
uploadFile(e) {
e.preventDefault();
EmbarkJS.Storage.uploadFile(this.state.fileToUpload)
.then((hash) => {
this.setState({
fileHash: hash,
imageToDownload: hash,
storageError: ''
});
this.addToLog("EmbarkJS.Storage.uploadFile(this.state.fileToUpload).then(function(hash) { })");
})
.catch((err) => {
if (err) {
this.setState({storageError: err.message});
console.log("Storage uploadFile Error => " + err.message);
}
});
}
loadFile(_e) {
let _url = EmbarkJS.Storage.getUrl(this.state.imageToDownload);
this.setState({url: _url});
this.addToLog("EmbarkJS.Storage.getUrl('" + this.state.imageToDownload + "')");
}
ipnsRegister(e) {
e.preventDefault();
this.setState({ registering: true, responseRegister: false });
this.addToLog("EmbarkJS.Storage.register(this.state.ipfsHash).then(function(hash) { })");
EmbarkJS.Storage.register(this.state.valueRegister, (err, name) => {
let responseRegister;
let isRegisterError = false;
if (err) {
isRegisterError = true;
responseRegister = "Name Register Error: " + (err.message || err);
} else {
responseRegister = name;
}
this.setState({
registering: false,
responseRegister,
isRegisterError
});
});
}
ipnsResolve(e) {
e.preventDefault();
this.setState({ resolving: true, responseResolver: false });
this.addToLog("EmbarkJS.Storage.resolve(this.state.ipnsName, function(err, path) { })");
EmbarkJS.Storage.resolve(this.state.valueResolver, (err, path) => {
let responseResolver;
let isResolverError = false;
if (err) {
isResolverError = true;
responseResolver = "Name Resolve Error: " + (err.message || err);
} else {
responseResolver = path;
}
this.setState({
resolving: false,
responseResolver,
isResolverError
});
});
}
isIpfs(){
return EmbarkJS.Storage.currentProviderName === 'ipfs';
}
render() {
return <React.Fragment>
{!this.props.enabled &&
<React.Fragment>
<Alert color="warning">The node you are using does not support IPFS. If
you haven't explicitly disabled IPFS in <code>config/storage.js</code> then
please ensure <a href="https://github.com/ipfs/js-ipfs-api#cors"
target="_blank">CORS</a> is setup for the IPFS node.</Alert>
</React.Fragment>}
{this.state.storageError !== '' &&
<Alert color="danger">{this.state.storageError}</Alert>}
<h3>Save text to storage</h3>
<Form onKeyDown={(e) => this.checkEnter(e, this.setText)}>
<FormGroup className="inline-input-btn">
<Input
type="text"
defaultValue={this.state.textToSave}
onChange={e => this.handleChange(e, 'textToSave')}/>
<Button color="primary" onClick={(e) => this.setText(e)}>Save Text</Button>
{this.state.generatedHash && <FormText>Generated Hash: <span className="textHash font-weight-bold">{this.state.generatedHash}</span></FormText>}
</FormGroup>
</Form>
<h3>Load text from storage given an hash</h3>
<Form onKeyDown={(e) => this.checkEnter(e, this.loadHash)}>
<FormGroup className="inline-input-btn">
<Input
type="text"
value={this.state.loadText}
onChange={e => this.handleChange(e, 'loadText')}/>
<Button color="primary" onClick={(e) => this.loadHash(e)}>Load</Button>
{this.state.storedText && <FormText>Result: <span className="textHash font-weight-bold">{this.state.storedText}</span></FormText>}
</FormGroup>
</Form>
<h3>Upload file to storage</h3>
<Form>
<FormGroup>
<Input
type="file"
onChange={(e) => this.handleFileUpload(e)}/>
<Button color="primary" onClick={(e) => this.uploadFile(e)} className="mt-2">Upload</Button>
{this.state.fileHash && <FormText>Generated hash: <span className="fileHash">{this.state.fileHash}</span></FormText>}
</FormGroup>
</Form>
<h3>Get file or image from storage</h3>
<Form onKeyDown={(e) => this.checkEnter(e, this.loadFile)}>
<FormGroup className="inline-input-btn">
<Input
type="text"
value={this.state.imageToDownload}
onChange={e => this.handleChange(e, 'imageToDownload')}/>
<Button color="primary" onClick={(e) => this.loadFile(e)}>Download</Button>
{this.state.url && <Fragment>
<FormText>
File available at: <span><a href={this.state.url} target="_blank">{this.state.url}</a></span>
</FormText>
<FormText><img alt="file image" src={this.state.url}/></FormText>
</Fragment>}
</FormGroup>
</Form>
{!this.isIpfs() && <Alert color="warning">The 2 functions below are only available with IPFS</Alert>}
<h3>Register to IPNS</h3>
<Form onKeyDown={(e) => this.checkEnter(e, this.ipnsRegister)}>
<FormGroup className="inline-input-btn">
<Input
type="text"
value={this.state.valueRegister}
onChange={e => this.handleChange(e, 'valueRegister')}/>
<Button color="primary" onClick={(e) => this.ipnsRegister(e)}>
{this.state.registering ? 'Registering...' : 'Register' }
</Button>
<FormText>It will take around 1 minute</FormText>
{this.state.responseRegister &&
<Alert className="alert-result" color={this.state.isRegisterError ? 'danger' : 'success'}>
<span className="value">{this.state.responseRegister}</span>
</Alert>}
</FormGroup>
</Form>
<h3>Resolve name</h3>
<Form onKeyDown={(e) => this.checkEnter(e, this.ipnsResolve)}>
<FormGroup className="inline-input-btn">
<Input
type="text"
value={this.state.valueResolver}
onChange={e => this.handleChange(e, 'valueResolver')}/>
<Button color="primary" onClick={(e) => this.ipnsResolve(e)}>
{this.state.resolving ? 'Resolving...' : 'Resolve' }
</Button>
<FormText>It will take around 1 minute</FormText>
{this.state.responseResolver &&
<Alert className="alert-result" color={this.state.isResolverError ? 'danger' : 'success'}>
<span className="value">{this.state.responseResolver}</span>
</Alert>}
</FormGroup>
</Form>
<p>Javascript calls being made: </p>
<div className="logs">
<p>EmbarkJS.Storage.setProvider('ipfs',{'{'}server: 'localhost', port: '5001'{'}'})</p>
{
this.state.logs.map((item, i) => <p key={i}>{item}</p>)
}
</div>
</React.Fragment>;
}
}
export default Storage;

140
app/components/whisper.js Normal file
View File

@ -0,0 +1,140 @@
import EmbarkJS from 'Embark/EmbarkJS';
import React from 'react';
import {Alert, Form, FormGroup, Input, Button, FormText} from 'reactstrap';
class Whisper extends React.Component {
constructor (props) {
super(props);
this.state = {
listenTo: '',
channel: '',
message: '',
subscribedChannels: [],
channelIsValid: false,
listenToChannelIsValid: false,
messageList: [],
logs: []
};
}
handleChange (e, name) {
this.state[name] = e.target.value;
if (name === 'listenTo') {
this.state.listenToChannelIsValid = this.isChannelValid(e.target.value);
} else if (name === "channel") {
this.state.channelIsValid = this.isChannelValid(e.target.value);
}
this.setState(this.state);
}
checkEnter(e, func) {
if (e.key !== 'Enter') {
return;
}
e.preventDefault();
func.apply(this, [e]);
}
sendMessage (e) {
e.preventDefault();
EmbarkJS.Messages.sendMessage({topic: this.state.channel, data: this.state.message});
this.addToLog("EmbarkJS.Messages.sendMessage({topic: '" + this.state.channel + "', data: '" + this.state.message + "'})");
}
listenToChannel (e) {
e.preventDefault();
const subscribedChannels = this.state.subscribedChannels;
subscribedChannels.push(this.state.listenTo);
this.setState({
subscribedChannels
});
const messageList = this.state.messageList;
EmbarkJS.Messages.listenTo({topic: [this.state.listenTo]}).subscribe(
message => {
messageList.push(<span>Channel: <b>{message.topic}</b> | Message: <b>{message.data}</b></span>);
this.setState({messageList});
},
error => {
messageList.push(<span className="alert-danger">Error: {error.message || "Unknown Error"}</span>);
this.setState({messageList});
}
);
this.addToLog("EmbarkJS.Messages.listenTo({topic: ['" + this.state.listenTo + "']}).then(function(message) {})");
}
addToLog (txt) {
this.state.logs.push(txt);
this.setState({logs: this.state.logs});
}
isChannelValid(name) {
return name.length >= 4;
}
render () {
return (
<React.Fragment>
{
!this.props.enabled &&
<React.Fragment>
<Alert color="warning">The node you are using does not support Whisper</Alert>
<Alert color="warning">The node uses an unsupported version of Whisper</Alert>
</React.Fragment>}
<h3>Listen To channel</h3>
<Form onKeyDown={(e) => this.checkEnter(e, this.listenToChannel)}>
<FormGroup className="inline-input-btn">
<Input
type="text"
defaultValue={this.state.listenTo}
placeholder="channel"
onChange={e => this.handleChange(e, 'listenTo')}/>
<Button disabled={!this.state.listenToChannelIsValid} color="primary" onClick={(e) => this.listenToChannel(e)}>Start Listening</Button>
{!this.state.listenToChannelIsValid && <FormText color="danger">Channel has to be at least 4 characters long</FormText>}
<div id="subscribeList">
{this.state.subscribedChannels.map((item, i) => <p key={i}><span>Subscribed to <b>{item}</b>. Now try sending a message</span></p>)}
</div>
<h5>Messages received:</h5>
<div id="messagesList">
{this.state.messageList.map((item, i) => <p key={i}>{item}</p>)}
</div>
</FormGroup>
</Form>
<h3>Send Message</h3>
<Form inline onKeyDown={(e) => this.checkEnter(e, this.sendMessage)}>
<FormGroup>
<Input
type="text"
defaultValue={this.state.channel}
placeholder="channel"
onChange={e => this.handleChange(e, 'channel')}/>
<div className="inline-input-btn m-0">
<Input
type="text"
defaultValue={this.state.message}
placeholder="message"
onChange={e => this.handleChange(e, 'message')}/>
<Button color="primary" disabled={!this.state.channelIsValid} onClick={(e) => this.sendMessage(e)}>Send
Message</Button>
</div>
</FormGroup>
</Form>
<p>Javascript calls being made: </p>
<div className="logs">
<p>EmbarkJS.Messages.setProvider('whisper')</p>
{
this.state.logs.map((item, i) => <p key={i}>{item}</p>)
}
</div>
</React.Fragment>
);
}
}
export default Whisper;

72
app/dapp.css Normal file
View File

@ -0,0 +1,72 @@
div {
margin: 15px;
}
.logs {
background-color: black;
font-size: 14px;
color: white;
font-weight: bold;
padding: 10px;
border-radius: 8px;
}
.tab-content {
border-left: 1px solid #ddd;
border-right: 1px solid #ddd;
border-bottom: 1px solid #ddd;
padding: 10px;
margin: 0px;
}
.nav-tabs {
margin-bottom: 0;
}
.status-offline {
display: inline-block;
vertical-align: middle;
margin-left: 5px;
width: 12px;
height: 12px;
background: red;
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
border-radius: 10px;
}
.status-online {
display: inline-block;
vertical-align: middle;
margin-left: 5px;
width: 12px;
height: 12px;
background: mediumseagreen;
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
border-radius: 10px;
}
input.form-control {
margin-right: 5px;
}
.alert-result {
margin-left: 0;
}
.small-input {
width: 200px;
}
.inline-input-btn .form-control {
margin: 0;
width: 200px;
border-radius: 0.25rem 0 0 0.25rem;
float: left;
border-right: 0;
}
.inline-input-btn .btn {
border-radius: 0 0.25rem 0.25rem 0;
}

122
app/dapp.js Normal file
View File

@ -0,0 +1,122 @@
import React from 'react';
import ReactDOM from 'react-dom';
import {TabContent, TabPane, Nav, NavItem, NavLink} from 'reactstrap';
import classnames from 'classnames';
import EmbarkJS from 'Embark/EmbarkJS';
import Blockchain from './components/blockchain';
import Whisper from './components/whisper';
import Storage from './components/storage';
import ENS from './components/ens';
import StatusApi from './components/status';
import 'bootstrap/dist/css/bootstrap.css';
import './dapp.css';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
error: null,
activeKey: '5',
whisperEnabled: false,
storageEnabled: false,
blockchainEnabled: false
};
}
componentDidMount() {
EmbarkJS.onReady((err) => {
this.setState({blockchainEnabled: true});
if (err) {
// If err is not null then it means something went wrong connecting to ethereum
// you can use this to ask the user to enable metamask for e.g
return this.setState({error: err.message || err});
}
EmbarkJS.Messages.isAvailable().then(result => {
this.setState({whisperEnabled: result});
});
EmbarkJS.Storage.isAvailable().then((result) => {
this.setState({storageEnabled: result});
}).catch(() => {
this.setState({storageEnabled: false});
});
});
}
_renderStatus(title, available) {
let className = available ? 'pull-right status-online' : 'pull-right status-offline';
return <React.Fragment>
{title}
<span className={className}/>
</React.Fragment>;
}
handleSelect(key) {
this.setState({activeKey: key});
}
render() {
const ensEnabled = EmbarkJS.Names.currentNameSystems && EmbarkJS.Names.isAvailable();
const statusAvaliable = !!window.ethereum && !!window.ethereum.status
if (this.state.error) {
return (<div>
<div>Something went wrong connecting to ethereum. Please make sure you have a node running or are using metamask
to connect to the ethereum network:
</div>
<div>{this.state.error}</div>
</div>);
}
return (<div>
<Nav tabs>
<NavItem>
<NavLink onClick={() => this.handleSelect('5')} className={classnames({ active: this.state.activeKey === '5' })}>
{this._renderStatus('Status Api', statusAvaliable)}
</NavLink>
</NavItem>
<NavItem>
<NavLink onClick={() => this.handleSelect('1')} className={classnames({ active: this.state.activeKey === '1' })}>
{this._renderStatus('Blockchain', this.state.blockchainEnabled)}
</NavLink>
</NavItem>
<NavItem>
<NavLink onClick={() => this.handleSelect('2')} className={classnames({ active: this.state.activeKey === '2' })}>
{this._renderStatus('Decentralized Storage', this.state.storageEnabled)}
</NavLink>
</NavItem>
<NavItem>
<NavLink onClick={() => this.handleSelect('3')} className={classnames({ active: this.state.activeKey === '3' })}>
{this._renderStatus('P2P communication (Whisper)', this.state.whisperEnabled)}
</NavLink>
</NavItem>
<NavItem>
<NavLink onClick={() => this.handleSelect('4')} className={classnames({ active: this.state.activeKey === '4' })}>
{this._renderStatus('Naming (ENS)', ensEnabled)}
</NavLink>
</NavItem>
</Nav>
<TabContent activeTab={this.state.activeKey}>
<TabPane tabId="5">
<StatusApi />
</TabPane>
<TabPane tabId="1">
<Blockchain/>
</TabPane>
<TabPane tabId="2">
<Storage enabled={this.state.storageEnabled}/>
</TabPane>
<TabPane tabId="3">
<Whisper enabled={this.state.whisperEnabled}/>
</TabPane>
<TabPane tabId="4">
<ENS enabled={ensEnabled}/>
</TabPane>
</TabContent>
</div>);
}
}
ReactDOM.render(<App/>, document.getElementById('app'));

0
app/images/.gitkeep Normal file
View File

11
app/index.html Normal file
View File

@ -0,0 +1,11 @@
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Status Api Testing</title>
</head>
<body class="container">
<div id="app">
</div>
<script src="js/dapp.js"></script>
</body>
</html>

150
config/blockchain.js Normal file
View File

@ -0,0 +1,150 @@
module.exports = {
// applies to all environments
default: {
enabled: true,
rpcHost: "localhost", // HTTP-RPC server listening interface (default: "localhost")
rpcPort: 8545, // HTTP-RPC server listening port (default: 8545)
rpcCorsDomain: { // Domains from which to accept cross origin requests (browser enforced). This can also be a comma separated list
auto: true, // When "auto" is true, Embark will automatically set the cors to the address of the webserver
additionalCors: [] // Additional CORS domains to add to the list. If "auto" is false, only those will be added
},
wsRPC: true, // Enable the WS-RPC server
wsOrigins: { // Same thing as "rpcCorsDomain", but for WS origins
auto: true,
additionalCors: []
},
wsHost: "localhost", // WS-RPC server listening interface (default: "localhost")
wsPort: 8546 // WS-RPC server listening port (default: 8546)
// Accounts to use as node accounts
// The order here corresponds to the order of `web3.eth.getAccounts`, so the first one is the `defaultAccount`
/*,accounts: [
{
nodeAccounts: true, // Accounts use for the node
numAddresses: "1", // Number of addresses/accounts (defaults to 1)
password: "config/development/devpassword" // Password file for the accounts
},
// Below are additional accounts that will count as `nodeAccounts` in the `deployment` section of your contract config
// Those will not be unlocked in the node itself
{
privateKey: "your_private_key"
},
{
privateKeyFile: "path/to/file", // Either a keystore or a list of keys, separated by , or ;
password: "passwordForTheKeystore" // Needed to decrypt the keystore file
},
{
mnemonic: "12 word mnemonic",
addressIndex: "0", // Optional. The index to start getting the address
numAddresses: "1", // Optional. The number of addresses to get
hdpath: "m/44'/60'/0'/0/" // Optional. HD derivation path
}
]*/
},
// default environment, merges with the settings in default
// assumed to be the intended environment by `embark run` and `embark blockchain`
development: {
ethereumClientName: "geth", // Can be geth or parity (default:geth)
//ethereumClientBin: "geth", // path to the client binary. Useful if it is not in the global PATH
networkType: "custom", // Can be: testnet, rinkeby, livenet or custom, in which case, it will use the specified networkId
networkId: 1337, // Network id used when networkType is custom
isDev: true, // Uses and ephemeral proof-of-authority network with a pre-funded developer account, mining enabled
datadir: ".embark/development/datadir", // Data directory for the databases and keystore (Geth 1.8.15 and Parity 2.0.4 can use the same base folder, till now they does not conflict with each other)
mineWhenNeeded: true, // Uses our custom script (if isDev is false) to mine only when needed
nodiscover: true, // Disables the peer discovery mechanism (manual peer addition)
maxpeers: 0, // Maximum number of network peers (network disabled if set to 0) (default: 25)
proxy: true, // Proxy is used to present meaningful information about transactions
targetGasLimit: 8000000, // Target gas limit sets the artificial target gas floor for the blocks to mine
simulatorBlocktime: 0 // Specify blockTime in seconds for automatic mining. Default is 0 and no auto-mining.
},
// merges with the settings in default
// used with "embark run privatenet" and/or "embark blockchain privatenet"
privatenet: {
networkType: "custom",
networkId: 1337,
isDev: false,
datadir: ".embark/privatenet/datadir",
// -- mineWhenNeeded --
// This options is only valid when isDev is false.
// Enabling this option uses our custom script to mine only when needed.
// Embark creates a development account for you (using `geth account new`) and funds the account. This account can be used for
// development (and even imported in to MetaMask). To enable correct usage, a password for this account must be specified
// in the `account > password` setting below.
// NOTE: once `mineWhenNeeded` is enabled, you must run an `embark reset` on your dApp before running
// `embark blockchain` or `embark run` for the first time.
mineWhenNeeded: true,
// -- genesisBlock --
// This option is only valid when mineWhenNeeded is true (which is only valid if isDev is false).
// When enabled, geth uses POW to mine transactions as it would normally, instead of using POA as it does in --dev mode.
// On the first `embark blockchain or embark run` after this option is enabled, geth will create a new chain with a
// genesis block, which can be configured using the `genesisBlock` configuration option below.
genesisBlock: "config/privatenet/genesis.json", // Genesis block to initiate on first creation of a development node
nodiscover: true,
maxpeers: 0,
proxy: true,
accounts: [
{
nodeAccounts: true,
password: "config/privatenet/password" // Password to unlock the account
}
],
targetGasLimit: 8000000,
simulatorBlocktime: 0
},
privateparitynet: {
ethereumClientName: "parity",
networkType: "custom",
networkId: 1337,
isDev: false,
genesisBlock: "config/privatenet/genesis-parity.json", // Genesis block to initiate on first creation of a development node
datadir: ".embark/privatenet/datadir",
mineWhenNeeded: false,
nodiscover: true,
maxpeers: 0,
proxy: true,
accounts: [
{
nodeAccounts: true,
password: "config/privatenet/password"
}
],
targetGasLimit: 8000000,
simulatorBlocktime: 0
},
// merges with the settings in default
// used with "embark run testnet" and/or "embark blockchain testnet"
testnet: {
networkType: "testnet",
syncMode: "light",
accounts: [
{
nodeAccounts: true,
password: "config/testnet/password"
}
]
},
// merges with the settings in default
// used with "embark run livenet" and/or "embark blockchain livenet"
livenet: {
networkType: "livenet",
syncMode: "light",
rpcCorsDomain: "http://localhost:8000",
wsOrigins: "http://localhost:8000",
accounts: [
{
nodeAccounts: true,
password: "config/livenet/password"
}
]
}
// you can name an environment with specific settings and then specify with
// "embark run custom_name" or "embark blockchain custom_name"
//custom_name: {
//}
};

46
config/communication.js Normal file
View File

@ -0,0 +1,46 @@
module.exports = {
// default applies to all environments
default: {
enabled: true,
provider: "whisper", // Communication provider. Currently, Embark only supports whisper
available_providers: ["whisper"], // Array of available providers
},
// default environment, merges with the settings in default
// assumed to be the intended environment by `embark run`
development: {
connection: {
host: "localhost", // Host of the blockchain node
port: 8546, // Port of the blockchain node
type: "ws" // Type of connection (ws or rpc)
}
},
// merges with the settings in default
// used with "embark run privatenet"
privatenet: {
},
// merges with the settings in default
// used with "embark run testnet"
testnet: {
},
// merges with the settings in default
// used with "embark run livenet"
livenet: {
},
// you can name an environment with specific settings and then specify with
// "embark run custom_name"
//custom_name: {
//}
// Use this section when you need a specific symmetric or private keys in whisper
/*
,keys: {
symmetricKey: "your_symmetric_key",// Symmetric key for message decryption
privateKey: "your_private_key" // Private Key to be used as a signing key and for message decryption
}
*/
};

96
config/contracts.js Normal file
View File

@ -0,0 +1,96 @@
module.exports = {
// default applies to all environments
default: {
// Blockchain node to deploy the contracts
deployment: {
host: "localhost", // Host of the blockchain node
port: 8546, // Port of the blockchain node
type: "ws" // Type of connection (ws or rpc),
// Accounts to use instead of the default account to populate your wallet
// The order here corresponds to the order of `web3.eth.getAccounts`, so the first one is the `defaultAccount`
/*,accounts: [
{
privateKey: "your_private_key",
balance: "5 ether" // You can set the balance of the account in the dev environment
// Balances are in Wei, but you can specify the unit with its name
},
{
privateKeyFile: "path/to/file", // Either a keystore or a list of keys, separated by , or ;
password: "passwordForTheKeystore" // Needed to decrypt the keystore file
},
{
mnemonic: "12 word mnemonic",
addressIndex: "0", // Optional. The index to start getting the address
numAddresses: "1", // Optional. The number of addresses to get
hdpath: "m/44'/60'/0'/0/" // Optional. HD derivation path
},
{
"nodeAccounts": true // Uses the Ethereum node's accounts
}
]*/
},
// order of connections the dapp should connect to
dappConnection: [
"$WEB3", // uses pre existing web3 object if available (e.g in Mist)
"ws://localhost:8546",
"http://localhost:8545"
],
// Automatically call `ethereum.enable` if true.
// If false, the following code must run before sending any transaction: `await EmbarkJS.enableEthereum();`
// Default value is true.
// dappAutoEnable: true,
gas: "auto",
// Strategy for the deployment of the contracts:
// - implicit will try to deploy all the contracts located inside the contracts directory
// or the directory configured for the location of the contracts. This is default one
// when not specified
// - explicit will only attempt to deploy the contracts that are explicitly specified inside the
// contracts section.
//strategy: 'implicit',
// minimalContractSize, when set to true, tells Embark to generate contract files without the heavy bytecodes
// Using filteredFields lets you customize which field you want to filter out of the contract file (requires minimalContractSize: true)
// minimalContractSize: false,
// filteredFields: [],
contracts: {
SimpleStorage: {
fromIndex: 0,
args: [100]
}
}
},
// default environment, merges with the settings in default
// assumed to be the intended environment by `embark run`
development: {
dappConnection: [
"ws://localhost:8546",
"http://localhost:8545",
"$WEB3" // uses pre existing web3 object if available (e.g in Mist)
]
},
// merges with the settings in default
// used with "embark run privatenet"
privatenet: {
},
// merges with the settings in default
// used with "embark run testnet"
testnet: {
},
// merges with the settings in default
// used with "embark run livenet"
livenet: {
},
// you can name an environment with specific settings and then specify with
// "embark run custom_name" or "embark blockchain custom_name"
//custom_name: {
//}
};

View File

@ -0,0 +1 @@
dev_password

39
config/namesystem.js Normal file
View File

@ -0,0 +1,39 @@
module.exports = {
// default applies to all environments
default: {
enabled: true,
available_providers: ["ens"],
provider: "ens"
},
// default environment, merges with the settings in default
// assumed to be the intended environment by `embark run`
development: {
register: {
rootDomain: "eth",
subdomains: {
'embark': '0x1a2f3b98e434c02363f3dac3174af93c1d690914'
}
}
},
// merges with the settings in default
// used with "embark run privatenet"
privatenet: {
},
// merges with the settings in default
// used with "embark run testnet"
testnet: {
},
// merges with the settings in default
// used with "embark run livenet"
livenet: {
},
// you can name an environment with specific settings and then specify with
// "embark run custom_name" or "embark blockchain custom_name"
//custom_name: {
//}
};

27
config/pipeline.js Normal file
View File

@ -0,0 +1,27 @@
// Embark has support for Flow enabled by default in its built-in webpack
// config: type annotations will automatically be stripped out of DApp sources
// without any additional configuration. Note that type checking is not
// performed during builds.
// To enable Flow type checking refer to the preconfigured template:
// https://github.com/embark-framework/embark-flow-template
// A new DApp can be created from that template with:
// embark new --template flow
module.exports = {
typescript: false,
// Setting `typescript: true` in this config will disable Flow support in
// Embark's default webpack config and enable TypeScript support: .ts and
// .tsx sources will automatically be transpiled into JavaScript without any
// additional configuration. Note that type checking is not performed during
// builds.
// To enable TypeScript type checking refer to the preconfigured template:
// https://github.com/embark-framework/embark-typescript-template
// A new DApp can be created from that template with:
// embark new --template typescript
enabled: true
// Setting `enabled: false` in this config will disable Embark's built-in Webpack
// pipeline. The developer will need to use a different frontend build tool, such as
// `create-react-app` or Angular CLI to build their dapp
};

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,20 @@
{
"config": {
"homesteadBlock": 0,
"byzantiumBlock": 0,
"eip155Block": 0,
"eip158Block": 0,
"daoForkSupport": true
},
"nonce": "0x0000000000000042",
"difficulty": "0x0",
"alloc": {
"0x3333333333333333333333333333333333333333": {"balance": "15000000000000000000"}
},
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0x3333333333333333333333333333333333333333",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x",
"gasLimit": "0x7a1200"
}

View File

@ -0,0 +1 @@
dev_password

59
config/storage.js Normal file
View File

@ -0,0 +1,59 @@
module.exports = {
// default applies to all environments
default: {
enabled: true,
ipfs_bin: "ipfs",
available_providers: ["ipfs"],
upload: {
provider: "ipfs",
host: "localhost",
port: 5001
},
dappConnection: [
{
provider:"ipfs",
host: "localhost",
port: 5001,
getUrl: "http://localhost:8080/ipfs/"
}
]
// Configuration to start Swarm in the same terminal as `embark run`
/*,account: {
address: "YOUR_ACCOUNT_ADDRESS", // Address of account accessing Swarm
password: "PATH/TO/PASSWORD/FILE" // File containing the password of the account
},
swarmPath: "PATH/TO/SWARM/EXECUTABLE" // Path to swarm executable (default: swarm)*/
},
// default environment, merges with the settings in default
// assumed to be the intended environment by `embark run`
development: {
enabled: true,
upload: {
provider: "ipfs",
host: "localhost",
port: 5001,
getUrl: "http://localhost:8080/ipfs/"
}
},
// merges with the settings in default
// used with "embark run privatenet"
privatenet: {
},
// merges with the settings in default
// used with "embark run testnet"
testnet: {
},
// merges with the settings in default
// used with "embark run livenet"
livenet: {
},
// you can name an environment with specific settings and then specify with
// "embark run custom_name"
//custom_name: {
//}
};

1
config/testnet/password Normal file
View File

@ -0,0 +1 @@
test_password

6
config/webserver.js Normal file
View File

@ -0,0 +1,6 @@
module.exports = {
enabled: true,
host: "localhost",
openBrowser: true,
port: 8000
};

View File

@ -0,0 +1,17 @@
pragma solidity ^0.5.0;
contract SimpleStorage {
uint public storedData;
constructor(uint initialValue) public {
storedData = initialValue;
}
function set(uint x) public {
storedData = x;
}
function get() public view returns (uint retVal) {
return storedData;
}
}

25
embark.json Normal file
View File

@ -0,0 +1,25 @@
{
"contracts": ["contracts/**"],
"app": {
"js/dapp.js": ["app/dapp.js"],
"index.html": "app/index.html",
"images/": ["app/images/**"],
"css/bootstrap.min.css": "node_modules/bootstrap/dist/css/bootstrap.min.css"
},
"buildDir": "dist/",
"config": "config/",
"versions": {
"web3": "1.2.4",
"solc": "0.5.0",
"ipfs-api": "17.2.4"
},
"plugins": {
},
"options": {
"solc": {
"optimize": true,
"optimize-runs": 200
}
},
"generationDir": "embarkArtifacts"
}

394
package-lock.json generated Normal file
View File

@ -0,0 +1,394 @@
{
"name": "embark_demo",
"version": "4.2.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@babel/runtime": {
"version": "7.10.3",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.10.3.tgz",
"integrity": "sha512-RzGO0RLSdokm9Ipe/YD+7ww8X2Ro79qiXZF3HU9ljrM+qnJmH1Vqth+hbiQZy761LnMJTMitHDuKVYTk3k4dLw==",
"dev": true,
"requires": {
"regenerator-runtime": "^0.13.4"
}
},
"bootstrap": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.3.1.tgz",
"integrity": "sha512-rXqOmH1VilAt2DyPzluTi2blhk17bO7ef+zLLPlWvG494pDxcM234pJ8wTc/6R40UWizAIIMgxjvxZg5kmsbag==",
"dev": true
},
"classnames": {
"version": "2.2.6",
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz",
"integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==",
"dev": true
},
"create-react-context": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/create-react-context/-/create-react-context-0.3.0.tgz",
"integrity": "sha512-dNldIoSuNSvlTJ7slIKC/ZFGKexBMBrrcc+TTe1NdmROnaASuLPvqpwj9v4XS4uXZ8+YPu0sNmShX2rXI5LNsw==",
"dev": true,
"requires": {
"gud": "^1.0.0",
"warning": "^4.0.3"
}
},
"deep-equal": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz",
"integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==",
"dev": true,
"requires": {
"is-arguments": "^1.0.4",
"is-date-object": "^1.0.1",
"is-regex": "^1.0.4",
"object-is": "^1.0.1",
"object-keys": "^1.1.1",
"regexp.prototype.flags": "^1.2.0"
}
},
"define-properties": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
"integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
"dev": true,
"requires": {
"object-keys": "^1.0.12"
}
},
"dom-helpers": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz",
"integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==",
"dev": true,
"requires": {
"@babel/runtime": "^7.1.2"
}
},
"es-abstract": {
"version": "1.17.6",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz",
"integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==",
"dev": true,
"requires": {
"es-to-primitive": "^1.2.1",
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.1",
"is-callable": "^1.2.0",
"is-regex": "^1.1.0",
"object-inspect": "^1.7.0",
"object-keys": "^1.1.1",
"object.assign": "^4.1.0",
"string.prototype.trimend": "^1.0.1",
"string.prototype.trimstart": "^1.0.1"
}
},
"es-to-primitive": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
"integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
"dev": true,
"requires": {
"is-callable": "^1.1.4",
"is-date-object": "^1.0.1",
"is-symbol": "^1.0.2"
}
},
"function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
"dev": true
},
"gud": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/gud/-/gud-1.0.0.tgz",
"integrity": "sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw==",
"dev": true
},
"has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
"dev": true,
"requires": {
"function-bind": "^1.1.1"
}
},
"has-symbols": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
"integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==",
"dev": true
},
"is-arguments": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz",
"integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==",
"dev": true
},
"is-callable": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz",
"integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==",
"dev": true
},
"is-date-object": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz",
"integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==",
"dev": true
},
"is-regex": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz",
"integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==",
"dev": true,
"requires": {
"has-symbols": "^1.0.1"
}
},
"is-symbol": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz",
"integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==",
"dev": true,
"requires": {
"has-symbols": "^1.0.1"
}
},
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"dev": true
},
"lodash.isfunction": {
"version": "3.0.9",
"resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz",
"integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==",
"dev": true
},
"lodash.isobject": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-3.0.2.tgz",
"integrity": "sha1-PI+41bW/S/kK4G4U8qUwpO2TXh0=",
"dev": true
},
"lodash.tonumber": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/lodash.tonumber/-/lodash.tonumber-4.0.3.tgz",
"integrity": "sha1-C5azGzVnJ5Prf1pj7nkfG56QJdk=",
"dev": true
},
"loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"dev": true,
"requires": {
"js-tokens": "^3.0.0 || ^4.0.0"
}
},
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
"dev": true
},
"object-inspect": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz",
"integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==",
"dev": true
},
"object-is": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.2.tgz",
"integrity": "sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"es-abstract": "^1.17.5"
}
},
"object-keys": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
"dev": true
},
"object.assign": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz",
"integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==",
"dev": true,
"requires": {
"define-properties": "^1.1.2",
"function-bind": "^1.1.1",
"has-symbols": "^1.0.0",
"object-keys": "^1.0.11"
}
},
"popper.js": {
"version": "1.16.1",
"resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz",
"integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==",
"dev": true
},
"prop-types": {
"version": "15.7.2",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
"integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
"dev": true,
"requires": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
"react-is": "^16.8.1"
}
},
"react": {
"version": "16.9.0",
"resolved": "https://registry.npmjs.org/react/-/react-16.9.0.tgz",
"integrity": "sha512-+7LQnFBwkiw+BobzOF6N//BdoNw0ouwmSJTEm9cglOOmsg/TMiFHZLe2sEoN5M7LgJTj9oHH0gxklfnQe66S1w==",
"dev": true,
"requires": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1",
"prop-types": "^15.6.2"
}
},
"react-dom": {
"version": "16.9.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.9.0.tgz",
"integrity": "sha512-YFT2rxO9hM70ewk9jq0y6sQk8cL02xm4+IzYBz75CQGlClQQ1Bxq0nhHF6OtSbit+AIahujJgb/CPRibFkMNJQ==",
"dev": true,
"requires": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1",
"prop-types": "^15.6.2",
"scheduler": "^0.15.0"
}
},
"react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
"dev": true
},
"react-lifecycles-compat": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==",
"dev": true
},
"react-popper": {
"version": "1.3.7",
"resolved": "https://registry.npmjs.org/react-popper/-/react-popper-1.3.7.tgz",
"integrity": "sha512-nmqYTx7QVjCm3WUZLeuOomna138R1luC4EqkW3hxJUrAe+3eNz3oFCLYdnPwILfn0mX1Ew2c3wctrjlUMYYUww==",
"dev": true,
"requires": {
"@babel/runtime": "^7.1.2",
"create-react-context": "^0.3.0",
"deep-equal": "^1.1.1",
"popper.js": "^1.14.4",
"prop-types": "^15.6.1",
"typed-styles": "^0.0.7",
"warning": "^4.0.2"
}
},
"react-transition-group": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz",
"integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==",
"dev": true,
"requires": {
"dom-helpers": "^3.4.0",
"loose-envify": "^1.4.0",
"prop-types": "^15.6.2",
"react-lifecycles-compat": "^3.0.4"
}
},
"reactstrap": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/reactstrap/-/reactstrap-8.0.1.tgz",
"integrity": "sha512-GvUWEL+a2+3npK1OxTXcNBMHXX4x6uc1KQRzK7yAOl+8sAHTRWqjunvMUfny3oDh8yKVzgqpqQlWWvs1B2HR9A==",
"dev": true,
"requires": {
"@babel/runtime": "^7.2.0",
"classnames": "^2.2.3",
"lodash.isfunction": "^3.0.9",
"lodash.isobject": "^3.0.2",
"lodash.tonumber": "^4.0.3",
"prop-types": "^15.5.8",
"react-lifecycles-compat": "^3.0.4",
"react-popper": "^1.3.3",
"react-transition-group": "^2.3.1"
}
},
"regenerator-runtime": {
"version": "0.13.5",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz",
"integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==",
"dev": true
},
"regexp.prototype.flags": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz",
"integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"es-abstract": "^1.17.0-next.1"
}
},
"scheduler": {
"version": "0.15.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.15.0.tgz",
"integrity": "sha512-xAefmSfN6jqAa7Kuq7LIJY0bwAPG3xlCj0HMEBQk1lxYiDKZscY2xJ5U/61ZTrYbmNQbXa+gc7czPkVo11tnCg==",
"dev": true,
"requires": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1"
}
},
"string.prototype.trimend": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz",
"integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"es-abstract": "^1.17.5"
}
},
"string.prototype.trimstart": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz",
"integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"es-abstract": "^1.17.5"
}
},
"typed-styles": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/typed-styles/-/typed-styles-0.0.7.tgz",
"integrity": "sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q==",
"dev": true
},
"warning": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
"integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
"dev": true,
"requires": {
"loose-envify": "^1.0.0"
}
}
}
}

28
package.json Normal file
View File

@ -0,0 +1,28 @@
{
"name": "embark_demo",
"version": "4.2.0",
"description": "Demo DApp for Embark",
"homepage": "https://github.com/embark-framework/embark/tree/master/dapps/templates/demo#readme",
"bugs": "https://github.com/embark-framework/embark/issues",
"scripts": {
"test": "embark test"
},
"keywords": [],
"author": "",
"license": "MIT",
"repository": {
"directory": "dapps/templates/demo",
"type": "git",
"url": "https://github.com/embark-framework/embark.git"
},
"devDependencies": {
"bootstrap": "4.3.1",
"classnames": "2.2.6",
"react": "16.9.0",
"react-dom": "16.9.0",
"reactstrap": "8.0.1"
},
"dependencies": {
"formik": "^2.1.4"
}
}

View File

@ -0,0 +1,41 @@
/*global contract, config, it, assert, web3*/
const SimpleStorage = require('Embark/contracts/SimpleStorage');
let accounts;
// For documentation please see https://embark.status.im/docs/contracts_testing.html
config({
//deployment: {
// accounts: [
// // you can configure custom accounts with a custom balance
// // see https://embark.status.im/docs/contracts_testing.html#Configuring-accounts
// ]
//},
contracts: {
"SimpleStorage": {
args: [100]
}
}
}, (_err, web3_accounts) => {
accounts = web3_accounts;
});
contract("SimpleStorage", function () {
this.timeout(0);
it("should set constructor value", async function () {
let result = await SimpleStorage.methods.storedData().call();
assert.strictEqual(parseInt(result, 10), 100);
});
it("set storage value", async function () {
await SimpleStorage.methods.set(150).send();
let result = await SimpleStorage.methods.get().call();
assert.strictEqual(parseInt(result, 10), 150);
});
it("should have account with balance", async function() {
let balance = await web3.eth.getBalance(accounts[0]);
assert.ok(parseInt(balance, 10) > 0);
});
});

380
yarn.lock Normal file
View File

@ -0,0 +1,380 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@babel/runtime@^7.1.2", "@babel/runtime@^7.2.0":
version "7.10.3"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.3.tgz#670d002655a7c366540c67f6fd3342cd09500364"
integrity sha512-RzGO0RLSdokm9Ipe/YD+7ww8X2Ro79qiXZF3HU9ljrM+qnJmH1Vqth+hbiQZy761LnMJTMitHDuKVYTk3k4dLw==
dependencies:
regenerator-runtime "^0.13.4"
bootstrap@4.3.1:
version "4.3.1"
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.3.1.tgz#280ca8f610504d99d7b6b4bfc4b68cec601704ac"
integrity sha512-rXqOmH1VilAt2DyPzluTi2blhk17bO7ef+zLLPlWvG494pDxcM234pJ8wTc/6R40UWizAIIMgxjvxZg5kmsbag==
classnames@2.2.6, classnames@^2.2.3:
version "2.2.6"
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==
create-react-context@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/create-react-context/-/create-react-context-0.3.0.tgz#546dede9dc422def0d3fc2fe03afe0bc0f4f7d8c"
integrity sha512-dNldIoSuNSvlTJ7slIKC/ZFGKexBMBrrcc+TTe1NdmROnaASuLPvqpwj9v4XS4uXZ8+YPu0sNmShX2rXI5LNsw==
dependencies:
gud "^1.0.0"
warning "^4.0.3"
deep-equal@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a"
integrity sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==
dependencies:
is-arguments "^1.0.4"
is-date-object "^1.0.1"
is-regex "^1.0.4"
object-is "^1.0.1"
object-keys "^1.1.1"
regexp.prototype.flags "^1.2.0"
deepmerge@^2.1.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170"
integrity sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==
define-properties@^1.1.2, define-properties@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
dependencies:
object-keys "^1.0.12"
dom-helpers@^3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.4.0.tgz#e9b369700f959f62ecde5a6babde4bccd9169af8"
integrity sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==
dependencies:
"@babel/runtime" "^7.1.2"
es-abstract@^1.17.0-next.1, es-abstract@^1.17.5:
version "1.17.6"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.6.tgz#9142071707857b2cacc7b89ecb670316c3e2d52a"
integrity sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==
dependencies:
es-to-primitive "^1.2.1"
function-bind "^1.1.1"
has "^1.0.3"
has-symbols "^1.0.1"
is-callable "^1.2.0"
is-regex "^1.1.0"
object-inspect "^1.7.0"
object-keys "^1.1.1"
object.assign "^4.1.0"
string.prototype.trimend "^1.0.1"
string.prototype.trimstart "^1.0.1"
es-to-primitive@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==
dependencies:
is-callable "^1.1.4"
is-date-object "^1.0.1"
is-symbol "^1.0.2"
formik@^2.1.4:
version "2.1.4"
resolved "https://registry.yarnpkg.com/formik/-/formik-2.1.4.tgz#8deef07ec845ea98f75e03da4aad7aab4ac46570"
integrity sha512-oKz8S+yQBzuQVSEoxkqqJrKQS5XJASWGVn6mrs+oTWrBoHgByVwwI1qHiVc9GKDpZBU9vAxXYAKz2BvujlwunA==
dependencies:
deepmerge "^2.1.1"
hoist-non-react-statics "^3.3.0"
lodash "^4.17.14"
lodash-es "^4.17.14"
react-fast-compare "^2.0.1"
scheduler "^0.18.0"
tiny-warning "^1.0.2"
tslib "^1.10.0"
function-bind@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
gud@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0"
integrity sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw==
has-symbols@^1.0.0, has-symbols@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8"
integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==
has@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
dependencies:
function-bind "^1.1.1"
hoist-non-react-statics@^3.3.0:
version "3.3.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
dependencies:
react-is "^16.7.0"
is-arguments@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.0.4.tgz#3faf966c7cba0ff437fb31f6250082fcf0448cf3"
integrity sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==
is-callable@^1.1.4, is-callable@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.0.tgz#83336560b54a38e35e3a2df7afd0454d691468bb"
integrity sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==
is-date-object@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e"
integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==
is-regex@^1.0.4, is-regex@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.0.tgz#ece38e389e490df0dc21caea2bd596f987f767ff"
integrity sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==
dependencies:
has-symbols "^1.0.1"
is-symbol@^1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937"
integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==
dependencies:
has-symbols "^1.0.1"
"js-tokens@^3.0.0 || ^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
lodash-es@^4.17.14:
version "4.17.15"
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.15.tgz#21bd96839354412f23d7a10340e5eac6ee455d78"
integrity sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ==
lodash.isfunction@^3.0.9:
version "3.0.9"
resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz#06de25df4db327ac931981d1bdb067e5af68d051"
integrity sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==
lodash.isobject@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/lodash.isobject/-/lodash.isobject-3.0.2.tgz#3c8fb8d5b5bf4bf90ae06e14f2a530a4ed935e1d"
integrity sha1-PI+41bW/S/kK4G4U8qUwpO2TXh0=
lodash.tonumber@^4.0.3:
version "4.0.3"
resolved "https://registry.yarnpkg.com/lodash.tonumber/-/lodash.tonumber-4.0.3.tgz#0b96b31b35672793eb7f5a63ee791f1b9e9025d9"
integrity sha1-C5azGzVnJ5Prf1pj7nkfG56QJdk=
lodash@^4.17.14:
version "4.17.15"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
dependencies:
js-tokens "^3.0.0 || ^4.0.0"
object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
object-inspect@^1.7.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0"
integrity sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==
object-is@^1.0.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.2.tgz#c5d2e87ff9e119f78b7a088441519e2eec1573b6"
integrity sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ==
dependencies:
define-properties "^1.1.3"
es-abstract "^1.17.5"
object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
object.assign@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da"
integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==
dependencies:
define-properties "^1.1.2"
function-bind "^1.1.1"
has-symbols "^1.0.0"
object-keys "^1.0.11"
popper.js@^1.14.4:
version "1.16.1"
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b"
integrity sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==
prop-types@^15.5.8, prop-types@^15.6.1, prop-types@^15.6.2:
version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
dependencies:
loose-envify "^1.4.0"
object-assign "^4.1.1"
react-is "^16.8.1"
react-dom@16.9.0:
version "16.9.0"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.9.0.tgz#5e65527a5e26f22ae3701131bcccaee9fb0d3962"
integrity sha512-YFT2rxO9hM70ewk9jq0y6sQk8cL02xm4+IzYBz75CQGlClQQ1Bxq0nhHF6OtSbit+AIahujJgb/CPRibFkMNJQ==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
prop-types "^15.6.2"
scheduler "^0.15.0"
react-fast-compare@^2.0.1:
version "2.0.4"
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9"
integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==
react-is@^16.7.0, react-is@^16.8.1:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
react-lifecycles-compat@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
react-popper@^1.3.3:
version "1.3.7"
resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-1.3.7.tgz#f6a3471362ef1f0d10a4963673789de1baca2324"
integrity sha512-nmqYTx7QVjCm3WUZLeuOomna138R1luC4EqkW3hxJUrAe+3eNz3oFCLYdnPwILfn0mX1Ew2c3wctrjlUMYYUww==
dependencies:
"@babel/runtime" "^7.1.2"
create-react-context "^0.3.0"
deep-equal "^1.1.1"
popper.js "^1.14.4"
prop-types "^15.6.1"
typed-styles "^0.0.7"
warning "^4.0.2"
react-transition-group@^2.3.1:
version "2.9.0"
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.9.0.tgz#df9cdb025796211151a436c69a8f3b97b5b07c8d"
integrity sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==
dependencies:
dom-helpers "^3.4.0"
loose-envify "^1.4.0"
prop-types "^15.6.2"
react-lifecycles-compat "^3.0.4"
react@16.9.0:
version "16.9.0"
resolved "https://registry.yarnpkg.com/react/-/react-16.9.0.tgz#40ba2f9af13bc1a38d75dbf2f4359a5185c4f7aa"
integrity sha512-+7LQnFBwkiw+BobzOF6N//BdoNw0ouwmSJTEm9cglOOmsg/TMiFHZLe2sEoN5M7LgJTj9oHH0gxklfnQe66S1w==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
prop-types "^15.6.2"
reactstrap@8.0.1:
version "8.0.1"
resolved "https://registry.yarnpkg.com/reactstrap/-/reactstrap-8.0.1.tgz#0b663c8195f540bc1d6d5dbcbcf73cab56fe7c79"
integrity sha512-GvUWEL+a2+3npK1OxTXcNBMHXX4x6uc1KQRzK7yAOl+8sAHTRWqjunvMUfny3oDh8yKVzgqpqQlWWvs1B2HR9A==
dependencies:
"@babel/runtime" "^7.2.0"
classnames "^2.2.3"
lodash.isfunction "^3.0.9"
lodash.isobject "^3.0.2"
lodash.tonumber "^4.0.3"
prop-types "^15.5.8"
react-lifecycles-compat "^3.0.4"
react-popper "^1.3.3"
react-transition-group "^2.3.1"
regenerator-runtime@^0.13.4:
version "0.13.5"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697"
integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==
regexp.prototype.flags@^1.2.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz#7aba89b3c13a64509dabcf3ca8d9fbb9bdf5cb75"
integrity sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==
dependencies:
define-properties "^1.1.3"
es-abstract "^1.17.0-next.1"
scheduler@^0.15.0:
version "0.15.0"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.15.0.tgz#6bfcf80ff850b280fed4aeecc6513bc0b4f17f8e"
integrity sha512-xAefmSfN6jqAa7Kuq7LIJY0bwAPG3xlCj0HMEBQk1lxYiDKZscY2xJ5U/61ZTrYbmNQbXa+gc7czPkVo11tnCg==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
scheduler@^0.18.0:
version "0.18.0"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.18.0.tgz#5901ad6659bc1d8f3fdaf36eb7a67b0d6746b1c4"
integrity sha512-agTSHR1Nbfi6ulI0kYNK0203joW2Y5W4po4l+v03tOoiJKpTBbxpNhWDvqc/4IcOw+KLmSiQLTasZ4cab2/UWQ==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
string.prototype.trimend@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913"
integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==
dependencies:
define-properties "^1.1.3"
es-abstract "^1.17.5"
string.prototype.trimstart@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54"
integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==
dependencies:
define-properties "^1.1.3"
es-abstract "^1.17.5"
tiny-warning@^1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
tslib@^1.10.0:
version "1.13.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043"
integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==
typed-styles@^0.0.7:
version "0.0.7"
resolved "https://registry.yarnpkg.com/typed-styles/-/typed-styles-0.0.7.tgz#93392a008794c4595119ff62dde6809dbc40a3d9"
integrity sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q==
warning@^4.0.2, warning@^4.0.3:
version "4.0.3"
resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3"
integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==
dependencies:
loose-envify "^1.0.0"