diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..f4b5311d5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,12 @@ +_Before filing a new issue, please **provide the following information**._ + +> I'm running: +> +> - **Parity version**: 0.0.0 +> - **Operating system**: Windows / MacOS / Linux +> - **And installed**: via installer / homebrew / binaries / from source + +_Your issue description goes here below. Try to include **actual** vs. **expected behavior** and **steps to reproduce** the issue._ + +--- + diff --git a/CHANGELOG.md b/CHANGELOG.md index 59eb1d0b4..78bf895ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,41 +1,45 @@ -## Parity [v1.6.10](https://github.com/paritytech/parity/releases/tag/v1.6.10) (2017-07-23) - -This is a hotfix release for the stable channel addressing the recent [multi-signature wallet vulnerability](https://blog.parity.io/security-alert-high-2/). Note, upgrading is not mandatory, and all future multi-sig wallets created by any version of Parity are secure. - -All Changes: - -- Backports for stable [#6116](https://github.com/paritytech/parity/pull/6116) - - Remove chunk to restore from pending set only upon successful import [#6112](https://github.com/paritytech/parity/pull/6112) - - Blacklist bad snapshot manifest hashes upon failure [#5874](https://github.com/paritytech/parity/pull/5874) - - Bump snap version and tweak importing detection logic [#6079](https://github.com/paritytech/parity/pull/6079) (modified to work) -- Fix docker build for stable [#6118](https://github.com/paritytech/parity/pull/6118) -- Backported wallet fix [#6104](https://github.com/paritytech/parity/pull/6104) - - Fix initialisation bug. ([#6102](https://github.com/paritytech/parity/pull/6102)) - - Update wallet library modifiers ([#6103](https://github.com/paritytech/parity/pull/6103)) -- Bump to v1.6.10 - -## Parity [v1.7.0](https://github.com/paritytech/parity/releases/tag/v1.7.0) (2017-07-23) +## Parity [v1.7.0](https://github.com/paritytech/parity/releases/tag/v1.7.0) (2017-07-28) Parity 1.7.0 is a major release introducing several important features: -- **Experimental [Light client](https://github.com/paritytech/parity/wiki/The-Parity-Light-Protocol-(PIP)) support**. Start Parity with `--light` to enable light mode. +- **Experimental [Light client](https://github.com/paritytech/parity/wiki/The-Parity-Light-Protocol-(PIP)) support**. Start Parity with `--light` to enable light mode. Please, note: The wallet UI integration for the light client is not included, yet. - **Experimental web wallet**. A hosted version of Parity that keeps the keys and signs transactions using your browser storage. Try it at https://wallet.parity.io or run your own with `--public-node`. - **WASM contract support**. Private networks can run contracts compiled into WASM bytecode. _More information and documentation to follow_. - **DApps and RPC server merge**. DApp and RPC are now available through a single API endpoint. DApp server related settings are deprecated. - **Export accounts from the wallet**. Backing up your keys can now simply be managed through the wallet interface. -- **PoA/Kovan validator set contract**. The PoA network validator-set management via smart contract is now supported by warp and light sync. +- **PoA/Kovan validator set contract**. The PoA network validator-set management via smart contract is now supported by warp and, in the near future, light sync. - **PubSub API**. https://github.com/paritytech/parity/wiki/JSONRPC-Parity-Pub-Sub-module - **Signer apps for IOS and Android**. Full list of included changes: +- Backports [#6163](https://github.com/paritytech/parity/pull/6163) + - Light client improvements ([#6156](https://github.com/paritytech/parity/pull/6156)) + - No seal checking + - Import command and --no-seal-check for light client + - Fix eth_call + - Tweak registry dapps lookup + - Ignore failed requests to non-server peers + - Fix connecting to wildcard addresses. ([#6167](https://github.com/paritytech/parity/pull/6167)) + - Don't display an overlay in case the time sync check fails. ([#6164](https://github.com/paritytech/parity/pull/6164)) + - Small improvements to time estimation. + - Temporarily disable NTP time check by default. +- Light client fixes ([#6148](https://github.com/paritytech/parity/pull/6148)) [#6151](https://github.com/paritytech/parity/pull/6151) + - Light client fixes + - Fix memory-lru-cache + - Clear pending reqs on disconnect +- Filter tokens logs from current block, not genesis ([#6128](https://github.com/paritytech/parity/pull/6128)) [#6141](https://github.com/paritytech/parity/pull/6141) +- Fix QR scanner returning null on confirm [#6122](https://github.com/paritytech/parity/pull/6122) - Check QR before lowercase ([#6119](https://github.com/paritytech/parity/pull/6119)) [#6120](https://github.com/paritytech/parity/pull/6120) - Remove chunk to restore from pending set only upon successful import [#6117](https://github.com/paritytech/parity/pull/6117) - Fixed node address detection on incoming connection [#6094](https://github.com/paritytech/parity/pull/6094) - Place RETURNDATA behind block number gate [#6095](https://github.com/paritytech/parity/pull/6095) +- Update wallet library binaries [#6108](https://github.com/paritytech/parity/pull/6108) - Backported wallet fix [#6105](https://github.com/paritytech/parity/pull/6105) - Fix initialisation bug. ([#6102](https://github.com/paritytech/parity/pull/6102)) - Update wallet library modifiers ([#6103](https://github.com/paritytech/parity/pull/6103)) +- Place RETURNDATA behind block number gate [#6095](https://github.com/paritytech/parity/pull/6095) +- Fixed node address detection on incoming connection [#6094](https://github.com/paritytech/parity/pull/6094) - Bump snap version and tweak importing detection logic ([#6079](https://github.com/paritytech/parity/pull/6079)) [#6081](https://github.com/paritytech/parity/pull/6081) - bump last tick just before printing info and restore sync detection - bump kovan snapshot version @@ -439,6 +443,23 @@ Full list of included changes: - Update the Wallet Library Registry key [#4817](https://github.com/paritytech/parity/pull/4817) - Update Wallet to new Wallet Code [#4805](https://github.com/paritytech/parity/pull/4805) +## Parity [v1.6.10](https://github.com/paritytech/parity/releases/tag/v1.6.10) (2017-07-25) + +This is a hotfix release for the stable channel addressing the recent [multi-signature wallet vulnerability](https://blog.parity.io/security-alert-high-2/). Note, upgrading is not mandatory, and all future multi-sig wallets created by any version of Parity are secure. + +All Changes: + +- Backports for stable [#6116](https://github.com/paritytech/parity/pull/6116) + - Remove chunk to restore from pending set only upon successful import [#6112](https://github.com/paritytech/parity/pull/6112) + - Blacklist bad snapshot manifest hashes upon failure [#5874](https://github.com/paritytech/parity/pull/5874) + - Bump snap version and tweak importing detection logic [#6079](https://github.com/paritytech/parity/pull/6079) (modified to work) +- Fix docker build for stable [#6118](https://github.com/paritytech/parity/pull/6118) +- Update wallet library binaries [#6108](https://github.com/paritytech/parity/pull/6108) +- Backported wallet fix [#6104](https://github.com/paritytech/parity/pull/6104) + - Fix initialisation bug. ([#6102](https://github.com/paritytech/parity/pull/6102)) + - Update wallet library modifiers ([#6103](https://github.com/paritytech/parity/pull/6103)) +- Bump to v1.6.10 + ## Parity [v1.6.9](https://github.com/paritytech/parity/releases/tag/v1.6.9) (2017-07-16) This is a first stable release of 1.6 series. It contains a number of minor fixes and introduces the `--reseal-on-uncles` option for miners. diff --git a/Cargo.lock b/Cargo.lock index 359b2d2f9..20c11bda7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,15 @@ [root] -name = "using_queue" +name = "wasm" version = "0.1.0" +dependencies = [ + "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethcore-logger 1.8.0", + "ethcore-util 1.8.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-wasm 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", + "vm 0.1.0", + "wasm-utils 0.1.0 (git+https://github.com/paritytech/wasm-utils)", +] [[package]] name = "advapi32-sys" @@ -116,10 +125,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bigint" -version = "3.0.0" +version = "4.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -181,6 +191,14 @@ name = "blastfig" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bloomable" +version = "0.1.0" +dependencies = [ + "ethcore-bigint 0.1.3", + "tiny-keccak 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bloomchain" version = "0.1.0" @@ -220,6 +238,15 @@ name = "cfg-if" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "chainspec" +version = "0.1.0" +dependencies = [ + "ethjson 0.1.0", + "serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cid" version = "0.2.2" @@ -271,9 +298,11 @@ dependencies = [ name = "common-types" version = "0.1.0" dependencies = [ + "bloomable 0.1.0", "ethcore-util 1.8.0", "ethjson 0.1.0", "rlp 0.2.0", + "rlp_derive 0.1.0", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -318,7 +347,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "crunchy" -version = "0.1.3" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -443,14 +472,14 @@ dependencies = [ "serde 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ethash" version = "1.8.0" dependencies = [ - "crunchy 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "primal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -462,6 +491,7 @@ name = "ethcore" version = "1.8.0" dependencies = [ "bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bloomable 0.1.0", "bloomchain 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "bn 0.4.4 (git+https://github.com/paritytech/bn)", "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -498,19 +528,24 @@ dependencies = [ "price-info 1.7.0", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.0", + "rlp_derive 0.1.0", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "stats 0.1.0", + "table 0.1.0", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "transient-hashmap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "using_queue 0.1.0", + "vm 0.1.0", + "wasm 0.1.0", ] [[package]] name = "ethcore-bigint" version = "0.1.3" dependencies = [ - "bigint 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bigint 4.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -620,11 +655,13 @@ dependencies = [ "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.0", + "rlp_derive 0.1.0", "serde 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "stats 0.1.0", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", + "vm 0.1.0", ] [[package]] @@ -656,6 +693,7 @@ dependencies = [ "ethcrypto 0.1.0", "ethkey 0.2.0", "igd 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ipnetwork 0.12.6 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -668,7 +706,7 @@ dependencies = [ "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -689,6 +727,7 @@ dependencies = [ "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "native-contracts 0.1.0", "parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -738,7 +777,6 @@ dependencies = [ "ethcore-devtools 1.8.0", "ethcore-logger 1.8.0", "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "lru-cache 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -751,11 +789,9 @@ dependencies = [ "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "sha3 0.1.0", - "table 0.1.0", "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "using_queue 0.1.0", + "tiny-keccak 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "vergen 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -768,7 +804,7 @@ dependencies = [ "ethkey 0.2.0", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "subtle 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -776,7 +812,7 @@ name = "ethjson" version = "0.1.0" dependencies = [ "clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore-util 1.8.0", + "ethcore-bigint 0.1.3", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -794,7 +830,7 @@ dependencies = [ "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -830,7 +866,7 @@ dependencies = [ "smallvec 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -862,6 +898,7 @@ dependencies = [ "ethcore-util 1.8.0", "ethkey 0.2.0", "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ipnetwork 0.12.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -878,6 +915,7 @@ dependencies = [ "bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "common-types 0.1.0", + "ethcore-logger 1.8.0", "ethcore-util 1.8.0", "ethjson 0.1.0", "evmjit 1.8.0", @@ -886,6 +924,7 @@ dependencies = [ "parity-wasm 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.0", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "vm 0.1.0", "wasm-utils 0.1.0 (git+https://github.com/paritytech/wasm-utils)", ] @@ -901,13 +940,14 @@ dependencies = [ "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "vm 0.1.0", ] [[package]] name = "evmjit" version = "1.8.0" dependencies = [ - "tiny-keccak 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1149,6 +1189,11 @@ dependencies = [ "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ipnetwork" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "isatty" version = "0.1.1" @@ -1175,7 +1220,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "jsonrpc-core" version = "7.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#4d3ec22c7aba426988a678b489b2791e95283699" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#b5490782884218c5ccf74cd61e54904cb3a3aeed" dependencies = [ "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1187,7 +1232,7 @@ dependencies = [ [[package]] name = "jsonrpc-http-server" version = "7.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#4d3ec22c7aba426988a678b489b2791e95283699" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#b5490782884218c5ccf74cd61e54904cb3a3aeed" dependencies = [ "hyper 0.10.0-a.0 (git+https://github.com/paritytech/hyper)", "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", @@ -1200,7 +1245,7 @@ dependencies = [ [[package]] name = "jsonrpc-ipc-server" version = "7.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#4d3ec22c7aba426988a678b489b2791e95283699" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#b5490782884218c5ccf74cd61e54904cb3a3aeed" dependencies = [ "bytes 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", @@ -1213,7 +1258,7 @@ dependencies = [ [[package]] name = "jsonrpc-macros" version = "7.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#4d3ec22c7aba426988a678b489b2791e95283699" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#b5490782884218c5ccf74cd61e54904cb3a3aeed" dependencies = [ "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-pubsub 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", @@ -1223,7 +1268,7 @@ dependencies = [ [[package]] name = "jsonrpc-minihttp-server" version = "7.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#4d3ec22c7aba426988a678b489b2791e95283699" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#b5490782884218c5ccf74cd61e54904cb3a3aeed" dependencies = [ "bytes 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", @@ -1238,7 +1283,7 @@ dependencies = [ [[package]] name = "jsonrpc-pubsub" version = "7.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#4d3ec22c7aba426988a678b489b2791e95283699" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#b5490782884218c5ccf74cd61e54904cb3a3aeed" dependencies = [ "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1248,7 +1293,7 @@ dependencies = [ [[package]] name = "jsonrpc-server-utils" version = "7.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#4d3ec22c7aba426988a678b489b2791e95283699" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#b5490782884218c5ccf74cd61e54904cb3a3aeed" dependencies = [ "bytes 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "globset 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1261,7 +1306,7 @@ dependencies = [ [[package]] name = "jsonrpc-tcp-server" version = "7.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#4d3ec22c7aba426988a678b489b2791e95283699" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#b5490782884218c5ccf74cd61e54904cb3a3aeed" dependencies = [ "bytes 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", @@ -1275,7 +1320,7 @@ dependencies = [ [[package]] name = "jsonrpc-ws-server" version = "7.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#4d3ec22c7aba426988a678b489b2791e95283699" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#b5490782884218c5ccf74cd61e54904cb3a3aeed" dependencies = [ "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-server-utils 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", @@ -1504,7 +1549,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ring 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1539,7 +1584,7 @@ version = "0.1.0" dependencies = [ "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore-util 1.8.0", + "ethcore-bigint 0.1.3", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "native-contract-generator 0.1.0", ] @@ -1745,7 +1790,7 @@ dependencies = [ [[package]] name = "parity" -version = "1.7.0" +version = "1.8.0" dependencies = [ "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "app_dirs 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1763,6 +1808,7 @@ dependencies = [ "ethcore-ipc-tests 0.1.0", "ethcore-light 1.8.0", "ethcore-logger 1.8.0", + "ethcore-network 1.8.0", "ethcore-secretstore 1.0.0", "ethcore-stratum 1.8.0", "ethcore-util 1.8.0", @@ -1771,6 +1817,7 @@ dependencies = [ "fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "ipnetwork 0.12.6 (registry+https://github.com/rust-lang/crates.io-index)", "isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1816,6 +1863,7 @@ dependencies = [ "fetch 0.1.0", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-http-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1924,10 +1972,10 @@ dependencies = [ "ethkey 0.2.0", "ethstore 0.1.0", "ethsync 1.8.0", - "evm 0.1.0", "fetch 0.1.0", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-http-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-ipc-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", @@ -1953,6 +2001,7 @@ dependencies = [ "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "transient-hashmap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "vm 0.1.0", ] [[package]] @@ -2009,7 +2058,7 @@ dependencies = [ [[package]] name = "parity-ui-precompiled" version = "1.4.0" -source = "git+https://github.com/paritytech/js-precompiled.git#5a357d01c459d3f371a87bfa138567b30603222c" +source = "git+https://github.com/paritytech/js-precompiled.git#416ced84c23b1a776d53ee4a3023eb4eb4736cf8" dependencies = [ "parity-dapps-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2070,7 +2119,7 @@ dependencies = [ "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2165,10 +2214,10 @@ dependencies = [ name = "price-info" version = "1.7.0" dependencies = [ - "ethcore-util 1.8.0", "fetch 0.1.0", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2261,7 +2310,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "quote" -version = "0.3.10" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2352,6 +2401,15 @@ dependencies = [ "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rlp_derive" +version = "0.1.0" +dependencies = [ + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "rlp 0.2.0", + "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rocksdb" version = "0.4.5" @@ -2409,7 +2467,7 @@ dependencies = [ name = "rpc-cli" version = "1.4.0" dependencies = [ - "bigint 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bigint 4.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-util 1.8.0", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "parity-rpc 1.8.0", @@ -2544,7 +2602,7 @@ name = "serde_derive" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quote 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive_internals 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2558,6 +2616,14 @@ dependencies = [ "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "serde_ignored" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "serde_json" version = "1.0.2" @@ -2678,7 +2744,7 @@ name = "syn" version = "0.11.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quote 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2812,7 +2878,7 @@ dependencies = [ [[package]] name = "tiny-keccak" -version = "1.2.1" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -3035,6 +3101,10 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "using_queue" +version = "0.1.0" + [[package]] name = "utf8-ranges" version = "1.0.0" @@ -3063,6 +3133,20 @@ dependencies = [ "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "vm" +version = "0.1.0" +dependencies = [ + "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "common-types 0.1.0", + "ethcore-util 1.8.0", + "ethjson 0.1.0", + "evmjit 1.8.0", + "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "rlp 0.2.0", +] + [[package]] name = "void" version = "1.0.2" @@ -3071,7 +3155,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "wasm-utils" version = "0.1.0" -source = "git+https://github.com/paritytech/wasm-utils#fee06b6d5826c2dc1fc1aa183b0c2c75e3e140c3" +source = "git+https://github.com/paritytech/wasm-utils#9462bcc0680f0ec2c876abdf75bae981dd4344a5" dependencies = [ "clap 2.24.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3161,7 +3245,7 @@ dependencies = [ "checksum backtrace-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3a0d842ea781ce92be2bf78a9b38883948542749640b8378b3b2f03d1fd9f1ff" "checksum base-x 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f59103b47307f76e03bef1633aec7fa9e29bfb5aa6daf5a334f94233c71f6c1" "checksum base32 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1b9605ba46d61df0410d8ac686b0007add8172eba90e8e909c347856fe794d8c" -"checksum bigint 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d0673c930652d3d4d6dcd5c45b5db4fa5f8f33994d7323618c43c083b223e8c" +"checksum bigint 4.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f56c9f1cd09cdcafcccdab1fd58797d39b7d4d203238b2e3768807590723bdf0" "checksum bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e103c8b299b28a9c6990458b7013dc4a8356a9b854c51b9883241f5866fac36e" "checksum bit-set 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e6e1e6fb1c9e3d6fcdec57216a74eaa03e41f52a22f13a16438251d8e88b89da" "checksum bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9bf6104718e80d7b26a68fdbacff3481cfc05df670821affc7e9cbc1884400c" @@ -3186,7 +3270,7 @@ dependencies = [ "checksum core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "20a6d0448d3a99d977ae4a2aa5a98d886a923e863e81ad9ff814645b6feb3bbd" "checksum core-foundation-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "05eed248dc504a5391c63794fe4fb64f46f071280afaa1b73308f3c0ce4574c5" "checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97" -"checksum crunchy 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6aa9cb5f2d7bffc4eecfaf924fe450549dc4f0c3a6502298dc24f968b1eabbe" +"checksum crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda" "checksum crypt32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e34988f7e069e0b2f3bfc064295161e489b2d4e04a2e4248fb94360cdf00b4ec" "checksum ctrlc 1.1.1 (git+https://github.com/paritytech/rust-ctrlc.git)" = "" "checksum custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9" @@ -3226,6 +3310,7 @@ dependencies = [ "checksum igd 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "356a0dc23a4fa0f8ce4777258085d00a01ea4923b2efd93538fc44bf5e1bda76" "checksum integer-encoding 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a053c9c7dcb7db1f2aa012c37dc176c62e4cdf14898dee0eecc606de835b8acb" "checksum iovec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29d062ee61fccdf25be172e70f34c9f6efc597e1fb8f6526e8437b2046ab26be" +"checksum ipnetwork 0.12.6 (registry+https://github.com/rust-lang/crates.io-index)" = "232e76922883005380e831068f731ef0305541c9f77b30df3a1635047b16f370" "checksum isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7408a548dc0e406b7912d9f84c261cc533c1866e047644a811c133c56041ac0c" "checksum itertools 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "d95557e7ba6b71377b0f2c3b3ae96c53f1b75a926a6901a500f557a370af730a" "checksum itoa 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "91fd9dc2c587067de817fec4ad355e3818c3d893a78cab32a0a474c7a15bb8d5" @@ -3313,7 +3398,7 @@ dependencies = [ "checksum quasi_macros 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29cec87bc2816766d7e4168302d505dd06b0a825aed41b00633d296e922e02dd" "checksum quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0aad603e8d7fb67da22dbdf1f4b826ce8829e406124109e73cf1b2454b93a71c" "checksum quine-mc_cluskey 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6683b0e23d80813b1a535841f0048c1537d3f86d63c999e8373b39a9b0eb74a" -"checksum quote 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)" = "6732e32663c9c271bfc7c1823486b471f18c47a2dbf87c066897b7b51afc83be" +"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" "checksum rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2791d88c6defac799c3f20d74f094ca33b9332612d9aef9078519c82e4fe04a5" "checksum rayon 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8c83adcb08e5b922e804fe1918142b422602ef11f2fd670b0b52218cb5984a20" "checksum rayon-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "767d91bacddf07d442fe39257bf04fd95897d1c47c545d009f6beb03efd038f8" @@ -3345,6 +3430,7 @@ dependencies = [ "checksum serde 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6a7c6b751a2e8d5df57a5ff71b5b4fc8aaee9ee28ff1341d640dd130bb5f4f7a" "checksum serde_derive 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "2f6ca58905ebd3c3b285a8a6d4f3ac92b92c0d7951d5649b1bdd212549c06639" "checksum serde_derive_internals 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37aee4e0da52d801acfbc0cc219eb1eda7142112339726e427926a6f6ee65d3a" +"checksum serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "190e9765dcedb56be63b6e0993a006c7e3b071a016a304736e4a315dc01fb142" "checksum serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "48b04779552e92037212c3615370f6bd57a40ebba7f20e554ff9f55e41a69a7b" "checksum serde_urlencoded 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce0fd303af908732989354c6f02e05e2e6d597152870f2c6990efb0577137480" "checksum sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c" @@ -3375,7 +3461,7 @@ dependencies = [ "checksum thread-id 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4437c97558c70d129e40629a5b385b3fb1ffac301e63941335e4d354081ec14a" "checksum thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c85048c6260d17cf486ceae3282d9fb6b90be220bf5b28c400f5485ffc29f0c7" "checksum time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "3c7ec6d62a20df54e07ab3b78b9a3932972f4b7981de295563686849eb3989af" -"checksum tiny-keccak 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b50173faa6ee499206f77b189d7ff3bef40f6969f228c9ec22b82080df9aa41" +"checksum tiny-keccak 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d52d12ad79e4063e0cb0ca5efa202ed7244b6ce4d25f4d3abe410b2a66128292" "checksum tokio-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "99e958104a67877907c1454386d5482fe8e965a55d60be834a15a44328e7dc76" "checksum tokio-io 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "48f55df1341bb92281f229a6030bc2abffde2c7a44c6d6b802b7687dd8be0775" "checksum tokio-minihttp 0.1.0 (git+https://github.com/tomusdrw/tokio-minihttp)" = "" diff --git a/Cargo.toml b/Cargo.toml index 21961776e..3adaf62d4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] description = "Parity Ethereum client" name = "parity" -version = "1.7.0" +version = "1.8.0" license = "GPL-3.0" authors = ["Parity Technologies "] build = "build.rs" @@ -41,6 +41,7 @@ ethcore-ipc-hypervisor = { path = "ipc/hypervisor" } ethcore-light = { path = "ethcore/light" } ethcore-logger = { path = "logger" } ethcore-stratum = { path = "stratum" } +ethcore-network = { path = "util/network" } ethkey = { path = "ethkey" } rlp = { path = "util/rlp" } rpc-cli = { path = "rpc_cli" } @@ -65,6 +66,7 @@ rustc_version = "0.2" [dev-dependencies] ethcore-ipc-tests = { path = "ipc/tests" } pretty_assertions = "0.1" +ipnetwork = "0.12.6" [target.'cfg(windows)'.dependencies] winapi = "0.2" @@ -108,4 +110,4 @@ lto = false panic = "abort" [workspace] -members = ["ethstore/cli", "ethkey/cli", "evmbin", "whisper"] +members = ["ethstore/cli", "ethkey/cli", "evmbin", "whisper", "chainspec"] diff --git a/README.md b/README.md index 37b06f01c..24178edbe 100644 --- a/README.md +++ b/README.md @@ -1,61 +1,47 @@ -# [Parity](https://parity.io/parity.html) -### Fast, light, and robust Ethereum implementation +# [Parity](https://parity.io/parity.html) - fast, light, and robust Ethereum client -### [Download latest release](https://github.com/paritytech/parity/releases) +[![build status](https://gitlab.parity.io/parity/parity/badges/master/build.svg)](https://gitlab.parity.io/parity/parity/commits/master) +[![Snap Status](https://build.snapcraft.io/badge/paritytech/parity.svg)](https://build.snapcraft.io/user/paritytech/parity) +[![GPLv3](https://img.shields.io/badge/license-GPL%20v3-green.svg)](https://www.gnu.org/licenses/gpl-3.0.en.html) -[![build status](https://gitlab.parity.io/parity/parity/badges/master/build.svg)](https://gitlab.parity.io/parity/parity/commits/master) [![Coverage Status][coveralls-image]][coveralls-url] [![GPLv3][license-image]][license-url] [![Snap Status](https://build.snapcraft.io/badge/paritytech/parity.svg)](https://build.snapcraft.io/user/paritytech/parity) +- [Download the latest release here.](https://github.com/paritytech/parity/releases) ### Join the chat! -Parity [![Join the chat at https://gitter.im/ethcore/parity][gitter-image]][gitter-url] and -parity.js [![Join the chat at https://gitter.im/ethcore/parity.js](https://badges.gitter.im/ethcore/parity.js.svg)](https://gitter.im/ethcore/parity.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - -[Internal Documentation][doc-url] - - -Be sure to check out [our wiki][wiki-url] for more information. - -[coveralls-image]: https://coveralls.io/repos/github/paritytech/parity/badge.svg?branch=master -[coveralls-url]: https://coveralls.io/github/paritytech/parity?branch=master -[gitter-image]: https://badges.gitter.im/Join%20Chat.svg -[gitter-url]: https://gitter.im/ethcore/parity?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge -[license-image]: https://img.shields.io/badge/license-GPL%20v3-green.svg -[license-url]: https://www.gnu.org/licenses/gpl-3.0.en.html -[doc-url]: https://paritytech.github.io/parity/ethcore/index.html -[wiki-url]: https://github.com/paritytech/parity/wiki +Get in touch with us on Gitter: +[![Gitter: Parity](https://img.shields.io/badge/gitter-parity-4AB495.svg)](https://gitter.im/paritytech/parity) +[![Gitter: Parity.js](https://img.shields.io/badge/gitter-parity.js-4AB495.svg)](https://gitter.im/paritytech/parity.js) +[![Gitter: Parity/Miners](https://img.shields.io/badge/gitter-parity/miners-4AB495.svg)](https://gitter.im/paritytech/parity/miners) +[![Gitter: Parity-PoA](https://img.shields.io/badge/gitter-parity--poa-4AB495.svg)](https://gitter.im/paritytech/parity-poa) +Be sure to check out [our wiki](https://github.com/paritytech/parity/wiki) and the [internal documentation](https://paritytech.github.io/parity/ethcore/index.html) for more information. ---- - ## About Parity -Parity's goal is to be the fastest, lightest, and most secure Ethereum client. We are developing Parity using the sophisticated and -cutting-edge Rust programming language. Parity is licensed under the GPLv3, and can be used for all your Ethereum needs. +Parity's goal is to be the fastest, lightest, and most secure Ethereum client. We are developing Parity using the sophisticated and cutting-edge Rust programming language. Parity is licensed under the GPLv3, and can be used for all your Ethereum needs. + +Parity comes with a built-in wallet. To access [Parity Wallet](http://web3.site/) simply go to http://web3.site/ (if you don't have access to the internet, but still want to use the service, you can also use http://127.0.0.1:8180/). It includes various functionality allowing you to: -Parity comes with a built-in wallet. To access [Parity Wallet](http://web3.site/) simply go to http://web3.site/ (if you don't have access to the internet, but still want to use the service, you can also use http://127.0.0.1:8180/). It -includes various functionality allowing you to: - create and manage your Ethereum accounts; - manage your Ether and any Ethereum tokens; - create and register your own tokens; - and much more. -By default, Parity will also run a JSONRPC server on `127.0.0.1:8545`. This is fully configurable and supports a number -of RPC APIs. +By default, Parity will also run a JSONRPC server on `127.0.0.1:8545`. This is fully configurable and supports a number of RPC APIs. -If you run into an issue while using parity, feel free to file one in this repository -or hop on our [gitter chat room][gitter-url] to ask a question. We are glad to help! +If you run into an issue while using parity, feel free to file one in this repository or hop on our [gitter chat room](https://gitter.im/paritytech/parity) to ask a question. We are glad to help! **For security-critical issues**, please refer to the security policy outlined in `SECURITY.MD`. -Parity's current release is 1.6. You can download it at https://github.com/paritytech/parity/releases or follow the instructions -below to build from source. +Parity's current release is 1.7. You can download it at https://github.com/paritytech/parity/releases or follow the instructions below to build from source. ---- ## Build dependencies -**Parity requires Rust version 1.18.0 to build** +**Parity requires Rust version 1.19.0 to build** We recommend installing Rust through [rustup](https://www.rustup.rs/). If you don't already have rustup, you can install it like this: diff --git a/chainspec/Cargo.toml b/chainspec/Cargo.toml new file mode 100644 index 000000000..73daf795a --- /dev/null +++ b/chainspec/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "chainspec" +version = "0.1.0" +authors = ["debris "] + +[dependencies] +ethjson = { path = "../json" } +serde_json = "1.0" +serde_ignored = "0.0.4" diff --git a/chainspec/src/main.rs b/chainspec/src/main.rs new file mode 100644 index 000000000..bcef53f3f --- /dev/null +++ b/chainspec/src/main.rs @@ -0,0 +1,48 @@ +extern crate serde_json; +extern crate serde_ignored; +extern crate ethjson; + +use std::collections::BTreeSet; +use std::{fs, env, process}; +use ethjson::spec::Spec; + +fn quit(s: &str) -> ! { + println!("{}", s); + process::exit(1); +} + +fn main() { + let mut args = env::args(); + if args.len() != 2 { + quit("You need to specify chainspec.json\n\ + \n\ + ./chainspec "); + } + + let path = args.nth(1).expect("args.len() == 2; qed"); + let file = match fs::File::open(&path) { + Ok(file) => file, + Err(_) => quit(&format!("{} could not be opened", path)), + }; + + let mut unused = BTreeSet::new(); + let mut deserializer = serde_json::Deserializer::from_reader(file); + + let spec: Result = serde_ignored::deserialize(&mut deserializer, |field| { + unused.insert(field.to_string()); + }); + + if let Err(err) = spec { + quit(&format!("{} {}", path, err.to_string())); + } + + if !unused.is_empty() { + let err = unused.into_iter() + .map(|field| format!("{} unexpected field `{}`", path, field)) + .collect::>() + .join("\n"); + quit(&err); + } + + println!("{} is valid", path); +} diff --git a/dapps/Cargo.toml b/dapps/Cargo.toml index 75e15e396..143bbe30f 100644 --- a/dapps/Cargo.toml +++ b/dapps/Cargo.toml @@ -27,6 +27,7 @@ time = "0.1.35" unicase = "1.3" url = "1.0" zip = { version = "0.1", default-features = false } +itertools = "0.5" jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" } jsonrpc-http-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" } diff --git a/dapps/src/api/api.rs b/dapps/src/api/api.rs index 3f1c50de8..7bd7fa049 100644 --- a/dapps/src/api/api.rs +++ b/dapps/src/api/api.rs @@ -21,7 +21,7 @@ use hyper::method::Method; use hyper::status::StatusCode; use api::{response, types}; -use api::time::TimeChecker; +use api::time::{TimeChecker, MAX_DRIFT}; use apps::fetcher::Fetcher; use handlers::{self, extract_url}; use endpoint::{Endpoint, Handler, EndpointPath}; @@ -122,7 +122,6 @@ impl RestApiRouter { // Check time let time = { - const MAX_DRIFT: i64 = 500; let (status, message, details) = match time { Ok(Ok(diff)) if diff < MAX_DRIFT && diff > -MAX_DRIFT => { (HealthStatus::Ok, "".into(), diff) diff --git a/dapps/src/api/time.rs b/dapps/src/api/time.rs index b81b4a844..06b9cee7f 100644 --- a/dapps/src/api/time.rs +++ b/dapps/src/api/time.rs @@ -33,17 +33,22 @@ use std::io; use std::{fmt, mem, time}; - use std::collections::VecDeque; +use std::sync::atomic::{self, AtomicUsize}; +use std::sync::Arc; + use futures::{self, Future, BoxFuture}; -use futures_cpupool::CpuPool; +use futures::future::{self, IntoFuture}; +use futures_cpupool::{CpuPool, CpuFuture}; use ntp; use time::{Duration, Timespec}; -use util::{Arc, RwLock}; +use util::RwLock; /// Time checker error. #[derive(Debug, Clone, PartialEq)] pub enum Error { + /// No servers are currently available for a query. + NoServersAvailable, /// There was an error when trying to reach the NTP server. Ntp(String), /// IO error when reading NTP response. @@ -55,6 +60,7 @@ impl fmt::Display for Error { use self::Error::*; match *self { + NoServersAvailable => write!(fmt, "No NTP servers available"), Ntp(ref err) => write!(fmt, "NTP error: {}", err), Io(ref err) => write!(fmt, "Connection Error: {}", err), } @@ -71,58 +77,123 @@ impl From for Error { /// NTP time drift checker. pub trait Ntp { + /// Returned Future. + type Future: IntoFuture; + /// Returns the current time drift. - fn drift(&self) -> BoxFuture; + fn drift(&self) -> Self::Future; +} + +const SERVER_MAX_POLL_INTERVAL_SECS: u64 = 60; +#[derive(Debug)] +struct Server { + pub address: String, + next_call: RwLock, + failures: AtomicUsize, +} + +impl Server { + pub fn is_available(&self) -> bool { + *self.next_call.read() < time::Instant::now() + } + + pub fn report_success(&self) { + self.failures.store(0, atomic::Ordering::SeqCst); + self.update_next_call(1) + } + + pub fn report_failure(&self) { + let errors = self.failures.fetch_add(1, atomic::Ordering::SeqCst); + self.update_next_call(1 << errors) + } + + fn update_next_call(&self, delay: usize) { + *self.next_call.write() = time::Instant::now() + time::Duration::from_secs(delay as u64 * SERVER_MAX_POLL_INTERVAL_SECS); + } +} + +impl> From for Server { + fn from(t: T) -> Self { + Server { + address: t.as_ref().to_owned(), + next_call: RwLock::new(time::Instant::now()), + failures: Default::default(), + } + } } /// NTP client using the SNTP algorithm for calculating drift. #[derive(Clone)] pub struct SimpleNtp { - address: Arc, + addresses: Vec>, pool: CpuPool, } impl fmt::Debug for SimpleNtp { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Ntp {{ address: {} }}", self.address) + f + .debug_struct("SimpleNtp") + .field("addresses", &self.addresses) + .finish() } } impl SimpleNtp { - fn new(address: &str, pool: CpuPool) -> SimpleNtp { + fn new>(addresses: &[T], pool: CpuPool) -> SimpleNtp { SimpleNtp { - address: Arc::new(address.to_owned()), + addresses: addresses.iter().map(Server::from).map(Arc::new).collect(), pool: pool, } } } impl Ntp for SimpleNtp { - fn drift(&self) -> BoxFuture { - let address = self.address.clone(); - if &*address == "none" { - return futures::future::err(Error::Ntp("NTP server is not provided.".into())).boxed(); - } + type Future = future::Either< + CpuFuture, + future::FutureResult, + >; - self.pool.spawn_fn(move || { - let packet = ntp::request(&*address)?; - let dest_time = ::time::now_utc().to_timespec(); - let orig_time = Timespec::from(packet.orig_time); - let recv_time = Timespec::from(packet.recv_time); - let transmit_time = Timespec::from(packet.transmit_time); + fn drift(&self) -> Self::Future { + use self::future::Either::{A, B}; - let drift = ((recv_time - orig_time) + (transmit_time - dest_time)) / 2; + let server = self.addresses.iter().find(|server| server.is_available()); + server.map(|server| { + let server = server.clone(); + A(self.pool.spawn_fn(move || { + debug!(target: "dapps", "Fetching time from {}.", server.address); - Ok(drift) - }).boxed() + match ntp::request(&server.address) { + Ok(packet) => { + let dest_time = ::time::now_utc().to_timespec(); + let orig_time = Timespec::from(packet.orig_time); + let recv_time = Timespec::from(packet.recv_time); + let transmit_time = Timespec::from(packet.transmit_time); + + let drift = ((recv_time - orig_time) + (transmit_time - dest_time)) / 2; + + server.report_success(); + Ok(drift) + }, + Err(err) => { + server.report_failure(); + Err(err.into()) + }, + } + })) + }).unwrap_or_else(|| B(future::err(Error::NoServersAvailable))) } } // NOTE In a positive scenario first results will be seen after: -// MAX_RESULTS * UPDATE_TIMEOUT_OK_SECS seconds. -const MAX_RESULTS: usize = 7; -const UPDATE_TIMEOUT_OK_SECS: u64 = 30; -const UPDATE_TIMEOUT_ERR_SECS: u64 = 2; +// MAX_RESULTS * UPDATE_TIMEOUT_INCOMPLETE_SECS seconds. +const MAX_RESULTS: usize = 4; +const UPDATE_TIMEOUT_OK_SECS: u64 = 6 * 60 * 60; +const UPDATE_TIMEOUT_WARN_SECS: u64 = 15 * 60; +const UPDATE_TIMEOUT_ERR_SECS: u64 = 60; +const UPDATE_TIMEOUT_INCOMPLETE_SECS: u64 = 10; + +/// Maximal valid time drift. +pub const MAX_DRIFT: i64 = 500; #[derive(Debug, Clone)] /// A time checker. @@ -133,13 +204,13 @@ pub struct TimeChecker { impl TimeChecker { /// Creates new time checker given the NTP server address. - pub fn new(ntp_address: String, pool: CpuPool) -> Self { + pub fn new>(ntp_addresses: &[T], pool: CpuPool) -> Self { let last_result = Arc::new(RwLock::new( // Assume everything is ok at the very beginning. (time::Instant::now(), vec![Ok(0)].into()) )); - let ntp = SimpleNtp::new(&ntp_address, pool); + let ntp = SimpleNtp::new(ntp_addresses, pool); TimeChecker { ntp, @@ -148,22 +219,34 @@ impl TimeChecker { } } -impl TimeChecker { +impl TimeChecker where ::Future: Send + 'static { /// Updates the time pub fn update(&self) -> BoxFuture { + trace!(target: "dapps", "Updating time from NTP."); let last_result = self.last_result.clone(); - self.ntp.drift().then(move |res| { + self.ntp.drift().into_future().then(move |res| { + let res = res.map(|d| d.num_milliseconds()); + + if let Err(Error::NoServersAvailable) = res { + debug!(target: "dapps", "No NTP servers available. Selecting an older result."); + return select_result(last_result.read().1.iter()); + } + + // Update the results. let mut results = mem::replace(&mut last_result.write().1, VecDeque::new()); + let has_all_results = results.len() >= MAX_RESULTS; let valid_till = time::Instant::now() + time::Duration::from_secs( - if res.is_ok() && results.len() == MAX_RESULTS { - UPDATE_TIMEOUT_OK_SECS - } else { - UPDATE_TIMEOUT_ERR_SECS + match res { + Ok(time) if has_all_results && time < MAX_DRIFT => UPDATE_TIMEOUT_OK_SECS, + Ok(_) if has_all_results => UPDATE_TIMEOUT_WARN_SECS, + Err(_) if has_all_results => UPDATE_TIMEOUT_ERR_SECS, + _ => UPDATE_TIMEOUT_INCOMPLETE_SECS, } ); + trace!(target: "dapps", "New time drift received: {:?}", res); // Push the result. - results.push_back(res.map(|d| d.num_milliseconds())); + results.push_back(res); while results.len() > MAX_RESULTS { results.pop_front(); } @@ -208,7 +291,7 @@ mod tests { use std::cell::{Cell, RefCell}; use std::time::Instant; use time::Duration; - use futures::{self, BoxFuture, Future}; + use futures::{future, Future}; use super::{Ntp, TimeChecker, Error}; use util::RwLock; @@ -223,9 +306,11 @@ mod tests { } impl Ntp for FakeNtp { - fn drift(&self) -> BoxFuture { + type Future = future::FutureResult; + + fn drift(&self) -> Self::Future { self.1.set(self.1.get() + 1); - futures::future::ok(self.0.borrow_mut().pop().expect("Unexpected call to drift().")).boxed() + future::ok(self.0.borrow_mut().pop().expect("Unexpected call to drift().")) } } diff --git a/dapps/src/apps/mod.rs b/dapps/src/apps/mod.rs index 376b8a36f..c38c6784a 100644 --- a/dapps/src/apps/mod.rs +++ b/dapps/src/apps/mod.rs @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::collections::BTreeMap; use std::path::PathBuf; use std::sync::Arc; @@ -30,8 +29,8 @@ use {WebProxyTokens, ParentFrameSettings}; mod app; mod cache; -mod fs; mod ui; +pub mod fs; pub mod fetcher; pub mod manifest; @@ -64,9 +63,10 @@ pub fn all_endpoints( web_proxy_tokens: Arc, remote: Remote, fetch: F, -) -> Endpoints { +) -> (Vec, Endpoints) { // fetch fs dapps at first to avoid overwriting builtins - let mut pages = fs::local_endpoints(dapps_path, embeddable.clone()); + let mut pages = fs::local_endpoints(dapps_path.clone(), embeddable.clone()); + let local_endpoints: Vec = pages.keys().cloned().collect(); for path in extra_dapps { if let Some((id, endpoint)) = fs::local_endpoint(path.clone(), embeddable.clone()) { pages.insert(id, endpoint); @@ -80,10 +80,10 @@ pub fn all_endpoints( pages.insert("proxy".into(), ProxyPac::boxed(embeddable.clone(), dapps_domain.to_owned())); pages.insert(WEB_PATH.into(), Web::boxed(embeddable.clone(), web_proxy_tokens.clone(), remote.clone(), fetch.clone())); - Arc::new(pages) + (local_endpoints, pages) } -fn insert(pages: &mut BTreeMap>, id: &str, embed_at: Embeddable) { +fn insert(pages: &mut Endpoints, id: &str, embed_at: Embeddable) { pages.insert(id.to_owned(), Box::new(match embed_at { Embeddable::Yes(address) => PageEndpoint::new_safe_to_embed(T::default(), address), Embeddable::No => PageEndpoint::new(T::default()), diff --git a/dapps/src/endpoint.rs b/dapps/src/endpoint.rs index ea8fd0a38..ea5825b74 100644 --- a/dapps/src/endpoint.rs +++ b/dapps/src/endpoint.rs @@ -16,7 +16,6 @@ //! URL Endpoint traits -use std::sync::Arc; use std::collections::BTreeMap; use hyper::{self, server, net}; @@ -39,7 +38,7 @@ pub struct EndpointInfo { pub icon_url: String, } -pub type Endpoints = Arc>>; +pub type Endpoints = BTreeMap>; pub type Handler = server::Handler + Send; pub trait Endpoint : Send + Sync { diff --git a/dapps/src/handlers/mod.rs b/dapps/src/handlers/mod.rs index 7937ce667..a8beabe84 100644 --- a/dapps/src/handlers/mod.rs +++ b/dapps/src/handlers/mod.rs @@ -31,8 +31,7 @@ pub use self::redirect::Redirection; pub use self::streaming::StreamingHandler; use std::iter; -use util::Itertools; - +use itertools::Itertools; use url::Url; use hyper::{server, header, net, uri}; use {apps, address, Embeddable}; @@ -67,10 +66,20 @@ pub fn add_security_headers(headers: &mut header::Headers, embeddable_on: Embedd // Allow fonts from data: and HTTPS. b"font-src 'self' data: https:;".to_vec(), // Allow inline scripts and scripts eval (webpack/jsconsole) - b"script-src 'self' 'unsafe-inline' 'unsafe-eval';".to_vec(), - // Same restrictions as script-src (fallback) with additional + { + let script_src = embeddable_on.as_ref() + .map(|e| e.extra_script_src.iter() + .map(|&(ref host, port)| address(host, port)) + .join(" ") + ).unwrap_or_default(); + format!( + "script-src 'self' 'unsafe-inline' 'unsafe-eval' {};", + script_src + ).into_bytes() + }, + // Same restrictions as script-src with additional // blob: that is required for camera access (worker) - b"worker-src 'self' 'unsafe-inline' 'unsafe-eval' blob: ;".to_vec(), + b"worker-src 'self' 'unsafe-inline' 'unsafe-eval' https: blob:;".to_vec(), // Restrict everything else to the same origin. b"default-src 'self';".to_vec(), // Run in sandbox mode (although it's not fully safe since we allow same-origin and script) @@ -90,7 +99,7 @@ pub fn add_security_headers(headers: &mut header::Headers, embeddable_on: Embedd .into_iter() .chain(embed.extra_embed_on .iter() - .map(|&(ref host, port)| format!("{}:{}", host, port)) + .map(|&(ref host, port)| address(host, port)) ); let ancestors = if embed.host == "127.0.0.1" { diff --git a/dapps/src/lib.rs b/dapps/src/lib.rs index 0cb7024cc..135f0bb36 100644 --- a/dapps/src/lib.rs +++ b/dapps/src/lib.rs @@ -22,6 +22,7 @@ extern crate base32; extern crate futures; extern crate futures_cpupool; +extern crate itertools; extern crate linked_hash_map; extern crate mime_guess; extern crate ntp; @@ -69,9 +70,11 @@ mod web; #[cfg(test)] mod tests; +use std::collections::HashMap; +use std::mem; use std::path::PathBuf; use std::sync::Arc; -use std::collections::HashMap; +use util::RwLock; use jsonrpc_http_server::{self as http, hyper, Origin}; @@ -101,36 +104,59 @@ impl WebProxyTokens for F where F: Fn(String) -> Option + Send + Sync } /// Current supported endpoints. +#[derive(Default, Clone)] pub struct Endpoints { - endpoints: endpoint::Endpoints, + local_endpoints: Arc>>, + endpoints: Arc>, + dapps_path: PathBuf, + embeddable: Option, } impl Endpoints { /// Returns a current list of app endpoints. pub fn list(&self) -> Vec { - self.endpoints.iter().filter_map(|(ref k, ref e)| { + self.endpoints.read().iter().filter_map(|(ref k, ref e)| { e.info().map(|ref info| apps::App::from_info(k, info)) }).collect() } + + /// Check for any changes in the local dapps folder and update. + pub fn refresh_local_dapps(&self) { + let new_local = apps::fs::local_endpoints(&self.dapps_path, self.embeddable.clone()); + let old_local = mem::replace(&mut *self.local_endpoints.write(), new_local.keys().cloned().collect()); + let (_, to_remove): (_, Vec<_>) = old_local + .into_iter() + .partition(|k| new_local.contains_key(&k.clone())); + + let mut endpoints = self.endpoints.write(); + // remove the dead dapps + for k in to_remove { + endpoints.remove(&k); + } + // new dapps to be added + for (k, v) in new_local { + if !endpoints.contains_key(&k) { + endpoints.insert(k, v); + } + } + } } /// Dapps server as `jsonrpc-http-server` request middleware. pub struct Middleware { + endpoints: Endpoints, router: router::Router, - endpoints: endpoint::Endpoints, } impl Middleware { /// Get local endpoints handle. - pub fn endpoints(&self) -> Endpoints { - Endpoints { - endpoints: self.endpoints.clone(), - } + pub fn endpoints(&self) -> &Endpoints { + &self.endpoints } /// Creates new middleware for UI server. pub fn ui( - ntp_server: &str, + ntp_servers: &[String], pool: CpuPool, remote: Remote, dapps_domain: &str, @@ -146,7 +172,7 @@ impl Middleware { ).embeddable_on(None).allow_dapps(false)); let special = { let mut special = special_endpoints( - ntp_server, + ntp_servers, pool, content_fetcher.clone(), remote.clone(), @@ -164,18 +190,19 @@ impl Middleware { ); Middleware { - router: router, endpoints: Default::default(), + router: router, } } /// Creates new Dapps server middleware. pub fn dapps( - ntp_server: &str, + ntp_servers: &[String], pool: CpuPool, remote: Remote, ui_address: Option<(String, u16)>, extra_embed_on: Vec<(String, u16)>, + extra_script_src: Vec<(String, u16)>, dapps_path: PathBuf, extra_dapps: Vec, dapps_domain: &str, @@ -184,15 +211,15 @@ impl Middleware { web_proxy_tokens: Arc, fetch: F, ) -> Self { - let embeddable = as_embeddable(ui_address, extra_embed_on, dapps_domain); + let embeddable = as_embeddable(ui_address, extra_embed_on, extra_script_src, dapps_domain); let content_fetcher = Arc::new(apps::fetcher::ContentFetcher::new( hash_fetch::urlhint::URLHintContract::new(registrar), sync_status.clone(), remote.clone(), fetch.clone(), ).embeddable_on(embeddable.clone()).allow_dapps(true)); - let endpoints = apps::all_endpoints( - dapps_path, + let (local_endpoints, endpoints) = apps::all_endpoints( + dapps_path.clone(), extra_dapps, dapps_domain, embeddable.clone(), @@ -200,10 +227,16 @@ impl Middleware { remote.clone(), fetch.clone(), ); + let endpoints = Endpoints { + endpoints: Arc::new(RwLock::new(endpoints)), + dapps_path, + local_endpoints: Arc::new(RwLock::new(local_endpoints)), + embeddable: embeddable.clone(), + }; let special = { let mut special = special_endpoints( - ntp_server, + ntp_servers, pool, content_fetcher.clone(), remote.clone(), @@ -225,8 +258,8 @@ impl Middleware { ); Middleware { - router: router, - endpoints: endpoints, + endpoints, + router, } } } @@ -237,8 +270,8 @@ impl http::RequestMiddleware for Middleware { } } -fn special_endpoints( - ntp_server: &str, +fn special_endpoints>( + ntp_servers: &[T], pool: CpuPool, content_fetcher: Arc, remote: Remote, @@ -250,7 +283,7 @@ fn special_endpoints( special.insert(router::SpecialEndpoint::Api, Some(api::RestApi::new( content_fetcher, sync_status, - api::TimeChecker::new(ntp_server.into(), pool), + api::TimeChecker::new(ntp_servers, pool), remote, ))); special @@ -263,12 +296,14 @@ fn address(host: &str, port: u16) -> String { fn as_embeddable( ui_address: Option<(String, u16)>, extra_embed_on: Vec<(String, u16)>, + extra_script_src: Vec<(String, u16)>, dapps_domain: &str, ) -> Option { ui_address.map(|(host, port)| ParentFrameSettings { host, port, extra_embed_on, + extra_script_src, dapps_domain: dapps_domain.to_owned(), }) } @@ -289,8 +324,10 @@ pub struct ParentFrameSettings { pub host: String, /// Port pub port: u16, - /// Additional pages the pages can be embedded on. + /// Additional URLs the dapps can be embedded on. pub extra_embed_on: Vec<(String, u16)>, + /// Additional URLs the dapp scripts can be loaded from. + pub extra_script_src: Vec<(String, u16)>, /// Dapps Domain (web3.site) pub dapps_domain: String, } diff --git a/dapps/src/router.rs b/dapps/src/router.rs index 5cf92ff7e..2b74d51df 100644 --- a/dapps/src/router.rs +++ b/dapps/src/router.rs @@ -28,7 +28,8 @@ use jsonrpc_http_server as http; use apps; use apps::fetcher::Fetcher; -use endpoint::{Endpoint, Endpoints, EndpointPath, Handler}; +use endpoint::{Endpoint, EndpointPath, Handler}; +use Endpoints; use handlers; use Embeddable; @@ -50,26 +51,27 @@ pub struct Router { dapps_domain: String, } -impl http::RequestMiddleware for Router { - fn on_request(&self, req: &server::Request, control: &Control) -> http::RequestMiddlewareAction { +impl Router { + fn resolve_request(&self, req: &server::Request, control: Control, refresh_dapps: bool) -> (bool, Option>) { // Choose proper handler depending on path / domain let url = handlers::extract_url(req); let endpoint = extract_endpoint(&url, &self.dapps_domain); let referer = extract_referer_endpoint(req, &self.dapps_domain); let is_utils = endpoint.1 == SpecialEndpoint::Utils; - let is_origin_set = req.headers().get::().is_some(); let is_get_request = *req.method() == hyper::Method::Get; let is_head_request = *req.method() == hyper::Method::Head; + let has_dapp = |dapp: &str| self.endpoints + .as_ref() + .map_or(false, |endpoints| endpoints.endpoints.read().contains_key(dapp)); trace!(target: "dapps", "Routing request to {:?}. Details: {:?}", url, req); - - let control = control.clone(); debug!(target: "dapps", "Handling endpoint request: {:?}", endpoint); - let handler: Option> = match (endpoint.0, endpoint.1, referer) { + + (is_utils, match (endpoint.0, endpoint.1, referer) { // Handle invalid web requests that we can recover from (ref path, SpecialEndpoint::None, Some((ref referer, ref referer_url))) if referer.app_id == apps::WEB_PATH - && self.endpoints.as_ref().map(|ep| ep.contains_key(apps::WEB_PATH)).unwrap_or(false) + && has_dapp(apps::WEB_PATH) && !is_web_endpoint(path) => { @@ -88,11 +90,13 @@ impl http::RequestMiddleware for Router { .map(|special| special.to_async_handler(path.clone().unwrap_or_default(), control)) }, // Then delegate to dapp - (Some(ref path), _, _) if self.endpoints.as_ref().map(|ep| ep.contains_key(&path.app_id)).unwrap_or(false) => { + (Some(ref path), _, _) if has_dapp(&path.app_id) => { trace!(target: "dapps", "Resolving to local/builtin dapp."); Some(self.endpoints .as_ref() .expect("endpoints known to be set; qed") + .endpoints + .read() .get(&path.app_id) .expect("endpoints known to contain key; qed") .to_async_handler(path.clone(), control)) @@ -110,13 +114,19 @@ impl http::RequestMiddleware for Router { => { trace!(target: "dapps", "Resolving to 404."); - Some(Box::new(handlers::ContentHandler::error( - hyper::StatusCode::NotFound, - "404 Not Found", - "Requested content was not found.", - None, - self.embeddable_on.clone(), - ))) + if refresh_dapps { + debug!(target: "dapps", "Refreshing dapps and re-trying."); + self.endpoints.as_ref().map(|endpoints| endpoints.refresh_local_dapps()); + return self.resolve_request(req, control, false) + } else { + Some(Box::new(handlers::ContentHandler::error( + hyper::StatusCode::NotFound, + "404 Not Found", + "Requested content was not found.", + None, + self.embeddable_on.clone(), + ))) + } }, // Any other GET|HEAD requests to home page. _ if (is_get_request || is_head_request) && self.special.contains_key(&SpecialEndpoint::Home) => { @@ -130,8 +140,15 @@ impl http::RequestMiddleware for Router { trace!(target: "dapps", "Resolving to RPC call."); None } - }; + }) + } +} +impl http::RequestMiddleware for Router { + fn on_request(&self, req: &server::Request, control: &Control) -> http::RequestMiddlewareAction { + let control = control.clone(); + let is_origin_set = req.headers().get::().is_some(); + let (is_utils, handler) = self.resolve_request(req, control, self.endpoints.is_some()); match handler { Some(handler) => http::RequestMiddlewareAction::Respond { should_validate_hosts: !is_utils, diff --git a/dapps/src/tests/fetch.rs b/dapps/src/tests/fetch.rs index 8abc86196..f12323155 100644 --- a/dapps/src/tests/fetch.rs +++ b/dapps/src/tests/fetch.rs @@ -39,7 +39,7 @@ fn should_resolve_dapp() { // then response.assert_status("HTTP/1.1 404 Not Found"); - assert_eq!(registrar.calls.lock().len(), 2); + assert_eq!(registrar.calls.lock().len(), 4); assert_security_headers_for_embed(&response.headers); } diff --git a/dapps/src/tests/helpers/mod.rs b/dapps/src/tests/helpers/mod.rs index 2d9d5f341..30d3ba8f9 100644 --- a/dapps/src/tests/helpers/mod.rs +++ b/dapps/src/tests/helpers/mod.rs @@ -255,11 +255,12 @@ impl Server { fetch: F, ) -> Result { let middleware = Middleware::dapps( - "pool.ntp.org:123", + &["0.pool.ntp.org:123".into(), "1.pool.ntp.org:123".into()], CpuPool::new(4), remote, signer_address, vec![], + vec![], dapps_path, extra_dapps, DAPPS_DOMAIN.into(), diff --git a/dapps/src/tests/redirection.rs b/dapps/src/tests/redirection.rs index 1e9b039e2..81d3ec76c 100644 --- a/dapps/src/tests/redirection.rs +++ b/dapps/src/tests/redirection.rs @@ -204,4 +204,3 @@ fn should_serve_utils() { assert_eq!(response.body.contains("function(){"), true); assert_security_headers(&response.headers); } - diff --git a/dapps/src/web.rs b/dapps/src/web.rs index 637a5287e..5222f51b5 100644 --- a/dapps/src/web.rs +++ b/dapps/src/web.rs @@ -241,5 +241,3 @@ impl server::Handler for WebHandler { } } } - - diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 71e329201..c49e31898 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -47,12 +47,18 @@ num_cpus = "1.2" price-info = { path = "../price-info" } rand = "0.3" rlp = { path = "../util/rlp" } +rlp_derive = { path = "../util/rlp_derive" } rust-crypto = "0.2.34" rustc-hex = "1.0" semver = "0.6" stats = { path = "../util/stats" } time = "0.1" transient-hashmap = "0.4" +using_queue = { path = "../util/using_queue" } +table = { path = "../util/table" } +bloomable = { path = "../util/bloomable" } +vm = { path = "vm" } +wasm = { path = "wasm" } [dev-dependencies] native-contracts = { path = "native_contracts", features = ["test_contracts"] } diff --git a/ethcore/evm/Cargo.toml b/ethcore/evm/Cargo.toml index b48dd2346..2780703da 100644 --- a/ethcore/evm/Cargo.toml +++ b/ethcore/evm/Cargo.toml @@ -13,7 +13,9 @@ ethjson = { path = "../../json" } lazy_static = "0.2" log = "0.3" rlp = { path = "../../util/rlp" } +vm = { path = "../vm" } parity-wasm = "0.12" +ethcore-logger = { path = "../../logger" } wasm-utils = { git = "https://github.com/paritytech/wasm-utils" } [dev-dependencies] diff --git a/ethcore/evm/src/benches/mod.rs b/ethcore/evm/src/benches/mod.rs index 4463696d6..ecb7d379a 100644 --- a/ethcore/evm/src/benches/mod.rs +++ b/ethcore/evm/src/benches/mod.rs @@ -25,7 +25,7 @@ extern crate test; use self::test::{Bencher, black_box}; use util::*; -use evm::action_params::ActionParams; +use vm::ActionParams; use evm::{self, Factory, VMType}; use evm::tests::FakeExt; diff --git a/ethcore/evm/src/evm.rs b/ethcore/evm/src/evm.rs index c27caf8b3..d593143a6 100644 --- a/ethcore/evm/src/evm.rs +++ b/ethcore/evm/src/evm.rs @@ -17,142 +17,8 @@ //! Evm interface. use std::{ops, cmp, fmt}; -use util::{U128, U256, U512, trie}; -use action_params::ActionParams; -use {Ext}; - -use super::wasm; - -/// Evm errors. -#[derive(Debug, Clone, PartialEq)] -pub enum Error { - /// `OutOfGas` is returned when transaction execution runs out of gas. - /// The state should be reverted to the state from before the - /// transaction execution. But it does not mean that transaction - /// was invalid. Balance still should be transfered and nonce - /// should be increased. - OutOfGas, - /// `BadJumpDestination` is returned when execution tried to move - /// to position that wasn't marked with JUMPDEST instruction - BadJumpDestination { - /// Position the code tried to jump to. - destination: usize - }, - /// `BadInstructions` is returned when given instruction is not supported - BadInstruction { - /// Unrecognized opcode - instruction: u8, - }, - /// `StackUnderflow` when there is not enough stack elements to execute instruction - StackUnderflow { - /// Invoked instruction - instruction: &'static str, - /// How many stack elements was requested by instruction - wanted: usize, - /// How many elements were on stack - on_stack: usize - }, - /// When execution would exceed defined Stack Limit - OutOfStack { - /// Invoked instruction - instruction: &'static str, - /// How many stack elements instruction wanted to push - wanted: usize, - /// What was the stack limit - limit: usize - }, - /// Built-in contract failed on given input - BuiltIn(&'static str), - /// When execution tries to modify the state in static context - MutableCallInStaticContext, - /// Likely to cause consensus issues. - Internal(String), - /// Wasm runtime error - Wasm(String), -} - -impl From> for Error { - fn from(err: Box) -> Self { - Error::Internal(format!("Internal error: {}", err)) - } -} - -impl From for Error { - fn from(err: wasm::RuntimeError) -> Self { - Error::Wasm(format!("Runtime error: {:?}", err)) - } -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use self::Error::*; - match *self { - OutOfGas => write!(f, "Out of gas"), - BadJumpDestination { destination } => write!(f, "Bad jump destination {:x}", destination), - BadInstruction { instruction } => write!(f, "Bad instruction {:x}", instruction), - StackUnderflow { instruction, wanted, on_stack } => write!(f, "Stack underflow {} {}/{}", instruction, wanted, on_stack), - OutOfStack { instruction, wanted, limit } => write!(f, "Out of stack {} {}/{}", instruction, wanted, limit), - BuiltIn(name) => write!(f, "Built-in failed: {}", name), - Internal(ref msg) => write!(f, "Internal error: {}", msg), - MutableCallInStaticContext => write!(f, "Mutable call in static context"), - Wasm(ref msg) => write!(f, "Internal error: {}", msg), - } - } -} - -/// A specialized version of Result over EVM errors. -pub type Result = ::std::result::Result; - -/// Return data buffer. Holds memory from a previous call and a slice into that memory. -#[derive(Debug)] -pub struct ReturnData { - mem: Vec, - offset: usize, - size: usize, -} - -impl ::std::ops::Deref for ReturnData { - type Target = [u8]; - fn deref(&self) -> &[u8] { - &self.mem[self.offset..self.offset + self.size] - } -} - -impl ReturnData { - /// Create empty `ReturnData`. - pub fn empty() -> Self { - ReturnData { - mem: Vec::new(), - offset: 0, - size: 0, - } - } - /// Create `ReturnData` from give buffer and slice. - pub fn new(mem: Vec, offset: usize, size: usize) -> Self { - ReturnData { - mem: mem, - offset: offset, - size: size, - } - } -} - -/// Gas Left: either it is a known value, or it needs to be computed by processing -/// a return instruction. -#[derive(Debug)] -pub enum GasLeft { - /// Known gas left - Known(U256), - /// Return or Revert instruction must be processed. - NeedsReturn { - /// Amount of gas left. - gas_left: U256, - /// Return data buffer. - data: ReturnData, - /// Apply or revert state changes on revert. - apply_state: bool - }, -} +use util::{U128, U256, U512}; +use vm::{Ext, Result, ReturnData, GasLeft, Error}; /// Finalization result. Gas Left: either it is a known value, or it needs to be computed by processing /// a return instruction. @@ -281,15 +147,6 @@ impl CostType for usize { } } -/// Evm interface -pub trait Evm { - /// This function should be used to execute transaction. - /// - /// It returns either an error, a known amount of gas left, or parameters to be used - /// to compute the final gas left. - fn exec(&mut self, params: ActionParams, ext: &mut Ext) -> Result; -} - #[cfg(test)] mod tests { use util::U256; diff --git a/ethcore/evm/src/factory.rs b/ethcore/evm/src/factory.rs index 2d8934ca1..20275dbff 100644 --- a/ethcore/evm/src/factory.rs +++ b/ethcore/evm/src/factory.rs @@ -17,7 +17,7 @@ //! Evm factory. //! use std::sync::Arc; -use evm::Evm; +use vm::Vm; use util::U256; use super::interpreter::SharedCache; use super::vmtype::VMType; @@ -33,7 +33,7 @@ impl Factory { /// Create fresh instance of VM /// Might choose implementation depending on supplied gas. #[cfg(feature = "jit")] - pub fn create(&self, gas: U256) -> Box { + pub fn create(&self, gas: U256) -> Box { match self.evm { VMType::Jit => { Box::new(super::jit::JitEvm::default()) @@ -49,7 +49,7 @@ impl Factory { /// Create fresh instance of VM /// Might choose implementation depending on supplied gas. #[cfg(not(feature = "jit"))] - pub fn create(&self, gas: U256) -> Box { + pub fn create(&self, gas: U256) -> Box { match self.evm { VMType::Interpreter => if Self::can_fit_in_usize(gas) { Box::new(super::interpreter::Interpreter::::new(self.evm_cache.clone())) diff --git a/ethcore/evm/src/interpreter/gasometer.rs b/ethcore/evm/src/interpreter/gasometer.rs index c2dcf5412..161c7db39 100644 --- a/ethcore/evm/src/interpreter/gasometer.rs +++ b/ethcore/evm/src/interpreter/gasometer.rs @@ -14,18 +14,19 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use std::cmp; use util::*; use super::u256_to_address; -use {evm, ext}; +use {evm, vm}; use instructions::{self, Instruction, InstructionInfo}; use interpreter::stack::Stack; -use schedule::Schedule; +use vm::Schedule; macro_rules! overflowing { ($x: expr) => {{ let (v, overflow) = $x; - if overflow { return Err(evm::Error::OutOfGas); } + if overflow { return Err(vm::Error::OutOfGas); } v }} } @@ -59,16 +60,16 @@ impl Gasometer { } } - pub fn verify_gas(&self, gas_cost: &Gas) -> evm::Result<()> { + pub fn verify_gas(&self, gas_cost: &Gas) -> vm::Result<()> { match &self.current_gas < gas_cost { - true => Err(evm::Error::OutOfGas), + true => Err(vm::Error::OutOfGas), false => Ok(()) } } /// How much gas is provided to a CALL/CREATE, given that we need to deduct `needed` for this operation /// and that we `requested` some. - pub fn gas_provided(&self, schedule: &Schedule, needed: Gas, requested: Option) -> evm::Result { + pub fn gas_provided(&self, schedule: &Schedule, needed: Gas, requested: Option) -> vm::Result { // Try converting requested gas to `Gas` (`U256/u64`) // but in EIP150 even if we request more we should never fail from OOG let requested = requested.map(Gas::from_u256); @@ -82,7 +83,7 @@ impl Gasometer { }; if let Some(Ok(r)) = requested { - Ok(min(r, max_gas_provided)) + Ok(cmp::min(r, max_gas_provided)) } else { Ok(max_gas_provided) } @@ -107,12 +108,12 @@ impl Gasometer { /// it will be the amount of gas that the current context provides to the child context. pub fn requirements( &mut self, - ext: &ext::Ext, + ext: &vm::Ext, instruction: Instruction, info: &InstructionInfo, stack: &Stack, current_mem_size: usize, - ) -> evm::Result> { + ) -> vm::Result> { let schedule = ext.schedule(); let tier = instructions::get_tier_idx(info.tier); let default_gas = Gas::from(schedule.tier_step_gas[tier]); @@ -291,7 +292,7 @@ impl Gasometer { }) } - fn mem_gas_cost(&self, schedule: &Schedule, current_mem_size: usize, mem_size: &Gas) -> evm::Result<(Gas, Gas, usize)> { + fn mem_gas_cost(&self, schedule: &Schedule, current_mem_size: usize, mem_size: &Gas) -> vm::Result<(Gas, Gas, usize)> { let gas_for_mem = |mem_size: Gas| { let s = mem_size >> 5; // s * memory_gas + s * s / quad_coeff_div @@ -319,12 +320,12 @@ impl Gasometer { #[inline] -fn mem_needed_const(mem: &U256, add: usize) -> evm::Result { +fn mem_needed_const(mem: &U256, add: usize) -> vm::Result { Gas::from_u256(overflowing!(mem.overflowing_add(U256::from(add)))) } #[inline] -fn mem_needed(offset: &U256, size: &U256) -> evm::Result { +fn mem_needed(offset: &U256, size: &U256) -> vm::Result { if size.is_zero() { return Ok(Gas::from(0)); } diff --git a/ethcore/evm/src/interpreter/memory.rs b/ethcore/evm/src/interpreter/memory.rs index 017b5777d..a13c99a82 100644 --- a/ethcore/evm/src/interpreter/memory.rs +++ b/ethcore/evm/src/interpreter/memory.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . use util::U256; -use {ReturnData}; +use vm::ReturnData; const MAX_RETURN_WASTE_BYTES: usize = 16384; diff --git a/ethcore/evm/src/interpreter/mod.rs b/ethcore/evm/src/interpreter/mod.rs index 30b431912..3069ab2fe 100644 --- a/ethcore/evm/src/interpreter/mod.rs +++ b/ethcore/evm/src/interpreter/mod.rs @@ -23,17 +23,23 @@ mod stack; mod memory; mod shared_cache; +use std::marker::PhantomData; +use std::{cmp, mem}; +use std::sync::Arc; + +use vm::{ + self, ActionParams, ActionValue, CallType, MessageCallResult, + ContractCreateResult, CreateContractAddress, ReturnData, GasLeft +}; + +use evm::CostType; +use instructions::{self, Instruction, InstructionInfo}; + use self::gasometer::Gasometer; use self::stack::{Stack, VecStack}; use self::memory::Memory; pub use self::shared_cache::SharedCache; -use std::marker::PhantomData; -use action_params::{ActionParams, ActionValue}; -use call_type::CallType; -use instructions::{self, Instruction, InstructionInfo}; -use evm::{self, GasLeft, CostType, ReturnData}; -use ext::{self, MessageCallResult, ContractCreateResult, CreateContractAddress}; use bit_set::BitSet; use util::*; @@ -107,8 +113,8 @@ pub struct Interpreter { _type: PhantomData, } -impl evm::Evm for Interpreter { - fn exec(&mut self, params: ActionParams, ext: &mut ext::Ext) -> evm::Result { +impl vm::Vm for Interpreter { + fn exec(&mut self, params: ActionParams, ext: &mut vm::Ext) -> vm::Result { self.mem.clear(); let mut informant = informant::EvmInformant::new(ext.depth()); @@ -205,7 +211,7 @@ impl Interpreter { } } - fn verify_instruction(&self, ext: &ext::Ext, instruction: Instruction, info: &InstructionInfo, stack: &Stack) -> evm::Result<()> { + fn verify_instruction(&self, ext: &vm::Ext, instruction: Instruction, info: &InstructionInfo, stack: &Stack) -> vm::Result<()> { let schedule = ext.schedule(); if (instruction == instructions::DELEGATECALL && !schedule.have_delegate_call) || @@ -214,25 +220,25 @@ impl Interpreter { ((instruction == instructions::RETURNDATACOPY || instruction == instructions::RETURNDATASIZE) && !schedule.have_return_data) || (instruction == instructions::REVERT && !schedule.have_revert) { - return Err(evm::Error::BadInstruction { + return Err(vm::Error::BadInstruction { instruction: instruction }); } if info.tier == instructions::GasPriceTier::Invalid { - return Err(evm::Error::BadInstruction { + return Err(vm::Error::BadInstruction { instruction: instruction }); } if !stack.has(info.args) { - Err(evm::Error::StackUnderflow { + Err(vm::Error::StackUnderflow { instruction: info.name, wanted: info.args, on_stack: stack.size() }) } else if stack.size() - info.args + info.ret > schedule.stack_limit { - Err(evm::Error::OutOfStack { + Err(vm::Error::OutOfStack { instruction: info.name, wanted: info.ret - info.args, limit: schedule.stack_limit @@ -272,12 +278,12 @@ impl Interpreter { &mut self, gas: Cost, params: &ActionParams, - ext: &mut ext::Ext, + ext: &mut vm::Ext, instruction: Instruction, code: &mut CodeReader, stack: &mut Stack, provided: Option - ) -> evm::Result> { + ) -> vm::Result> { match instruction { instructions::JUMP => { let jump = stack.pop_back(); @@ -593,13 +599,13 @@ impl Interpreter { } } - fn verify_jump(&self, jump_u: U256, valid_jump_destinations: &BitSet) -> evm::Result { + fn verify_jump(&self, jump_u: U256, valid_jump_destinations: &BitSet) -> vm::Result { let jump = jump_u.low_u64() as usize; if valid_jump_destinations.contains(jump) && U256::from(jump) == jump_u { Ok(jump) } else { - Err(evm::Error::BadJumpDestination { + Err(vm::Error::BadJumpDestination { destination: jump }) } @@ -617,7 +623,7 @@ impl Interpreter { } } - fn exec_stack_instruction(&self, instruction: Instruction, stack: &mut Stack) -> evm::Result<()> { + fn exec_stack_instruction(&self, instruction: Instruction, stack: &mut Stack) -> vm::Result<()> { match instruction { instructions::DUP1...instructions::DUP16 => { let position = instructions::get_dup_position(instruction); @@ -822,7 +828,7 @@ impl Interpreter { } }, _ => { - return Err(evm::Error::BadInstruction { + return Err(vm::Error::BadInstruction { instruction: instruction }); } diff --git a/ethcore/evm/src/jit.rs b/ethcore/evm/src/jit.rs index f27e9b5d3..22262cbb6 100644 --- a/ethcore/evm/src/jit.rs +++ b/ethcore/evm/src/jit.rs @@ -19,6 +19,7 @@ use util::*; use evmjit; use evm::{self, GasLeft}; use evm::CallType; +use vm::{self, Vm}; /// Should be used to convert jit types to ethcore trait FromJit: Sized { @@ -318,7 +319,7 @@ pub struct JitEvm { context: Option, } -impl evm::Evm for JitEvm { +impl vm::Vm for JitEvm { fn exec(&mut self, params: ActionParams, ext: &mut evm::Ext) -> evm::Result { // Dirty hack. This is unsafe, but we interact with ffi, so it's justified. let ext_adapter: ExtAdapter<'static> = unsafe { ::std::mem::transmute(ExtAdapter::new(ext, params.address.clone())) }; @@ -370,8 +371,8 @@ impl evm::Evm for JitEvm { ext.suicide(&Address::from_jit(&context.suicide_refund_address())); Ok(GasLeft::Known(U256::from(context.gas_left()))) }, - evmjit::ReturnCode::OutOfGas => Err(evm::Error::OutOfGas), - _err => Err(evm::Error::Internal) + evmjit::ReturnCode::OutOfGas => Err(vm::Error::OutOfGas), + _err => Err(vm::Error::Internal) } } } diff --git a/ethcore/evm/src/lib.rs b/ethcore/evm/src/lib.rs index fa4d12315..833b26664 100644 --- a/ethcore/evm/src/lib.rs +++ b/ethcore/evm/src/lib.rs @@ -24,11 +24,12 @@ extern crate ethjson; extern crate rlp; extern crate parity_wasm; extern crate wasm_utils; +extern crate ethcore_logger; +extern crate vm; #[macro_use] extern crate lazy_static; -#[macro_use] extern crate log; #[cfg(feature = "jit")] @@ -37,14 +38,8 @@ extern crate evmjit; #[cfg(test)] extern crate rustc_hex; -pub mod action_params; -pub mod call_type; -pub mod env_info; -pub mod ext; pub mod evm; pub mod interpreter; -pub mod schedule; -pub mod wasm; #[macro_use] pub mod factory; @@ -59,12 +54,12 @@ mod tests; #[cfg(all(feature="benches", test))] mod benches; -pub use self::action_params::ActionParams; -pub use self::call_type::CallType; -pub use self::env_info::EnvInfo; -pub use self::evm::{Evm, Error, Finalize, FinalizationResult, GasLeft, Result, CostType, ReturnData}; -pub use self::ext::{Ext, ContractCreateResult, MessageCallResult, CreateContractAddress}; +pub use vm::{ + Schedule, CleanDustMode, EnvInfo, CallType, ActionParams, Ext, + ContractCreateResult, MessageCallResult, CreateContractAddress, + GasLeft, ReturnData +}; +pub use self::evm::{Finalize, FinalizationResult, CostType}; pub use self::instructions::{InstructionInfo, INSTRUCTIONS, push_bytes}; pub use self::vmtype::VMType; pub use self::factory::Factory; -pub use self::schedule::{Schedule, CleanDustMode}; diff --git a/ethcore/evm/src/tests.rs b/ethcore/evm/src/tests.rs index d0502f79a..7263d1779 100644 --- a/ethcore/evm/src/tests.rs +++ b/ethcore/evm/src/tests.rs @@ -15,212 +15,17 @@ // along with Parity. If not, see . use std::fmt::Debug; +use std::str::FromStr; +use std::hash::Hash; +use std::sync::Arc; +use std::collections::{HashMap, HashSet}; use rustc_hex::FromHex; use util::*; -use action_params::{ActionParams, ActionValue}; -use env_info::EnvInfo; -use call_type::CallType; -use schedule::Schedule; -use evm::{self, GasLeft, ReturnData}; -use ext::{Ext, ContractCreateResult, MessageCallResult, CreateContractAddress}; +use vm::{self, ActionParams, ActionValue}; +use vm::tests::{FakeExt, FakeCall, FakeCallType, test_finalize}; use factory::Factory; use vmtype::VMType; -pub struct FakeLogEntry { - topics: Vec, - data: Bytes -} - -#[derive(PartialEq, Eq, Hash, Debug)] -pub enum FakeCallType { - Call, Create -} - -#[derive(PartialEq, Eq, Hash, Debug)] -pub struct FakeCall { - pub call_type: FakeCallType, - pub gas: U256, - pub sender_address: Option
, - pub receive_address: Option
, - pub value: Option, - pub data: Bytes, - pub code_address: Option
, -} - -/// Fake externalities test structure. -/// -/// Can't do recursive calls. -#[derive(Default)] -pub struct FakeExt { - pub store: HashMap, - pub suicides: HashSet
, - pub calls: HashSet, - sstore_clears: usize, - depth: usize, - blockhashes: HashMap, - codes: HashMap>, - logs: Vec, - info: EnvInfo, - schedule: Schedule, - balances: HashMap, -} - -// similar to the normal `finalize` function, but ignoring NeedsReturn. -fn test_finalize(res: Result) -> Result { - match res { - Ok(GasLeft::Known(gas)) => Ok(gas), - Ok(GasLeft::NeedsReturn{..}) => unimplemented!(), // since ret is unimplemented. - Err(e) => Err(e), - } -} - -impl FakeExt { - pub fn new() -> Self { - FakeExt::default() - } -} - -impl Default for Schedule { - fn default() -> Self { - Schedule::new_frontier() - } -} - -impl Ext for FakeExt { - fn storage_at(&self, key: &H256) -> evm::Result { - Ok(self.store.get(key).unwrap_or(&H256::new()).clone()) - } - - fn set_storage(&mut self, key: H256, value: H256) -> evm::Result<()> { - self.store.insert(key, value); - Ok(()) - } - - fn exists(&self, address: &Address) -> evm::Result { - Ok(self.balances.contains_key(address)) - } - - fn exists_and_not_null(&self, address: &Address) -> evm::Result { - Ok(self.balances.get(address).map_or(false, |b| !b.is_zero())) - } - - fn origin_balance(&self) -> evm::Result { - unimplemented!() - } - - fn balance(&self, address: &Address) -> evm::Result { - Ok(self.balances[address]) - } - - fn blockhash(&mut self, number: &U256) -> H256 { - self.blockhashes.get(number).unwrap_or(&H256::new()).clone() - } - - fn create(&mut self, gas: &U256, value: &U256, code: &[u8], _address: CreateContractAddress) -> ContractCreateResult { - self.calls.insert(FakeCall { - call_type: FakeCallType::Create, - gas: *gas, - sender_address: None, - receive_address: None, - value: Some(*value), - data: code.to_vec(), - code_address: None - }); - ContractCreateResult::Failed - } - - fn call(&mut self, - gas: &U256, - sender_address: &Address, - receive_address: &Address, - value: Option, - data: &[u8], - code_address: &Address, - _output: &mut [u8], - _call_type: CallType - ) -> MessageCallResult { - - self.calls.insert(FakeCall { - call_type: FakeCallType::Call, - gas: *gas, - sender_address: Some(sender_address.clone()), - receive_address: Some(receive_address.clone()), - value: value, - data: data.to_vec(), - code_address: Some(code_address.clone()) - }); - MessageCallResult::Success(*gas, ReturnData::empty()) - } - - fn extcode(&self, address: &Address) -> evm::Result> { - Ok(self.codes.get(address).unwrap_or(&Arc::new(Bytes::new())).clone()) - } - - fn extcodesize(&self, address: &Address) -> evm::Result { - Ok(self.codes.get(address).map_or(0, |c| c.len())) - } - - fn log(&mut self, topics: Vec, data: &[u8]) -> evm::Result<()> { - self.logs.push(FakeLogEntry { - topics: topics, - data: data.to_vec() - }); - Ok(()) - } - - fn ret(self, _gas: &U256, _data: &ReturnData) -> evm::Result { - unimplemented!(); - } - - fn suicide(&mut self, refund_address: &Address) -> evm::Result<()> { - self.suicides.insert(refund_address.clone()); - Ok(()) - } - - fn schedule(&self) -> &Schedule { - &self.schedule - } - - fn env_info(&self) -> &EnvInfo { - &self.info - } - - fn depth(&self) -> usize { - self.depth - } - - fn inc_sstore_clears(&mut self) { - self.sstore_clears += 1; - } -} - -#[test] -fn test_stack_underflow() { - let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); - let code = "01600055".from_hex().unwrap(); - - let mut params = ActionParams::default(); - params.address = address.clone(); - params.gas = U256::from(100_000); - params.code = Some(Arc::new(code)); - let mut ext = FakeExt::new(); - - let err = { - let mut vm : Box = Box::new(super::interpreter::Interpreter::::new(Arc::new(super::interpreter::SharedCache::default()))); - test_finalize(vm.exec(params, &mut ext)).unwrap_err() - }; - - match err { - evm::Error::StackUnderflow {wanted, on_stack, ..} => { - assert_eq!(wanted, 2); - assert_eq!(on_stack, 0); - } - _ => { - assert!(false, "Expected StackUndeflow") - } - }; -} - evm_test!{test_add: test_add_jit, test_add_int} fn test_add(factory: super::Factory) { let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); @@ -849,7 +654,7 @@ fn test_badinstruction_int() { }; match err { - evm::Error::BadInstruction { instruction: 0xaf } => (), + vm::Error::BadInstruction { instruction: 0xaf } => (), _ => assert!(false, "Expected bad instruction") } } diff --git a/ethcore/light/Cargo.toml b/ethcore/light/Cargo.toml index 09f2e0e1a..9fda78f47 100644 --- a/ethcore/light/Cargo.toml +++ b/ethcore/light/Cargo.toml @@ -19,7 +19,9 @@ ethcore-io = { path = "../../util/io" } ethcore-ipc = { path = "../../ipc/rpc", optional = true } ethcore-devtools = { path = "../../devtools" } evm = { path = "../evm" } +vm = { path = "../vm" } rlp = { path = "../../util/rlp" } +rlp_derive = { path = "../../util/rlp_derive" } time = "0.1" smallvec = "0.4" futures = "0.1" diff --git a/ethcore/light/src/client/mod.rs b/ethcore/light/src/client/mod.rs index ec15f79a7..9c8e1da50 100644 --- a/ethcore/light/src/client/mod.rs +++ b/ethcore/light/src/client/mod.rs @@ -105,8 +105,8 @@ pub trait LightChainClient: Send + Sync { /// Get an iterator over a block and its ancestry. fn ancestry_iter<'a>(&'a self, start: BlockId) -> Box + 'a>; - /// Get the signing network ID. - fn signing_network_id(&self) -> Option; + /// Get the signing chain ID. + fn signing_chain_id(&self) -> Option; /// Get environment info for execution at a given block. /// Fails if that block's header is not stored. @@ -287,9 +287,9 @@ impl Client { self.chain.ancestry_iter(start) } - /// Get the signing network id. - pub fn signing_network_id(&self) -> Option { - self.engine.signing_network_id(&self.latest_env_info()) + /// Get the signing chain id. + pub fn signing_chain_id(&self) -> Option { + self.engine.signing_chain_id(&self.latest_env_info()) } /// Flush the header queue. @@ -552,8 +552,8 @@ impl LightChainClient for Client { Box::new(Client::ancestry_iter(self, start)) } - fn signing_network_id(&self) -> Option { - Client::signing_network_id(self) + fn signing_chain_id(&self) -> Option { + Client::signing_chain_id(self) } fn env_info(&self, id: BlockId) -> Option { diff --git a/ethcore/light/src/lib.rs b/ethcore/light/src/lib.rs index 49928bd98..c2ab483d2 100644 --- a/ethcore/light/src/lib.rs +++ b/ethcore/light/src/lib.rs @@ -76,10 +76,13 @@ extern crate futures; extern crate itertools; extern crate rand; extern crate rlp; +#[macro_use] +extern crate rlp_derive; extern crate serde; extern crate smallvec; extern crate stats; extern crate time; +extern crate vm; #[cfg(feature = "ipc")] extern crate ethcore_ipc as ipc; diff --git a/ethcore/light/src/on_demand/request.rs b/ethcore/light/src/on_demand/request.rs index 09dd6cc89..f35373a5c 100644 --- a/ethcore/light/src/on_demand/request.rs +++ b/ethcore/light/src/on_demand/request.rs @@ -24,7 +24,7 @@ use ethcore::engines::{Engine, StateDependentProof}; use ethcore::receipt::Receipt; use ethcore::state::{self, ProvedExecution}; use ethcore::transaction::SignedTransaction; -use evm::env_info::EnvInfo; +use vm::EnvInfo; use request::{self as net_request, IncompleteRequest, CompleteRequest, Output, OutputKind, Field}; diff --git a/ethcore/light/src/types/request/mod.rs b/ethcore/light/src/types/request/mod.rs index c9863a354..0139564ee 100644 --- a/ethcore/light/src/types/request/mod.rs +++ b/ethcore/light/src/types/request/mod.rs @@ -677,7 +677,7 @@ pub mod header { use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; /// Potentially incomplete headers request. - #[derive(Debug, Clone, PartialEq, Eq)] + #[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)] pub struct Incomplete { /// Start block. pub start: Field, @@ -689,27 +689,6 @@ pub mod header { pub reverse: bool, } - impl Decodable for Incomplete { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(Incomplete { - start: rlp.val_at(0)?, - skip: rlp.val_at(1)?, - max: rlp.val_at(2)?, - reverse: rlp.val_at(3)? - }) - } - } - - impl Encodable for Incomplete { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(4) - .append(&self.start) - .append(&self.skip) - .append(&self.max) - .append(&self.reverse); - } - } - impl super::IncompleteRequest for Incomplete { type Complete = Complete; type Response = Response; @@ -811,26 +790,12 @@ pub mod header_proof { use util::{Bytes, U256, H256}; /// Potentially incomplete header proof request. - #[derive(Debug, Clone, PartialEq, Eq)] + #[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)] pub struct Incomplete { /// Block number. pub num: Field, } - impl Decodable for Incomplete { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(Incomplete { - num: rlp.val_at(0)?, - }) - } - } - - impl Encodable for Incomplete { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(1).append(&self.num); - } - } - impl super::IncompleteRequest for Incomplete { type Complete = Complete; type Response = Response; @@ -916,30 +881,15 @@ pub mod header_proof { /// Request and response for transaction index. pub mod transaction_index { use super::{Field, NoSuchOutput, OutputKind, Output}; - use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; use util::H256; /// Potentially incomplete transaction index request. - #[derive(Debug, Clone, PartialEq, Eq)] + #[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)] pub struct Incomplete { /// Transaction hash to get index for. pub hash: Field, } - impl Decodable for Incomplete { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(Incomplete { - hash: rlp.val_at(0)?, - }) - } - } - - impl Encodable for Incomplete { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(1).append(&self.hash); - } - } - impl super::IncompleteRequest for Incomplete { type Complete = Complete; type Response = Response; @@ -986,7 +936,7 @@ pub mod transaction_index { } /// The output of a request for transaction index. - #[derive(Debug, Clone, PartialEq, Eq)] + #[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)] pub struct Response { /// Block number. pub num: u64, @@ -1003,55 +953,21 @@ pub mod transaction_index { f(1, Output::Hash(self.hash)); } } - - impl Decodable for Response { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(Response { - num: rlp.val_at(0)?, - hash: rlp.val_at(1)?, - index: rlp.val_at(2)?, - }) - } - } - - impl Encodable for Response { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(3) - .append(&self.num) - .append(&self.hash) - .append(&self.index); - } - } } /// Request and response for block receipts pub mod block_receipts { use super::{Field, NoSuchOutput, OutputKind, Output}; use ethcore::receipt::Receipt; - use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; use util::H256; /// Potentially incomplete block receipts request. - #[derive(Debug, Clone, PartialEq, Eq)] + #[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)] pub struct Incomplete { /// Block hash to get receipts for. pub hash: Field, } - impl Decodable for Incomplete { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(Incomplete { - hash: rlp.val_at(0)?, - }) - } - } - - impl Encodable for Incomplete { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(1).append(&self.hash); - } - } - impl super::IncompleteRequest for Incomplete { type Complete = Complete; type Response = Response; @@ -1095,7 +1011,7 @@ pub mod block_receipts { } /// The output of a request for block receipts. - #[derive(Debug, Clone, PartialEq, Eq)] + #[derive(Debug, Clone, PartialEq, Eq, RlpEncodableWrapper, RlpDecodableWrapper)] pub struct Response { /// The block receipts. pub receipts: Vec @@ -1105,20 +1021,6 @@ pub mod block_receipts { /// Fill reusable outputs by providing them to the function. fn fill_outputs(&self, _: F) where F: FnMut(usize, Output) {} } - - impl Decodable for Response { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(Response { - receipts: rlp.as_list()?, - }) - } - } - - impl Encodable for Response { - fn rlp_append(&self, s: &mut RlpStream) { - s.append_list(&self.receipts); - } - } } /// Request and response for a block body @@ -1129,26 +1031,12 @@ pub mod block_body { use util::H256; /// Potentially incomplete block body request. - #[derive(Debug, Clone, PartialEq, Eq)] + #[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)] pub struct Incomplete { /// Block hash to get receipts for. pub hash: Field, } - impl Decodable for Incomplete { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(Incomplete { - hash: rlp.val_at(0)?, - }) - } - } - - impl Encodable for Incomplete { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(1).append(&self.hash); - } - } - impl super::IncompleteRequest for Incomplete { type Complete = Complete; type Response = Response; @@ -1228,11 +1116,10 @@ pub mod block_body { /// A request for an account proof. pub mod account { use super::{Field, NoSuchOutput, OutputKind, Output}; - use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; use util::{Bytes, U256, H256}; /// Potentially incomplete request for an account proof. - #[derive(Debug, Clone, PartialEq, Eq)] + #[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)] pub struct Incomplete { /// Block hash to request state proof for. pub block_hash: Field, @@ -1240,23 +1127,6 @@ pub mod account { pub address_hash: Field, } - impl Decodable for Incomplete { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(Incomplete { - block_hash: rlp.val_at(0)?, - address_hash: rlp.val_at(1)?, - }) - } - } - - impl Encodable for Incomplete { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(2) - .append(&self.block_hash) - .append(&self.address_hash); - } - } - impl super::IncompleteRequest for Incomplete { type Complete = Complete; type Response = Response; @@ -1319,7 +1189,7 @@ pub mod account { } /// The output of a request for an account state proof. - #[derive(Debug, Clone, PartialEq, Eq)] + #[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)] pub struct Response { /// Inclusion/exclusion proof pub proof: Vec, @@ -1340,39 +1210,15 @@ pub mod account { f(1, Output::Hash(self.storage_root)); } } - - impl Decodable for Response { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(Response { - proof: rlp.list_at(0)?, - nonce: rlp.val_at(1)?, - balance: rlp.val_at(2)?, - code_hash: rlp.val_at(3)?, - storage_root: rlp.val_at(4)? - }) - } - } - - impl Encodable for Response { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(5) - .append_list::,_>(&self.proof[..]) - .append(&self.nonce) - .append(&self.balance) - .append(&self.code_hash) - .append(&self.storage_root); - } - } } /// A request for a storage proof. pub mod storage { use super::{Field, NoSuchOutput, OutputKind, Output}; - use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; use util::{Bytes, H256}; /// Potentially incomplete request for an storage proof. - #[derive(Debug, Clone, PartialEq, Eq)] + #[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)] pub struct Incomplete { /// Block hash to request state proof for. pub block_hash: Field, @@ -1382,25 +1228,6 @@ pub mod storage { pub key_hash: Field, } - impl Decodable for Incomplete { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(Incomplete { - block_hash: rlp.val_at(0)?, - address_hash: rlp.val_at(1)?, - key_hash: rlp.val_at(2)?, - }) - } - } - - impl Encodable for Incomplete { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(3) - .append(&self.block_hash) - .append(&self.address_hash) - .append(&self.key_hash); - } - } - impl super::IncompleteRequest for Incomplete { type Complete = Complete; type Response = Response; @@ -1477,7 +1304,7 @@ pub mod storage { } /// The output of a request for an account state proof. - #[derive(Debug, Clone, PartialEq, Eq)] + #[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)] pub struct Response { /// Inclusion/exclusion proof pub proof: Vec, @@ -1491,33 +1318,15 @@ pub mod storage { f(0, Output::Hash(self.value)); } } - - impl Decodable for Response { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(Response { - proof: rlp.list_at(0)?, - value: rlp.val_at(1)?, - }) - } - } - - impl Encodable for Response { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(2) - .append_list::,_>(&self.proof[..]) - .append(&self.value); - } - } } /// A request for contract code. pub mod contract_code { use super::{Field, NoSuchOutput, OutputKind, Output}; - use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; use util::{Bytes, H256}; /// Potentially incomplete contract code request. - #[derive(Debug, Clone, PartialEq, Eq)] + #[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)] pub struct Incomplete { /// The block hash to request the state for. pub block_hash: Field, @@ -1525,23 +1334,6 @@ pub mod contract_code { pub code_hash: Field, } - impl Decodable for Incomplete { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(Incomplete { - block_hash: rlp.val_at(0)?, - code_hash: rlp.val_at(1)?, - }) - } - } - - impl Encodable for Incomplete { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(2) - .append(&self.block_hash) - .append(&self.code_hash); - } - } - impl super::IncompleteRequest for Incomplete { type Complete = Complete; type Response = Response; @@ -1600,7 +1392,7 @@ pub mod contract_code { } /// The output of a request for - #[derive(Debug, Clone, PartialEq, Eq)] + #[derive(Debug, Clone, PartialEq, Eq, RlpEncodableWrapper, RlpDecodableWrapper)] pub struct Response { /// The requested code. pub code: Bytes, @@ -1610,21 +1402,6 @@ pub mod contract_code { /// Fill reusable outputs by providing them to the function. fn fill_outputs(&self, _: F) where F: FnMut(usize, Output) {} } - - impl Decodable for Response { - fn decode(rlp: &UntrustedRlp) -> Result { - - Ok(Response { - code: rlp.as_val()?, - }) - } - } - - impl Encodable for Response { - fn rlp_append(&self, s: &mut RlpStream) { - s.append(&self.code); - } - } } /// A request for proof of execution. @@ -1635,7 +1412,7 @@ pub mod execution { use util::{Bytes, Address, U256, H256, DBValue}; /// Potentially incomplete execution proof request. - #[derive(Debug, Clone, PartialEq, Eq)] + #[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)] pub struct Incomplete { /// The block hash to request the state for. pub block_hash: Field, @@ -1653,38 +1430,6 @@ pub mod execution { pub data: Bytes, } - impl Decodable for Incomplete { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(Incomplete { - block_hash: rlp.val_at(0)?, - from: rlp.val_at(1)?, - action: rlp.val_at(2)?, - gas: rlp.val_at(3)?, - gas_price: rlp.val_at(4)?, - value: rlp.val_at(5)?, - data: rlp.val_at(6)?, - }) - } - } - - impl Encodable for Incomplete { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(7) - .append(&self.block_hash) - .append(&self.from); - - match self.action { - Action::Create => s.append_empty_data(), - Action::Call(ref addr) => s.append(addr), - }; - - s.append(&self.gas) - .append(&self.gas_price) - .append(&self.value) - .append(&self.data); - } - } - impl super::IncompleteRequest for Incomplete { type Complete = Complete; type Response = Response; diff --git a/ethcore/native_contracts/Cargo.toml b/ethcore/native_contracts/Cargo.toml index 5dc18c8f5..2f91a4848 100644 --- a/ethcore/native_contracts/Cargo.toml +++ b/ethcore/native_contracts/Cargo.toml @@ -9,7 +9,7 @@ build = "build.rs" ethabi = "2.0" futures = "0.1" byteorder = "1.0" -ethcore-util = { path = "../../util" } +ethcore-bigint = { path = "../../util/bigint" } [build-dependencies] native-contract-generator = { path = "generator" } diff --git a/ethcore/native_contracts/build.rs b/ethcore/native_contracts/build.rs index cec830929..bcb64067c 100644 --- a/ethcore/native_contracts/build.rs +++ b/ethcore/native_contracts/build.rs @@ -21,6 +21,7 @@ use std::fs::File; use std::io::Write; // TODO: just walk the "res" directory and generate whole crate automatically. +const KEY_SERVER_SET_ABI: &'static str = include_str!("res/key_server_set.json"); const REGISTRY_ABI: &'static str = include_str!("res/registrar.json"); const URLHINT_ABI: &'static str = include_str!("res/urlhint.json"); const SERVICE_TRANSACTION_ABI: &'static str = include_str!("res/service_transaction.json"); @@ -45,6 +46,7 @@ fn build_test_contracts() { } fn main() { + build_file("KeyServerSet", KEY_SERVER_SET_ABI, "key_server_set.rs"); build_file("Registry", REGISTRY_ABI, "registry.rs"); build_file("Urlhint", URLHINT_ABI, "urlhint.rs"); build_file("ServiceTransactionChecker", SERVICE_TRANSACTION_ABI, "service_transaction.rs"); diff --git a/ethcore/native_contracts/generator/src/lib.rs b/ethcore/native_contracts/generator/src/lib.rs index 793ad6085..996ee4969 100644 --- a/ethcore/native_contracts/generator/src/lib.rs +++ b/ethcore/native_contracts/generator/src/lib.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . //! Rust code contract generator. -//! The code generated will require a dependence on the `ethcore-util`, +//! The code generated will require a dependence on the `ethcore-bigint::prelude`, //! `ethabi`, `byteorder`, and `futures` crates. //! This currently isn't hygienic, so compilation of generated code may fail //! due to missing crates or name collisions. This will change when @@ -48,14 +48,14 @@ pub fn generate_module(struct_name: &str, abi: &str) -> Result { use byteorder::{{BigEndian, ByteOrder}}; use futures::{{future, Future, IntoFuture, BoxFuture}}; use ethabi::{{Contract, Interface, Token, Event}}; -use util; +use bigint; /// Generated Rust bindings to an Ethereum contract. #[derive(Clone, Debug)] pub struct {name} {{ contract: Contract, /// Address to make calls to. - pub address: util::Address, + pub address: bigint::prelude::H160, }} const ABI: &'static str = r#"{abi_str}"#; @@ -63,7 +63,7 @@ const ABI: &'static str = r#"{abi_str}"#; impl {name} {{ /// Create a new instance of `{name}` with an address. /// Calls can be made, given a callback for dispatching calls asynchronously. - pub fn new(address: util::Address) -> Self {{ + pub fn new(address: bigint::prelude::H160) -> Self {{ let contract = Contract::new(Interface::load(ABI.as_bytes()) .expect("ABI checked at generation-time; qed")); {name} {{ @@ -108,7 +108,7 @@ fn generate_functions(contract: &Contract) -> Result { /// Outputs: {abi_outputs:?} pub fn {snake_name}(&self, call: F, {params}) -> BoxFuture<{output_type}, String> where - F: FnOnce(util::Address, Vec) -> U, + F: FnOnce(bigint::prelude::H160, Vec) -> U, U: IntoFuture, Error=String>, U::Future: Send + 'static {{ @@ -217,8 +217,8 @@ fn output_params_codegen(outputs: &[ParamType]) -> Result<(String, String), Para // create code for an argument type from param type. fn rust_type(input: ParamType) -> Result { Ok(match input { - ParamType::Address => "util::Address".into(), - ParamType::FixedBytes(len) if len <= 32 => format!("util::H{}", len * 8), + ParamType::Address => "bigint::prelude::H160".into(), + ParamType::FixedBytes(len) if len <= 32 => format!("bigint::prelude::H{}", len * 8), ParamType::Bytes | ParamType::FixedBytes(_) => "Vec".into(), ParamType::Int(width) => match width { 8 | 16 | 32 | 64 => format!("i{}", width), @@ -226,7 +226,7 @@ fn rust_type(input: ParamType) -> Result { }, ParamType::Uint(width) => match width { 8 | 16 | 32 | 64 => format!("u{}", width), - 128 | 160 | 256 => format!("util::U{}", width), + 128 | 160 | 256 => format!("bigint::prelude::U{}", width), _ => return Err(ParamType::Uint(width)), }, ParamType::Bool => "bool".into(), @@ -259,8 +259,8 @@ fn tokenize(name: &str, input: ParamType) -> (bool, String) { }, ParamType::Uint(width) => format!( "let mut r = [0; 32]; {}.to_big_endian(&mut r); Token::Uint(r)", - if width <= 64 { format!("util::U256::from({} as u64)", name) } - else { format!("util::U256::from({})", name) } + if width <= 64 { format!("bigint::prelude::U256::from({} as u64)", name) } + else { format!("bigint::prelude::U256::from({})", name) } ), ParamType::Bool => format!("Token::Bool({})", name), ParamType::String => format!("Token::String({})", name), @@ -281,11 +281,11 @@ fn tokenize(name: &str, input: ParamType) -> (bool, String) { // panics on unsupported types. fn detokenize(name: &str, output_type: ParamType) -> String { match output_type { - ParamType::Address => format!("{}.to_address().map(util::H160)", name), + ParamType::Address => format!("{}.to_address().map(bigint::prelude::H160)", name), ParamType::Bytes => format!("{}.to_bytes()", name), ParamType::FixedBytes(len) if len <= 32 => { // ensure no panic on slice too small. - let read_hash = format!("b.resize({}, 0); util::H{}::from_slice(&b[..{}])", + let read_hash = format!("b.resize({}, 0); bigint::prelude::H{}::from_slice(&b[..{}])", len, len * 8, len); format!("{}.to_fixed_bytes().map(|mut b| {{ {} }})", @@ -302,8 +302,8 @@ fn detokenize(name: &str, output_type: ParamType) -> String { } ParamType::Uint(width) => { let read_uint = match width { - 8 | 16 | 32 | 64 => format!("util::U256(u).low_u64() as u{}", width), - _ => format!("util::U{}::from(&u[..])", width), + 8 | 16 | 32 | 64 => format!("bigint::prelude::U256(u).low_u64() as u{}", width), + _ => format!("bigint::prelude::U{}::from(&u[..])", width), }; format!("{}.to_uint().map(|u| {})", name, read_uint) @@ -328,30 +328,30 @@ mod tests { #[test] fn input_types() { assert_eq!(::input_params_codegen(&[]).unwrap().0, ""); - assert_eq!(::input_params_codegen(&[ParamType::Address]).unwrap().0, "param_0: util::Address, "); + assert_eq!(::input_params_codegen(&[ParamType::Address]).unwrap().0, "param_0: bigint::prelude::H160, "); assert_eq!(::input_params_codegen(&[ParamType::Address, ParamType::Bytes]).unwrap().0, - "param_0: util::Address, param_1: Vec, "); + "param_0: bigint::prelude::H160, param_1: Vec, "); } #[test] fn output_types() { assert_eq!(::output_params_codegen(&[]).unwrap().0, "()"); - assert_eq!(::output_params_codegen(&[ParamType::Address]).unwrap().0, "(util::Address)"); + assert_eq!(::output_params_codegen(&[ParamType::Address]).unwrap().0, "(bigint::prelude::H160)"); assert_eq!(::output_params_codegen(&[ParamType::Address, ParamType::Array(Box::new(ParamType::Bytes))]).unwrap().0, - "(util::Address, Vec>)"); + "(bigint::prelude::H160, Vec>)"); } #[test] fn rust_type() { - assert_eq!(::rust_type(ParamType::FixedBytes(32)).unwrap(), "util::H256"); + assert_eq!(::rust_type(ParamType::FixedBytes(32)).unwrap(), "bigint::prelude::H256"); assert_eq!(::rust_type(ParamType::Array(Box::new(ParamType::FixedBytes(32)))).unwrap(), - "Vec"); + "Vec"); assert_eq!(::rust_type(ParamType::Uint(64)).unwrap(), "u64"); assert!(::rust_type(ParamType::Uint(63)).is_err()); assert_eq!(::rust_type(ParamType::Int(32)).unwrap(), "i32"); - assert_eq!(::rust_type(ParamType::Uint(256)).unwrap(), "util::U256"); + assert_eq!(::rust_type(ParamType::Uint(256)).unwrap(), "bigint::prelude::U256"); } // codegen tests will need bootstrapping of some kind. diff --git a/ethcore/native_contracts/res/key_server_set.json b/ethcore/native_contracts/res/key_server_set.json new file mode 100644 index 000000000..93f68837a --- /dev/null +++ b/ethcore/native_contracts/res/key_server_set.json @@ -0,0 +1 @@ +[{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"keyServersList","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"keyServer","type":"address"}],"name":"getKeyServerPublic","outputs":[{"name":"","type":"bytes"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"getKeyServers","outputs":[{"name":"","type":"address[]"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"keyServer","type":"address"}],"name":"getKeyServerAddress","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"keyServer","type":"address"}],"name":"removeKeyServer","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"keyServerPublic","type":"bytes"},{"name":"keyServerIp","type":"string"}],"name":"addKeyServer","outputs":[],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"keyServer","type":"address"}],"name":"KeyServerAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"keyServer","type":"address"}],"name":"KeyServerRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"old","type":"address"},{"indexed":true,"name":"current","type":"address"}],"name":"NewOwner","type":"event"}] \ No newline at end of file diff --git a/util/src/standard.rs b/ethcore/native_contracts/src/key_server_set.rs similarity index 52% rename from util/src/standard.rs rename to ethcore/native_contracts/src/key_server_set.rs index 19521a5d5..60b137aae 100644 --- a/util/src/standard.rs +++ b/ethcore/native_contracts/src/key_server_set.rs @@ -14,32 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -//! Std lib global reexports. +#![allow(unused_mut, unused_variables, unused_imports)] -pub use std::io; -pub use std::fs; -pub use std::str; -pub use std::fmt; -pub use std::cmp; -pub use std::ptr; -pub use std::mem; -pub use std::ops; -pub use std::slice; -pub use std::result; -pub use std::option; +//! Secret store Key Server set contract. -pub use std::path::Path; -pub use std::str::{FromStr}; -pub use std::io::{Read,Write}; -pub use std::hash::{Hash, Hasher}; -pub use std::error::Error as StdError; - -pub use std::ops::*; -pub use std::cmp::*; -pub use std::sync::Arc; -pub use std::collections::*; - -pub use heapsize::HeapSizeOf; -pub use itertools::Itertools; - -pub use parking_lot::{Condvar, Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard}; +include!(concat!(env!("OUT_DIR"), "/key_server_set.rs")); diff --git a/ethcore/native_contracts/src/lib.rs b/ethcore/native_contracts/src/lib.rs index e35a4ec19..58875f8a2 100644 --- a/ethcore/native_contracts/src/lib.rs +++ b/ethcore/native_contracts/src/lib.rs @@ -21,8 +21,9 @@ extern crate futures; extern crate byteorder; extern crate ethabi; -extern crate ethcore_util as util; +extern crate ethcore_bigint as bigint; +mod key_server_set; mod registry; mod urlhint; mod service_transaction; @@ -32,6 +33,7 @@ mod validator_report; pub mod test_contracts; +pub use self::key_server_set::KeyServerSet; pub use self::registry::Registry; pub use self::urlhint::Urlhint; pub use self::service_transaction::ServiceTransactionChecker; diff --git a/ethcore/res/authority_round.json b/ethcore/res/authority_round.json index d8014ff25..a56618d1c 100644 --- a/ethcore/res/authority_round.json +++ b/ethcore/res/authority_round.json @@ -3,7 +3,6 @@ "engine": { "authorityRound": { "params": { - "gasLimitBoundDivisor": "0x0400", "stepDuration": 1, "startStep": 2, "validators": { @@ -17,6 +16,7 @@ } }, "params": { + "gasLimitBoundDivisor": "0x0400", "accountStartNonce": "0x0", "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", diff --git a/ethcore/res/basic_authority.json b/ethcore/res/basic_authority.json index 6b9f4c0ed..192b48cad 100644 --- a/ethcore/res/basic_authority.json +++ b/ethcore/res/basic_authority.json @@ -3,7 +3,6 @@ "engine": { "basicAuthority": { "params": { - "gasLimitBoundDivisor": "0x0400", "durationLimit": "0x0d", "validators": { "list": ["0x9cce34f7ab185c7aba1b7c8140d620b4bda941d6"] @@ -12,6 +11,7 @@ } }, "params": { + "gasLimitBoundDivisor": "0x0400", "accountStartNonce": "0x0100000", "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", diff --git a/ethcore/res/constructor.json b/ethcore/res/constructor.json index 0be5b3be4..9b1de7020 100644 --- a/ethcore/res/constructor.json +++ b/ethcore/res/constructor.json @@ -4,6 +4,7 @@ "null": null }, "params": { + "gasLimitBoundDivisor": "0x0400", "accountStartNonce": "0x0", "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", diff --git a/ethcore/res/ethereum/classic.json b/ethcore/res/ethereum/classic.json index 6edfef460..bfd64248e 100644 --- a/ethcore/res/ethereum/classic.json +++ b/ethcore/res/ethereum/classic.json @@ -4,15 +4,11 @@ "engine": { "Ethash": { "params": { - "gasLimitBoundDivisor": "0x0400", "minimumDifficulty": "0x020000", "difficultyBoundDivisor": "0x0800", "durationLimit": "0x0d", - "blockReward": "0x4563918244F40000", - "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "homesteadTransition": 1150000, "eip150Transition": 2500000, - "eip155Transition": 3000000, "eip160Transition": 3000000, "ecip1010PauseTransition": 3000000, "ecip1010ContinueTransition": 5000000, @@ -24,6 +20,9 @@ } }, "params": { + "gasLimitBoundDivisor": "0x0400", + "blockReward": "0x4563918244F40000", + "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "accountStartNonce": "0x00", "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", @@ -31,6 +30,8 @@ "chainID": "0x3d", "forkBlock": "0x1d4c00", "forkCanonHash": "0x94365e3a8c0b35089c1d1195081fe7489b528a84b22199c916180db8b28ade7f", + "eip155Transition": 3000000, + "eip98Transition": "0x7fffffffffffff", "eip86Transition": "0x7fffffffffffff" }, diff --git a/ethcore/res/ethereum/eip150_test.json b/ethcore/res/ethereum/eip150_test.json index 3091ee27b..22ebf5500 100644 --- a/ethcore/res/ethereum/eip150_test.json +++ b/ethcore/res/ethereum/eip150_test.json @@ -3,15 +3,11 @@ "engine": { "Ethash": { "params": { - "gasLimitBoundDivisor": "0x0400", "minimumDifficulty": "0x020000", "difficultyBoundDivisor": "0x0800", "durationLimit": "0x0d", - "blockReward": "0x4563918244F40000", - "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "homesteadTransition": "0x0", "eip150Transition": "0x0", - "eip155Transition": "0x7fffffffffffffff", "eip160Transition": "0x7fffffffffffffff", "eip161abcTransition": "0x7fffffffffffffff", "eip161dTransition": "0x7fffffffffffffff", @@ -20,12 +16,16 @@ } }, "params": { + "gasLimitBoundDivisor": "0x0400", + "blockReward": "0x4563918244F40000", + "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "accountStartNonce": "0x00", "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", "networkID" : "0x1", "eip98Transition": "0x7fffffffffffffff", - "eip86Transition": "0x7fffffffffffffff" + "eip86Transition": "0x7fffffffffffffff", + "eip155Transition": "0x7fffffffffffffff" }, "genesis": { "seal": { diff --git a/ethcore/res/ethereum/eip161_test.json b/ethcore/res/ethereum/eip161_test.json index e6e8bf3bb..50d28570b 100644 --- a/ethcore/res/ethereum/eip161_test.json +++ b/ethcore/res/ethereum/eip161_test.json @@ -3,15 +3,11 @@ "engine": { "Ethash": { "params": { - "gasLimitBoundDivisor": "0x0400", "minimumDifficulty": "0x020000", "difficultyBoundDivisor": "0x0800", "durationLimit": "0x0d", - "blockReward": "0x4563918244F40000", - "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "homesteadTransition": "0x0", "eip150Transition": "0x0", - "eip155Transition": "0x7fffffffffffffff", "eip160Transition": "0x0", "eip161abcTransition": "0x0", "eip161dTransition": "0x0", @@ -20,12 +16,16 @@ } }, "params": { + "gasLimitBoundDivisor": "0x0400", + "blockReward": "0x4563918244F40000", + "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "accountStartNonce": "0x00", "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", "networkID" : "0x1", "eip98Transition": "0x7fffffffffffffff", - "eip86Transition": "0x7fffffffffffffff" + "eip86Transition": "0x7fffffffffffffff", + "eip155Transition": "0x7fffffffffffffff" }, "genesis": { "seal": { diff --git a/ethcore/res/ethereum/expanse.json b/ethcore/res/ethereum/expanse.json index b7d22ac3e..d79ab6b3c 100644 --- a/ethcore/res/ethereum/expanse.json +++ b/ethcore/res/ethereum/expanse.json @@ -4,19 +4,15 @@ "engine": { "Ethash": { "params": { - "gasLimitBoundDivisor": "0x0400", "minimumDifficulty": "0x020000", "difficultyBoundDivisor": "0x0800", "difficultyIncrementDivisor": "60", "durationLimit": "0x3C", - "blockReward": "0x6f05b59d3b200000", - "registrar" : "0x6c221ca53705f3497ec90ca7b84c59ae7382fc21", "homesteadTransition": "0x30d40", "difficultyHardforkTransition": "0x59d9", "difficultyHardforkBoundDivisor": "0x0200", "bombDefuseTransition": "0x30d40", "eip150Transition": "0x927C0", - "eip155Transition": "0x927C0", "eip160Transition": "0x927C0", "eip161abcTransition": "0x927C0", "eip161dTransition": "0x927C0" @@ -24,6 +20,9 @@ } }, "params": { + "gasLimitBoundDivisor": "0x0400", + "blockReward": "0x6f05b59d3b200000", + "registrar" : "0x6c221ca53705f3497ec90ca7b84c59ae7382fc21", "accountStartNonce": "0x00", "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", @@ -31,7 +30,8 @@ "chainID": "0x2", "subprotocolName": "exp", "eip98Transition": "0x7fffffffffffff", - "eip86Transition": "0x7fffffffffffff" + "eip86Transition": "0x7fffffffffffff", + "eip155Transition": "0x927C0" }, "genesis": { "seal": { diff --git a/ethcore/res/ethereum/foundation.json b/ethcore/res/ethereum/foundation.json index a77b39934..b30453082 100644 --- a/ethcore/res/ethereum/foundation.json +++ b/ethcore/res/ethereum/foundation.json @@ -4,12 +4,9 @@ "engine": { "Ethash": { "params": { - "gasLimitBoundDivisor": "0x0400", "minimumDifficulty": "0x020000", "difficultyBoundDivisor": "0x0800", "durationLimit": "0x0d", - "blockReward": "0x4563918244F40000", - "registrar" : "0xe3389675d0338462dC76C6f9A3e432550c36A142", "homesteadTransition": "0x118c30", "daoHardforkTransition": "0x1d4c00", "daoHardforkBeneficiary": "0xbf4ed7b27f1d666546e30d74d50d173d20bca754", @@ -132,7 +129,6 @@ "0x807640a13483f8ac783c557fcdf27be11ea4ac7a" ], "eip150Transition": "0x259518", - "eip155Transition": 2675000, "eip160Transition": 2675000, "eip161abcTransition": 2675000, "eip161dTransition": 2675000, @@ -141,12 +137,17 @@ } }, "params": { + "gasLimitBoundDivisor": "0x0400", + "blockReward": "0x4563918244F40000", + "registrar" : "0xe3389675d0338462dC76C6f9A3e432550c36A142", "accountStartNonce": "0x00", "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", "networkID" : "0x1", "forkBlock": "0x1d4c00", "forkCanonHash": "0x4985f5ca3d2afbec36529aa96f74de3cc10a2a4a6c44f2157a57d2c6059a11bb", + "eip155Transition": 2675000, + "eip98Transition": "0x7fffffffffffff", "eip86Transition": "0x7fffffffffffff" }, diff --git a/ethcore/res/ethereum/frontier_like_test.json b/ethcore/res/ethereum/frontier_like_test.json index fde04f6b5..0f4b8850f 100644 --- a/ethcore/res/ethereum/frontier_like_test.json +++ b/ethcore/res/ethereum/frontier_like_test.json @@ -3,12 +3,9 @@ "engine": { "Ethash": { "params": { - "gasLimitBoundDivisor": "0x0400", "minimumDifficulty": "0x020000", "difficultyBoundDivisor": "0x0800", "durationLimit": "0x0d", - "blockReward": "0x4563918244F40000", - "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "homesteadTransition": "0x118c30", "daoHardforkTransition": "0x1d4c00", "daoHardforkBeneficiary": "0xbf4ed7b27f1d666546e30d74d50d173d20bca754", @@ -131,7 +128,6 @@ "0x807640a13483f8ac783c557fcdf27be11ea4ac7a" ], "eip150Transition": "0x7fffffffffffffff", - "eip155Transition": "0x7fffffffffffffff", "eip160Transition": "0x7fffffffffffffff", "eip161abcTransition": "0x7fffffffffffffff", "eip161dTransition": "0x7fffffffffffffff" @@ -139,12 +135,16 @@ } }, "params": { + "gasLimitBoundDivisor": "0x0400", + "blockReward": "0x4563918244F40000", + "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "accountStartNonce": "0x00", "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", "networkID" : "0x1", "eip98Transition": "0x7fffffffffffff", - "eip86Transition": "0x7fffffffffffff" + "eip86Transition": "0x7fffffffffffff", + "eip155Transition": "0x7fffffffffffffff" }, "genesis": { "seal": { diff --git a/ethcore/res/ethereum/frontier_test.json b/ethcore/res/ethereum/frontier_test.json index 6761c79f3..802a77f8d 100644 --- a/ethcore/res/ethereum/frontier_test.json +++ b/ethcore/res/ethereum/frontier_test.json @@ -3,15 +3,11 @@ "engine": { "Ethash": { "params": { - "gasLimitBoundDivisor": "0x0400", "minimumDifficulty": "0x020000", "difficultyBoundDivisor": "0x0800", "durationLimit": "0x0d", - "blockReward": "0x4563918244F40000", - "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "homesteadTransition": "0x7fffffffffffffff", "eip150Transition": "0x7fffffffffffffff", - "eip155Transition": "0x7fffffffffffffff", "eip160Transition": "0x7fffffffffffffff", "eip161abcTransition": "0x7fffffffffffffff", "eip161dTransition": "0x7fffffffffffffff" @@ -19,12 +15,16 @@ } }, "params": { + "gasLimitBoundDivisor": "0x0400", + "blockReward": "0x4563918244F40000", + "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "accountStartNonce": "0x00", "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", "networkID" : "0x1", "eip98Transition": "0x7fffffffffffff", - "eip86Transition": "0x7fffffffffffff" + "eip86Transition": "0x7fffffffffffff", + "eip155Transition": "0x7fffffffffffffff" }, "genesis": { "seal": { diff --git a/ethcore/res/ethereum/homestead_test.json b/ethcore/res/ethereum/homestead_test.json index 25b061857..557a48a64 100644 --- a/ethcore/res/ethereum/homestead_test.json +++ b/ethcore/res/ethereum/homestead_test.json @@ -3,15 +3,11 @@ "engine": { "Ethash": { "params": { - "gasLimitBoundDivisor": "0x0400", "minimumDifficulty": "0x020000", "difficultyBoundDivisor": "0x0800", "durationLimit": "0x0d", - "blockReward": "0x4563918244F40000", - "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "homesteadTransition": "0x0", "eip150Transition": "0x7fffffffffffffff", - "eip155Transition": "0x7fffffffffffffff", "eip160Transition": "0x7fffffffffffffff", "eip161abcTransition": "0x7fffffffffffffff", "eip161dTransition": "0x7fffffffffffffff" @@ -19,12 +15,16 @@ } }, "params": { + "gasLimitBoundDivisor": "0x0400", + "blockReward": "0x4563918244F40000", + "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "accountStartNonce": "0x00", "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", "networkID" : "0x1", "eip98Transition": "0x7fffffffffffff", - "eip86Transition": "0x7fffffffffffff" + "eip86Transition": "0x7fffffffffffff", + "eip155Transition": "0x7fffffffffffffff" }, "genesis": { "seal": { diff --git a/ethcore/res/ethereum/kovan.json b/ethcore/res/ethereum/kovan.json index 7cdb79e16..ca7638e33 100644 --- a/ethcore/res/ethereum/kovan.json +++ b/ethcore/res/ethereum/kovan.json @@ -4,10 +4,7 @@ "engine": { "authorityRound": { "params": { - "gasLimitBoundDivisor": "0x400", - "registrar" : "0xfAb104398BBefbd47752E7702D9fE23047E1Bca3", "stepDuration": "4", - "blockReward": "0x4563918244F40000", "validators" : { "list": [ "0x00D6Cc1BA9cf89BD2e58009741f4F7325BAdc0ED", @@ -25,16 +22,19 @@ ] }, "validateScoreTransition": 1000000, - "eip155Transition": 1000000, "validateStepTransition": 1500000 } } }, "params": { - "maximumExtraDataSize": "0x20", + "gasLimitBoundDivisor": "0x400", + "registrar" : "0xfAb104398BBefbd47752E7702D9fE23047E1Bca3", + "blockReward": "0x4563918244F40000", + "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", "networkID" : "0x2A", - "validateReceiptsTransition" : 1000000 + "validateReceiptsTransition" : 1000000, + "eip155Transition": 1000000 }, "genesis": { "seal": { diff --git a/ethcore/res/ethereum/metropolis_test.json b/ethcore/res/ethereum/metropolis_test.json index 76189e731..a452e5a80 100644 --- a/ethcore/res/ethereum/metropolis_test.json +++ b/ethcore/res/ethereum/metropolis_test.json @@ -3,15 +3,12 @@ "engine": { "Ethash": { "params": { - "gasLimitBoundDivisor": "0x0400", "minimumDifficulty": "0x020000", "difficultyBoundDivisor": "0x0800", "durationLimit": "0x0d", - "blockReward": "0x4563918244F40000", - "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", + "homesteadTransition": "0x0", "eip150Transition": "0x0", - "eip155Transition": "0x0", "eip160Transition": "0x0", "eip161abcTransition": "0x0", "eip161dTransition": "0x0", @@ -20,6 +17,9 @@ } }, "params": { + "gasLimitBoundDivisor": "0x0400", + "blockReward": "0x4563918244F40000", + "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "accountStartNonce": "0x00", "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", @@ -27,7 +27,8 @@ "eip98Transition": "0x0", "eip86Transition": "0x0", "eip140Transition": "0x0", - "eip210Transition": "0x0" + "eip210Transition": "0x0", + "eip155Transition": "0x0" }, "genesis": { "seal": { diff --git a/ethcore/res/ethereum/morden.json b/ethcore/res/ethereum/morden.json index 495849daf..f316fdf5f 100644 --- a/ethcore/res/ethereum/morden.json +++ b/ethcore/res/ethereum/morden.json @@ -4,15 +4,11 @@ "engine": { "Ethash": { "params": { - "gasLimitBoundDivisor": "0x0400", "minimumDifficulty": "0x020000", "difficultyBoundDivisor": "0x0800", "durationLimit": "0x0d", - "blockReward": "0x4563918244F40000", - "registrar": "0x52dff57a8a1532e6afb3dc07e2af58bb9eb05b3d", "homesteadTransition": 494000, "eip150Transition": 1783000, - "eip155Transition": 1915000, "eip160Transition": 1915000, "ecip1010PauseTransition": 1915000, "ecip1010ContinueTransition": 3415000, @@ -23,6 +19,9 @@ } }, "params": { + "gasLimitBoundDivisor": "0x0400", + "blockReward": "0x4563918244F40000", + "registrar": "0x52dff57a8a1532e6afb3dc07e2af58bb9eb05b3d", "accountStartNonce": "0x0100000", "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", @@ -30,6 +29,8 @@ "chainID": "0x3e", "forkBlock": "0x1b34d8", "forkCanonHash": "0xf376243aeff1f256d970714c3de9fd78fa4e63cf63e32a51fe1169e375d98145", + "eip155Transition": 1915000, + "eip98Transition": "0x7fffffffffffff", "eip86Transition": "0x7fffffffffffff" }, diff --git a/ethcore/res/ethereum/olympic.json b/ethcore/res/ethereum/olympic.json index 3d2e7baf9..c73dcb815 100644 --- a/ethcore/res/ethereum/olympic.json +++ b/ethcore/res/ethereum/olympic.json @@ -3,15 +3,11 @@ "engine": { "Ethash": { "params": { - "gasLimitBoundDivisor": "0x0400", "minimumDifficulty": "0x020000", "difficultyBoundDivisor": "0x0800", "durationLimit": "0x08", - "blockReward": "0x14D1120D7B160000", - "registrar": "5e70c0bbcd5636e0f9f9316e9f8633feb64d4050", "homesteadTransition": "0x7fffffffffffffff", "eip150Transition": "0x7fffffffffffffff", - "eip155Transition": "0x7fffffffffffffff", "eip160Transition": "0x7fffffffffffffff", "eip161abcTransition": "0x7fffffffffffffff", "eip161dTransition": "0x7fffffffffffffff" @@ -19,12 +15,16 @@ } }, "params": { + "gasLimitBoundDivisor": "0x0400", + "blockReward": "0x14D1120D7B160000", + "registrar": "5e70c0bbcd5636e0f9f9316e9f8633feb64d4050", "accountStartNonce": "0x00", "maximumExtraDataSize": "0x0400", "minGasLimit": "125000", "networkID" : "0x0", "eip98Transition": "0x7fffffffffffff", - "eip86Transition": "0x7fffffffffffff" + "eip86Transition": "0x7fffffffffffff", + "eip155Transition": "0x7fffffffffffffff" }, "genesis": { "seal": { diff --git a/ethcore/res/ethereum/ropsten.json b/ethcore/res/ethereum/ropsten.json index 1e350d636..1706c433b 100644 --- a/ethcore/res/ethereum/ropsten.json +++ b/ethcore/res/ethereum/ropsten.json @@ -4,15 +4,11 @@ "engine": { "Ethash": { "params": { - "gasLimitBoundDivisor": "0x0400", "minimumDifficulty": "0x020000", "difficultyBoundDivisor": "0x0800", "durationLimit": "0x0d", - "blockReward": "0x4563918244F40000", - "registrar": "0x81a4b044831c4f12ba601adb9274516939e9b8a2", "homesteadTransition": 0, "eip150Transition": 0, - "eip155Transition": 10, "eip160Transition": 10, "eip161abcTransition": 10, "eip161dTransition": 10, @@ -21,12 +17,17 @@ } }, "params": { + "gasLimitBoundDivisor": "0x0400", + "blockReward": "0x4563918244F40000", + "registrar": "0x81a4b044831c4f12ba601adb9274516939e9b8a2", "accountStartNonce": "0x0", "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", "networkID" : "0x3", "forkBlock": 641350, "forkCanonHash": "0x8033403e9fe5811a7b6d6b469905915de1c59207ce2172cbcf5d6ff14fa6a2eb", + "eip155Transition": 10, + "eip98Transition": "0x7fffffffffffff", "eip86Transition": "0x7fffffffffffff" }, diff --git a/ethcore/res/ethereum/transition_test.json b/ethcore/res/ethereum/transition_test.json index 7709ba015..409210a76 100644 --- a/ethcore/res/ethereum/transition_test.json +++ b/ethcore/res/ethereum/transition_test.json @@ -3,12 +3,9 @@ "engine": { "Ethash": { "params": { - "gasLimitBoundDivisor": "0x0400", "minimumDifficulty": "0x020000", "difficultyBoundDivisor": "0x0800", "durationLimit": "0x0d", - "blockReward": "0x4563918244F40000", - "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "homesteadTransition": "0x5", "daoHardforkTransition": "0x8", "daoHardforkBeneficiary": "0xbf4ed7b27f1d666546e30d74d50d173d20bca754", @@ -131,7 +128,6 @@ "0x807640a13483f8ac783c557fcdf27be11ea4ac7a" ], "eip150Transition": "0xa", - "eip155Transition": "0x7fffffffffffffff", "eip160Transition": "0x7fffffffffffffff", "eip161abcTransition": "0x7fffffffffffffff", "eip161dTransition": "0x7fffffffffffffff" @@ -139,12 +135,16 @@ } }, "params": { + "gasLimitBoundDivisor": "0x0400", + "blockReward": "0x4563918244F40000", + "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "accountStartNonce": "0x00", "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", "networkID" : "0x1", "eip98Transition": "0x7fffffffffffff", - "eip86Transition": "0x7fffffffffffff" + "eip86Transition": "0x7fffffffffffff", + "eip155Transition": "0x7fffffffffffffff" }, "genesis": { "seal": { diff --git a/ethcore/res/instant_seal.json b/ethcore/res/instant_seal.json index c791b9a2d..f59feb0bd 100644 --- a/ethcore/res/instant_seal.json +++ b/ethcore/res/instant_seal.json @@ -1,13 +1,10 @@ { "name": "DevelopmentChain", "engine": { - "instantSeal": { - "params": { - "registrar": "0x0000000000000000000000000000000000000005" - } - } + "instantSeal": null }, "params": { + "gasLimitBoundDivisor": "0x0400", "accountStartNonce": "0x0", "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", diff --git a/ethcore/res/null.json b/ethcore/res/null.json index ffb0ea061..97ce1afc5 100644 --- a/ethcore/res/null.json +++ b/ethcore/res/null.json @@ -4,6 +4,7 @@ "null": null }, "params": { + "gasLimitBoundDivisor": "0x0400", "accountStartNonce": "0x0", "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", diff --git a/ethcore/res/null_morden.json b/ethcore/res/null_morden.json index 96d804b5b..b615cdc29 100644 --- a/ethcore/res/null_morden.json +++ b/ethcore/res/null_morden.json @@ -4,6 +4,7 @@ "null": null }, "params": { + "gasLimitBoundDivisor": "0x0400", "accountStartNonce": "0x0", "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", diff --git a/ethcore/res/tendermint.json b/ethcore/res/tendermint.json index 642f5b385..e7fa69ea0 100644 --- a/ethcore/res/tendermint.json +++ b/ethcore/res/tendermint.json @@ -3,7 +3,6 @@ "engine": { "tendermint": { "params": { - "gasLimitBoundDivisor": "0x0400", "validators" : { "list": [ "0x82a978b3f5962a5b0957d9ee9eef472ee55b42f1", @@ -18,6 +17,7 @@ } }, "params": { + "gasLimitBoundDivisor": "0x0400", "accountStartNonce": "0x0", "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", diff --git a/ethcore/res/validator_contract.json b/ethcore/res/validator_contract.json index 3faec7665..9d007ac23 100644 --- a/ethcore/res/validator_contract.json +++ b/ethcore/res/validator_contract.json @@ -3,7 +3,6 @@ "engine": { "authorityRound": { "params": { - "gasLimitBoundDivisor": "0x0400", "stepDuration": 1, "startStep": 2, "validators": { @@ -14,6 +13,7 @@ } }, "params": { + "gasLimitBoundDivisor": "0x0400", "accountStartNonce": "0x0", "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", diff --git a/ethcore/res/validator_multi.json b/ethcore/res/validator_multi.json index 5d51b73da..9eba2d5ba 100644 --- a/ethcore/res/validator_multi.json +++ b/ethcore/res/validator_multi.json @@ -3,7 +3,6 @@ "engine": { "basicAuthority": { "params": { - "gasLimitBoundDivisor": "0x0400", "durationLimit": "0x0d", "validators": { "multi": { @@ -15,6 +14,7 @@ } }, "params": { + "gasLimitBoundDivisor": "0x0400", "accountStartNonce": "0x0", "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", diff --git a/ethcore/res/validator_safe_contract.json b/ethcore/res/validator_safe_contract.json index 3f5241c96..63dfb948d 100644 --- a/ethcore/res/validator_safe_contract.json +++ b/ethcore/res/validator_safe_contract.json @@ -3,7 +3,6 @@ "engine": { "basicAuthority": { "params": { - "gasLimitBoundDivisor": "0x0400", "durationLimit": "0x0d", "validators": { "safeContract": "0x0000000000000000000000000000000000000005" @@ -12,6 +11,7 @@ } }, "params": { + "gasLimitBoundDivisor": "0x0400", "accountStartNonce": "0x0", "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", diff --git a/ethcore/res/wasm-tests b/ethcore/res/wasm-tests index 9ed630431..85e76c5ea 160000 --- a/ethcore/res/wasm-tests +++ b/ethcore/res/wasm-tests @@ -1 +1 @@ -Subproject commit 9ed6304313fa949ed92aa0570fb2bc759fb6dc58 +Subproject commit 85e76c5ea2a54c6c54e35014643b5080a50460c5 diff --git a/ethcore/src/account_db.rs b/ethcore/src/account_db.rs index 10e63dba3..5ce555aef 100644 --- a/ethcore/src/account_db.rs +++ b/ethcore/src/account_db.rs @@ -15,6 +15,7 @@ // along with Parity. If not, see . //! DB backend wrapper for Account trie +use std::collections::HashMap; use util::*; use rlp::NULL_RLP; diff --git a/ethcore/src/account_provider/mod.rs b/ethcore/src/account_provider/mod.rs index 249ca40af..752cec964 100755 --- a/ethcore/src/account_provider/mod.rs +++ b/ethcore/src/account_provider/mod.rs @@ -519,6 +519,11 @@ impl AccountProvider { } } + /// Returns account public key. + pub fn account_public(&self, address: Address, password: &str) -> Result { + self.sstore.public(&self.sstore.account_ref(&address)?, password) + } + /// Returns each account along with name and meta. pub fn set_account_name(&self, address: Address, name: String) -> Result<(), Error> { self.sstore.set_name(&self.sstore.account_ref(&address)?, name)?; @@ -697,6 +702,13 @@ impl AccountProvider { Ok(self.sstore.decrypt(&account, &password, shared_mac, message)?) } + /// Agree on shared key. + pub fn agree(&self, address: Address, password: Option, other_public: &Public) -> Result { + let account = self.sstore.account_ref(&address)?; + let password = password.map(Ok).unwrap_or_else(|| self.password(&account))?; + Ok(self.sstore.agree(&account, &password, other_public)?) + } + /// Returns the underlying `SecretStore` reference if one exists. pub fn list_geth_accounts(&self, testnet: bool) -> Vec
{ self.sstore.list_geth_accounts(testnet).into_iter().map(|a| Address::from(a).into()).collect() diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 8cd1e22b6..64958700e 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -25,7 +25,7 @@ use util::{Bytes, Address, Hashable, U256, H256, ordered_trie_root, SHA3_NULL_RL use util::error::{Mismatch, OutOfBounds}; use basic_types::{LogBloom, Seal}; -use evm::env_info::{EnvInfo, LastHashes}; +use vm::{EnvInfo, LastHashes}; use engines::Engine; use error::{Error, BlockError, TransactionError}; use factory::Factories; @@ -667,7 +667,7 @@ mod tests { use tests::helpers::*; use super::*; use engines::Engine; - use evm::env_info::LastHashes; + use vm::LastHashes; use error::Error; use header::Header; use factory::Factories; diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 4412df567..001df861c 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -16,6 +16,10 @@ //! Blockchain database. +use std::collections::{HashMap, HashSet}; +use std::sync::Arc; +use std::mem; +use itertools::Itertools; use bloomchain as bc; use util::*; use rlp::*; diff --git a/ethcore/src/blockchain/extras.rs b/ethcore/src/blockchain/extras.rs index 04c12d53a..0e2396f8c 100644 --- a/ethcore/src/blockchain/extras.rs +++ b/ethcore/src/blockchain/extras.rs @@ -16,6 +16,8 @@ //! Blockchain DB extras. +use std::ops; +use std::io::Write; use bloomchain; use blooms::{GroupPosition, BloomGroup}; use db::Key; @@ -23,11 +25,9 @@ use engines::epoch::{Transition as EpochTransition}; use header::BlockNumber; use receipt::Receipt; -use rlp::*; -use util::*; +use util::{HeapSizeOf, H256, H264, U256}; use util::kvdb::PREFIX_LEN as DB_PREFIX_LEN; - /// Represents index of extra data in database #[derive(Copy, Debug, Hash, Eq, PartialEq, Clone)] pub enum ExtrasIndex { @@ -56,7 +56,7 @@ fn with_index(hash: &H256, i: ExtrasIndex) -> H264 { pub struct BlockNumberKey([u8; 5]); -impl Deref for BlockNumberKey { +impl ops::Deref for BlockNumberKey { type Target = [u8]; fn deref(&self) -> &Self::Target { @@ -88,7 +88,7 @@ impl Key for H256 { pub struct LogGroupKey([u8; 6]); -impl Deref for LogGroupKey { +impl ops::Deref for LogGroupKey { type Target = [u8]; fn deref(&self) -> &Self::Target { @@ -160,7 +160,8 @@ pub const EPOCH_KEY_PREFIX: &'static [u8; DB_PREFIX_LEN] = &[ ]; pub struct EpochTransitionsKey([u8; EPOCH_KEY_LEN]); -impl Deref for EpochTransitionsKey { + +impl ops::Deref for EpochTransitionsKey { type Target = [u8]; fn deref(&self) -> &[u8] { &self.0[..] } @@ -181,7 +182,7 @@ impl Key for u64 { } /// Familial details concerning a block -#[derive(Debug, Clone)] +#[derive(Debug, Clone, RlpEncodable, RlpDecodable)] pub struct BlockDetails { /// Block number pub number: BlockNumber, @@ -199,30 +200,8 @@ impl HeapSizeOf for BlockDetails { } } -impl Decodable for BlockDetails { - fn decode(rlp: &UntrustedRlp) -> Result { - let details = BlockDetails { - number: rlp.val_at(0)?, - total_difficulty: rlp.val_at(1)?, - parent: rlp.val_at(2)?, - children: rlp.list_at(3)?, - }; - Ok(details) - } -} - -impl Encodable for BlockDetails { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(4); - s.append(&self.number); - s.append(&self.total_difficulty); - s.append(&self.parent); - s.append_list(&self.children); - } -} - /// Represents address of certain transaction within block -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Clone, RlpEncodable, RlpDecodable)] pub struct TransactionAddress { /// Block hash pub block_hash: H256, @@ -234,27 +213,8 @@ impl HeapSizeOf for TransactionAddress { fn heap_size_of_children(&self) -> usize { 0 } } -impl Decodable for TransactionAddress { - fn decode(rlp: &UntrustedRlp) -> Result { - let tx_address = TransactionAddress { - block_hash: rlp.val_at(0)?, - index: rlp.val_at(1)?, - }; - - Ok(tx_address) - } -} - -impl Encodable for TransactionAddress { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(2); - s.append(&self.block_hash); - s.append(&self.index); - } -} - /// Contains all block receipts. -#[derive(Clone)] +#[derive(Clone, RlpEncodableWrapper, RlpDecodableWrapper)] pub struct BlockReceipts { pub receipts: Vec, } @@ -267,20 +227,6 @@ impl BlockReceipts { } } -impl Decodable for BlockReceipts { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(BlockReceipts { - receipts: rlp.as_list()?, - }) - } -} - -impl Encodable for BlockReceipts { - fn rlp_append(&self, s: &mut RlpStream) { - s.append_list(&self.receipts); - } -} - impl HeapSizeOf for BlockReceipts { fn heap_size_of_children(&self) -> usize { self.receipts.heap_size_of_children() @@ -288,27 +234,12 @@ impl HeapSizeOf for BlockReceipts { } /// Candidate transitions to an epoch with specific number. -#[derive(Clone)] +#[derive(Clone, RlpEncodable, RlpDecodable)] pub struct EpochTransitions { pub number: u64, pub candidates: Vec, } -impl Encodable for EpochTransitions { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(2).append(&self.number).append_list(&self.candidates); - } -} - -impl Decodable for EpochTransitions { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(EpochTransitions { - number: rlp.val_at(0)?, - candidates: rlp.list_at(1)?, - }) - } -} - #[cfg(test)] mod tests { use rlp::*; diff --git a/ethcore/src/blooms/bloom.rs b/ethcore/src/blooms/bloom.rs index cac9ff448..c79091cb4 100644 --- a/ethcore/src/blooms/bloom.rs +++ b/ethcore/src/blooms/bloom.rs @@ -15,12 +15,11 @@ // along with Parity. If not, see . use bloomchain as bc; -use rlp::*; use util::HeapSizeOf; use basic_types::LogBloom; /// Helper structure representing bloom of the trace. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, RlpEncodableWrapper, RlpDecodableWrapper)] pub struct Bloom(LogBloom); impl From for Bloom { @@ -43,18 +42,6 @@ impl Into for Bloom { } } -impl Decodable for Bloom { - fn decode(rlp: &UntrustedRlp) -> Result { - LogBloom::decode(rlp).map(Bloom) - } -} - -impl Encodable for Bloom { - fn rlp_append(&self, s: &mut RlpStream) { - Encodable::rlp_append(&self.0, s) - } -} - impl HeapSizeOf for Bloom { fn heap_size_of_children(&self) -> usize { 0 diff --git a/ethcore/src/builtin.rs b/ethcore/src/builtin.rs index 7f71802b3..9e49e610c 100644 --- a/ethcore/src/builtin.rs +++ b/ethcore/src/builtin.rs @@ -36,9 +36,9 @@ impl From<&'static str> for Error { } } -impl Into<::evm::Error> for Error { - fn into(self) -> ::evm::Error { - ::evm::Error::BuiltIn(self.0) +impl Into<::vm::Error> for Error { + fn into(self) -> ::vm::Error { + ::vm::Error::BuiltIn(self.0) } } diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index dafef82f6..2355fbfdf 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -20,9 +20,10 @@ use std::sync::{Arc, Weak}; use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering}; use std::time::{Instant}; use time::precise_time_ns; +use itertools::Itertools; // util -use util::{Bytes, PerfTimer, Itertools, Mutex, RwLock, MutexGuard, Hashable}; +use util::{Bytes, PerfTimer, Mutex, RwLock, MutexGuard, Hashable}; use util::{journaldb, DBValue, TrieFactory, Trie}; use util::{U256, H256, Address, H2048}; use util::trie::TrieSpec; @@ -42,9 +43,8 @@ use client::{ }; use encoded; use engines::{Engine, EpochTransition}; -use evm::env_info::EnvInfo; -use evm::env_info::LastHashes; use error::{ImportError, ExecutionError, CallError, BlockError, ImportResult, Error as EthcoreError}; +use vm::{EnvInfo, LastHashes}; use evm::{Factory as EvmFactory, Schedule}; use executive::{Executive, Executed, TransactOptions, contract_address}; use factory::Factories; @@ -907,7 +907,7 @@ impl Client { pub fn state_at(&self, id: BlockId) -> Option> { // fast path for latest state. match id.clone() { - BlockId::Pending => return self.miner.pending_state().or_else(|| Some(self.state())), + BlockId::Pending => return self.miner.pending_state(self.chain.read().best_block_number()).or_else(|| Some(self.state())), BlockId::Latest => return Some(self.state()), _ => {}, } @@ -1056,19 +1056,20 @@ impl Client { self.history } - fn block_hash(chain: &BlockChain, id: BlockId) -> Option { + fn block_hash(chain: &BlockChain, miner: &Miner, id: BlockId) -> Option { match id { BlockId::Hash(hash) => Some(hash), BlockId::Number(number) => chain.block_hash(number), BlockId::Earliest => chain.block_hash(0), - BlockId::Latest | BlockId::Pending => Some(chain.best_block_hash()), + BlockId::Latest => Some(chain.best_block_hash()), + BlockId::Pending => miner.pending_block_header(chain.best_block_number()).map(|header| header.hash()) } } fn transaction_address(&self, id: TransactionId) -> Option { match id { TransactionId::Hash(ref hash) => self.chain.read().transaction_address(hash), - TransactionId::Location(id, index) => Self::block_hash(&self.chain.read(), id).map(|hash| TransactionAddress { + TransactionId::Location(id, index) => Self::block_hash(&self.chain.read(), &self.miner, id).map(|hash| TransactionAddress { block_hash: hash, index: index, }) @@ -1111,6 +1112,20 @@ impl Client { data: data, }.fake_sign(from) } + + fn do_call(&self, env_info: &EnvInfo, state: &mut State, t: &SignedTransaction, analytics: CallAnalytics) -> Result { + let original_state = if analytics.state_diffing { Some(state.clone()) } else { None }; + + let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false }; + let mut ret = Executive::new(state, env_info, &*self.engine).transact_virtual(t, options)?; + + // TODO gav move this into Executive. + if let Some(original) = original_state { + ret.state_diff = Some(state.diff_from(original).map_err(ExecutionError::from)?); + } + + Ok(ret) + } } impl snapshot::DatabaseRestore for Client { @@ -1135,23 +1150,31 @@ impl snapshot::DatabaseRestore for Client { } impl BlockChainClient for Client { - fn call(&self, t: &SignedTransaction, block: BlockId, analytics: CallAnalytics) -> Result { + fn call(&self, transaction: &SignedTransaction, analytics: CallAnalytics, block: BlockId) -> Result { let mut env_info = self.env_info(block).ok_or(CallError::StatePruned)?; env_info.gas_limit = U256::max_value(); // that's just a copy of the state. let mut state = self.state_at(block).ok_or(CallError::StatePruned)?; - let original_state = if analytics.state_diffing { Some(state.clone()) } else { None }; - let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false }; - let mut ret = Executive::new(&mut state, &env_info, &*self.engine).transact_virtual(t, options)?; + self.do_call(&env_info, &mut state, transaction, analytics) + } - // TODO gav move this into Executive. - if let Some(original) = original_state { - ret.state_diff = Some(state.diff_from(original).map_err(ExecutionError::from)?); + fn call_many(&self, transactions: &[(SignedTransaction, CallAnalytics)], block: BlockId) -> Result, CallError> { + let mut env_info = self.env_info(block).ok_or(CallError::StatePruned)?; + env_info.gas_limit = U256::max_value(); + + // that's just a copy of the state. + let mut state = self.state_at(block).ok_or(CallError::StatePruned)?; + let mut results = Vec::with_capacity(transactions.len()); + + for &(ref t, analytics) in transactions { + let ret = self.do_call(&env_info, &mut state, t, analytics)?; + env_info.gas_used = ret.cumulative_gas_used; + results.push(ret); } - Ok(ret) + Ok(results) } fn estimate_gas(&self, t: &SignedTransaction, block: BlockId) -> Result { @@ -1304,7 +1327,16 @@ impl BlockChainClient for Client { fn block_header(&self, id: BlockId) -> Option<::encoded::Header> { let chain = self.chain.read(); - Self::block_hash(&chain, id).and_then(|hash| chain.block_header_data(&hash)) + + if let BlockId::Pending = id { + if let Some(block) = self.miner.pending_block(chain.best_block_number()) { + return Some(encoded::Header::new(block.header.rlp(Seal::Without))); + } + // fall back to latest + return self.block_header(BlockId::Latest); + } + + Self::block_hash(&chain, &self.miner, id).and_then(|hash| chain.block_header_data(&hash)) } fn block_number(&self, id: BlockId) -> Option { @@ -1312,30 +1344,48 @@ impl BlockChainClient for Client { BlockId::Number(number) => Some(number), BlockId::Hash(ref hash) => self.chain.read().block_number(hash), BlockId::Earliest => Some(0), - BlockId::Latest | BlockId::Pending => Some(self.chain.read().best_block_number()), + BlockId::Latest => Some(self.chain.read().best_block_number()), + BlockId::Pending => Some(self.chain.read().best_block_number() + 1), } } fn block_body(&self, id: BlockId) -> Option { let chain = self.chain.read(); - Self::block_hash(&chain, id).and_then(|hash| chain.block_body(&hash)) + + if let BlockId::Pending = id { + if let Some(block) = self.miner.pending_block(chain.best_block_number()) { + return Some(encoded::Body::new(BlockChain::block_to_body(&block.rlp_bytes(Seal::Without)))); + } + // fall back to latest + return self.block_body(BlockId::Latest); + } + + Self::block_hash(&chain, &self.miner, id).and_then(|hash| chain.block_body(&hash)) } fn block(&self, id: BlockId) -> Option { + let chain = self.chain.read(); + if let BlockId::Pending = id { - if let Some(block) = self.miner.pending_block() { + if let Some(block) = self.miner.pending_block(chain.best_block_number()) { return Some(encoded::Block::new(block.rlp_bytes(Seal::Without))); } + // fall back to latest + return self.block(BlockId::Latest); } - let chain = self.chain.read(); - Self::block_hash(&chain, id).and_then(|hash| { + + Self::block_hash(&chain, &self.miner, id).and_then(|hash| { chain.block(&hash) }) } fn block_status(&self, id: BlockId) -> BlockStatus { + if let BlockId::Pending = id { + return BlockStatus::Pending; + } + let chain = self.chain.read(); - match Self::block_hash(&chain, id) { + match Self::block_hash(&chain, &self.miner, id) { Some(ref hash) if chain.is_known(hash) => BlockStatus::InChain, Some(hash) => self.block_queue.status(&hash).into(), None => BlockStatus::Unknown @@ -1343,13 +1393,18 @@ impl BlockChainClient for Client { } fn block_total_difficulty(&self, id: BlockId) -> Option { - if let BlockId::Pending = id { - if let Some(block) = self.miner.pending_block() { - return Some(*block.header.difficulty() + self.block_total_difficulty(BlockId::Latest).expect("blocks in chain have details; qed")); - } - } let chain = self.chain.read(); - Self::block_hash(&chain, id).and_then(|hash| chain.block_details(&hash)).map(|d| d.total_difficulty) + if let BlockId::Pending = id { + let latest_difficulty = self.block_total_difficulty(BlockId::Latest).expect("blocks in chain have details; qed"); + let pending_difficulty = self.miner.pending_block_header(chain.best_block_number()).map(|header| *header.difficulty()); + if let Some(difficulty) = pending_difficulty { + return Some(difficulty + latest_difficulty); + } + // fall back to latest + return Some(latest_difficulty); + } + + Self::block_hash(&chain, &self.miner, id).and_then(|hash| chain.block_details(&hash)).map(|d| d.total_difficulty) } fn nonce(&self, address: &Address, id: BlockId) -> Option { @@ -1362,7 +1417,7 @@ impl BlockChainClient for Client { fn block_hash(&self, id: BlockId) -> Option { let chain = self.chain.read(); - Self::block_hash(&chain, id) + Self::block_hash(&chain, &self.miner, id) } fn code(&self, address: &Address, id: BlockId) -> Option> { @@ -1527,7 +1582,8 @@ impl BlockChainClient for Client { if self.chain.read().is_known(&unverified.hash()) { return Err(BlockImportError::Import(ImportError::AlreadyInChain)); } - if self.block_status(BlockId::Hash(unverified.parent_hash())) == BlockStatus::Unknown { + let status = self.block_status(BlockId::Hash(unverified.parent_hash())); + if status == BlockStatus::Unknown || status == BlockStatus::Pending { return Err(BlockImportError::Block(BlockError::UnknownParent(unverified.parent_hash()))); } } @@ -1541,7 +1597,8 @@ impl BlockChainClient for Client { if self.chain.read().is_known(&header.hash()) { return Err(BlockImportError::Import(ImportError::AlreadyInChain)); } - if self.block_status(BlockId::Hash(header.parent_hash())) == BlockStatus::Unknown { + let status = self.block_status(BlockId::Hash(header.parent_hash())); + if status == BlockStatus::Unknown || status == BlockStatus::Pending { return Err(BlockImportError::Block(BlockError::UnknownParent(header.parent_hash()))); } } @@ -1663,8 +1720,8 @@ impl BlockChainClient for Client { } } - fn signing_network_id(&self) -> Option { - self.engine.signing_network_id(&self.latest_env_info()) + fn signing_chain_id(&self) -> Option { + self.engine.signing_chain_id(&self.latest_env_info()) } fn block_extra_info(&self, id: BlockId) -> Option> { @@ -1687,7 +1744,7 @@ impl BlockChainClient for Client { fn call_contract(&self, block_id: BlockId, address: Address, data: Bytes) -> Result { let transaction = self.contract_call_tx(block_id, address, data); - self.call(&transaction, block_id, Default::default()) + self.call(&transaction, Default::default(), block_id) .map_err(|e| format!("{:?}", e)) .map(|executed| { executed.output @@ -1703,9 +1760,9 @@ impl BlockChainClient for Client { value: U256::zero(), data: data, }; - let network_id = self.engine.signing_network_id(&self.latest_env_info()); - let signature = self.engine.sign(transaction.hash(network_id))?; - let signed = SignedTransaction::new(transaction.with_signature(signature, network_id))?; + let chain_id = self.engine.signing_chain_id(&self.latest_env_info()); + let signature = self.engine.sign(transaction.hash(chain_id))?; + let signed = SignedTransaction::new(transaction.with_signature(signature, chain_id))?; self.miner.import_own_transaction(self, signed.into()) } diff --git a/ethcore/src/client/evm_test_client.rs b/ethcore/src/client/evm_test_client.rs index 5f23f449d..cd8501c31 100644 --- a/ethcore/src/client/evm_test_client.rs +++ b/ethcore/src/client/evm_test_client.rs @@ -23,7 +23,7 @@ use util::kvdb::{self, KeyValueDB}; use {state, state_db, client, executive, trace, db, spec}; use factory::Factories; use evm::{self, VMType}; -use evm::action_params::ActionParams; +use vm::{self, ActionParams}; /// EVM test Error. #[derive(Debug)] @@ -31,7 +31,7 @@ pub enum EvmTestError { /// Trie integrity error. Trie(util::TrieError), /// EVM error. - Evm(evm::Error), + Evm(vm::Error), /// Initialization error. Initialization(::error::Error), /// Low-level database error. diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index b2d1ce991..f7c7417ad 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -40,7 +40,7 @@ pub use types::pruning_info::PruningInfo; pub use types::call_analytics::CallAnalytics; pub use executive::{Executed, Executive, TransactOptions}; -pub use evm::env_info::{LastHashes, EnvInfo}; +pub use vm::{LastHashes, EnvInfo}; pub use error::{BlockImportError, TransactionImportError, TransactionImportResult}; pub use verification::VerifierType; diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 1d30c5800..f60878216 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -17,6 +17,10 @@ //! Test client. use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrder}; +use std::sync::Arc; +use std::collections::{HashMap, BTreeMap}; +use std::mem; +use itertools::Itertools; use rustc_hex::FromHex; use util::*; use rlp::*; @@ -36,7 +40,8 @@ use log_entry::LocalizedLogEntry; use receipt::{Receipt, LocalizedReceipt}; use blockchain::extras::BlockReceipts; use error::{ImportResult, Error as EthcoreError}; -use evm::{Factory as EvmFactory, VMType, Schedule}; +use evm::{Factory as EvmFactory, VMType}; +use vm::Schedule; use miner::{Miner, MinerService, TransactionImportResult}; use spec::Spec; use types::basic_account::BasicAccount; @@ -397,10 +402,18 @@ impl MiningBlockChainClient for TestBlockChainClient { } impl BlockChainClient for TestBlockChainClient { - fn call(&self, _t: &SignedTransaction, _block: BlockId, _analytics: CallAnalytics) -> Result { + fn call(&self, _t: &SignedTransaction, _analytics: CallAnalytics, _block: BlockId) -> Result { self.execution_result.read().clone().unwrap() } + fn call_many(&self, txs: &[(SignedTransaction, CallAnalytics)], block: BlockId) -> Result, CallError> { + let mut res = Vec::with_capacity(txs.len()); + for &(ref tx, analytics) in txs { + res.push(self.call(tx, analytics, block)?); + } + Ok(res) + } + fn estimate_gas(&self, _t: &SignedTransaction, _block: BlockId) -> Result { Ok(21000.into()) } @@ -419,7 +432,7 @@ impl BlockChainClient for TestBlockChainClient { fn nonce(&self, address: &Address, id: BlockId) -> Option { match id { - BlockId::Latest => Some(self.nonces.read().get(address).cloned().unwrap_or(self.spec.params().account_start_nonce)), + BlockId::Latest | BlockId::Pending => Some(self.nonces.read().get(address).cloned().unwrap_or(self.spec.params().account_start_nonce)), _ => None, } } @@ -434,16 +447,15 @@ impl BlockChainClient for TestBlockChainClient { fn code(&self, address: &Address, id: BlockId) -> Option> { match id { - BlockId::Latest => Some(self.code.read().get(address).cloned()), + BlockId::Latest | BlockId::Pending => Some(self.code.read().get(address).cloned()), _ => None, } } fn balance(&self, address: &Address, id: BlockId) -> Option { - if let BlockId::Latest = id { - Some(self.balances.read().get(address).cloned().unwrap_or_else(U256::zero)) - } else { - None + match id { + BlockId::Latest | BlockId::Pending => Some(self.balances.read().get(address).cloned().unwrap_or_else(U256::zero)), + _ => None, } } @@ -452,10 +464,9 @@ impl BlockChainClient for TestBlockChainClient { } fn storage_at(&self, address: &Address, position: &H256, id: BlockId) -> Option { - if let BlockId::Latest = id { - Some(self.storage.read().get(&(address.clone(), position.clone())).cloned().unwrap_or_else(H256::new)) - } else { - None + match id { + BlockId::Latest | BlockId::Pending => Some(self.storage.read().get(&(address.clone(), position.clone())).cloned().unwrap_or_else(H256::new)), + _ => None, } } @@ -544,7 +555,8 @@ impl BlockChainClient for TestBlockChainClient { match id { BlockId::Number(number) if (number as usize) < self.blocks.read().len() => BlockStatus::InChain, BlockId::Hash(ref hash) if self.blocks.read().get(hash).is_some() => BlockStatus::InChain, - BlockId::Latest | BlockId::Pending | BlockId::Earliest => BlockStatus::InChain, + BlockId::Latest | BlockId::Earliest => BlockStatus::InChain, + BlockId::Pending => BlockStatus::Pending, _ => BlockStatus::Unknown, } } @@ -722,7 +734,7 @@ impl BlockChainClient for TestBlockChainClient { self.miner.ready_transactions(info.best_block_number, info.best_block_timestamp) } - fn signing_network_id(&self) -> Option { None } + fn signing_chain_id(&self) -> Option { None } fn mode(&self) -> Mode { Mode::Active } @@ -753,9 +765,9 @@ impl BlockChainClient for TestBlockChainClient { value: U256::default(), data: data, }; - let network_id = Some(self.spec.params().network_id); - let sig = self.spec.engine.sign(transaction.hash(network_id)).unwrap(); - let signed = SignedTransaction::new(transaction.with_signature(sig, network_id)).unwrap(); + let chain_id = Some(self.spec.chain_id()); + let sig = self.spec.engine.sign(transaction.hash(chain_id)).unwrap(); + let signed = SignedTransaction::new(transaction.with_signature(sig, chain_id)).unwrap(); self.miner.import_own_transaction(self, signed.into()) } diff --git a/ethcore/src/client/traits.rs b/ethcore/src/client/traits.rs index 47cb51e3f..2cb33975d 100644 --- a/ethcore/src/client/traits.rs +++ b/ethcore/src/client/traits.rs @@ -15,11 +15,12 @@ // along with Parity. If not, see . use std::collections::BTreeMap; +use itertools::Itertools; use block::{OpenBlock, SealedBlock, ClosedBlock}; use blockchain::TreeRoute; use encoded; -use evm::env_info::LastHashes; +use vm::LastHashes; use error::{ImportResult, CallError, Error as EthcoreError}; use error::{TransactionImportResult, BlockImportError}; use evm::{Factory as EvmFactory, Schedule}; @@ -33,7 +34,7 @@ use trace::LocalizedTrace; use transaction::{LocalizedTransaction, PendingTransaction, SignedTransaction}; use verification::queue::QueueInfo as BlockQueueInfo; -use util::{U256, Address, H256, H2048, Bytes, Itertools}; +use util::{U256, Address, H256, H2048, Bytes}; use util::hashdb::DBValue; use types::ids::*; @@ -182,7 +183,11 @@ pub trait BlockChainClient : Sync + Send { fn logs(&self, filter: Filter) -> Vec; /// Makes a non-persistent transaction call. - fn call(&self, t: &SignedTransaction, block: BlockId, analytics: CallAnalytics) -> Result; + fn call(&self, tx: &SignedTransaction, analytics: CallAnalytics, block: BlockId) -> Result; + + /// Makes multiple non-persistent but dependent transaction calls. + /// Returns a vector of successes or a failure if any of the transaction fails. + fn call_many(&self, txs: &[(SignedTransaction, CallAnalytics)], block: BlockId) -> Result, CallError>; /// Estimates how much gas will be necessary for a call. fn estimate_gas(&self, t: &SignedTransaction, block: BlockId) -> Result; @@ -235,8 +240,8 @@ pub trait BlockChainClient : Sync + Send { corpus.into() } - /// Get the preferred network ID to sign on - fn signing_network_id(&self) -> Option; + /// Get the preferred chain ID to sign on + fn signing_chain_id(&self) -> Option; /// Get the mode. fn mode(&self) -> Mode; diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index a2e75ee4a..33979e01c 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -17,8 +17,10 @@ //! A blockchain engine that supports a non-instant BFT proof-of-authority. use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering}; -use std::sync::Weak; +use std::sync::{Weak, Arc}; use std::time::{UNIX_EPOCH, Duration}; +use std::collections::{BTreeMap, HashSet, HashMap}; +use std::cmp; use account_provider::AccountProvider; use block::*; @@ -47,22 +49,14 @@ mod finality; /// `AuthorityRound` params. pub struct AuthorityRoundParams { - /// Gas limit divisor. - pub gas_limit_bound_divisor: U256, /// Time to wait before next block or authority switching. pub step_duration: Duration, - /// Block reward. - pub block_reward: U256, - /// Namereg contract address. - pub registrar: Address, /// Starting step, pub start_step: Option, /// Valid validators. pub validators: Box, /// Chain score validation transition block. pub validate_score_transition: u64, - /// Number of first block where EIP-155 rules are validated. - pub eip155_transition: u64, /// Monotonic step validation transition block. pub validate_step_transition: u64, /// Immediate transitions. @@ -72,14 +66,10 @@ pub struct AuthorityRoundParams { impl From for AuthorityRoundParams { fn from(p: ethjson::spec::AuthorityRoundParams) -> Self { AuthorityRoundParams { - gas_limit_bound_divisor: p.gas_limit_bound_divisor.into(), step_duration: Duration::from_secs(p.step_duration.into()), validators: new_validator_set(p.validators), - block_reward: p.block_reward.map_or_else(U256::zero, Into::into), - registrar: p.registrar.map_or_else(Address::new, Into::into), start_step: p.start_step.map(Into::into), validate_score_transition: p.validate_score_transition.map_or(0, Into::into), - eip155_transition: p.eip155_transition.map_or(0, Into::into), validate_step_transition: p.validate_step_transition.map_or(0, Into::into), immediate_transitions: p.immediate_transitions.unwrap_or(false), } @@ -214,9 +204,6 @@ impl EpochManager { /// Engine using `AuthorityRound` proof-of-authority BFT consensus. pub struct AuthorityRound { params: CommonParams, - gas_limit_bound_divisor: U256, - block_reward: U256, - registrar: Address, builtins: BTreeMap, transition_service: IoService<()>, step: Arc, @@ -225,7 +212,6 @@ pub struct AuthorityRound { signer: RwLock, validators: Box, validate_score_transition: u64, - eip155_transition: u64, validate_step_transition: u64, epoch_manager: Mutex, immediate_transitions: bool, @@ -362,9 +348,6 @@ impl AuthorityRound { let engine = Arc::new( AuthorityRound { params: params, - gas_limit_bound_divisor: our_params.gas_limit_bound_divisor, - block_reward: our_params.block_reward, - registrar: our_params.registrar, builtins: builtins, transition_service: IoService::<()>::start()?, step: Arc::new(Step { @@ -377,7 +360,6 @@ impl AuthorityRound { signer: Default::default(), validators: our_params.validators, validate_score_transition: our_params.validate_score_transition, - eip155_transition: our_params.eip155_transition, validate_step_transition: our_params.validate_step_transition, epoch_manager: Mutex::new(EpochManager::blank()), immediate_transitions: our_params.immediate_transitions, @@ -433,7 +415,9 @@ impl Engine for AuthorityRound { fn params(&self) -> &CommonParams { &self.params } - fn additional_params(&self) -> HashMap { hash_map!["registrar".to_owned() => self.registrar.hex()] } + fn additional_params(&self) -> HashMap { + hash_map!["registrar".to_owned() => self.params().registrar.hex()] + } fn builtins(&self) -> &BTreeMap { &self.builtins } @@ -461,11 +445,11 @@ impl Engine for AuthorityRound { header.set_difficulty(new_difficulty); header.set_gas_limit({ let gas_limit = parent.gas_limit().clone(); - let bound_divisor = self.gas_limit_bound_divisor; + let bound_divisor = self.params().gas_limit_bound_divisor; if gas_limit < gas_floor_target { - min(gas_floor_target, gas_limit + gas_limit / bound_divisor - 1.into()) + cmp::min(gas_floor_target, gas_limit + gas_limit / bound_divisor - 1.into()) } else { - max(gas_floor_target, gas_limit - gas_limit / bound_divisor + 1.into()) + cmp::max(gas_floor_target, gas_limit - gas_limit / bound_divisor + 1.into()) } }); } @@ -532,7 +516,7 @@ impl Engine for AuthorityRound { fn on_new_block( &self, block: &mut ExecutedBlock, - last_hashes: Arc<::evm::env_info::LastHashes>, + last_hashes: Arc<::vm::LastHashes>, epoch_begin: bool, ) -> Result<(), Error> { let parent_hash = block.fields().header.parent_hash().clone(); @@ -564,7 +548,8 @@ impl Engine for AuthorityRound { fn on_close_block(&self, block: &mut ExecutedBlock) -> Result<(), Error> { let fields = block.fields_mut(); // Bestow block reward - let res = fields.state.add_balance(fields.header.author(), &self.block_reward, CleanupMode::NoEmpty) + let reward = self.params().block_reward; + let res = fields.state.add_balance(fields.header.author(), &reward, CleanupMode::NoEmpty) .map_err(::error::Error::from) .and_then(|_| fields.state.commit()); // Commit state so that we can actually figure out the state root. @@ -629,7 +614,7 @@ impl Engine for AuthorityRound { } } - let gas_limit_divisor = self.gas_limit_bound_divisor; + let gas_limit_divisor = self.params().gas_limit_bound_divisor; let min_gas = parent.gas_limit().clone() - parent.gas_limit().clone() / gas_limit_divisor; let max_gas = parent.gas_limit().clone() + parent.gas_limit().clone() / gas_limit_divisor; if header.gas_limit() <= &min_gas || header.gas_limit() >= &max_gas { @@ -707,6 +692,7 @@ impl Engine for AuthorityRound { // apply immediate transitions. if let Some(change) = self.validators.is_epoch_end(first, chain_head) { + let change = combine_proofs(chain_head.number(), &change, &[]); return Some(change) } @@ -817,12 +803,12 @@ impl Engine for AuthorityRound { } } - fn verify_transaction_basic(&self, t: &UnverifiedTransaction, header: &Header) -> result::Result<(), Error> { + fn verify_transaction_basic(&self, t: &UnverifiedTransaction, header: &Header) -> Result<(), Error> { t.check_low_s()?; - if let Some(n) = t.network_id() { - if header.number() >= self.eip155_transition && n != self.params().chain_id { - return Err(TransactionError::InvalidNetworkId.into()); + if let Some(n) = t.chain_id() { + if header.number() >= self.params().eip155_transition && n != self.params().chain_id { + return Err(TransactionError::InvalidChainId.into()); } } @@ -853,6 +839,7 @@ impl Engine for AuthorityRound { #[cfg(test)] mod tests { + use std::sync::Arc; use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering}; use util::*; use header::Header; @@ -943,10 +930,10 @@ mod tests { let addr = tap.insert_account("0".sha3().into(), "0").unwrap(); let mut parent_header: Header = Header::default(); parent_header.set_seal(vec![encode(&0usize).into_vec()]); - parent_header.set_gas_limit(U256::from_str("222222").unwrap()); + parent_header.set_gas_limit("222222".parse::().unwrap()); let mut header: Header = Header::default(); header.set_number(1); - header.set_gas_limit(U256::from_str("222222").unwrap()); + header.set_gas_limit("222222".parse::().unwrap()); header.set_author(addr); let engine = Spec::new_test_round().engine; @@ -969,10 +956,10 @@ mod tests { let mut parent_header: Header = Header::default(); parent_header.set_seal(vec![encode(&0usize).into_vec()]); - parent_header.set_gas_limit(U256::from_str("222222").unwrap()); + parent_header.set_gas_limit("222222".parse::().unwrap()); let mut header: Header = Header::default(); header.set_number(1); - header.set_gas_limit(U256::from_str("222222").unwrap()); + header.set_gas_limit("222222".parse::().unwrap()); header.set_author(addr); let engine = Spec::new_test_round().engine; @@ -995,10 +982,10 @@ mod tests { let mut parent_header: Header = Header::default(); parent_header.set_seal(vec![encode(&4usize).into_vec()]); - parent_header.set_gas_limit(U256::from_str("222222").unwrap()); + parent_header.set_gas_limit("222222".parse::().unwrap()); let mut header: Header = Header::default(); header.set_number(1); - header.set_gas_limit(U256::from_str("222222").unwrap()); + header.set_gas_limit("222222".parse::().unwrap()); header.set_author(addr); let engine = Spec::new_test_round().engine; @@ -1016,25 +1003,26 @@ mod tests { fn reports_skipped() { let last_benign = Arc::new(AtomicUsize::new(0)); let params = AuthorityRoundParams { - gas_limit_bound_divisor: U256::from_str("400").unwrap(), step_duration: Default::default(), - block_reward: Default::default(), - registrar: Default::default(), start_step: Some(1), validators: Box::new(TestSet::new(Default::default(), last_benign.clone())), validate_score_transition: 0, validate_step_transition: 0, - eip155_transition: 0, immediate_transitions: true, }; - let aura = AuthorityRound::new(Default::default(), params, Default::default()).unwrap(); + + let aura = { + let mut c_params = ::spec::CommonParams::default(); + c_params.gas_limit_bound_divisor = 5.into(); + AuthorityRound::new(c_params, params, Default::default()).unwrap() + }; let mut parent_header: Header = Header::default(); parent_header.set_seal(vec![encode(&1usize).into_vec()]); - parent_header.set_gas_limit(U256::from_str("222222").unwrap()); + parent_header.set_gas_limit("222222".parse::().unwrap()); let mut header: Header = Header::default(); header.set_number(1); - header.set_gas_limit(U256::from_str("222222").unwrap()); + header.set_gas_limit("222222".parse::().unwrap()); header.set_seal(vec![encode(&3usize).into_vec()]); // Do not report when signer not present. diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index 83a0c0ca3..86acd211c 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -16,7 +16,9 @@ //! A blockchain engine that supports a basic, non-BFT proof-of-authority. -use std::sync::Weak; +use std::sync::{Weak, Arc}; +use std::collections::BTreeMap; +use std::cmp; use util::*; use ethkey::{recover, public_to_address, Signature}; use account_provider::AccountProvider; @@ -35,8 +37,6 @@ use super::validator_set::{ValidatorSet, SimpleList, new_validator_set}; /// `BasicAuthority` params. #[derive(Debug, PartialEq)] pub struct BasicAuthorityParams { - /// Gas limit divisor. - pub gas_limit_bound_divisor: U256, /// Valid signatories. pub validators: ethjson::spec::ValidatorSet, } @@ -44,7 +44,6 @@ pub struct BasicAuthorityParams { impl From for BasicAuthorityParams { fn from(p: ethjson::spec::BasicAuthorityParams) -> Self { BasicAuthorityParams { - gas_limit_bound_divisor: p.gas_limit_bound_divisor.into(), validators: p.validators, } } @@ -80,7 +79,6 @@ fn verify_external(header: &Header, validators: &ValidatorSet) -> Result<(), Err /// Engine using `BasicAuthority`, trivial proof-of-authority consensus. pub struct BasicAuthority { params: CommonParams, - gas_limit_bound_divisor: U256, builtins: BTreeMap, signer: RwLock, validators: Box, @@ -91,7 +89,6 @@ impl BasicAuthority { pub fn new(params: CommonParams, our_params: BasicAuthorityParams, builtins: BTreeMap) -> Self { BasicAuthority { params: params, - gas_limit_bound_divisor: our_params.gas_limit_bound_divisor, builtins: builtins, validators: new_validator_set(our_params.validators), signer: Default::default(), @@ -119,11 +116,11 @@ impl Engine for BasicAuthority { header.set_difficulty(parent.difficulty().clone()); header.set_gas_limit({ let gas_limit = parent.gas_limit().clone(); - let bound_divisor = self.gas_limit_bound_divisor; + let bound_divisor = self.params().gas_limit_bound_divisor; if gas_limit < gas_floor_target { - min(gas_floor_target, gas_limit + gas_limit / bound_divisor - 1.into()) + cmp::min(gas_floor_target, gas_limit + gas_limit / bound_divisor - 1.into()) } else { - max(gas_floor_target, gas_limit - gas_limit / bound_divisor + 1.into()) + cmp::max(gas_floor_target, gas_limit - gas_limit / bound_divisor + 1.into()) } }); } @@ -147,7 +144,7 @@ impl Engine for BasicAuthority { Seal::None } - fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> { + fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> Result<(), Error> { // check the seal fields. // TODO: pull this out into common code. if header.seal().len() != self.seal_fields() { @@ -158,11 +155,11 @@ impl Engine for BasicAuthority { Ok(()) } - fn verify_block_unordered(&self, _header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> { + fn verify_block_unordered(&self, _header: &Header, _block: Option<&[u8]>) -> Result<(), Error> { Ok(()) } - fn verify_block_family(&self, header: &Header, parent: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> { + fn verify_block_family(&self, header: &Header, parent: &Header, _block: Option<&[u8]>) -> Result<(), Error> { // Do not calculate difficulty for genesis blocks. if header.number() == 0 { return Err(From::from(BlockError::RidiculousNumber(OutOfBounds { min: Some(1), max: None, found: header.number() }))); @@ -172,7 +169,7 @@ impl Engine for BasicAuthority { if header.difficulty() != parent.difficulty() { return Err(From::from(BlockError::InvalidDifficulty(Mismatch { expected: *parent.difficulty(), found: *header.difficulty() }))) } - let gas_limit_divisor = self.gas_limit_bound_divisor; + let gas_limit_divisor = self.params().gas_limit_bound_divisor; let min_gas = parent.gas_limit().clone() - parent.gas_limit().clone() / gas_limit_divisor; let max_gas = parent.gas_limit().clone() + parent.gas_limit().clone() / gas_limit_divisor; if header.gas_limit() <= &min_gas || header.gas_limit() >= &max_gas { @@ -254,6 +251,7 @@ impl Engine for BasicAuthority { #[cfg(test)] mod tests { + use std::sync::Arc; use util::*; use block::*; use error::{BlockError, Error}; diff --git a/ethcore/src/engines/epoch.rs b/ethcore/src/engines/epoch.rs index f738113cf..586059e83 100644 --- a/ethcore/src/engines/epoch.rs +++ b/ethcore/src/engines/epoch.rs @@ -16,14 +16,12 @@ //! Epoch verifiers and transitions. +use util::H256; use error::Error; use header::Header; -use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp}; -use util::H256; - /// A full epoch transition. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, RlpEncodable, RlpDecodable)] pub struct Transition { /// Block hash at which the transition occurred. pub block_hash: H256, @@ -33,46 +31,14 @@ pub struct Transition { pub proof: Vec, } -impl Encodable for Transition { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(3) - .append(&self.block_hash) - .append(&self.block_number) - .append(&self.proof); - } -} - -impl Decodable for Transition { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(Transition { - block_hash: rlp.val_at(0)?, - block_number: rlp.val_at(1)?, - proof: rlp.val_at(2)?, - }) - } -} - /// An epoch transition pending a finality proof. /// Not all transitions need one. +#[derive(RlpEncodableWrapper, RlpDecodableWrapper)] pub struct PendingTransition { /// "transition/epoch" proof from the engine. pub proof: Vec, } -impl Encodable for PendingTransition { - fn rlp_append(&self, s: &mut RlpStream) { - s.append(&self.proof); - } -} - -impl Decodable for PendingTransition { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(PendingTransition { - proof: rlp.as_val()?, - }) - } -} - /// Verifier for all blocks within an epoch with self-contained state. /// /// See docs on `Engine` relating to proving functions for more details. diff --git a/ethcore/src/engines/instant_seal.rs b/ethcore/src/engines/instant_seal.rs index 38834622c..976f815e0 100644 --- a/ethcore/src/engines/instant_seal.rs +++ b/ethcore/src/engines/instant_seal.rs @@ -14,26 +14,24 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::collections::BTreeMap; -use util::{Address, HashMap}; +use std::collections::{BTreeMap, HashMap}; +use util::Address; use builtin::Builtin; use engines::{Engine, Seal}; use spec::CommonParams; -use block::ExecutedBlock; +use block::{ExecutedBlock, IsBlock}; /// An engine which does not provide any consensus mechanism, just seals blocks internally. pub struct InstantSeal { params: CommonParams, - registrar: Address, builtins: BTreeMap, } impl InstantSeal { /// Returns new instance of InstantSeal with default VM Factory - pub fn new(params: CommonParams, registrar: Address, builtins: BTreeMap) -> Self { + pub fn new(params: CommonParams, builtins: BTreeMap) -> Self { InstantSeal { params: params, - registrar: registrar, builtins: builtins, } } @@ -49,7 +47,7 @@ impl Engine for InstantSeal { } fn additional_params(&self) -> HashMap { - hash_map!["registrar".to_owned() => self.registrar.hex()] + hash_map!["registrar".to_owned() => self.params().registrar.hex()] } fn builtins(&self) -> &BTreeMap { @@ -58,13 +56,14 @@ impl Engine for InstantSeal { fn seals_internally(&self) -> Option { Some(true) } - fn generate_seal(&self, _block: &ExecutedBlock) -> Seal { - Seal::Regular(Vec::new()) + fn generate_seal(&self, block: &ExecutedBlock) -> Seal { + if block.transactions().is_empty() { Seal::None } else { Seal::Regular(Vec::new()) } } } #[cfg(test)] mod tests { + use std::sync::Arc; use util::*; use tests::helpers::*; use spec::Spec; diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index fc7a7186e..b454f8fc0 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -35,7 +35,9 @@ pub use self::instant_seal::InstantSeal; pub use self::null_engine::NullEngine; pub use self::tendermint::Tendermint; -use std::sync::Weak; +use std::sync::{Weak, Arc}; +use std::collections::{BTreeMap, HashMap}; +use std::fmt; use self::epoch::PendingTransition; @@ -43,15 +45,13 @@ use account_provider::AccountProvider; use block::ExecutedBlock; use builtin::Builtin; use client::EngineClient; -use evm::env_info::{EnvInfo, LastHashes}; +use vm::{EnvInfo, LastHashes, Schedule, CreateContractAddress}; use error::Error; -use evm::Schedule; use header::{Header, BlockNumber}; use receipt::Receipt; use snapshot::SnapshotComponents; use spec::CommonParams; use transaction::{UnverifiedTransaction, SignedTransaction}; -use evm::CreateContractAddress; use ethkey::Signature; use util::*; @@ -273,7 +273,7 @@ pub trait Engine : Sync + Send { // TODO: Add flags for which bits of the transaction to check. // TODO: consider including State in the params. fn verify_transaction_basic(&self, t: &UnverifiedTransaction, _header: &Header) -> Result<(), Error> { - t.verify_basic(true, Some(self.params().network_id), true)?; + t.verify_basic(true, Some(self.params().chain_id), true)?; Ok(()) } @@ -283,7 +283,7 @@ pub trait Engine : Sync + Send { } /// The network ID that transactions should be signed with. - fn signing_network_id(&self, _env_info: &EnvInfo) -> Option { + fn signing_chain_id(&self, _env_info: &EnvInfo) -> Option { Some(self.params().chain_id) } @@ -403,13 +403,12 @@ pub trait Engine : Sync + Send { /// Common engine utilities pub mod common { + use std::sync::Arc; use block::ExecutedBlock; - use evm::env_info::{EnvInfo, LastHashes}; use error::Error; use transaction::SYSTEM_ADDRESS; use executive::Executive; - use evm::CallType; - use evm::action_params::{ActionParams, ActionValue}; + use vm::{CallType, ActionParams, ActionValue, EnvInfo, LastHashes}; use trace::{NoopTracer, NoopVMTracer}; use state::Substate; diff --git a/ethcore/src/engines/null_engine.rs b/ethcore/src/engines/null_engine.rs index 3bdef480c..552154580 100644 --- a/ethcore/src/engines/null_engine.rs +++ b/ethcore/src/engines/null_engine.rs @@ -62,6 +62,6 @@ impl Engine for NullEngine { } fn snapshot_components(&self) -> Option> { - Some(Box::new(::snapshot::PowSnapshot(10000))) + Some(Box::new(::snapshot::PowSnapshot::new(10000, 10000))) } } diff --git a/ethcore/src/engines/signer.rs b/ethcore/src/engines/signer.rs index 4ec4318c9..4069488ab 100644 --- a/ethcore/src/engines/signer.rs +++ b/ethcore/src/engines/signer.rs @@ -16,7 +16,8 @@ //! A signer used by Engines which need to sign messages. -use util::{Arc, H256, Address}; +use std::sync::Arc; +use util::{H256, Address}; use ethkey::Signature; use account_provider::{self, AccountProvider}; diff --git a/ethcore/src/engines/tendermint/message.rs b/ethcore/src/engines/tendermint/message.rs index b9465f429..68bdcb0f7 100644 --- a/ethcore/src/engines/tendermint/message.rs +++ b/ethcore/src/engines/tendermint/message.rs @@ -16,6 +16,7 @@ //! Tendermint message handling. +use std::cmp; use util::*; use super::{Height, View, BlockHash, Step}; use error::Error; @@ -110,13 +111,13 @@ impl Default for VoteStep { } impl PartialOrd for VoteStep { - fn partial_cmp(&self, m: &VoteStep) -> Option { + fn partial_cmp(&self, m: &VoteStep) -> Option { Some(self.cmp(m)) } } impl Ord for VoteStep { - fn cmp(&self, m: &VoteStep) -> Ordering { + fn cmp(&self, m: &VoteStep) -> cmp::Ordering { if self.height != m.height { self.height.cmp(&m.height) } else if self.view != m.view { @@ -198,6 +199,7 @@ pub fn message_hash(vote_step: VoteStep, block_hash: H256) -> H256 { #[cfg(test)] mod tests { + use std::sync::Arc; use util::*; use rlp::*; use account_provider::AccountProvider; diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 4e84f130e..45aa67b0f 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -25,8 +25,10 @@ mod message; mod params; -use std::sync::Weak; +use std::sync::{Weak, Arc}; use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering}; +use std::collections::{HashSet, BTreeMap, HashMap}; +use std::cmp; use util::*; use client::EngineClient; use error::{Error, BlockError}; @@ -71,12 +73,9 @@ pub type BlockHash = H256; /// Engine using `Tendermint` consensus algorithm, suitable for EVM chain. pub struct Tendermint { params: CommonParams, - gas_limit_bound_divisor: U256, builtins: BTreeMap, step_service: IoService, client: RwLock>>, - block_reward: U256, - registrar: Address, /// Blockchain height. height: AtomicUsize, /// Consensus view. @@ -166,12 +165,9 @@ impl Tendermint { let engine = Arc::new( Tendermint { params: params, - gas_limit_bound_divisor: our_params.gas_limit_bound_divisor, builtins: builtins, client: RwLock::new(None), step_service: IoService::::start()?, - block_reward: our_params.block_reward, - registrar: our_params.registrar, height: AtomicUsize::new(1), view: AtomicUsize::new(0), step: RwLock::new(Step::Propose), @@ -446,7 +442,9 @@ impl Engine for Tendermint { fn params(&self) -> &CommonParams { &self.params } - fn additional_params(&self) -> HashMap { hash_map!["registrar".to_owned() => self.registrar.hex()] } + fn additional_params(&self) -> HashMap { + hash_map!["registrar".to_owned() => self.params().registrar.hex()] + } fn builtins(&self) -> &BTreeMap { &self.builtins } @@ -471,11 +469,11 @@ impl Engine for Tendermint { header.set_difficulty(new_difficulty); header.set_gas_limit({ let gas_limit = parent.gas_limit().clone(); - let bound_divisor = self.gas_limit_bound_divisor; + let bound_divisor = self.params().gas_limit_bound_divisor; if gas_limit < gas_floor_target { - min(gas_floor_target, gas_limit + gas_limit / bound_divisor - 1.into()) + cmp::min(gas_floor_target, gas_limit + gas_limit / bound_divisor - 1.into()) } else { - max(gas_floor_target, gas_limit - gas_limit / bound_divisor + 1.into()) + cmp::max(gas_floor_target, gas_limit - gas_limit / bound_divisor + 1.into()) } }); } @@ -545,7 +543,8 @@ impl Engine for Tendermint { fn on_close_block(&self, block: &mut ExecutedBlock) -> Result<(), Error>{ let fields = block.fields_mut(); // Bestow block reward - let res = fields.state.add_balance(fields.header.author(), &self.block_reward, CleanupMode::NoEmpty) + let reward = self.params().block_reward; + let res = fields.state.add_balance(fields.header.author(), &reward, CleanupMode::NoEmpty) .map_err(::error::Error::from) .and_then(|_| fields.state.commit()); // Commit state so that we can actually figure out the state root. @@ -583,7 +582,7 @@ impl Engine for Tendermint { return Err(BlockError::RidiculousNumber(OutOfBounds { min: Some(1), max: None, found: header.number() }).into()); } - let gas_limit_divisor = self.gas_limit_bound_divisor; + let gas_limit_divisor = self.params().gas_limit_bound_divisor; let min_gas = parent.gas_limit().clone() - parent.gas_limit().clone() / gas_limit_divisor; let max_gas = parent.gas_limit().clone() + parent.gas_limit().clone() / gas_limit_divisor; if header.gas_limit() <= &min_gas || header.gas_limit() >= &max_gas { @@ -651,6 +650,7 @@ impl Engine for Tendermint { let first = chain_head.number() == 0; if let Some(change) = self.validators.is_epoch_end(first, chain_head) { + let change = combine_proofs(chain_head.number(), &change, &[]); return Some(change) } else if let Some(pending) = transition_store(chain_head.hash()) { let signal_number = chain_head.number(); @@ -777,6 +777,7 @@ impl Engine for Tendermint { #[cfg(test)] mod tests { + use std::str::FromStr; use rustc_hex::FromHex; use util::*; use block::*; @@ -1055,7 +1056,7 @@ mod tests { client.miner().import_own_transaction(client.as_ref(), transaction.into()).unwrap(); // Propose - let proposal = Some(client.miner().pending_block().unwrap().header.bare_hash()); + let proposal = Some(client.miner().pending_block(0).unwrap().header.bare_hash()); // Propose timeout engine.step(); diff --git a/ethcore/src/engines/tendermint/params.rs b/ethcore/src/engines/tendermint/params.rs index 16b47a0fb..7ff3d697f 100644 --- a/ethcore/src/engines/tendermint/params.rs +++ b/ethcore/src/engines/tendermint/params.rs @@ -17,7 +17,6 @@ //! Tendermint specific parameters. use ethjson; -use util::{U256, Address}; use time::Duration; use super::super::validator_set::{ValidatorSet, new_validator_set}; use super::super::transition::Timeouts; @@ -25,16 +24,10 @@ use super::Step; /// `Tendermint` params. pub struct TendermintParams { - /// Gas limit divisor. - pub gas_limit_bound_divisor: U256, /// List of validators. pub validators: Box, /// Timeout durations for different steps. pub timeouts: TendermintTimeouts, - /// Block reward. - pub block_reward: U256, - /// Namereg contract address. - pub registrar: Address, } /// Base timeout of each step in ms. @@ -81,7 +74,6 @@ impl From for TendermintParams { fn from(p: ethjson::spec::TendermintParams) -> Self { let dt = TendermintTimeouts::default(); TendermintParams { - gas_limit_bound_divisor: p.gas_limit_bound_divisor.into(), validators: new_validator_set(p.validators), timeouts: TendermintTimeouts { propose: p.timeout_propose.map_or(dt.propose, to_duration), @@ -89,8 +81,6 @@ impl From for TendermintParams { precommit: p.timeout_precommit.map_or(dt.precommit, to_duration), commit: p.timeout_commit.map_or(dt.commit, to_duration), }, - block_reward: p.block_reward.map_or_else(U256::zero, Into::into), - registrar: p.registrar.map_or_else(Address::new, Into::into), } } } diff --git a/ethcore/src/engines/validator_set/contract.rs b/ethcore/src/engines/validator_set/contract.rs index a802db43a..6ce690819 100644 --- a/ethcore/src/engines/validator_set/contract.rs +++ b/ethcore/src/engines/validator_set/contract.rs @@ -126,6 +126,7 @@ impl ValidatorSet for ValidatorContract { #[cfg(test)] mod tests { + use std::sync::Arc; use rustc_hex::FromHex; use util::*; use rlp::encode; @@ -142,11 +143,11 @@ mod tests { #[test] fn fetches_validators() { let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_contract, None); - let vc = Arc::new(ValidatorContract::new(Address::from_str("0000000000000000000000000000000000000005").unwrap())); + let vc = Arc::new(ValidatorContract::new("0000000000000000000000000000000000000005".parse::
().unwrap())); vc.register_client(Arc::downgrade(&client) as _); let last_hash = client.best_block_header().hash(); - assert!(vc.contains(&last_hash, &Address::from_str("7d577a597b2742b498cb5cf0c26cdcd726d39e6e").unwrap())); - assert!(vc.contains(&last_hash, &Address::from_str("82a978b3f5962a5b0957d9ee9eef472ee55b42f1").unwrap())); + assert!(vc.contains(&last_hash, &"7d577a597b2742b498cb5cf0c26cdcd726d39e6e".parse::
().unwrap())); + assert!(vc.contains(&last_hash, &"82a978b3f5962a5b0957d9ee9eef472ee55b42f1".parse::
().unwrap())); } #[test] @@ -155,7 +156,7 @@ mod tests { let v1 = tap.insert_account("1".sha3().into(), "").unwrap(); let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_contract, Some(tap.clone())); client.engine().register_client(Arc::downgrade(&client) as _); - let validator_contract = Address::from_str("0000000000000000000000000000000000000005").unwrap(); + let validator_contract = "0000000000000000000000000000000000000005".parse::
().unwrap(); // Make sure reporting can be done. client.miner().set_gas_floor_target(1_000_000.into()); diff --git a/ethcore/src/engines/validator_set/multi.rs b/ethcore/src/engines/validator_set/multi.rs index 086f45b98..454ea889a 100644 --- a/ethcore/src/engines/validator_set/multi.rs +++ b/ethcore/src/engines/validator_set/multi.rs @@ -142,6 +142,8 @@ impl ValidatorSet for Multi { #[cfg(test)] mod tests { + use std::sync::Arc; + use std::collections::BTreeMap; use account_provider::AccountProvider; use client::BlockChainClient; use engines::EpochChange; diff --git a/ethcore/src/engines/validator_set/safe_contract.rs b/ethcore/src/engines/validator_set/safe_contract.rs index 9c08ab963..ba2470239 100644 --- a/ethcore/src/engines/validator_set/safe_contract.rs +++ b/ethcore/src/engines/validator_set/safe_contract.rs @@ -16,7 +16,7 @@ /// Validator set maintained in a contract, updated using `getValidators` method. -use std::sync::Weak; +use std::sync::{Weak, Arc}; use futures::Future; use native_contracts::ValidatorSet as Provider; @@ -95,7 +95,7 @@ fn check_first_proof(engine: &Engine, provider: &Provider, old_header: Header, s // TODO: match client contract_call_tx more cleanly without duplication. const PROVIDED_GAS: u64 = 50_000_000; - let env_info = ::evm::env_info::EnvInfo { + let env_info = ::vm::EnvInfo { number: old_header.number(), author: *old_header.author(), difficulty: *old_header.difficulty(), @@ -454,6 +454,7 @@ impl ValidatorSet for ValidatorSafeContract { #[cfg(test)] mod tests { + use std::sync::Arc; use rustc_hex::FromHex; use util::*; use types::ids::BlockId; @@ -470,11 +471,11 @@ mod tests { #[test] fn fetches_validators() { let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_safe_contract, None); - let vc = Arc::new(ValidatorSafeContract::new(Address::from_str("0000000000000000000000000000000000000005").unwrap())); + let vc = Arc::new(ValidatorSafeContract::new("0000000000000000000000000000000000000005".parse::
().unwrap())); vc.register_client(Arc::downgrade(&client) as _); let last_hash = client.best_block_header().hash(); - assert!(vc.contains(&last_hash, &Address::from_str("7d577a597b2742b498cb5cf0c26cdcd726d39e6e").unwrap())); - assert!(vc.contains(&last_hash, &Address::from_str("82a978b3f5962a5b0957d9ee9eef472ee55b42f1").unwrap())); + assert!(vc.contains(&last_hash, &"7d577a597b2742b498cb5cf0c26cdcd726d39e6e".parse::
().unwrap())); + assert!(vc.contains(&last_hash, &"82a978b3f5962a5b0957d9ee9eef472ee55b42f1".parse::
().unwrap())); } #[test] @@ -483,10 +484,10 @@ mod tests { let s0: Secret = "1".sha3().into(); let v0 = tap.insert_account(s0.clone(), "").unwrap(); let v1 = tap.insert_account("0".sha3().into(), "").unwrap(); - let network_id = Spec::new_validator_safe_contract().network_id(); + let chain_id = Spec::new_validator_safe_contract().chain_id(); let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_safe_contract, Some(tap)); client.engine().register_client(Arc::downgrade(&client) as _); - let validator_contract = Address::from_str("0000000000000000000000000000000000000005").unwrap(); + let validator_contract = "0000000000000000000000000000000000000005".parse::
().unwrap(); client.miner().set_engine_signer(v1, "".into()).unwrap(); // Remove "1" validator. @@ -497,7 +498,7 @@ mod tests { action: Action::Call(validator_contract), value: 0.into(), data: "bfc708a000000000000000000000000082a978b3f5962a5b0957d9ee9eef472ee55b42f1".from_hex().unwrap(), - }.sign(&s0, Some(network_id)); + }.sign(&s0, Some(chain_id)); client.miner().import_own_transaction(client.as_ref(), tx.into()).unwrap(); ::client::EngineClient::update_sealing(&*client); assert_eq!(client.chain_info().best_block_number, 1); @@ -509,7 +510,7 @@ mod tests { action: Action::Call(validator_contract), value: 0.into(), data: "4d238c8e00000000000000000000000082a978b3f5962a5b0957d9ee9eef472ee55b42f1".from_hex().unwrap(), - }.sign(&s0, Some(network_id)); + }.sign(&s0, Some(chain_id)); client.miner().import_own_transaction(client.as_ref(), tx.into()).unwrap(); ::client::EngineClient::update_sealing(&*client); // The transaction is not yet included so still unable to seal. @@ -528,7 +529,7 @@ mod tests { action: Action::Call(Address::default()), value: 0.into(), data: Vec::new(), - }.sign(&s0, Some(network_id)); + }.sign(&s0, Some(chain_id)); client.miner().import_own_transaction(client.as_ref(), tx.into()).unwrap(); ::client::EngineClient::update_sealing(&*client); // Able to seal again. @@ -552,7 +553,7 @@ mod tests { let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_safe_contract, None); let engine = client.engine().clone(); - let validator_contract = Address::from_str("0000000000000000000000000000000000000005").unwrap(); + let validator_contract = "0000000000000000000000000000000000000005".parse::
().unwrap(); let last_hash = client.best_block_header().hash(); let mut new_header = Header::default(); diff --git a/ethcore/src/engines/validator_set/test.rs b/ethcore/src/engines/validator_set/test.rs index 4960ee7be..25eeff66e 100644 --- a/ethcore/src/engines/validator_set/test.rs +++ b/ethcore/src/engines/validator_set/test.rs @@ -17,8 +17,9 @@ /// Used for Engine testing. use std::str::FromStr; +use std::sync::Arc; use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering}; -use util::{Arc, Bytes, H256, Address, HeapSizeOf}; +use util::{Bytes, H256, Address, HeapSizeOf}; use engines::{Call, Engine}; use header::{Header, BlockNumber}; diff --git a/ethcore/src/engines/vote_collector.rs b/ethcore/src/engines/vote_collector.rs index d01d07f15..b934fdb2e 100644 --- a/ethcore/src/engines/vote_collector.rs +++ b/ethcore/src/engines/vote_collector.rs @@ -17,6 +17,8 @@ //! Collects votes on hashes at each Message::Round. use std::fmt::Debug; +use std::collections::{BTreeMap, HashSet, HashMap}; +use std::hash::Hash; use util::*; use rlp::{Encodable, RlpStream}; diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs index 2d908cdb6..172323c0d 100644 --- a/ethcore/src/error.rs +++ b/ethcore/src/error.rs @@ -16,6 +16,7 @@ //! General error types for use in ethcore. +use std::fmt; use util::*; use io::*; use header::BlockNumber; @@ -77,8 +78,8 @@ pub enum TransactionError { RecipientBanned, /// Contract creation code is banned. CodeBanned, - /// Invalid network ID given. - InvalidNetworkId, + /// Invalid chain ID given. + InvalidChainId, } impl fmt::Display for TransactionError { @@ -102,7 +103,7 @@ impl fmt::Display for TransactionError { SenderBanned => "Sender is temporarily banned.".into(), RecipientBanned => "Recipient is temporarily banned.".into(), CodeBanned => "Contract code is temporarily banned.".into(), - InvalidNetworkId => "Transaction of this network ID is not allowed on this chain.".into(), + InvalidChainId => "Transaction of this chain ID is not allowed on this chain.".into(), }; f.write_fmt(format_args!("Transaction error ({})", msg)) diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 1fbd711c9..6235255e4 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -15,11 +15,14 @@ // along with Parity. If not, see . use std::path::Path; +use std::cmp; +use std::collections::{BTreeMap, HashMap}; +use std::sync::Arc; use ethash::{quick_get_difficulty, slow_get_seedhash, EthashManager}; use util::*; use block::*; use builtin::Builtin; -use evm::env_info::EnvInfo; +use vm::EnvInfo; use error::{BlockError, Error, TransactionError}; use header::{Header, BlockNumber}; use state::CleanupMode; @@ -29,20 +32,21 @@ use engines::{self, Engine}; use evm::Schedule; use ethjson; use rlp::{self, UntrustedRlp}; -use evm::env_info::LastHashes; +use vm::LastHashes; /// Parity tries to round block.gas_limit to multiple of this constant pub const PARITY_GAS_LIMIT_DETERMINANT: U256 = U256([37, 0, 0, 0]); /// Number of blocks in an ethash snapshot. // make dependent on difficulty incrment divisor? -const SNAPSHOT_BLOCKS: u64 = 30000; +const SNAPSHOT_BLOCKS: u64 = 5000; +/// Maximum number of blocks allowed in an ethash snapshot. +const MAX_SNAPSHOT_BLOCKS: u64 = 30000; + /// Ethash params. #[derive(Debug, PartialEq)] pub struct EthashParams { - /// Gas limit divisor. - pub gas_limit_bound_divisor: U256, /// Minimum difficulty. pub minimum_difficulty: U256, /// Difficulty bound divisor. @@ -53,10 +57,6 @@ pub struct EthashParams { pub metropolis_difficulty_increment_divisor: u64, /// Block duration. pub duration_limit: u64, - /// Block reward. - pub block_reward: U256, - /// Namereg contract address. - pub registrar: Address, /// Homestead transition block number. pub homestead_transition: u64, /// DAO hard-fork transition block (X). @@ -75,8 +75,6 @@ pub struct EthashParams { pub eip100b_transition: u64, /// Number of first block where EIP-150 rules begin. pub eip150_transition: u64, - /// Number of first block where EIP-155 rules begin. - pub eip155_transition: u64, /// Number of first block where EIP-160 rules begin. pub eip160_transition: u64, /// Number of first block where EIP-161.abc begin. @@ -104,14 +102,11 @@ pub struct EthashParams { impl From for EthashParams { fn from(p: ethjson::spec::EthashParams) -> Self { EthashParams { - gas_limit_bound_divisor: p.gas_limit_bound_divisor.into(), minimum_difficulty: p.minimum_difficulty.into(), difficulty_bound_divisor: p.difficulty_bound_divisor.into(), difficulty_increment_divisor: p.difficulty_increment_divisor.map_or(10, Into::into), metropolis_difficulty_increment_divisor: p.metropolis_difficulty_increment_divisor.map_or(9, Into::into), duration_limit: p.duration_limit.map_or(0, Into::into), - block_reward: p.block_reward.into(), - registrar: p.registrar.map_or_else(Address::new, Into::into), homestead_transition: p.homestead_transition.map_or(0, Into::into), dao_hardfork_transition: p.dao_hardfork_transition.map_or(u64::max_value(), Into::into), dao_hardfork_beneficiary: p.dao_hardfork_beneficiary.map_or_else(Address::new, Into::into), @@ -121,7 +116,6 @@ impl From for EthashParams { bomb_defuse_transition: p.bomb_defuse_transition.map_or(u64::max_value(), Into::into), eip100b_transition: p.eip100b_transition.map_or(u64::max_value(), Into::into), eip150_transition: p.eip150_transition.map_or(0, Into::into), - eip155_transition: p.eip155_transition.map_or(0, Into::into), eip160_transition: p.eip160_transition.map_or(0, Into::into), eip161abc_transition: p.eip161abc_transition.map_or(0, Into::into), eip161d_transition: p.eip161d_transition.map_or(u64::max_value(), Into::into), @@ -185,7 +179,7 @@ impl Engine for Arc { fn seal_fields(&self) -> usize { 2 } fn params(&self) -> &CommonParams { &self.params } - fn additional_params(&self) -> HashMap { hash_map!["registrar".to_owned() => self.ethash_params.registrar.hex()] } + fn additional_params(&self) -> HashMap { hash_map!["registrar".to_owned() => self.params().registrar.hex()] } fn builtins(&self) -> &BTreeMap { &self.builtins @@ -215,8 +209,8 @@ impl Engine for Arc { } } - fn signing_network_id(&self, env_info: &EnvInfo) -> Option { - if env_info.number >= self.ethash_params.eip155_transition { + fn signing_chain_id(&self, env_info: &EnvInfo) -> Option { + if env_info.number >= self.params().eip155_transition { Some(self.params().chain_id) } else { None @@ -231,19 +225,19 @@ impl Engine for Arc { } let gas_limit = { let gas_limit = parent.gas_limit().clone(); - let bound_divisor = self.ethash_params.gas_limit_bound_divisor; + let bound_divisor = self.params().gas_limit_bound_divisor; let lower_limit = gas_limit - gas_limit / bound_divisor + 1.into(); let upper_limit = gas_limit + gas_limit / bound_divisor - 1.into(); let gas_limit = if gas_limit < gas_floor_target { - let gas_limit = min(gas_floor_target, upper_limit); + let gas_limit = cmp::min(gas_floor_target, upper_limit); round_block_gas_limit(gas_limit, lower_limit, upper_limit) } else if gas_limit > gas_ceil_target { - let gas_limit = max(gas_ceil_target, lower_limit); + let gas_limit = cmp::max(gas_ceil_target, lower_limit); round_block_gas_limit(gas_limit, lower_limit, upper_limit) } else { - let total_lower_limit = max(lower_limit, gas_floor_target); - let total_upper_limit = min(upper_limit, gas_ceil_target); - let gas_limit = max(gas_floor_target, min(total_upper_limit, + let total_lower_limit = cmp::max(lower_limit, gas_floor_target); + let total_upper_limit = cmp::min(upper_limit, gas_ceil_target); + let gas_limit = cmp::max(gas_floor_target, cmp::min(total_upper_limit, lower_limit + (header.gas_used().clone() * 6.into() / 5.into()) / bound_divisor)); round_block_gas_limit(gas_limit, total_lower_limit, total_upper_limit) }; @@ -284,7 +278,7 @@ impl Engine for Arc { /// Apply the block reward on finalisation of the block. /// This assumes that all uncles are valid uncles (i.e. of at least one generation before the current). fn on_close_block(&self, block: &mut ExecutedBlock) -> Result<(), Error> { - let reward = self.ethash_params.block_reward; + let reward = self.params().block_reward; let fields = block.fields_mut(); let eras_rounds = self.ethash_params.ecip1017_era_rounds; let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, reward, fields.header.number()); @@ -319,7 +313,7 @@ impl Engine for Arc { Ok(()) } - fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> { + fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> Result<(), Error> { // check the seal fields. if header.seal().len() != self.seal_fields() { return Err(From::from(BlockError::InvalidSealArity( @@ -357,7 +351,7 @@ impl Engine for Arc { Ok(()) } - fn verify_block_unordered(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> { + fn verify_block_unordered(&self, header: &Header, _block: Option<&[u8]>) -> Result<(), Error> { if header.seal().len() != self.seal_fields() { return Err(From::from(BlockError::InvalidSealArity( Mismatch { expected: self.seal_fields(), found: header.seal().len() } @@ -376,7 +370,7 @@ impl Engine for Arc { Ok(()) } - fn verify_block_family(&self, header: &Header, parent: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> { + fn verify_block_family(&self, header: &Header, parent: &Header, _block: Option<&[u8]>) -> Result<(), Error> { // we should not calculate difficulty for genesis blocks if header.number() == 0 { return Err(From::from(BlockError::RidiculousNumber(OutOfBounds { min: Some(1), max: None, found: header.number() }))); @@ -387,7 +381,7 @@ impl Engine for Arc { if header.difficulty() != &expected_difficulty { return Err(From::from(BlockError::InvalidDifficulty(Mismatch { expected: expected_difficulty, found: header.difficulty().clone() }))) } - let gas_limit_divisor = self.ethash_params.gas_limit_bound_divisor; + let gas_limit_divisor = self.params().gas_limit_bound_divisor; let parent_gas_limit = *parent.gas_limit(); let min_gas = parent_gas_limit - parent_gas_limit / gas_limit_divisor; let max_gas = parent_gas_limit + parent_gas_limit / gas_limit_divisor; @@ -400,14 +394,14 @@ impl Engine for Arc { Ok(()) } - fn verify_transaction_basic(&self, t: &UnverifiedTransaction, header: &Header) -> result::Result<(), Error> { + fn verify_transaction_basic(&self, t: &UnverifiedTransaction, header: &Header) -> Result<(), Error> { if header.number() >= self.ethash_params.min_gas_price_transition && t.gas_price < self.ethash_params.min_gas_price { return Err(TransactionError::InsufficientGasPrice { minimal: self.ethash_params.min_gas_price, got: t.gas_price }.into()); } let check_low_s = header.number() >= self.ethash_params.homestead_transition; - let network_id = if header.number() >= self.ethash_params.eip155_transition { Some(self.params().chain_id) } else { None }; - t.verify_basic(check_low_s, network_id, false)?; + let chain_id = if header.number() >= self.params().eip155_transition { Some(self.params().chain_id) } else { None }; + t.verify_basic(check_low_s, chain_id, false)?; Ok(()) } @@ -416,7 +410,7 @@ impl Engine for Arc { } fn snapshot_components(&self) -> Option> { - Some(Box::new(::snapshot::PowSnapshot(SNAPSHOT_BLOCKS))) + Some(Box::new(::snapshot::PowSnapshot::new(SNAPSHOT_BLOCKS, MAX_SNAPSHOT_BLOCKS))) } } @@ -493,28 +487,28 @@ impl Ethash { if diff_inc <= threshold { *parent.difficulty() + *parent.difficulty() / difficulty_bound_divisor * (threshold - diff_inc).into() } else { - let multiplier = min(diff_inc - threshold, 99).into(); + let multiplier = cmp::min(diff_inc - threshold, 99).into(); parent.difficulty().saturating_sub( *parent.difficulty() / difficulty_bound_divisor * multiplier ) } }; - target = max(min_difficulty, target); + target = cmp::max(min_difficulty, target); if header.number() < self.ethash_params.bomb_defuse_transition { if header.number() < self.ethash_params.ecip1010_pause_transition { let period = ((parent.number() + 1) / EXP_DIFF_PERIOD) as usize; if period > 1 { - target = max(min_difficulty, target + (U256::from(1) << (period - 2))); + target = cmp::max(min_difficulty, target + (U256::from(1) << (period - 2))); } } else if header.number() < self.ethash_params.ecip1010_continue_transition { let fixed_difficulty = ((self.ethash_params.ecip1010_pause_transition / EXP_DIFF_PERIOD) - 2) as usize; - target = max(min_difficulty, target + (U256::from(1) << fixed_difficulty)); + target = cmp::max(min_difficulty, target + (U256::from(1) << fixed_difficulty)); } else { let period = ((parent.number() + 1) / EXP_DIFF_PERIOD) as usize; let delay = ((self.ethash_params.ecip1010_continue_transition - self.ethash_params.ecip1010_pause_transition) / EXP_DIFF_PERIOD) as usize; - target = max(min_difficulty, target + (U256::from(1) << (period - delay - 2))); + target = cmp::max(min_difficulty, target + (U256::from(1) << (period - delay - 2))); } } target @@ -559,6 +553,9 @@ impl Header { #[cfg(test)] mod tests { + use std::str::FromStr; + use std::collections::BTreeMap; + use std::sync::Arc; use util::*; use block::*; use tests::helpers::*; @@ -809,36 +806,32 @@ mod tests { #[test] fn has_valid_ecip1017_eras_block_reward() { - let ethparams = EthashParams { - // see ethcore/res/ethereum/classic.json - ecip1017_era_rounds: 5000000, - block_reward: U256::from_str("4563918244F40000").unwrap(), - ..get_default_ethash_params() - }; - let eras_rounds = ethparams.ecip1017_era_rounds; - let reward = ethparams.block_reward; + let eras_rounds = 5000000; + + let start_reward: U256 = "4563918244F40000".parse().unwrap(); + let block_number = 0; - let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, reward, block_number); + let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, start_reward, block_number); assert_eq!(0, eras); assert_eq!(U256::from_str("4563918244F40000").unwrap(), reward); - let reward = ethparams.block_reward; + let block_number = 5000000; - let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, reward, block_number); + let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, start_reward, block_number); assert_eq!(0, eras); assert_eq!(U256::from_str("4563918244F40000").unwrap(), reward); - let reward = ethparams.block_reward; + let block_number = 10000000; - let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, reward, block_number); + let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, start_reward, block_number); assert_eq!(1, eras); assert_eq!(U256::from_str("3782DACE9D900000").unwrap(), reward); - let reward = ethparams.block_reward; + let block_number = 20000000; - let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, reward, block_number); + let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, start_reward, block_number); assert_eq!(3, eras); assert_eq!(U256::from_str("2386F26FC1000000").unwrap(), reward); - let reward = ethparams.block_reward; + let block_number = 80000000; - let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, reward, block_number); + let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, start_reward, block_number); assert_eq!(15, eras); assert_eq!(U256::from_str("271000000000000").unwrap(), reward); } diff --git a/ethcore/src/ethereum/mod.rs b/ethcore/src/ethereum/mod.rs index e731ef7db..dee86883b 100644 --- a/ethcore/src/ethereum/mod.rs +++ b/ethcore/src/ethereum/mod.rs @@ -134,23 +134,4 @@ mod tests { let _ = frontier.engine; } - - #[test] - fn all_spec_files_valid() { - let tmp = ::std::env::temp_dir(); - new_olympic(&tmp); - new_foundation(&tmp); - new_classic(&tmp); - new_expanse(&tmp); - new_kovan(&tmp); - new_ropsten(&tmp); - new_morden(&tmp); - new_frontier_test(); - new_homestead_test(); - new_eip150_test(); - new_eip161_test(); - new_transition_test(); - new_mainnet_like(); - new_metropolis_test(); - } } diff --git a/ethcore/src/executed.rs b/ethcore/src/executed.rs index f6508668f..3154903ca 100644 --- a/ethcore/src/executed.rs +++ b/ethcore/src/executed.rs @@ -17,7 +17,7 @@ //! Transaction execution format module. use util::{Bytes, U256, Address, U512, trie}; -use evm; +use vm; use trace::{VMTrace, FlatTrace}; use log_entry::LogEntry; use state_diff::StateDiff; @@ -28,7 +28,7 @@ use std::fmt; #[derive(Debug, PartialEq, Clone)] pub struct Executed { /// True if the outer call/create resulted in an exceptional exit. - pub exception: Option, + pub exception: Option, /// Gas paid up front for execution of transaction. pub gas: U256, diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 9e25b6671..8f2fb06f2 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -15,14 +15,16 @@ // along with Parity. If not, see . //! Transaction Execution environment. +use std::cmp; +use std::sync::Arc; use util::*; -use evm::action_params::{ActionParams, ActionValue}; use state::{Backend as StateBackend, State, Substate, CleanupMode}; use engines::Engine; -use evm::CallType; -use evm::env_info::EnvInfo; +use vm::EnvInfo; use error::ExecutionError; -use evm::{self, wasm, Factory, Ext, Finalize, CreateContractAddress, FinalizationResult, ReturnData, CleanDustMode}; +use evm::{CallType, Factory, Finalize, FinalizationResult}; +use vm::{self, Ext, CreateContractAddress, ReturnData, CleanDustMode, ActionParams, ActionValue}; +use wasm; use externalities::*; use trace::{FlatTrace, Tracer, NoopTracer, ExecutiveTracer, VMTrace, VMTracer, ExecutiveVMTracer, NoopVMTracer}; use transaction::{Action, SignedTransaction}; @@ -74,8 +76,8 @@ pub struct TransactOptions { pub check_nonce: bool, } -pub fn executor(engine: &E, vm_factory: &Factory, params: &ActionParams) - -> Box where E: Engine + ?Sized +pub fn executor(engine: &E, vm_factory: &Factory, params: &ActionParams) + -> Box where E: Engine + ?Sized { if engine.supports_wasm() && params.code.as_ref().map_or(false, |code| code.len() > 4 && &code[0..4] == WASM_MAGIC_NUMBER) { Box::new( @@ -155,7 +157,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { pub fn transact_virtual(&'a mut self, t: &SignedTransaction, options: TransactOptions) -> Result { let sender = t.sender(); let balance = self.state.balance(&sender)?; - let needed_balance = t.value + t.gas * t.gas_price; + let needed_balance = t.value.saturating_add(t.gas.saturating_mul(t.gas_price)); if balance < needed_balance { // give the sender a sufficient balance self.state.add_balance(&sender, &(needed_balance - balance), CleanupMode::NoEmpty)?; @@ -269,7 +271,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { output_policy: OutputPolicy, tracer: &mut T, vm_tracer: &mut V - ) -> evm::Result where T: Tracer, V: VMTracer { + ) -> vm::Result where T: Tracer, V: VMTracer { let depth_threshold = ::io::LOCAL_STACK_SIZE.with(|sz| sz.get() / STACK_SIZE_PER_DEPTH); let static_call = params.call_type == CallType::StaticCall; @@ -299,7 +301,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { /// Calls contract function with given contract params. /// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides). /// Modifies the substate and the output. - /// Returns either gas_left or `evm::Error`. + /// Returns either gas_left or `vm::Error`. pub fn call( &mut self, params: ActionParams, @@ -307,14 +309,14 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { mut output: BytesRef, tracer: &mut T, vm_tracer: &mut V - ) -> evm::Result<(U256, ReturnData)> where T: Tracer, V: VMTracer { + ) -> vm::Result<(U256, ReturnData)> where T: Tracer, V: VMTracer { trace!("Executive::call(params={:?}) self.env_info={:?}", params, self.info); if (params.call_type == CallType::StaticCall || ((params.call_type == CallType::Call || params.call_type == CallType::DelegateCall) && self.static_flag)) && params.value.value() > 0.into() { - return Err(evm::Error::MutableCallInStaticContext); + return Err(vm::Error::MutableCallInStaticContext); } // backup used in case of running out of gas @@ -344,7 +346,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { if cost <= params.gas { if let Err(e) = builtin.execute(data, &mut output) { self.state.revert_to_checkpoint(); - let evm_err: evm::evm::Error = e.into(); + let evm_err: vm::Error = e.into(); tracer.trace_failed_call(trace_info, vec![], evm_err.clone().into()); Err(evm_err) } else { @@ -371,9 +373,9 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { // just drain the whole gas self.state.revert_to_checkpoint(); - tracer.trace_failed_call(trace_info, vec![], evm::Error::OutOfGas.into()); + tracer.trace_failed_call(trace_info, vec![], vm::Error::OutOfGas.into()); - Err(evm::Error::OutOfGas) + Err(vm::Error::OutOfGas) } } else { let trace_info = tracer.prepare_trace_call(¶ms); @@ -432,17 +434,17 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { substate: &mut Substate, tracer: &mut T, vm_tracer: &mut V, - ) -> evm::Result<(U256, ReturnData)> where T: Tracer, V: VMTracer { + ) -> vm::Result<(U256, ReturnData)> where T: Tracer, V: VMTracer { let scheme = self.engine.create_address_scheme(self.info.number); if scheme != CreateContractAddress::FromSenderAndNonce && self.state.exists_and_has_code(¶ms.address)? { - return Err(evm::Error::OutOfGas); + return Err(vm::Error::OutOfGas); } if params.call_type == CallType::StaticCall || self.static_flag { let trace_info = tracer.prepare_trace_create(¶ms); - tracer.trace_failed_create(trace_info, vec![], evm::Error::MutableCallInStaticContext.into()); - return Err(evm::Error::MutableCallInStaticContext); + tracer.trace_failed_create(trace_info, vec![], vm::Error::MutableCallInStaticContext.into()); + return Err(vm::Error::MutableCallInStaticContext); } // backup used in case of running out of gas @@ -496,7 +498,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { &mut self, t: &SignedTransaction, mut substate: Substate, - result: evm::Result<(U256, ReturnData)>, + result: vm::Result<(U256, ReturnData)>, output: Bytes, trace: Vec, vm_trace: Option @@ -538,7 +540,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { self.state.kill_garbage(&substate.touched, schedule.kill_empty, &min_balance, schedule.kill_dust == CleanDustMode::WithCodeAndStorage)?; match result { - Err(evm::Error::Internal(msg)) => Err(ExecutionError::Internal(msg)), + Err(vm::Error::Internal(msg)) => Err(ExecutionError::Internal(msg)), Err(exception) => { Ok(Executed { exception: Some(exception), @@ -572,20 +574,20 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { } } - fn enact_result(&mut self, result: &evm::Result, substate: &mut Substate, un_substate: Substate) { + fn enact_result(&mut self, result: &vm::Result, substate: &mut Substate, un_substate: Substate) { match *result { - Err(evm::Error::OutOfGas) - | Err(evm::Error::BadJumpDestination {..}) - | Err(evm::Error::BadInstruction {.. }) - | Err(evm::Error::StackUnderflow {..}) - | Err(evm::Error::BuiltIn {..}) - | Err(evm::Error::Wasm {..}) - | Err(evm::Error::OutOfStack {..}) - | Err(evm::Error::MutableCallInStaticContext) + Err(vm::Error::OutOfGas) + | Err(vm::Error::BadJumpDestination {..}) + | Err(vm::Error::BadInstruction {.. }) + | Err(vm::Error::StackUnderflow {..}) + | Err(vm::Error::BuiltIn {..}) + | Err(vm::Error::Wasm {..}) + | Err(vm::Error::OutOfStack {..}) + | Err(vm::Error::MutableCallInStaticContext) | Ok(FinalizationResult { apply_state: false, .. }) => { self.state.revert_to_checkpoint(); }, - Ok(_) | Err(evm::Error::Internal(_)) => { + Ok(_) | Err(vm::Error::Internal(_)) => { self.state.discard_checkpoint(); substate.accrue(un_substate); } @@ -597,14 +599,14 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> { #[allow(dead_code)] mod tests { use std::sync::Arc; + use std::str::FromStr; use rustc_hex::FromHex; use ethkey::{Generator, Random}; use super::*; - use util::{H256, U256, U512, Address, FromStr}; + use util::{H256, U256, U512, Address}; use util::bytes::BytesRef; - use evm::action_params::{ActionParams, ActionValue}; - use evm::env_info::EnvInfo; - use evm::{Factory, VMType, CreateContractAddress}; + use vm::{ActionParams, ActionValue, CallType, EnvInfo, CreateContractAddress}; + use evm::{Factory, VMType}; use error::ExecutionError; use state::{Substate, CleanupMode}; use tests::helpers::*; @@ -613,8 +615,6 @@ mod tests { use trace::{VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff, VMTracer, NoopVMTracer, ExecutiveVMTracer}; use transaction::{Action, Transaction}; - use evm::CallType; - #[test] fn test_contract_address() { let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index 39c8673a9..eae981f1b 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -15,14 +15,17 @@ // along with Parity. If not, see . //! Transaction Execution environment. +use std::cmp; +use std::sync::Arc; use util::*; -use evm::action_params::{ActionParams, ActionValue}; use state::{Backend as StateBackend, State, Substate, CleanupMode}; use engines::Engine; -use evm::env_info::EnvInfo; use executive::*; -use evm::{self, Schedule, Ext, ContractCreateResult, MessageCallResult, CreateContractAddress, ReturnData}; -use evm::CallType; +use vm::{ + self, ActionParams, ActionValue, EnvInfo, CallType, Schedule, + Ext, ContractCreateResult, MessageCallResult, CreateContractAddress, + ReturnData +}; use transaction::UNSIGNED_SENDER; use trace::{Tracer, VMTracer}; @@ -109,31 +112,31 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Externalities<'a, T, V, B, E> impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E> where T: Tracer, V: VMTracer, B: StateBackend, E: Engine + ?Sized { - fn storage_at(&self, key: &H256) -> evm::Result { + fn storage_at(&self, key: &H256) -> vm::Result { self.state.storage_at(&self.origin_info.address, key).map_err(Into::into) } - fn set_storage(&mut self, key: H256, value: H256) -> evm::Result<()> { + fn set_storage(&mut self, key: H256, value: H256) -> vm::Result<()> { if self.static_flag { - Err(evm::Error::MutableCallInStaticContext) + Err(vm::Error::MutableCallInStaticContext) } else { self.state.set_storage(&self.origin_info.address, key, value).map_err(Into::into) } } - fn exists(&self, address: &Address) -> evm::Result { + fn exists(&self, address: &Address) -> vm::Result { self.state.exists(address).map_err(Into::into) } - fn exists_and_not_null(&self, address: &Address) -> evm::Result { + fn exists_and_not_null(&self, address: &Address) -> vm::Result { self.state.exists_and_not_null(address).map_err(Into::into) } - fn origin_balance(&self) -> evm::Result { + fn origin_balance(&self) -> vm::Result { self.balance(&self.origin_info.address).map_err(Into::into) } - fn balance(&self, address: &Address) -> evm::Result { + fn balance(&self, address: &Address) -> vm::Result { self.state.balance(address).map_err(Into::into) } @@ -274,16 +277,16 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E> } } - fn extcode(&self, address: &Address) -> evm::Result> { + fn extcode(&self, address: &Address) -> vm::Result> { Ok(self.state.code(address)?.unwrap_or_else(|| Arc::new(vec![]))) } - fn extcodesize(&self, address: &Address) -> evm::Result { + fn extcodesize(&self, address: &Address) -> vm::Result { Ok(self.state.code_size(address)?.unwrap_or(0)) } #[cfg_attr(feature="dev", allow(match_ref_pats))] - fn ret(mut self, gas: &U256, data: &ReturnData) -> evm::Result + fn ret(mut self, gas: &U256, data: &ReturnData) -> vm::Result where Self: Sized { let handle_copy = |to: &mut Option<&mut Bytes>| { to.as_mut().map(|b| **b = data.to_vec()); @@ -307,7 +310,7 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E> let return_cost = U256::from(data.len()) * U256::from(self.schedule.create_data_gas); if return_cost > *gas || data.len() > self.schedule.create_data_limit { return match self.schedule.exceptional_failed_code_deposit { - true => Err(evm::Error::OutOfGas), + true => Err(vm::Error::OutOfGas), false => Ok(*gas) } } @@ -320,11 +323,11 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E> } } - fn log(&mut self, topics: Vec, data: &[u8]) -> evm::Result<()> { + fn log(&mut self, topics: Vec, data: &[u8]) -> vm::Result<()> { use log_entry::LogEntry; if self.static_flag { - return Err(evm::Error::MutableCallInStaticContext); + return Err(vm::Error::MutableCallInStaticContext); } let address = self.origin_info.address.clone(); @@ -337,9 +340,9 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E> Ok(()) } - fn suicide(&mut self, refund_address: &Address) -> evm::Result<()> { + fn suicide(&mut self, refund_address: &Address) -> vm::Result<()> { if self.static_flag { - return Err(evm::Error::MutableCallInStaticContext); + return Err(vm::Error::MutableCallInStaticContext); } let address = self.origin_info.address.clone(); @@ -396,13 +399,11 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E> mod tests { use util::*; use engines::Engine; - use evm::env_info::EnvInfo; - use evm::Ext; + use evm::{EnvInfo, Ext, CallType}; use state::{State, Substate}; use tests::helpers::*; use super::*; use trace::{NoopTracer, NoopVMTracer}; - use evm::CallType; fn get_test_origin() -> OriginInfo { OriginInfo { @@ -470,7 +471,7 @@ mod tests { let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); - let hash = ext.blockhash(&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap()); + let hash = ext.blockhash(&"0000000000000000000000000000000000000000000000000000000000120000".parse::().unwrap()); assert_eq!(hash, H256::zero()); } @@ -494,7 +495,7 @@ mod tests { let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); - let hash = ext.blockhash(&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap()); + let hash = ext.blockhash(&"0000000000000000000000000000000000000000000000000000000000120000".parse::().unwrap()); assert_eq!(test_hash, hash); } @@ -513,10 +514,10 @@ mod tests { // this should panic because we have no balance on any account ext.call( - &U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap(), + &"0000000000000000000000000000000000000000000000000000000000120000".parse::().unwrap(), &Address::new(), &Address::new(), - Some(U256::from_str("0000000000000000000000000000000000000000000000000000000000150000").unwrap()), + Some("0000000000000000000000000000000000000000000000000000000000150000".parse::().unwrap()), &[], &Address::new(), &mut output, diff --git a/ethcore/src/header.rs b/ethcore/src/header.rs index 83c69e97d..a9a4f948d 100644 --- a/ethcore/src/header.rs +++ b/ethcore/src/header.rs @@ -16,13 +16,13 @@ //! Block header. +use std::cmp; +use std::cell::RefCell; use util::*; use basic_types::{LogBloom, ZERO_LOGBLOOM}; use time::get_time; use rlp::*; -use std::cell::RefCell; - pub use basic_types::Seal; pub use types::BlockNumber; @@ -175,7 +175,7 @@ impl Header { /// Set the timestamp field of the header. pub fn set_timestamp(&mut self, a: u64) { self.timestamp = a; self.note_dirty(); } /// Set the timestamp field of the header to the current time. - pub fn set_timestamp_now(&mut self, but_later_than: u64) { self.timestamp = max(get_time().sec as u64, but_later_than + 1); self.note_dirty(); } + pub fn set_timestamp_now(&mut self, but_later_than: u64) { self.timestamp = cmp::max(get_time().sec as u64, but_later_than + 1); self.note_dirty(); } /// Set the number field of the header. pub fn set_number(&mut self, a: BlockNumber) { self.number = a; self.note_dirty(); } /// Set the author field of the header. @@ -275,7 +275,7 @@ impl Decodable for Header { number: r.val_at(8)?, gas_limit: r.val_at(9)?, gas_used: r.val_at(10)?, - timestamp: min(r.val_at::(11)?, u64::max_value().into()).as_u64(), + timestamp: cmp::min(r.val_at::(11)?, u64::max_value().into()).as_u64(), extra_data: r.val_at(12)?, seal: vec![], hash: RefCell::new(Some(r.as_raw().sha3())), diff --git a/ethcore/src/json_tests/chain.rs b/ethcore/src/json_tests/chain.rs index ccdd7d499..7047c9882 100644 --- a/ethcore/src/json_tests/chain.rs +++ b/ethcore/src/json_tests/chain.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use super::test_common::*; +use std::sync::Arc; use client::{BlockChainClient, Client, ClientConfig}; use block::Block; use ethereum; diff --git a/ethcore/src/json_tests/executive.rs b/ethcore/src/json_tests/executive.rs index 0c5a6a90d..f7b4bbe81 100644 --- a/ethcore/src/json_tests/executive.rs +++ b/ethcore/src/json_tests/executive.rs @@ -14,16 +14,18 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use std::sync::Arc; use super::test_common::*; -use evm::action_params::ActionParams; use state::{Backend as StateBackend, State, Substate}; use executive::*; use engines::Engine; -use evm::env_info::EnvInfo; -use evm; -use evm::{Schedule, Ext, Finalize, VMType, ContractCreateResult, MessageCallResult, CreateContractAddress, ReturnData}; +use evm::{VMType, Finalize}; +use vm::{ + self, ActionParams, CallType, Schedule, Ext, + ContractCreateResult, EnvInfo, MessageCallResult, + CreateContractAddress, ReturnData, +}; use externalities::*; -use evm::CallType; use tests::helpers::*; use ethjson; use trace::{Tracer, NoopTracer}; @@ -88,27 +90,27 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> TestExt<'a, T, V, B, E> impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for TestExt<'a, T, V, B, E> where T: Tracer, V: VMTracer, B: StateBackend, E: Engine + ?Sized { - fn storage_at(&self, key: &H256) -> evm::Result { + fn storage_at(&self, key: &H256) -> vm::Result { self.ext.storage_at(key) } - fn set_storage(&mut self, key: H256, value: H256) -> evm::Result<()> { + fn set_storage(&mut self, key: H256, value: H256) -> vm::Result<()> { self.ext.set_storage(key, value) } - fn exists(&self, address: &Address) -> evm::Result { + fn exists(&self, address: &Address) -> vm::Result { self.ext.exists(address) } - fn exists_and_not_null(&self, address: &Address) -> evm::Result { + fn exists_and_not_null(&self, address: &Address) -> vm::Result { self.ext.exists_and_not_null(address) } - fn balance(&self, address: &Address) -> evm::Result { + fn balance(&self, address: &Address) -> vm::Result { self.ext.balance(address) } - fn origin_balance(&self) -> evm::Result { + fn origin_balance(&self) -> vm::Result { self.ext.origin_balance() } @@ -146,23 +148,23 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for TestExt<'a, T, V, B, E> MessageCallResult::Success(*gas, ReturnData::empty()) } - fn extcode(&self, address: &Address) -> evm::Result> { + fn extcode(&self, address: &Address) -> vm::Result> { self.ext.extcode(address) } - fn extcodesize(&self, address: &Address) -> evm::Result { + fn extcodesize(&self, address: &Address) -> vm::Result { self.ext.extcodesize(address) } - fn log(&mut self, topics: Vec, data: &[u8]) -> evm::Result<()> { + fn log(&mut self, topics: Vec, data: &[u8]) -> vm::Result<()> { self.ext.log(topics, data) } - fn ret(self, gas: &U256, data: &ReturnData) -> Result { + fn ret(self, gas: &U256, data: &ReturnData) -> Result { self.ext.ret(gas, data) } - fn suicide(&mut self, refund_address: &Address) -> evm::Result<()> { + fn suicide(&mut self, refund_address: &Address) -> vm::Result<()> { self.ext.suicide(refund_address) } diff --git a/ethcore/src/json_tests/state.rs b/ethcore/src/json_tests/state.rs index 74bbfb266..2fdf8875f 100644 --- a/ethcore/src/json_tests/state.rs +++ b/ethcore/src/json_tests/state.rs @@ -22,7 +22,7 @@ use spec::Spec; use ethjson; use ethjson::state::test::ForkSpec; use transaction::SignedTransaction; -use evm::env_info::EnvInfo; +use vm::EnvInfo; lazy_static! { pub static ref FRONTIER: Spec = ethereum::new_frontier_test(); diff --git a/ethcore/src/json_tests/test_common.rs b/ethcore/src/json_tests/test_common.rs index f9716d221..fa1078776 100644 --- a/ethcore/src/json_tests/test_common.rs +++ b/ethcore/src/json_tests/test_common.rs @@ -15,6 +15,8 @@ // along with Parity. If not, see . pub use util::*; +use std::collections::HashSet; +use std::io::Read; use std::fs::{File, read_dir}; use std::path::Path; use std::ffi::OsString; diff --git a/ethcore/src/json_tests/transaction.rs b/ethcore/src/json_tests/transaction.rs index a3c3c889d..3d71a5faf 100644 --- a/ethcore/src/json_tests/transaction.rs +++ b/ethcore/src/json_tests/transaction.rs @@ -36,25 +36,25 @@ fn do_json_test(json_data: &[u8]) -> Vec { Some(x) if x < 3_000_000 => &homestead_schedule, Some(_) => &metropolis_schedule }; - let allow_network_id_of_one = number.map_or(false, |n| n >= 2_675_000); + let allow_chain_id_of_one = number.map_or(false, |n| n >= 2_675_000); let allow_unsigned = number.map_or(false, |n| n >= 3_000_000); let rlp: Vec = test.rlp.into(); let res = UntrustedRlp::new(&rlp) .as_val() .map_err(From::from) - .and_then(|t: UnverifiedTransaction| t.validate(schedule, schedule.have_delegate_call, allow_network_id_of_one, allow_unsigned)); + .and_then(|t: UnverifiedTransaction| t.validate(schedule, schedule.have_delegate_call, allow_chain_id_of_one, allow_unsigned)); fail_unless(test.transaction.is_none() == res.is_err(), "Validity different"); if let (Some(tx), Some(sender)) = (test.transaction, test.sender) { let t = res.unwrap(); fail_unless(SignedTransaction::new(t.clone()).unwrap().sender() == sender.into(), "sender mismatch"); - let is_acceptable_network_id = match t.network_id() { + let is_acceptable_chain_id = match t.chain_id() { None => true, - Some(1) if allow_network_id_of_one => true, + Some(1) if allow_chain_id_of_one => true, _ => false, }; - fail_unless(is_acceptable_network_id, "Network ID unacceptable"); + fail_unless(is_acceptable_chain_id, "Network ID unacceptable"); let data: Vec = tx.data.into(); fail_unless(t.data == data, "data mismatch"); fail_unless(t.gas_price == tx.gas_price.into(), "gas_price mismatch"); diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 89f9d2e57..15d44626b 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -101,11 +101,19 @@ extern crate num; extern crate price_info; extern crate rand; extern crate rlp; + +#[macro_use] +extern crate rlp_derive; extern crate rustc_hex; extern crate semver; extern crate stats; extern crate time; extern crate transient_hashmap; +extern crate using_queue; +extern crate table; +extern crate bloomable; +extern crate vm; +extern crate wasm; #[macro_use] extern crate log; diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 80971355b..0639c645f 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -15,12 +15,14 @@ // along with Parity. If not, see . use std::time::{Instant, Duration}; +use std::collections::{BTreeMap, HashSet}; +use std::sync::Arc; use util::*; -use util::using_queue::{UsingQueue, GetAction}; +use using_queue::{UsingQueue, GetAction}; use account_provider::{AccountProvider, SignError as AccountError}; -use state::{State, CleanupMode}; -use client::{MiningBlockChainClient, Executive, Executed, EnvInfo, TransactOptions, BlockId, CallAnalytics, TransactionId}; +use state::State; +use client::{MiningBlockChainClient, BlockId, TransactionId}; use client::TransactionImportResult; use executive::contract_address; use block::{ClosedBlock, IsBlock, Block}; @@ -37,7 +39,7 @@ use miner::local_transactions::{Status as LocalTransactionStatus}; use miner::service_transaction_checker::ServiceTransactionChecker; use price_info::{Client as PriceInfoClient, PriceInfo}; use price_info::fetch::Client as FetchClient; -use header::BlockNumber; +use header::{Header, BlockNumber}; /// Different possible definitions for pending transaction set. #[derive(Debug, PartialEq)] @@ -329,13 +331,28 @@ impl Miner { } /// Get `Some` `clone()` of the current pending block's state or `None` if we're not sealing. - pub fn pending_state(&self) -> Option> { - self.sealing_work.lock().queue.peek_last_ref().map(|b| b.block().fields().state.clone()) + pub fn pending_state(&self, latest_block_number: BlockNumber) -> Option> { + self.map_pending_block(|b| b.state().clone(), latest_block_number) } /// Get `Some` `clone()` of the current pending block or `None` if we're not sealing. - pub fn pending_block(&self) -> Option { - self.sealing_work.lock().queue.peek_last_ref().map(|b| b.to_base()) + pub fn pending_block(&self, latest_block_number: BlockNumber) -> Option { + self.map_pending_block(|b| b.to_base(), latest_block_number) + } + + /// Get `Some` `clone()` of the current pending block header or `None` if we're not sealing. + pub fn pending_block_header(&self, latest_block_number: BlockNumber) -> Option
{ + self.map_pending_block(|b| b.header().clone(), latest_block_number) + } + + fn map_pending_block(&self, f: F, latest_block_number: BlockNumber) -> Option where + F: FnOnce(&ClosedBlock) -> T, + { + self.from_pending_block( + latest_block_number, + || None, + |block| Some(f(block)), + ) } #[cfg_attr(feature="dev", allow(match_same_arms))] @@ -677,7 +694,7 @@ impl Miner { #[cfg_attr(feature="dev", allow(wrong_self_convention))] #[cfg_attr(feature="dev", allow(redundant_closure))] fn from_pending_block(&self, latest_block_number: BlockNumber, from_chain: F, map_block: G) -> H - where F: Fn() -> H, G: Fn(&ClosedBlock) -> H { + where F: Fn() -> H, G: FnOnce(&ClosedBlock) -> H { let sealing_work = self.sealing_work.lock(); sealing_work.queue.peek_last_ref().map_or_else( || from_chain(), @@ -715,84 +732,6 @@ impl MinerService for Miner { } } - fn call(&self, client: &MiningBlockChainClient, t: &SignedTransaction, analytics: CallAnalytics) -> Result { - let sealing_work = self.sealing_work.lock(); - match sealing_work.queue.peek_last_ref() { - Some(work) => { - let block = work.block(); - - // TODO: merge this code with client.rs's fn call somwhow. - let header = block.header(); - let last_hashes = Arc::new(client.last_hashes()); - let env_info = EnvInfo { - number: header.number(), - author: *header.author(), - timestamp: header.timestamp(), - difficulty: *header.difficulty(), - last_hashes: last_hashes, - gas_used: U256::zero(), - gas_limit: U256::max_value(), - }; - // that's just a copy of the state. - let mut state = block.state().clone(); - let original_state = if analytics.state_diffing { Some(state.clone()) } else { None }; - - let sender = t.sender(); - let balance = state.balance(&sender).map_err(ExecutionError::from)?; - let needed_balance = t.value + t.gas * t.gas_price; - if balance < needed_balance { - // give the sender a sufficient balance - state.add_balance(&sender, &(needed_balance - balance), CleanupMode::NoEmpty) - .map_err(ExecutionError::from)?; - } - let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false }; - let mut ret = Executive::new(&mut state, &env_info, &*self.engine).transact(t, options)?; - - // TODO gav move this into Executive. - if let Some(original) = original_state { - ret.state_diff = Some(state.diff_from(original).map_err(ExecutionError::from)?); - } - - Ok(ret) - }, - None => client.call(t, BlockId::Latest, analytics) - } - } - - // TODO: The `chain.latest_x` actually aren't infallible, they just panic on corruption. - // TODO: return trie::Result here, or other. - fn balance(&self, chain: &MiningBlockChainClient, address: &Address) -> Option { - self.from_pending_block( - chain.chain_info().best_block_number, - || Some(chain.latest_balance(address)), - |b| b.block().fields().state.balance(address).ok(), - ) - } - - fn storage_at(&self, chain: &MiningBlockChainClient, address: &Address, position: &H256) -> Option { - self.from_pending_block( - chain.chain_info().best_block_number, - || Some(chain.latest_storage_at(address, position)), - |b| b.block().fields().state.storage_at(address, position).ok(), - ) - } - - fn nonce(&self, chain: &MiningBlockChainClient, address: &Address) -> Option { - self.from_pending_block( - chain.chain_info().best_block_number, - || Some(chain.latest_nonce(address)), - |b| b.block().fields().state.nonce(address).ok(), - ) - } - - fn code(&self, chain: &MiningBlockChainClient, address: &Address) -> Option> { - self.from_pending_block( - chain.chain_info().best_block_number, - || Some(chain.latest_code(address)), - |b| b.block().fields().state.code(address).ok().map(|c| c.map(|c| (&*c).clone())) - ) - } - fn set_author(&self, author: Address) { if self.engine.seals_internally().is_some() { let mut sealing_work = self.sealing_work.lock(); @@ -1112,6 +1051,8 @@ impl MinerService for Miner { /// Prepare the block and work if the Engine does not seal internally. fn update_sealing(&self, chain: &MiningBlockChainClient) { trace!(target: "miner", "update_sealing"); + const NO_NEW_CHAIN_WITH_FORKS: &str = "Your chain specification contains one or more hard forks which are required to be \ + on by default. Please remove these forks and start your chain again."; if self.requires_reseal(chain.chain_info().best_block_number) { // -------------------------------------------------------------------------- @@ -1120,6 +1061,14 @@ impl MinerService for Miner { // -------------------------------------------------------------------------- trace!(target: "miner", "update_sealing: preparing a block"); let (block, original_work_hash) = self.prepare_block(chain); + + // refuse to seal the first block of the chain if it contains hard forks + // which should be on by default. + if block.block().fields().header.number() == 1 && self.engine.params().contains_bugfix_hard_fork() { + warn!("{}", NO_NEW_CHAIN_WITH_FORKS); + return; + } + match self.engine.seals_internally() { Some(true) => { trace!(target: "miner", "update_sealing: engine indicates internal sealing"); @@ -1127,11 +1076,11 @@ impl MinerService for Miner { trace!(target: "miner", "update_sealing: imported internally sealed block"); } }, + Some(false) => trace!(target: "miner", "update_sealing: engine is not keen to seal internally right now"), None => { trace!(target: "miner", "update_sealing: engine does not seal internally, preparing work"); self.prepare_work(block, original_work_hash) }, - _ => trace!(target: "miner", "update_sealing: engine is not keen to seal internally right now") } } } @@ -1357,10 +1306,10 @@ mod tests { } fn transaction() -> SignedTransaction { - transaction_with_network_id(2) + transaction_with_chain_id(2) } - fn transaction_with_network_id(id: u64) -> SignedTransaction { + fn transaction_with_chain_id(chain_id: u64) -> SignedTransaction { let keypair = Random.generate().unwrap(); Transaction { action: Action::Create, @@ -1369,7 +1318,7 @@ mod tests { gas: U256::from(100_000), gas_price: U256::zero(), nonce: U256::zero(), - }.sign(keypair.secret(), Some(id)) + }.sign(keypair.secret(), Some(chain_id)) } #[test] @@ -1450,18 +1399,18 @@ mod tests { let client = generate_dummy_client(2); - assert_eq!(miner.import_external_transactions(&*client, vec![transaction_with_network_id(spec.network_id()).into()]).pop().unwrap().unwrap(), TransactionImportResult::Current); + assert_eq!(miner.import_external_transactions(&*client, vec![transaction_with_chain_id(spec.chain_id()).into()]).pop().unwrap().unwrap(), TransactionImportResult::Current); miner.update_sealing(&*client); client.flush_queue(); - assert!(miner.pending_block().is_none()); + assert!(miner.pending_block(0).is_none()); assert_eq!(client.chain_info().best_block_number, 3 as BlockNumber); - assert_eq!(miner.import_own_transaction(&*client, PendingTransaction::new(transaction_with_network_id(spec.network_id()).into(), None)).unwrap(), TransactionImportResult::Current); + assert_eq!(miner.import_own_transaction(&*client, PendingTransaction::new(transaction_with_chain_id(spec.chain_id()).into(), None)).unwrap(), TransactionImportResult::Current); miner.update_sealing(&*client); client.flush_queue(); - assert!(miner.pending_block().is_none()); + assert!(miner.pending_block(0).is_none()); assert_eq!(client.chain_info().best_block_number, 4 as BlockNumber); } diff --git a/ethcore/src/miner/mod.rs b/ethcore/src/miner/mod.rs index 1c07f4fab..b4cb065fd 100644 --- a/ethcore/src/miner/mod.rs +++ b/ethcore/src/miner/mod.rs @@ -62,12 +62,12 @@ pub use self::stratum::{Stratum, Error as StratumError, Options as StratumOption use std::collections::BTreeMap; use util::{H256, U256, Address, Bytes}; -use client::{MiningBlockChainClient, Executed, CallAnalytics}; +use client::{MiningBlockChainClient}; use block::ClosedBlock; use header::BlockNumber; use receipt::{RichReceipt, Receipt}; -use error::{Error, CallError}; -use transaction::{UnverifiedTransaction, PendingTransaction, SignedTransaction}; +use error::{Error}; +use transaction::{UnverifiedTransaction, PendingTransaction}; /// Miner client API pub trait MinerService : Send + Sync { @@ -185,21 +185,6 @@ pub trait MinerService : Send + Sync { /// Suggested gas limit. fn sensible_gas_limit(&self) -> U256 { 21000.into() } - - /// Latest account balance in pending state. - fn balance(&self, chain: &MiningBlockChainClient, address: &Address) -> Option; - - /// Call into contract code using pending state. - fn call(&self, chain: &MiningBlockChainClient, t: &SignedTransaction, analytics: CallAnalytics) -> Result; - - /// Get storage value in pending state. - fn storage_at(&self, chain: &MiningBlockChainClient, address: &Address, position: &H256) -> Option; - - /// Get account nonce in pending state. - fn nonce(&self, chain: &MiningBlockChainClient, address: &Address) -> Option; - - /// Get contract code in pending state. - fn code(&self, chain: &MiningBlockChainClient, address: &Address) -> Option>; } /// Mining status diff --git a/ethcore/src/miner/stratum.rs b/ethcore/src/miner/stratum.rs index e419247f0..0031bb715 100644 --- a/ethcore/src/miner/stratum.rs +++ b/ethcore/src/miner/stratum.rs @@ -32,7 +32,6 @@ use util::Mutex; use miner::{self, Miner, MinerService}; use client::Client; use block::IsBlock; -use std::str::FromStr; use rlp::encode; /// Configures stratum server options. @@ -60,7 +59,7 @@ impl SubmitPayload { return Err(PayloadError::ArgumentsAmountUnexpected(payload.len())); } - let nonce = match H64::from_str(clean_0x(&payload[0])) { + let nonce = match clean_0x(&payload[0]).parse::() { Ok(nonce) => nonce, Err(e) => { warn!(target: "stratum", "submit_work ({}): invalid nonce ({:?})", &payload[0], e); @@ -68,7 +67,7 @@ impl SubmitPayload { } }; - let pow_hash = match H256::from_str(clean_0x(&payload[1])) { + let pow_hash = match clean_0x(&payload[1]).parse::() { Ok(pow_hash) => pow_hash, Err(e) => { warn!(target: "stratum", "submit_work ({}): invalid hash ({:?})", &payload[1], e); @@ -76,7 +75,7 @@ impl SubmitPayload { } }; - let mix_hash = match H256::from_str(clean_0x(&payload[2])) { + let mix_hash = match clean_0x(&payload[2]).parse::() { Ok(mix_hash) => mix_hash, Err(e) => { warn!(target: "stratum", "submit_work ({}): invalid mix-hash ({:?})", &payload[2], e); @@ -133,7 +132,7 @@ impl JobDispatcher for StratumJobDispatcher { fn submit(&self, payload: Vec) -> Result<(), StratumServiceError> { let payload = SubmitPayload::from_args(payload).map_err(|e| - StratumServiceError::Dispatch(format!("{}", e)) + StratumServiceError::Dispatch(e.to_string()) )?; trace!( @@ -144,14 +143,16 @@ impl JobDispatcher for StratumJobDispatcher { payload.mix_hash, ); - self.with_core_void(|client, miner| { + self.with_core_result(|client, miner| { let seal = vec![encode(&payload.mix_hash).into_vec(), encode(&payload.nonce).into_vec()]; - if let Err(e) = miner.submit_seal(&*client, payload.pow_hash, seal) { - warn!(target: "stratum", "submit_seal error: {:?}", e); - }; - }); - - Ok(()) + match miner.submit_seal(&*client, payload.pow_hash, seal) { + Ok(_) => Ok(()), + Err(e) => { + warn!(target: "stratum", "submit_seal error: {:?}", e); + Err(StratumServiceError::Dispatch(e.to_string())) + } + } + }) } } @@ -181,8 +182,11 @@ impl StratumJobDispatcher { self.client.upgrade().and_then(|client| self.miner.upgrade().and_then(|miner| (f)(client, miner))) } - fn with_core_void(&self, f: F) where F: Fn(Arc, Arc) { - self.client.upgrade().map(|client| self.miner.upgrade().map(|miner| (f)(client, miner))); + fn with_core_result(&self, f: F) -> Result<(), StratumServiceError> where F: Fn(Arc, Arc) -> Result<(), StratumServiceError> { + match (self.client.upgrade(), self.miner.upgrade()) { + (Some(client), Some(miner)) => f(client, miner), + _ => Ok(()), + } } } @@ -230,7 +234,7 @@ impl Stratum { let dispatcher = Arc::new(StratumJobDispatcher::new(miner, client)); let stratum_svc = StratumService::start( - &SocketAddr::new(IpAddr::from_str(&options.listen_addr)?, options.port), + &SocketAddr::new(options.listen_addr.parse::()?, options.port), dispatcher.clone(), options.secret.clone(), )?; diff --git a/ethcore/src/miner/transaction_queue.rs b/ethcore/src/miner/transaction_queue.rs index 542b42b93..263143ee8 100644 --- a/ethcore/src/miner/transaction_queue.rs +++ b/ethcore/src/miner/transaction_queue.rs @@ -106,7 +106,7 @@ use std::cmp; use std::collections::{HashSet, HashMap, BTreeSet, BTreeMap}; use linked_hash_map::LinkedHashMap; use util::{Address, H256, U256, HeapSizeOf}; -use util::table::Table; +use table::Table; use transaction::*; use error::{Error, TransactionError}; use client::TransactionImportResult; @@ -1447,7 +1447,7 @@ fn check_if_removed(sender: &Address, nonce: &U256, dropped: Option. +use std::fmt; +use std::collections::BTreeMap; +use itertools::Itertools; use util::*; use state::Account; use ethjson; @@ -166,7 +169,7 @@ pub fn diff_pod(pre: Option<&PodAccount>, post: Option<&PodAccount>) -> Option StateDiff { #[cfg(test)] mod test { - use util::*; + use std::collections::BTreeMap; use types::state_diff::*; use types::account_diff::*; use pod_account::PodAccount; diff --git a/ethcore/src/service.rs b/ethcore/src/service.rs index 5bc15d9bb..c1a7f806f 100644 --- a/ethcore/src/service.rs +++ b/ethcore/src/service.rs @@ -16,6 +16,8 @@ //! Creates and registers client and network services. +use std::sync::Arc; +use std::path::Path; use util::*; use io::*; use spec::Spec; diff --git a/ethcore/src/snapshot/consensus/work.rs b/ethcore/src/snapshot/consensus/work.rs index 4975203b7..2bf154fc4 100644 --- a/ethcore/src/snapshot/consensus/work.rs +++ b/ethcore/src/snapshot/consensus/work.rs @@ -37,11 +37,24 @@ use rand::OsRng; /// Snapshot creation and restoration for PoW chains. /// This includes blocks from the head of the chain as a /// loose assurance that the chain is valid. -/// -/// The field is the number of blocks from the head of the chain -/// to include in the snapshot. #[derive(Clone, Copy, PartialEq)] -pub struct PowSnapshot(pub u64); +pub struct PowSnapshot { + /// Number of blocks from the head of the chain + /// to include in the snapshot. + pub blocks: u64, + /// Number of to allow in the snapshot when restoring. + pub max_restore_blocks: u64, +} + +impl PowSnapshot { + /// Create a new instance. + pub fn new(blocks: u64, max_restore_blocks: u64) -> PowSnapshot { + PowSnapshot { + blocks: blocks, + max_restore_blocks: max_restore_blocks, + } + } +} impl SnapshotComponents for PowSnapshot { fn chunk_all( @@ -57,7 +70,7 @@ impl SnapshotComponents for PowSnapshot { current_hash: block_at, writer: chunk_sink, preferred_size: preferred_size, - }.chunk_all(self.0) + }.chunk_all(self.blocks) } fn rebuilder( @@ -66,7 +79,7 @@ impl SnapshotComponents for PowSnapshot { db: Arc, manifest: &ManifestData, ) -> Result, ::error::Error> { - PowRebuilder::new(chain, db, manifest, self.0).map(|r| Box::new(r) as Box<_>) + PowRebuilder::new(chain, db, manifest, self.max_restore_blocks).map(|r| Box::new(r) as Box<_>) } fn min_supported_version(&self) -> u64 { ::snapshot::MIN_SUPPORTED_STATE_CHUNK_VERSION } @@ -218,7 +231,7 @@ impl Rebuilder for PowRebuilder { trace!(target: "snapshot", "restoring block chunk with {} blocks.", item_count - 3); if self.fed_blocks + num_blocks > self.snapshot_blocks { - return Err(Error::TooManyBlocks(self.snapshot_blocks, self.fed_blocks).into()) + return Err(Error::TooManyBlocks(self.snapshot_blocks, self.fed_blocks + num_blocks).into()) } // todo: assert here that these values are consistent with chunks being in order. diff --git a/ethcore/src/snapshot/io.rs b/ethcore/src/snapshot/io.rs index 8cb778117..f28adcf7f 100644 --- a/ethcore/src/snapshot/io.rs +++ b/ethcore/src/snapshot/io.rs @@ -27,7 +27,7 @@ use std::path::{Path, PathBuf}; use util::Bytes; use util::hash::H256; -use rlp::{self, Encodable, RlpStream, UntrustedRlp}; +use rlp::{RlpStream, UntrustedRlp}; use super::ManifestData; @@ -49,24 +49,9 @@ pub trait SnapshotWriter { } // (hash, len, offset) +#[derive(RlpEncodable, RlpDecodable)] struct ChunkInfo(H256, u64, u64); -impl Encodable for ChunkInfo { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(3); - s.append(&self.0).append(&self.1).append(&self.2); - } -} - -impl rlp::Decodable for ChunkInfo { - fn decode(rlp: &UntrustedRlp) -> Result { - let hash = rlp.val_at(0)?; - let len = rlp.val_at(1)?; - let off = rlp.val_at(2)?; - Ok(ChunkInfo(hash, len, off)) - } -} - /// A packed snapshot writer. This writes snapshots to a single concatenated file. /// /// The file format is very simple and consists of three parts: diff --git a/ethcore/src/snapshot/tests/proof_of_authority.rs b/ethcore/src/snapshot/tests/proof_of_authority.rs index 1d4841a96..61a7db110 100644 --- a/ethcore/src/snapshot/tests/proof_of_authority.rs +++ b/ethcore/src/snapshot/tests/proof_of_authority.rs @@ -130,7 +130,7 @@ fn make_chain(accounts: Arc, blocks_beyond: usize, transitions: action: Action::Call(Address::new()), value: 1.into(), data: Vec::new(), - }.sign(&*RICH_SECRET, client.signing_network_id()); + }.sign(&*RICH_SECRET, client.signing_chain_id()); *nonce = *nonce + 1.into(); vec![transaction] @@ -176,7 +176,7 @@ fn make_chain(accounts: Arc, blocks_beyond: usize, transitions: action: Action::Call(addr), value: 0.into(), data: data, - }.sign(&*RICH_SECRET, client.signing_network_id()); + }.sign(&*RICH_SECRET, client.signing_chain_id()); pending.push(transaction); diff --git a/ethcore/src/snapshot/tests/proof_of_work.rs b/ethcore/src/snapshot/tests/proof_of_work.rs index e7d0a0964..a6c0166f5 100644 --- a/ethcore/src/snapshot/tests/proof_of_work.rs +++ b/ethcore/src/snapshot/tests/proof_of_work.rs @@ -30,7 +30,7 @@ use util::kvdb::{self, KeyValueDB, DBTransaction}; use std::sync::Arc; use std::sync::atomic::AtomicBool; -const SNAPSHOT_MODE: ::snapshot::PowSnapshot = ::snapshot::PowSnapshot(30000); +const SNAPSHOT_MODE: ::snapshot::PowSnapshot = ::snapshot::PowSnapshot { blocks: 30000, max_restore_blocks: 30000 }; fn chunk_and_restore(amount: u64) { let mut canon_chain = ChainGenerator::default(); diff --git a/ethcore/src/snapshot/tests/test_validator_contract.json b/ethcore/src/snapshot/tests/test_validator_contract.json index e2485fe82..b0aeb8785 100644 --- a/ethcore/src/snapshot/tests/test_validator_contract.json +++ b/ethcore/src/snapshot/tests/test_validator_contract.json @@ -3,7 +3,6 @@ "engine": { "authorityRound": { "params": { - "gasLimitBoundDivisor": "0x0400", "stepDuration": 1, "startStep": 0, "validators": { @@ -17,6 +16,7 @@ } }, "params": { + "gasLimitBoundDivisor": "0x0400", "accountStartNonce": "0x0", "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index df83d2e4f..7dcd0c6aa 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -16,14 +16,17 @@ //! Parameters for a block chain. +use std::io::Read; +use std::collections::BTreeMap; +use std::path::Path; +use std::sync::Arc; use rustc_hex::FromHex; use super::genesis::Genesis; use super::seal::Generic as GenericSeal; -use evm::action_params::{ActionValue, ActionParams}; use builtin::Builtin; use engines::{Engine, NullEngine, InstantSeal, BasicAuthority, AuthorityRound, Tendermint, DEFAULT_BLOCKHASH_CONTRACT}; -use evm::env_info::EnvInfo; +use vm::{EnvInfo, CallType, ActionValue, ActionParams}; use error::Error; use ethereum; use ethjson; @@ -35,10 +38,14 @@ use rlp::{Rlp, RlpStream}; use state::{Backend, State, Substate}; use state::backend::Basic as BasicBackend; use trace::{NoopTracer, NoopVMTracer}; -use evm::CallType; use util::*; -/// Parameters common to all engines. +/// Parameters common to ethereum-like blockchains. +/// NOTE: when adding bugfix hard-fork parameters, +/// add to `contains_bugfix_hard_fork` +/// +/// we define a "bugfix" hard fork as any hard fork which +/// you would put on-by-default in a new chain. #[derive(Debug, PartialEq, Default)] #[cfg_attr(test, derive(Clone))] pub struct CommonParams { @@ -58,8 +65,10 @@ pub struct CommonParams { pub fork_block: Option<(BlockNumber, H256)>, /// Number of first block where EIP-98 rules begin. pub eip98_transition: BlockNumber, + /// Number of first block where EIP-155 rules begin. + pub eip155_transition: BlockNumber, /// Validate block receipts root. - pub validate_receipts_transition: u64, + pub validate_receipts_transition: BlockNumber, /// Number of first block where EIP-86 (Metropolis) rules begin. pub eip86_transition: BlockNumber, /// Number of first block where EIP-140 (Metropolis: REVERT opcode) rules begin. @@ -84,18 +93,24 @@ pub struct CommonParams { pub remove_dust_contracts: bool, /// Wasm support pub wasm: bool, + /// Gas limit bound divisor (how much gas limit can change per block) + pub gas_limit_bound_divisor: U256, + /// Block reward in wei. + pub block_reward: U256, + /// Registrar contract address. + pub registrar: Address, } impl CommonParams { /// Schedule for an EVM in the post-EIP-150-era of the Ethereum main net. - pub fn schedule(&self, block_number: u64) -> ::evm::Schedule { - let mut schedule = ::evm::Schedule::new_post_eip150(usize::max_value(), true, true, true); + pub fn schedule(&self, block_number: u64) -> ::vm::Schedule { + let mut schedule = ::vm::Schedule::new_post_eip150(usize::max_value(), true, true, true); self.update_schedule(block_number, &mut schedule); schedule } /// Apply common spec config parameters to the schedule. - pub fn update_schedule(&self, block_number: u64, schedule: &mut ::evm::Schedule) { + pub fn update_schedule(&self, block_number: u64, schedule: &mut ::vm::Schedule) { schedule.have_create2 = block_number >= self.eip86_transition; schedule.have_revert = block_number >= self.eip140_transition; schedule.have_static_call = block_number >= self.eip214_transition; @@ -105,11 +120,24 @@ impl CommonParams { } if block_number >= self.dust_protection_transition { schedule.kill_dust = match self.remove_dust_contracts { - true => ::evm::CleanDustMode::WithCodeAndStorage, - false => ::evm::CleanDustMode::BasicOnly, + true => ::vm::CleanDustMode::WithCodeAndStorage, + false => ::vm::CleanDustMode::BasicOnly, }; } } + + /// Whether these params contain any bug-fix hard forks. + pub fn contains_bugfix_hard_fork(&self) -> bool { + self.eip98_transition != 0 && + self.eip155_transition != 0 && + self.validate_receipts_transition != 0 && + self.eip86_transition != 0 && + self.eip140_transition != 0 && + self.eip210_transition != 0 && + self.eip211_transition != 0 && + self.eip214_transition != 0 && + self.dust_protection_transition != 0 + } } impl From for CommonParams { @@ -123,6 +151,7 @@ impl From for CommonParams { min_gas_limit: p.min_gas_limit.into(), fork_block: if let (Some(n), Some(h)) = (p.fork_block, p.fork_hash) { Some((n.into(), h.into())) } else { None }, eip98_transition: p.eip98_transition.map_or(0, Into::into), + eip155_transition: p.eip155_transition.map_or(0, Into::into), validate_receipts_transition: p.validate_receipts_transition.map_or(0, Into::into), eip86_transition: p.eip86_transition.map_or(BlockNumber::max_value(), Into::into), eip140_transition: p.eip140_transition.map_or(BlockNumber::max_value(), Into::into), @@ -138,6 +167,9 @@ impl From for CommonParams { nonce_cap_increment: p.nonce_cap_increment.map_or(64, Into::into), remove_dust_contracts: p.remove_dust_contracts.unwrap_or(false), wasm: p.wasm.unwrap_or(false), + gas_limit_bound_divisor: p.gas_limit_bound_divisor.into(), + block_reward: p.block_reward.map_or_else(U256::zero, Into::into), + registrar: p.registrar.map_or_else(Address::new, Into::into), } } } @@ -241,7 +273,7 @@ impl Spec { ) -> Arc { match engine_spec { ethjson::spec::Engine::Null => Arc::new(NullEngine::new(params, builtins)), - ethjson::spec::Engine::InstantSeal(instant) => Arc::new(InstantSeal::new(params, instant.params.registrar.map_or_else(Address::new, Into::into), builtins)), + ethjson::spec::Engine::InstantSeal => Arc::new(InstantSeal::new(params, builtins)), ethjson::spec::Engine::Ethash(ethash) => Arc::new(ethereum::Ethash::new(cache_dir, params, From::from(ethash.params), builtins)), ethjson::spec::Engine::BasicAuthority(basic_authority) => Arc::new(BasicAuthority::new(params, From::from(basic_authority.params), builtins)), ethjson::spec::Engine::AuthorityRound(authority_round) => AuthorityRound::new(params, From::from(authority_round.params), builtins).expect("Failed to start AuthorityRound consensus engine."), @@ -347,6 +379,9 @@ impl Spec { /// Get the configured Network ID. pub fn network_id(&self) -> u64 { self.params().network_id } + /// Get the chain ID used for signing. + pub fn chain_id(&self) -> u64 { self.params().chain_id } + /// Get the configured subprotocol name. pub fn subprotocol_name(&self) -> String { self.params().subprotocol_name.clone() } @@ -483,6 +518,7 @@ impl Spec { #[cfg(test)] mod tests { + use std::str::FromStr; use util::*; use views::*; use tests::helpers::get_temp_state_db; @@ -495,19 +531,6 @@ mod tests { assert!(Spec::load(::std::env::temp_dir(), &[] as &[u8]).is_err()); } - #[test] - fn all_spec_files_valid() { - Spec::new_test(); - Spec::new_null(); - Spec::new_test_constructor(); - Spec::new_instant(); - Spec::new_test_round(); - Spec::new_test_tendermint(); - Spec::new_validator_safe_contract(); - Spec::new_validator_contract(); - Spec::new_validator_multi(); - } - #[test] fn test_chain() { let test_spec = Spec::new_test(); diff --git a/ethcore/src/state/account.rs b/ethcore/src/state/account.rs index 9e58f2ec0..1235fd289 100644 --- a/ethcore/src/state/account.rs +++ b/ethcore/src/state/account.rs @@ -16,6 +16,9 @@ //! Single account in the system. +use std::fmt; +use std::sync::Arc; +use std::collections::HashMap; use util::*; use pod_account::*; use rlp::*; diff --git a/ethcore/src/state/mod.rs b/ethcore/src/state/mod.rs index f15846b73..3898572a6 100644 --- a/ethcore/src/state/mod.rs +++ b/ethcore/src/state/mod.rs @@ -21,10 +21,13 @@ use std::cell::{RefCell, RefMut}; use std::collections::hash_map::Entry; +use std::collections::{HashMap, BTreeMap, HashSet}; +use std::fmt; +use std::sync::Arc; use receipt::Receipt; use engines::Engine; -use evm::env_info::EnvInfo; +use vm::EnvInfo; use error::Error; use executive::{Executive, TransactOptions}; use factory::Factories; @@ -1019,7 +1022,7 @@ mod tests { use ethkey::Secret; use util::{U256, H256, Address, Hashable}; use tests::helpers::*; - use evm::env_info::EnvInfo; + use vm::EnvInfo; use spec::*; use transaction::*; use ethcore_logger::init_log; diff --git a/ethcore/src/state_db.rs b/ethcore/src/state_db.rs index de5a3f75b..e2f6fdaf0 100644 --- a/ethcore/src/state_db.rs +++ b/ethcore/src/state_db.rs @@ -15,6 +15,7 @@ // along with Parity. If not, see . use std::collections::{VecDeque, HashSet}; +use std::sync::Arc; use lru_cache::LruCache; use util::cache::MemoryLruCache; use util::journaldb::JournalDB; @@ -23,7 +24,7 @@ use util::hash::{H256}; use util::hashdb::HashDB; use state::{self, Account}; use header::BlockNumber; -use util::{Arc, Address, DBTransaction, UtilError, Mutex, Hashable}; +use util::{Address, DBTransaction, UtilError, Mutex, Hashable}; use bloom_journal::{Bloom, BloomJournal}; use db::COL_ACCOUNT_BLOOM; use byteorder::{LittleEndian, ByteOrder}; diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index 3b32f9094..639fce3ab 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use std::str::FromStr; +use std::sync::Arc; use io::IoChannel; use client::{BlockChainClient, MiningBlockChainClient, Client, ClientConfig, BlockId}; use state::{self, State, CleanupMode}; diff --git a/ethcore/src/tests/evm.rs b/ethcore/src/tests/evm.rs index c97fd4ac0..7b0e03d24 100644 --- a/ethcore/src/tests/evm.rs +++ b/ethcore/src/tests/evm.rs @@ -1,9 +1,8 @@ //! Tests of EVM integration with transaction execution. -use evm::action_params::{ActionParams, ActionValue}; -use evm::env_info::EnvInfo; +use std::sync::Arc; +use vm::{EnvInfo, ActionParams, ActionValue, CallType}; use evm::{Factory, VMType}; -use evm::call_type::CallType; use executive::Executive; use state::Substate; use tests::helpers::*; diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index f8e412073..d8ba8313e 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use std::collections::BTreeMap; +use std::sync::Arc; use ethkey::KeyPair; use io::*; use client::{BlockChainClient, Client, ClientConfig}; @@ -209,7 +211,7 @@ pub fn generate_dummy_client_with_spec_accounts_and_data(get_test_spec: F, ac action: Action::Create, data: vec![], value: U256::zero(), - }.sign(kp.secret(), Some(test_spec.network_id())), None).unwrap(); + }.sign(kp.secret(), Some(test_spec.chain_id())), None).unwrap(); n += 1; } @@ -347,7 +349,7 @@ pub fn get_good_dummy_block_fork_seq(start_number: usize, count: usize, parent_h for i in start_number .. start_number + count + 1 { let mut block_header = Header::new(); block_header.set_gas_limit(test_engine.params().min_gas_limit); - block_header.set_difficulty(U256::from(i).mul(U256([0, 1, 0, 0]))); + block_header.set_difficulty(U256::from(i) * U256([0, 1, 0, 0])); block_header.set_timestamp(rolling_timestamp); block_header.set_number(i as u64); block_header.set_parent_hash(parent); @@ -394,16 +396,13 @@ pub fn get_bad_state_dummy_block() -> Bytes { create_test_block(&block_header) } -pub fn get_default_ethash_params() -> EthashParams{ +pub fn get_default_ethash_params() -> EthashParams { EthashParams { - gas_limit_bound_divisor: U256::from(1024), minimum_difficulty: U256::from(131072), difficulty_bound_divisor: U256::from(2048), difficulty_increment_divisor: 10, metropolis_difficulty_increment_divisor: 9, duration_limit: 13, - block_reward: U256::from(0), - registrar: "0000000000000000000000000000000000000001".into(), homestead_transition: 1150000, dao_hardfork_transition: u64::max_value(), dao_hardfork_beneficiary: "0000000000000000000000000000000000000001".into(), @@ -413,7 +412,6 @@ pub fn get_default_ethash_params() -> EthashParams{ bomb_defuse_transition: u64::max_value(), eip100b_transition: u64::max_value(), eip150_transition: u64::max_value(), - eip155_transition: u64::max_value(), eip160_transition: u64::max_value(), eip161abc_transition: u64::max_value(), eip161d_transition: u64::max_value(), diff --git a/ethcore/src/trace/bloom.rs b/ethcore/src/trace/bloom.rs index 561a83719..ed34d6505 100644 --- a/ethcore/src/trace/bloom.rs +++ b/ethcore/src/trace/bloom.rs @@ -1,10 +1,9 @@ use bloomchain::Bloom; use bloomchain::group::{BloomGroup, GroupPosition}; -use rlp::*; use basic_types::LogBloom; /// Helper structure representing bloom of the trace. -#[derive(Clone)] +#[derive(Clone, RlpEncodableWrapper, RlpDecodableWrapper)] pub struct BlockTracesBloom(LogBloom); impl From for BlockTracesBloom { @@ -28,7 +27,7 @@ impl Into for BlockTracesBloom { } /// Represents group of X consecutive blooms. -#[derive(Clone)] +#[derive(Clone, RlpEncodableWrapper, RlpDecodableWrapper)] pub struct BlockTracesBloomGroup { blooms: Vec, } @@ -59,34 +58,6 @@ impl Into for BlockTracesBloomGroup { } } -impl Decodable for BlockTracesBloom { - fn decode(rlp: &UntrustedRlp) -> Result { - LogBloom::decode(rlp).map(BlockTracesBloom) - } -} - -impl Encodable for BlockTracesBloom { - fn rlp_append(&self, s: &mut RlpStream) { - Encodable::rlp_append(&self.0, s) - } -} - -impl Decodable for BlockTracesBloomGroup { - fn decode(rlp: &UntrustedRlp) -> Result { - let blooms = rlp.as_list()?; - let group = BlockTracesBloomGroup { - blooms: blooms - }; - Ok(group) - } -} - -impl Encodable for BlockTracesBloomGroup { - fn rlp_append(&self, s: &mut RlpStream) { - s.append_list(&self.blooms); - } -} - /// Represents `BloomGroup` position in database. #[derive(PartialEq, Eq, Hash, Clone, Debug)] pub struct TraceGroupPosition { diff --git a/ethcore/src/trace/executive_tracer.rs b/ethcore/src/trace/executive_tracer.rs index cdfe1e004..860c74223 100644 --- a/ethcore/src/trace/executive_tracer.rs +++ b/ethcore/src/trace/executive_tracer.rs @@ -17,7 +17,7 @@ //! Simple executive tracer. use util::{Bytes, Address, U256}; -use evm::action_params::ActionParams; +use vm::ActionParams; use trace::trace::{Call, Create, Action, Res, CreateResult, CallResult, VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff, Suicide}; use trace::{Tracer, VMTracer, FlatTrace, TraceError}; diff --git a/ethcore/src/trace/mod.rs b/ethcore/src/trace/mod.rs index 39af8a08a..be830430b 100644 --- a/ethcore/src/trace/mod.rs +++ b/ethcore/src/trace/mod.rs @@ -39,7 +39,7 @@ pub use self::types::filter::{Filter, AddressesFilter}; use util::{Bytes, Address, U256, H256, DBTransaction}; use self::trace::{Call, Create}; -use evm::action_params::ActionParams; +use vm::ActionParams; use header::BlockNumber; /// This trait is used by executive to build traces. diff --git a/ethcore/src/trace/noop_tracer.rs b/ethcore/src/trace/noop_tracer.rs index 5fb8a7c55..2c0e1b830 100644 --- a/ethcore/src/trace/noop_tracer.rs +++ b/ethcore/src/trace/noop_tracer.rs @@ -17,7 +17,7 @@ //! Nonoperative tracer. use util::{Bytes, Address, U256}; -use evm::action_params::ActionParams; +use vm::ActionParams; use trace::{Tracer, VMTracer, FlatTrace, TraceError}; use trace::trace::{Call, Create, VMTrace}; diff --git a/ethcore/src/trace/types/error.rs b/ethcore/src/trace/types/error.rs index 4242bfad4..5cedefd09 100644 --- a/ethcore/src/trace/types/error.rs +++ b/ethcore/src/trace/types/error.rs @@ -18,7 +18,7 @@ use std::fmt; use rlp::{Encodable, RlpStream, Decodable, DecoderError, UntrustedRlp}; -use evm::Error as EvmError; +use vm::Error as VmError; /// Trace evm errors. #[derive(Debug, PartialEq, Clone)] @@ -45,24 +45,24 @@ pub enum Error { Wasm, } -impl<'a> From<&'a EvmError> for Error { - fn from(e: &'a EvmError) -> Self { +impl<'a> From<&'a VmError> for Error { + fn from(e: &'a VmError) -> Self { match *e { - EvmError::OutOfGas => Error::OutOfGas, - EvmError::BadJumpDestination { .. } => Error::BadJumpDestination, - EvmError::BadInstruction { .. } => Error::BadInstruction, - EvmError::StackUnderflow { .. } => Error::StackUnderflow, - EvmError::OutOfStack { .. } => Error::OutOfStack, - EvmError::BuiltIn { .. } => Error::BuiltIn, - EvmError::Wasm { .. } => Error::Wasm, - EvmError::Internal(_) => Error::Internal, - EvmError::MutableCallInStaticContext => Error::MutableCallInStaticContext, + VmError::OutOfGas => Error::OutOfGas, + VmError::BadJumpDestination { .. } => Error::BadJumpDestination, + VmError::BadInstruction { .. } => Error::BadInstruction, + VmError::StackUnderflow { .. } => Error::StackUnderflow, + VmError::OutOfStack { .. } => Error::OutOfStack, + VmError::BuiltIn { .. } => Error::BuiltIn, + VmError::Wasm { .. } => Error::Wasm, + VmError::Internal(_) => Error::Internal, + VmError::MutableCallInStaticContext => Error::MutableCallInStaticContext, } } } -impl From for Error { - fn from(e: EvmError) -> Self { +impl From for Error { + fn from(e: VmError) -> Self { Error::from(&e) } } diff --git a/ethcore/src/trace/types/filter.rs b/ethcore/src/trace/types/filter.rs index 2dc810442..1b2e2077a 100644 --- a/ethcore/src/trace/types/filter.rs +++ b/ethcore/src/trace/types/filter.rs @@ -20,7 +20,7 @@ use std::ops::Range; use bloomchain::{Filter as BloomFilter, Bloom, Number}; use util::Address; use util::sha3::Hashable; -use util::bloom::Bloomable; +use bloomable::Bloomable; use basic_types::LogBloom; use trace::flat::FlatTrace; use super::trace::{Action, Res}; @@ -137,7 +137,7 @@ impl Filter { mod tests { use util::Address; use util::sha3::Hashable; - use util::bloom::Bloomable; + use bloomable::Bloomable; use trace::trace::{Action, Call, Res, Create, CreateResult, Suicide}; use trace::flat::FlatTrace; use trace::{Filter, AddressesFilter, TraceError}; diff --git a/ethcore/src/trace/types/flat.rs b/ethcore/src/trace/types/flat.rs index da304694d..8b65f1f4c 100644 --- a/ethcore/src/trace/types/flat.rs +++ b/ethcore/src/trace/types/flat.rs @@ -77,7 +77,7 @@ impl Decodable for FlatTrace { } /// Represents all traces produced by a single transaction. -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Clone, RlpEncodableWrapper, RlpDecodableWrapper)] pub struct FlatTransactionTraces(Vec); impl From> for FlatTransactionTraces { @@ -99,18 +99,6 @@ impl FlatTransactionTraces { } } -impl Encodable for FlatTransactionTraces { - fn rlp_append(&self, s: &mut RlpStream) { - s.append_list(&self.0); - } -} - -impl Decodable for FlatTransactionTraces { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(FlatTransactionTraces(rlp.as_list()?)) - } -} - impl Into> for FlatTransactionTraces { fn into(self) -> Vec { self.0 @@ -118,7 +106,7 @@ impl Into> for FlatTransactionTraces { } /// Represents all traces produced by transactions in a single block. -#[derive(Debug, PartialEq, Clone, Default)] +#[derive(Debug, PartialEq, Clone, Default, RlpEncodableWrapper, RlpDecodableWrapper)] pub struct FlatBlockTraces(Vec); impl HeapSizeOf for FlatBlockTraces { @@ -140,18 +128,6 @@ impl FlatBlockTraces { } } -impl Encodable for FlatBlockTraces { - fn rlp_append(&self, s: &mut RlpStream) { - s.append_list(&self.0); - } -} - -impl Decodable for FlatBlockTraces { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(FlatBlockTraces(rlp.as_list()?)) - } -} - impl Into> for FlatBlockTraces { fn into(self) -> Vec { self.0 diff --git a/ethcore/src/trace/types/trace.rs b/ethcore/src/trace/types/trace.rs index 24250935f..5fa0260c6 100644 --- a/ethcore/src/trace/types/trace.rs +++ b/ethcore/src/trace/types/trace.rs @@ -18,16 +18,16 @@ use util::{U256, Bytes, Address}; use util::sha3::Hashable; -use util::bloom::Bloomable; +use bloomable::Bloomable; use rlp::*; -use evm::action_params::ActionParams; +use vm::ActionParams; use basic_types::LogBloom; use evm::CallType; use super::error::Error; /// `Call` result. -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, RlpEncodable, RlpDecodable)] #[cfg_attr(feature = "ipc", binary)] pub struct CallResult { /// Gas used by call. @@ -36,27 +36,8 @@ pub struct CallResult { pub output: Bytes, } -impl Encodable for CallResult { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(2); - s.append(&self.gas_used); - s.append(&self.output); - } -} - -impl Decodable for CallResult { - fn decode(rlp: &UntrustedRlp) -> Result { - let res = CallResult { - gas_used: rlp.val_at(0)?, - output: rlp.val_at(1)?, - }; - - Ok(res) - } -} - /// `Create` result. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable)] #[cfg_attr(feature = "ipc", binary)] pub struct CreateResult { /// Gas used by create. @@ -67,27 +48,6 @@ pub struct CreateResult { pub address: Address, } -impl Encodable for CreateResult { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(3); - s.append(&self.gas_used); - s.append(&self.code); - s.append(&self.address); - } -} - -impl Decodable for CreateResult { - fn decode(rlp: &UntrustedRlp) -> Result { - let res = CreateResult { - gas_used: rlp.val_at(0)?, - code: rlp.val_at(1)?, - address: rlp.val_at(2)?, - }; - - Ok(res) - } -} - impl CreateResult { /// Returns bloom. pub fn bloom(&self) -> LogBloom { @@ -96,7 +56,7 @@ impl CreateResult { } /// Description of a _call_ action, either a `CALL` operation or a message transction. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable)] #[cfg_attr(feature = "ipc", binary)] pub struct Call { /// The sending account. @@ -126,33 +86,6 @@ impl From for Call { } } -impl Encodable for Call { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(6); - s.append(&self.from); - s.append(&self.to); - s.append(&self.value); - s.append(&self.gas); - s.append(&self.input); - s.append(&self.call_type); - } -} - -impl Decodable for Call { - fn decode(rlp: &UntrustedRlp) -> Result { - let res = Call { - from: rlp.val_at(0)?, - to: rlp.val_at(1)?, - value: rlp.val_at(2)?, - gas: rlp.val_at(3)?, - input: rlp.val_at(4)?, - call_type: rlp.val_at(5)?, - }; - - Ok(res) - } -} - impl Call { /// Returns call action bloom. /// The bloom contains from and to addresses. @@ -163,7 +96,7 @@ impl Call { } /// Description of a _create_ action, either a `CREATE` operation or a create transction. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable)] #[cfg_attr(feature = "ipc", binary)] pub struct Create { /// The address of the creator. @@ -187,29 +120,6 @@ impl From for Create { } } -impl Encodable for Create { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(4); - s.append(&self.from); - s.append(&self.value); - s.append(&self.gas); - s.append(&self.init); - } -} - -impl Decodable for Create { - fn decode(rlp: &UntrustedRlp) -> Result { - let res = Create { - from: rlp.val_at(0)?, - value: rlp.val_at(1)?, - gas: rlp.val_at(2)?, - init: rlp.val_at(3)?, - }; - - Ok(res) - } -} - impl Create { /// Returns bloom create action bloom. /// The bloom contains only from address. @@ -219,7 +129,7 @@ impl Create { } /// Suicide action. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable)] #[cfg_attr(feature = "ipc", binary)] pub struct Suicide { /// Suicided address. @@ -238,28 +148,6 @@ impl Suicide { } } -impl Encodable for Suicide { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(3); - s.append(&self.address); - s.append(&self.refund_address); - s.append(&self.balance); - } -} - -impl Decodable for Suicide { - fn decode(rlp: &UntrustedRlp) -> Result { - let res = Suicide { - address: rlp.val_at(0)?, - refund_address: rlp.val_at(1)?, - balance: rlp.val_at(2)?, - }; - - Ok(res) - } -} - - /// Description of an action that we trace; will be either a call or a create. #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "ipc", binary)] @@ -394,7 +282,7 @@ impl Res { } } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable)] #[cfg_attr(feature = "ipc", binary)] /// A diff of some chunk of memory. pub struct MemoryDiff { @@ -404,24 +292,7 @@ pub struct MemoryDiff { pub data: Bytes, } -impl Encodable for MemoryDiff { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(2); - s.append(&self.offset); - s.append(&self.data); - } -} - -impl Decodable for MemoryDiff { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(MemoryDiff { - offset: rlp.val_at(0)?, - data: rlp.val_at(1)?, - }) - } -} - -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable)] #[cfg_attr(feature = "ipc", binary)] /// A diff of some storage value. pub struct StorageDiff { @@ -431,24 +302,7 @@ pub struct StorageDiff { pub value: U256, } -impl Encodable for StorageDiff { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(2); - s.append(&self.location); - s.append(&self.value); - } -} - -impl Decodable for StorageDiff { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(StorageDiff { - location: rlp.val_at(0)?, - value: rlp.val_at(1)?, - }) - } -} - -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable)] #[cfg_attr(feature = "ipc", binary)] /// A record of an executed VM operation. pub struct VMExecutedOperation { @@ -462,28 +316,7 @@ pub struct VMExecutedOperation { pub store_diff: Option, } -impl Encodable for VMExecutedOperation { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(4); - s.append(&self.gas_used); - s.append_list(&self.stack_push); - s.append(&self.mem_diff); - s.append(&self.store_diff); - } -} - -impl Decodable for VMExecutedOperation { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(VMExecutedOperation { - gas_used: rlp.val_at(0)?, - stack_push: rlp.list_at(1)?, - mem_diff: rlp.val_at(2)?, - store_diff: rlp.val_at(3)?, - }) - } -} - -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, RlpEncodable, RlpDecodable)] #[cfg_attr(feature = "ipc", binary)] /// A record of the execution of a single VM operation. pub struct VMOperation { @@ -497,30 +330,7 @@ pub struct VMOperation { pub executed: Option, } -impl Encodable for VMOperation { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(4); - s.append(&self.pc); - s.append(&self.instruction); - s.append(&self.gas_cost); - s.append(&self.executed); - } -} - -impl Decodable for VMOperation { - fn decode(rlp: &UntrustedRlp) -> Result { - let res = VMOperation { - pc: rlp.val_at(0)?, - instruction: rlp.val_at(1)?, - gas_cost: rlp.val_at(2)?, - executed: rlp.val_at(3)?, - }; - - Ok(res) - } -} - -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Default, RlpEncodable, RlpDecodable)] #[cfg_attr(feature = "ipc", binary)] /// A record of a full VM trace for a CALL/CREATE. pub struct VMTrace { @@ -534,26 +344,3 @@ pub struct VMTrace { /// Thre is a 1:1 correspondance between these and a CALL/CREATE/CALLCODE/DELEGATECALL instruction. pub subs: Vec, } - -impl Encodable for VMTrace { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(4); - s.append(&self.parent_step); - s.append(&self.code); - s.append_list(&self.operations); - s.append_list(&self.subs); - } -} - -impl Decodable for VMTrace { - fn decode(rlp: &UntrustedRlp) -> Result { - let res = VMTrace { - parent_step: rlp.val_at(0)?, - code: rlp.val_at(1)?, - operations: rlp.list_at(2)?, - subs: rlp.list_at(3)?, - }; - - Ok(res) - } -} diff --git a/ethcore/src/transaction.rs b/ethcore/src/transaction.rs index 6f5470028..0bd61dceb 100644 --- a/ethcore/src/transaction.rs +++ b/ethcore/src/transaction.rs @@ -56,6 +56,15 @@ impl Decodable for Action { } } +impl Encodable for Action { + fn rlp_append(&self, s: &mut RlpStream) { + match *self { + Action::Create => s.append_internal(&""), + Action::Call(ref addr) => s.append_internal(addr), + }; + } +} + /// Transaction activation condition. #[derive(Debug, Clone, PartialEq, Eq)] pub enum Condition { @@ -85,18 +94,15 @@ pub struct Transaction { impl Transaction { /// Append object with a without signature into RLP stream - pub fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream, network_id: Option) { - s.begin_list(if network_id.is_none() { 6 } else { 9 }); + pub fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream, chain_id: Option) { + s.begin_list(if chain_id.is_none() { 6 } else { 9 }); s.append(&self.nonce); s.append(&self.gas_price); s.append(&self.gas); - match self.action { - Action::Create => s.append_empty_data(), - Action::Call(ref to) => s.append(to) - }; + s.append(&self.action); s.append(&self.value); s.append(&self.data); - if let Some(n) = network_id { + if let Some(n) = chain_id { s.append(&n); s.append(&0u8); s.append(&0u8); @@ -157,27 +163,27 @@ impl From for UnverifiedTransaction { impl Transaction { /// The message hash of the transaction. - pub fn hash(&self, network_id: Option) -> H256 { + pub fn hash(&self, chain_id: Option) -> H256 { let mut stream = RlpStream::new(); - self.rlp_append_unsigned_transaction(&mut stream, network_id); + self.rlp_append_unsigned_transaction(&mut stream, chain_id); stream.as_raw().sha3() } /// Signs the transaction as coming from `sender`. - pub fn sign(self, secret: &Secret, network_id: Option) -> SignedTransaction { - let sig = ::ethkey::sign(secret, &self.hash(network_id)) + pub fn sign(self, secret: &Secret, chain_id: Option) -> SignedTransaction { + let sig = ::ethkey::sign(secret, &self.hash(chain_id)) .expect("data is valid and context has signing capabilities; qed"); - SignedTransaction::new(self.with_signature(sig, network_id)) + SignedTransaction::new(self.with_signature(sig, chain_id)) .expect("secret is valid so it's recoverable") } /// Signs the transaction with signature. - pub fn with_signature(self, sig: Signature, network_id: Option) -> UnverifiedTransaction { + pub fn with_signature(self, sig: Signature, chain_id: Option) -> UnverifiedTransaction { UnverifiedTransaction { unsigned: self, r: sig.r().into(), s: sig.s().into(), - v: sig.v() as u64 + if let Some(n) = network_id { 35 + n * 2 } else { 27 }, + v: sig.v() as u64 + if let Some(n) = chain_id { 35 + n * 2 } else { 27 }, hash: 0.into(), }.compute_hash() } @@ -210,13 +216,13 @@ impl Transaction { } /// Add EIP-86 compatible empty signature. - pub fn null_sign(self, network_id: u64) -> SignedTransaction { + pub fn null_sign(self, chain_id: u64) -> SignedTransaction { SignedTransaction { transaction: UnverifiedTransaction { unsigned: self, r: U256::zero(), s: U256::zero(), - v: network_id, + v: chain_id, hash: 0.into(), }.compute_hash(), sender: UNSIGNED_SENDER, @@ -244,7 +250,7 @@ pub struct UnverifiedTransaction { /// Plain Transaction. unsigned: Transaction, /// The V field of the signature; the LS bit described which half of the curve our point falls - /// in. The MS bits describe which network this transaction is for. If 27/28, its for all networks. + /// in. The MS bits describe which chain this transaction is for. If 27/28, its for all chains. v: u64, /// The R field of the signature; helps describe the point on the curve. r: U256, @@ -308,10 +314,7 @@ impl UnverifiedTransaction { s.append(&self.nonce); s.append(&self.gas_price); s.append(&self.gas); - match self.action { - Action::Create => s.append_empty_data(), - Action::Call(ref to) => s.append(to) - }; + s.append(&self.action); s.append(&self.value); s.append(&self.data); s.append(&self.v); @@ -330,8 +333,8 @@ impl UnverifiedTransaction { /// The `v` value that appears in the RLP. pub fn original_v(&self) -> u64 { self.v } - /// The network ID, or `None` if this is a global transaction. - pub fn network_id(&self) -> Option { + /// The chain ID, or `None` if this is a global transaction. + pub fn chain_id(&self) -> Option { match self.v { v if self.is_unsigned() => Some(v), v if v > 36 => Some((v - 35) / 2), @@ -360,15 +363,15 @@ impl UnverifiedTransaction { /// Recovers the public key of the sender. pub fn recover_public(&self) -> Result { - Ok(recover(&self.signature(), &self.unsigned.hash(self.network_id()))?) + Ok(recover(&self.signature(), &self.unsigned.hash(self.chain_id()))?) } /// Do basic validation, checking for valid signature and minimum gas, // TODO: consider use in block validation. #[cfg(test)] #[cfg(feature = "json-tests")] - pub fn validate(self, schedule: &Schedule, require_low: bool, allow_network_id_of_one: bool, allow_empty_signature: bool) -> Result { - let chain_id = if allow_network_id_of_one { Some(1) } else { None }; + pub fn validate(self, schedule: &Schedule, require_low: bool, allow_chain_id_of_one: bool, allow_empty_signature: bool) -> Result { + let chain_id = if allow_chain_id_of_one { Some(1) } else { None }; self.verify_basic(require_low, chain_id, allow_empty_signature)?; if !allow_empty_signature || !self.is_unsigned() { self.recover_public()?; @@ -388,10 +391,10 @@ impl UnverifiedTransaction { if allow_empty_signature && self.is_unsigned() && !(self.gas_price.is_zero() && self.value.is_zero() && self.nonce.is_zero()) { return Err(EthkeyError::InvalidSignature.into()) } - match (self.network_id(), chain_id) { + match (self.chain_id(), chain_id) { (None, _) => {}, (Some(n), Some(m)) if n == m => {}, - _ => return Err(TransactionError::InvalidNetworkId.into()), + _ => return Err(TransactionError::InvalidChainId.into()), }; Ok(()) } @@ -555,7 +558,7 @@ mod tests { } else { panic!(); } assert_eq!(t.value, U256::from(0x0au64)); assert_eq!(public_to_address(&t.recover_public().unwrap()), "0f65fe9276bc9a24ae7083ae28e2660ef72df99e".into()); - assert_eq!(t.network_id(), None); + assert_eq!(t.chain_id(), None); } #[test] @@ -572,7 +575,7 @@ mod tests { data: b"Hello!".to_vec() }.sign(&key.secret(), None); assert_eq!(Address::from(key.public().sha3()), t.sender()); - assert_eq!(t.network_id(), None); + assert_eq!(t.chain_id(), None); } #[test] @@ -586,15 +589,15 @@ mod tests { data: b"Hello!".to_vec() }.fake_sign(Address::from(0x69)); assert_eq!(Address::from(0x69), t.sender()); - assert_eq!(t.network_id(), None); + assert_eq!(t.chain_id(), None); let t = t.clone(); assert_eq!(Address::from(0x69), t.sender()); - assert_eq!(t.network_id(), None); + assert_eq!(t.chain_id(), None); } #[test] - fn should_recover_from_network_specific_signing() { + fn should_recover_from_chain_specific_signing() { use ethkey::{Random, Generator}; let key = Random.generate().unwrap(); let t = Transaction { @@ -606,7 +609,7 @@ mod tests { data: b"Hello!".to_vec() }.sign(&key.secret(), Some(69)); assert_eq!(Address::from(key.public().sha3()), t.sender()); - assert_eq!(t.network_id(), Some(69)); + assert_eq!(t.chain_id(), Some(69)); } #[test] @@ -617,7 +620,7 @@ mod tests { let signed = decode(&FromHex::from_hex(tx_data).unwrap()); let signed = SignedTransaction::new(signed).unwrap(); assert_eq!(signed.sender(), address.into()); - flushln!("networkid: {:?}", signed.network_id()); + flushln!("chainid: {:?}", signed.chain_id()); }; test_vector("f864808504a817c800825208943535353535353535353535353535353535353535808025a0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116da0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", "0xf0f6f18bca1b28cd68e4357452947e021241e9ce"); diff --git a/ethcore/src/verification/queue/mod.rs b/ethcore/src/verification/queue/mod.rs index 7e9a70f7c..ce0cb4179 100644 --- a/ethcore/src/verification/queue/mod.rs +++ b/ethcore/src/verification/queue/mod.rs @@ -19,7 +19,9 @@ use std::thread::{self, JoinHandle}; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering as AtomicOrdering}; -use std::sync::{Condvar as SCondvar, Mutex as SMutex}; +use std::sync::{Condvar as SCondvar, Mutex as SMutex, Arc}; +use std::cmp; +use std::collections::{VecDeque, HashSet, HashMap}; use util::*; use io::*; use error::*; @@ -234,8 +236,8 @@ impl VerificationQueue { let scale_verifiers = config.verifier_settings.scale_verifiers; let num_cpus = ::num_cpus::get(); - let max_verifiers = min(num_cpus, MAX_VERIFIERS); - let default_amount = max(1, min(max_verifiers, config.verifier_settings.num_verifiers)); + let max_verifiers = cmp::min(num_cpus, MAX_VERIFIERS); + let default_amount = cmp::max(1, cmp::min(max_verifiers, config.verifier_settings.num_verifiers)); let state = Arc::new((Mutex::new(State::Work(default_amount)), Condvar::new())); let mut verifier_handles = Vec::with_capacity(max_verifiers); @@ -278,8 +280,8 @@ impl VerificationQueue { processing: RwLock::new(HashMap::new()), empty: empty, ticks_since_adjustment: AtomicUsize::new(0), - max_queue_size: max(config.max_queue_size, MIN_QUEUE_LIMIT), - max_mem_use: max(config.max_mem_use, MIN_MEM_LIMIT), + max_queue_size: cmp::max(config.max_queue_size, MIN_QUEUE_LIMIT), + max_mem_use: cmp::max(config.max_mem_use, MIN_MEM_LIMIT), scale_verifiers: scale_verifiers, verifier_handles: verifier_handles, state: state, @@ -567,7 +569,7 @@ impl VerificationQueue { /// Removes up to `max` verified items from the queue pub fn drain(&self, max: usize) -> Vec { let mut verified = self.verification.verified.lock(); - let count = min(max, verified.len()); + let count = cmp::min(max, verified.len()); let result = verified.drain(..count).collect::>(); let drained_size = result.iter().map(HeapSizeOf::heap_size_of_children).fold(0, |a, c| a + c); @@ -687,8 +689,8 @@ impl VerificationQueue { // or below 1. fn scale_verifiers(&self, target: usize) { let current = self.num_verifiers(); - let target = min(self.verifier_handles.len(), target); - let target = max(1, target); + let target = cmp::min(self.verifier_handles.len(), target); + let target = cmp::max(1, target); debug!(target: "verification", "Scaling from {} to {} verifiers", current, target); @@ -725,7 +727,6 @@ impl Drop for VerificationQueue { #[cfg(test)] mod tests { - use util::*; use io::*; use spec::*; use super::{BlockQueue, Config, State}; diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index 823d2ef70..00976dca7 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -21,6 +21,7 @@ //! 2. Signatures verification done in the queue. //! 3. Final verification against the blockchain done before enactment. +use std::collections::HashSet; use util::*; use engines::Engine; use error::{BlockError, Error}; @@ -264,6 +265,7 @@ fn verify_block_integrity(block: &[u8], transactions_root: &H256, uncles_hash: & #[cfg(test)] mod tests { + use std::collections::{BTreeMap, HashMap}; use util::*; use ethkey::{Random, Generator}; use header::*; diff --git a/ethcore/types/Cargo.toml b/ethcore/types/Cargo.toml index 2a3ac6a80..82963f960 100644 --- a/ethcore/types/Cargo.toml +++ b/ethcore/types/Cargo.toml @@ -6,8 +6,10 @@ authors = ["Parity Technologies "] [dependencies] rlp = { path = "../../util/rlp" } +rlp_derive = { path = "../../util/rlp_derive" } ethcore-util = { path = "../../util" } ethjson = { path = "../../json" } +bloomable = { path = "../../util/bloomable" } [dev-dependencies] rustc-hex= "1.0" diff --git a/ethcore/types/src/basic_account.rs b/ethcore/types/src/basic_account.rs index c071040cf..f30872f6b 100644 --- a/ethcore/types/src/basic_account.rs +++ b/ethcore/types/src/basic_account.rs @@ -16,11 +16,10 @@ //! Basic account type -- the decoded RLP from the state trie. -use rlp::*; use util::{U256, H256}; /// Basic account type. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)] pub struct BasicAccount { /// Nonce of the account. pub nonce: U256, @@ -31,24 +30,3 @@ pub struct BasicAccount { /// Code hash of the account. pub code_hash: H256, } - -impl Encodable for BasicAccount { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(4) - .append(&self.nonce) - .append(&self.balance) - .append(&self.storage_root) - .append(&self.code_hash); - } -} - -impl Decodable for BasicAccount { - fn decode(rlp: &UntrustedRlp) -> Result { - Ok(BasicAccount { - nonce: rlp.val_at(0)?, - balance: rlp.val_at(1)?, - storage_root: rlp.val_at(2)?, - code_hash: rlp.val_at(3)?, - }) - } -} diff --git a/ethcore/types/src/block_status.rs b/ethcore/types/src/block_status.rs index 937077795..d330b9ed1 100644 --- a/ethcore/types/src/block_status.rs +++ b/ethcore/types/src/block_status.rs @@ -23,6 +23,8 @@ pub enum BlockStatus { Queued, /// Known as bad. Bad, + /// Pending block. + Pending, /// Unknown. Unknown, } diff --git a/ethcore/types/src/filter.rs b/ethcore/types/src/filter.rs index 6ab53b536..6e344b4ef 100644 --- a/ethcore/types/src/filter.rs +++ b/ethcore/types/src/filter.rs @@ -17,7 +17,7 @@ //! Blockchain filter use util::{Address, H256, Hashable, H2048}; -use util::bloom::Bloomable; +use bloomable::Bloomable; use ids::BlockId; use log_entry::LogEntry; diff --git a/ethcore/types/src/lib.rs b/ethcore/types/src/lib.rs index 589034066..10a4ac71e 100644 --- a/ethcore/types/src/lib.rs +++ b/ethcore/types/src/lib.rs @@ -19,6 +19,9 @@ extern crate ethcore_util as util; extern crate ethjson; extern crate rlp; +#[macro_use] +extern crate rlp_derive; +extern crate bloomable; #[cfg(test)] extern crate rustc_hex; diff --git a/ethcore/types/src/log_entry.rs b/ethcore/types/src/log_entry.rs index 724e6a7dc..152b48a0e 100644 --- a/ethcore/types/src/log_entry.rs +++ b/ethcore/types/src/log_entry.rs @@ -18,8 +18,7 @@ use std::ops::Deref; use util::{H256, Address, Bytes, HeapSizeOf, Hashable}; -use util::bloom::Bloomable; -use rlp::*; +use bloomable::Bloomable; use {BlockNumber}; use ethjson; @@ -27,7 +26,7 @@ use ethjson; pub type LogBloom = ::util::H2048; /// A record of execution for a `LOG` operation. -#[derive(Default, Debug, Clone, PartialEq, Eq)] +#[derive(Default, Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)] pub struct LogEntry { /// The address of the contract executing at the point of the `LOG` operation. pub address: Address, @@ -37,26 +36,6 @@ pub struct LogEntry { pub data: Bytes, } -impl Encodable for LogEntry { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(3); - s.append(&self.address); - s.append_list(&self.topics); - s.append(&self.data); - } -} - -impl Decodable for LogEntry { - fn decode(rlp: &UntrustedRlp) -> Result { - let entry = LogEntry { - address: rlp.val_at(0)?, - topics: rlp.list_at(1)?, - data: rlp.val_at(2)?, - }; - Ok(entry) - } -} - impl HeapSizeOf for LogEntry { fn heap_size_of_children(&self) -> usize { self.topics.heap_size_of_children() + self.data.heap_size_of_children() @@ -114,8 +93,8 @@ mod tests { #[test] fn test_empty_log_bloom() { - let bloom = H2048::from_str("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap(); - let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); + let bloom = "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".parse::().unwrap(); + let address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse::
().unwrap(); let log = LogEntry { address: address, topics: vec![], diff --git a/ethcore/vm/Cargo.toml b/ethcore/vm/Cargo.toml new file mode 100644 index 000000000..50efe936c --- /dev/null +++ b/ethcore/vm/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "vm" +version = "0.1.0" +authors = ["Parity Technologies "] + +[dependencies] +byteorder = "1.0" +ethcore-util = { path = "../../util" } +log = "0.3" +common-types = { path = "../types" } +evmjit = { path = "../../evmjit", optional = true } +ethjson = { path = "../../json" } +lazy_static = "0.2" +rlp = { path = "../../util/rlp" } \ No newline at end of file diff --git a/ethcore/evm/src/action_params.rs b/ethcore/vm/src/action_params.rs similarity index 98% rename from ethcore/evm/src/action_params.rs rename to ethcore/vm/src/action_params.rs index 62bb7fa5b..401d7ee57 100644 --- a/ethcore/evm/src/action_params.rs +++ b/ethcore/vm/src/action_params.rs @@ -20,7 +20,7 @@ use util::hash::{H256}; use util::sha3::{Hashable, SHA3_EMPTY}; use ethjson; -use {CallType}; +use call_type::CallType; use std::sync::Arc; @@ -48,7 +48,7 @@ impl ActionValue { /// Returns the apparent action value of the U256-convertable raw value pub fn apparent>(apparent_value: T) -> ActionValue { - ActionValue::Apparent(apparent_value.into()) + ActionValue::Apparent(apparent_value.into()) } } diff --git a/ethcore/evm/src/call_type.rs b/ethcore/vm/src/call_type.rs similarity index 100% rename from ethcore/evm/src/call_type.rs rename to ethcore/vm/src/call_type.rs diff --git a/ethcore/evm/src/env_info.rs b/ethcore/vm/src/env_info.rs similarity index 100% rename from ethcore/evm/src/env_info.rs rename to ethcore/vm/src/env_info.rs diff --git a/ethcore/vm/src/error.rs b/ethcore/vm/src/error.rs new file mode 100644 index 000000000..e4b199438 --- /dev/null +++ b/ethcore/vm/src/error.rs @@ -0,0 +1,100 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! VM errors module + +use util::trie; +use std::fmt; + +/// VM errors. +#[derive(Debug, Clone, PartialEq)] +pub enum Error { + /// `OutOfGas` is returned when transaction execution runs out of gas. + /// The state should be reverted to the state from before the + /// transaction execution. But it does not mean that transaction + /// was invalid. Balance still should be transfered and nonce + /// should be increased. + OutOfGas, + /// `BadJumpDestination` is returned when execution tried to move + /// to position that wasn't marked with JUMPDEST instruction + BadJumpDestination { + /// Position the code tried to jump to. + destination: usize + }, + /// `BadInstructions` is returned when given instruction is not supported + BadInstruction { + /// Unrecognized opcode + instruction: u8, + }, + /// `StackUnderflow` when there is not enough stack elements to execute instruction + StackUnderflow { + /// Invoked instruction + instruction: &'static str, + /// How many stack elements was requested by instruction + wanted: usize, + /// How many elements were on stack + on_stack: usize + }, + /// When execution would exceed defined Stack Limit + OutOfStack { + /// Invoked instruction + instruction: &'static str, + /// How many stack elements instruction wanted to push + wanted: usize, + /// What was the stack limit + limit: usize + }, + /// Built-in contract failed on given input + BuiltIn(&'static str), + /// When execution tries to modify the state in static context + MutableCallInStaticContext, + /// Likely to cause consensus issues. + Internal(String), + /// Wasm runtime error + Wasm(String), +} + + +impl From> for Error { + fn from(err: Box) -> Self { + Error::Internal(format!("Internal error: {}", err)) + } +} + +// impl From for Error { +// fn from(err: wasm::RuntimeError) -> Self { +// Error::Wasm(format!("Runtime error: {:?}", err)) +// } +// } + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::Error::*; + match *self { + OutOfGas => write!(f, "Out of gas"), + BadJumpDestination { destination } => write!(f, "Bad jump destination {:x}", destination), + BadInstruction { instruction } => write!(f, "Bad instruction {:x}", instruction), + StackUnderflow { instruction, wanted, on_stack } => write!(f, "Stack underflow {} {}/{}", instruction, wanted, on_stack), + OutOfStack { instruction, wanted, limit } => write!(f, "Out of stack {} {}/{}", instruction, wanted, limit), + BuiltIn(name) => write!(f, "Built-in failed: {}", name), + Internal(ref msg) => write!(f, "Internal error: {}", msg), + MutableCallInStaticContext => write!(f, "Mutable call in static context"), + Wasm(ref msg) => write!(f, "Internal error: {}", msg), + } + } +} + +pub type Result = ::std::result::Result; diff --git a/ethcore/evm/src/ext.rs b/ethcore/vm/src/ext.rs similarity index 85% rename from ethcore/evm/src/ext.rs rename to ethcore/vm/src/ext.rs index 1c3ddb317..54871e511 100644 --- a/ethcore/evm/src/ext.rs +++ b/ethcore/vm/src/ext.rs @@ -16,11 +16,13 @@ //! Interface for Evm externalities. +use std::sync::Arc; use util::*; use call_type::CallType; use env_info::EnvInfo; use schedule::Schedule; -use evm::{self, ReturnData}; +use return_data::ReturnData; +use error::Result; /// Result of externalities create function. pub enum ContractCreateResult { @@ -56,22 +58,22 @@ pub enum CreateContractAddress { /// Externalities interface for EVMs pub trait Ext { /// Returns a value for given key. - fn storage_at(&self, key: &H256) -> evm::Result; + fn storage_at(&self, key: &H256) -> Result; /// Stores a value for given key. - fn set_storage(&mut self, key: H256, value: H256) -> evm::Result<()>; + fn set_storage(&mut self, key: H256, value: H256) -> Result<()>; /// Determine whether an account exists. - fn exists(&self, address: &Address) -> evm::Result; + fn exists(&self, address: &Address) -> Result; /// Determine whether an account exists and is not null (zero balance/nonce, no code). - fn exists_and_not_null(&self, address: &Address) -> evm::Result; + fn exists_and_not_null(&self, address: &Address) -> Result; /// Balance of the origin account. - fn origin_balance(&self) -> evm::Result; + fn origin_balance(&self) -> Result; /// Returns address balance. - fn balance(&self, address: &Address) -> evm::Result; + fn balance(&self, address: &Address) -> Result; /// Returns the hash of one of the 256 most recent complete blocks. fn blockhash(&mut self, number: &U256) -> H256; @@ -99,21 +101,21 @@ pub trait Ext { ) -> MessageCallResult; /// Returns code at given address - fn extcode(&self, address: &Address) -> evm::Result>; + fn extcode(&self, address: &Address) -> Result>; /// Returns code size at given address - fn extcodesize(&self, address: &Address) -> evm::Result; + fn extcodesize(&self, address: &Address) -> Result; /// Creates log entry with given topics and data - fn log(&mut self, topics: Vec, data: &[u8]) -> evm::Result<()>; + fn log(&mut self, topics: Vec, data: &[u8]) -> Result<()>; /// Should be called when transaction calls `RETURN` opcode. /// Returns gas_left if cost of returning the data is not too high. - fn ret(self, gas: &U256, data: &ReturnData) -> evm::Result; + fn ret(self, gas: &U256, data: &ReturnData) -> Result; /// Should be called when contract commits suicide. /// Address to which funds should be refunded. - fn suicide(&mut self, refund_address: &Address) -> evm::Result<()> ; + fn suicide(&mut self, refund_address: &Address) -> Result<()> ; /// Returns schedule. fn schedule(&self) -> &Schedule; diff --git a/ethcore/vm/src/lib.rs b/ethcore/vm/src/lib.rs new file mode 100644 index 000000000..0c9e32dc6 --- /dev/null +++ b/ethcore/vm/src/lib.rs @@ -0,0 +1,48 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Virtual machines support library + +extern crate ethcore_util as util; +extern crate common_types as types; +extern crate ethjson; +extern crate rlp; + +mod action_params; +mod call_type; +mod env_info; +mod schedule; +mod ext; +mod return_data; +mod error; + +pub mod tests; + +pub use action_params::{ActionParams, ActionValue}; +pub use call_type::CallType; +pub use env_info::{EnvInfo, LastHashes}; +pub use schedule::{Schedule, CleanDustMode}; +pub use ext::{Ext, MessageCallResult, ContractCreateResult, CreateContractAddress}; +pub use return_data::{ReturnData, GasLeft}; +pub use error::{Error, Result}; + +/// Virtual Machine interface +pub trait Vm { + /// This function should be used to execute transaction. + /// It returns either an error, a known amount of gas left, or parameters to be used + /// to compute the final gas left. + fn exec(&mut self, params: ActionParams, ext: &mut Ext) -> Result; +} \ No newline at end of file diff --git a/ethcore/vm/src/return_data.rs b/ethcore/vm/src/return_data.rs new file mode 100644 index 000000000..3c8bd182f --- /dev/null +++ b/ethcore/vm/src/return_data.rs @@ -0,0 +1,68 @@ + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Return data structures + +use util::U256; + +/// Return data buffer. Holds memory from a previous call and a slice into that memory. +#[derive(Debug)] +pub struct ReturnData { + mem: Vec, + offset: usize, + size: usize, +} + +impl ::std::ops::Deref for ReturnData { + type Target = [u8]; + fn deref(&self) -> &[u8] { + &self.mem[self.offset..self.offset + self.size] + } +} + +impl ReturnData { + /// Create empty `ReturnData`. + pub fn empty() -> Self { + ReturnData { + mem: Vec::new(), + offset: 0, + size: 0, + } + } + /// Create `ReturnData` from give buffer and slice. + pub fn new(mem: Vec, offset: usize, size: usize) -> Self { + ReturnData { + mem: mem, + offset: offset, + size: size, + } + } +} + +/// Gas Left: either it is a known value, or it needs to be computed by processing +/// a return instruction. +#[derive(Debug)] +pub enum GasLeft { + /// Known gas left + Known(U256), + /// Return or Revert instruction must be processed. + NeedsReturn { + /// Amount of gas left. + gas_left: U256, + /// Return data buffer. + data: ReturnData, + /// Apply or revert state changes on revert. + apply_state: bool + }, +} \ No newline at end of file diff --git a/ethcore/evm/src/schedule.rs b/ethcore/vm/src/schedule.rs similarity index 98% rename from ethcore/evm/src/schedule.rs rename to ethcore/vm/src/schedule.rs index e721dc803..6966c26e6 100644 --- a/ethcore/evm/src/schedule.rs +++ b/ethcore/vm/src/schedule.rs @@ -250,6 +250,12 @@ impl Schedule { } } +impl Default for Schedule { + fn default() -> Self { + Schedule::new_frontier() + } +} + #[test] #[cfg(test)] fn schedule_evm_assumptions() { @@ -260,3 +266,4 @@ fn schedule_evm_assumptions() { assert_eq!(s1.quad_coeff_div, 512); assert_eq!(s2.quad_coeff_div, 512); } + diff --git a/ethcore/vm/src/tests.rs b/ethcore/vm/src/tests.rs new file mode 100644 index 000000000..c8afedaff --- /dev/null +++ b/ethcore/vm/src/tests.rs @@ -0,0 +1,187 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use std::sync::Arc; +use std::collections::{HashMap, HashSet}; + +use util::{H256, U256, Address, Bytes}; +use { + CallType, Schedule, EnvInfo, + ReturnData, Ext, ContractCreateResult, MessageCallResult, + CreateContractAddress, Result, GasLeft, +}; + +pub struct FakeLogEntry { + pub topics: Vec, + pub data: Bytes +} + +#[derive(PartialEq, Eq, Hash, Debug)] +pub enum FakeCallType { + Call, Create +} + +#[derive(PartialEq, Eq, Hash, Debug)] +pub struct FakeCall { + pub call_type: FakeCallType, + pub gas: U256, + pub sender_address: Option
, + pub receive_address: Option
, + pub value: Option, + pub data: Bytes, + pub code_address: Option
, +} + +/// Fake externalities test structure. +/// +/// Can't do recursive calls. +#[derive(Default)] +pub struct FakeExt { + pub store: HashMap, + pub suicides: HashSet
, + pub calls: HashSet, + pub sstore_clears: usize, + pub depth: usize, + pub blockhashes: HashMap, + pub codes: HashMap>, + pub logs: Vec, + pub info: EnvInfo, + pub schedule: Schedule, + pub balances: HashMap, +} + +// similar to the normal `finalize` function, but ignoring NeedsReturn. +pub fn test_finalize(res: Result) -> Result { + match res { + Ok(GasLeft::Known(gas)) => Ok(gas), + Ok(GasLeft::NeedsReturn{..}) => unimplemented!(), // since ret is unimplemented. + Err(e) => Err(e), + } +} + +impl FakeExt { + pub fn new() -> Self { + FakeExt::default() + } +} + +impl Ext for FakeExt { + fn storage_at(&self, key: &H256) -> Result { + Ok(self.store.get(key).unwrap_or(&H256::new()).clone()) + } + + fn set_storage(&mut self, key: H256, value: H256) -> Result<()> { + self.store.insert(key, value); + Ok(()) + } + + fn exists(&self, address: &Address) -> Result { + Ok(self.balances.contains_key(address)) + } + + fn exists_and_not_null(&self, address: &Address) -> Result { + Ok(self.balances.get(address).map_or(false, |b| !b.is_zero())) + } + + fn origin_balance(&self) -> Result { + unimplemented!() + } + + fn balance(&self, address: &Address) -> Result { + Ok(self.balances[address]) + } + + fn blockhash(&mut self, number: &U256) -> H256 { + self.blockhashes.get(number).unwrap_or(&H256::new()).clone() + } + + fn create(&mut self, gas: &U256, value: &U256, code: &[u8], _address: CreateContractAddress) -> ContractCreateResult { + self.calls.insert(FakeCall { + call_type: FakeCallType::Create, + gas: *gas, + sender_address: None, + receive_address: None, + value: Some(*value), + data: code.to_vec(), + code_address: None + }); + ContractCreateResult::Failed + } + + fn call(&mut self, + gas: &U256, + sender_address: &Address, + receive_address: &Address, + value: Option, + data: &[u8], + code_address: &Address, + _output: &mut [u8], + _call_type: CallType + ) -> MessageCallResult { + + self.calls.insert(FakeCall { + call_type: FakeCallType::Call, + gas: *gas, + sender_address: Some(sender_address.clone()), + receive_address: Some(receive_address.clone()), + value: value, + data: data.to_vec(), + code_address: Some(code_address.clone()) + }); + MessageCallResult::Success(*gas, ReturnData::empty()) + } + + fn extcode(&self, address: &Address) -> Result> { + Ok(self.codes.get(address).unwrap_or(&Arc::new(Bytes::new())).clone()) + } + + fn extcodesize(&self, address: &Address) -> Result { + Ok(self.codes.get(address).map_or(0, |c| c.len())) + } + + fn log(&mut self, topics: Vec, data: &[u8]) -> Result<()> { + self.logs.push(FakeLogEntry { + topics: topics, + data: data.to_vec() + }); + Ok(()) + } + + fn ret(self, _gas: &U256, _data: &ReturnData) -> Result { + unimplemented!(); + } + + fn suicide(&mut self, refund_address: &Address) -> Result<()> { + self.suicides.insert(refund_address.clone()); + Ok(()) + } + + fn schedule(&self) -> &Schedule { + &self.schedule + } + + fn env_info(&self) -> &EnvInfo { + &self.info + } + + fn depth(&self) -> usize { + self.depth + } + + fn inc_sstore_clears(&mut self) { + self.sstore_clears += 1; + } +} diff --git a/ethcore/wasm/Cargo.toml b/ethcore/wasm/Cargo.toml new file mode 100644 index 000000000..bbeeeffc5 --- /dev/null +++ b/ethcore/wasm/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "wasm" +version = "0.1.0" +authors = ["Parity Technologies "] + +[dependencies] +byteorder = "1.0" +ethcore-util = { path = "../../util" } +log = "0.3" +parity-wasm = "0.12" +wasm-utils = { git = "https://github.com/paritytech/wasm-utils" } +vm = { path = "../vm" } +ethcore-logger = { path = "../../logger" } \ No newline at end of file diff --git a/ethcore/evm/src/wasm/call_args.rs b/ethcore/wasm/src/call_args.rs similarity index 100% rename from ethcore/evm/src/wasm/call_args.rs rename to ethcore/wasm/src/call_args.rs diff --git a/ethcore/evm/src/wasm/env.rs b/ethcore/wasm/src/env.rs similarity index 75% rename from ethcore/evm/src/wasm/env.rs rename to ethcore/wasm/src/env.rs index cabd38bd9..777016a1b 100644 --- a/ethcore/evm/src/wasm/env.rs +++ b/ethcore/wasm/src/env.rs @@ -14,11 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -//! Wasm env module bindings +//! Wasm env module bindings use parity_wasm::elements::ValueType::*; -use parity_wasm::interpreter::UserFunctionDescriptor; +use parity_wasm::interpreter::{self, UserFunctionDescriptor}; use parity_wasm::interpreter::UserFunctionDescriptor::*; +use super::runtime::Runtime; pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[ Static( @@ -61,59 +62,49 @@ pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[ &[I32; 4], Some(I32), ), + Static( + "_ccall", + &[I32; 6], + Some(I32), + ), + Static( + "_dcall", + &[I32; 5], + Some(I32), + ), + Static( + "_scall", + &[I32; 5], + Some(I32), + ), Static( "abort", &[I32], None, ), - Static( - "_abort", - &[], - None, - ), - Static( - "invoke_vii", - &[I32; 3], - None, - ), - Static( - "invoke_vi", - &[I32; 2], - None, - ), - Static( - "invoke_v", - &[I32], - None, - ), - Static( - "invoke_iii", - &[I32; 3], - Some(I32), - ), - Static( - "___resumeException", - &[I32], - None, - ), - Static( - "_rust_begin_unwind", - &[I32; 4], - None, - ), - Static( - "___cxa_find_matching_catch_2", - &[], - Some(I32), - ), - Static( - "___gxx_personality_v0", - &[I32; 6], - Some(I32), - ), Static( "_emscripten_memcpy_big", &[I32; 3], Some(I32), - ) + ), + + // TODO: Get rid of it also somehow? + Static( + "_llvm_trap", + &[I32; 0], + None + ), + + Static( + "_llvm_bswap_i64", + &[I32; 2], + Some(I32) + ), ]; + +pub fn native_bindings<'a>(runtime: &'a mut Runtime) -> interpreter::UserFunctions<'a> { + interpreter::UserFunctions { + executor: runtime, + functions: ::std::borrow::Cow::from(SIGNATURES), + } +} \ No newline at end of file diff --git a/ethcore/evm/src/wasm/mod.rs b/ethcore/wasm/src/lib.rs similarity index 75% rename from ethcore/evm/src/wasm/mod.rs rename to ethcore/wasm/src/lib.rs index a7186add5..3fec0f781 100644 --- a/ethcore/evm/src/wasm/mod.rs +++ b/ethcore/wasm/src/lib.rs @@ -16,6 +16,14 @@ //! Wasm Interpreter +extern crate vm; +extern crate ethcore_util as util; +#[macro_use] extern crate log; +extern crate ethcore_logger; +extern crate byteorder; +extern crate parity_wasm; +extern crate wasm_utils; + mod runtime; mod ptr; mod call_args; @@ -24,17 +32,13 @@ mod result; mod tests; mod env; -use std::sync::Arc; - const DEFAULT_STACK_SPACE: u32 = 5 * 1024 * 1024; use parity_wasm::{interpreter, elements}; use parity_wasm::interpreter::ModuleInstanceInterface; -use wasm_utils; -use evm::{self, GasLeft, ReturnData}; -use action_params::ActionParams; -use self::runtime::Runtime; +use vm::{GasLeft, ReturnData, ActionParams}; +use self::runtime::{Runtime, RuntimeContext}; pub use self::runtime::Error as RuntimeError; @@ -56,9 +60,9 @@ impl WasmInterpreter { } } -impl evm::Evm for WasmInterpreter { +impl vm::Vm for WasmInterpreter { - fn exec(&mut self, params: ActionParams, ext: &mut ::ext::Ext) -> evm::Result { + fn exec(&mut self, params: ActionParams, ext: &mut vm::Ext) -> vm::Result { use parity_wasm::elements::Deserialize; let code = params.code.expect("exec is only called on contract with code; qed"); @@ -74,7 +78,7 @@ impl evm::Evm for WasmInterpreter { .expect("Linear memory to exist in wasm runtime"); if params.gas > ::std::u64::MAX.into() { - return Err(evm::Error::Wasm("Wasm interpreter cannot run contracts with gas >= 2^64".to_owned())); + return Err(vm::Error::Wasm("Wasm interpreter cannot run contracts with gas >= 2^64".to_owned())); } let mut runtime = Runtime::with_params( @@ -82,6 +86,8 @@ impl evm::Evm for WasmInterpreter { env_memory, DEFAULT_STACK_SPACE, params.gas.low_u64(), + RuntimeContext::new(params.address, params.sender), + &self.program, ); let mut cursor = ::std::io::Cursor::new(&*code); @@ -90,7 +96,7 @@ impl evm::Evm for WasmInterpreter { elements::Module::deserialize( &mut cursor ).map_err(|err| { - evm::Error::Wasm(format!("Error deserializing contract code ({:?})", err)) + vm::Error::Wasm(format!("Error deserializing contract code ({:?})", err)) })? ); @@ -105,27 +111,19 @@ impl evm::Evm for WasmInterpreter { )?; { - let execution_params = interpreter::ExecutionParams::with_external( - "env".into(), - Arc::new( - interpreter::env_native_module(env_instance, native_bindings(&mut runtime)) - .map_err(|err| { - // todo: prefer explicit panic here also? - evm::Error::Wasm(format!("Error instantiating native bindings: {:?}", err)) - })? - ) - ).add_argument(interpreter::RuntimeValue::I32(d_ptr.as_raw() as i32)); + let execution_params = runtime.execution_params() + .add_argument(interpreter::RuntimeValue::I32(d_ptr.as_raw() as i32)); let module_instance = self.program.add_module("contract", contract_module, Some(&execution_params.externals)) .map_err(|err| { trace!(target: "wasm", "Error adding contract module: {:?}", err); - evm::Error::from(RuntimeError::Interpreter(err)) + vm::Error::from(RuntimeError::Interpreter(err)) })?; module_instance.execute_export("_call", execution_params) .map_err(|err| { trace!(target: "wasm", "Error executing contract: {:?}", err); - evm::Error::from(RuntimeError::Interpreter(err)) + vm::Error::from(RuntimeError::Interpreter(err)) })?; } @@ -151,9 +149,8 @@ impl evm::Evm for WasmInterpreter { } } -fn native_bindings<'a>(runtime: &'a mut Runtime) -> interpreter::UserFunctions<'a> { - interpreter::UserFunctions { - executor: runtime, - functions: ::std::borrow::Cow::from(env::SIGNATURES), +impl From for vm::Error { + fn from(err: runtime::Error) -> vm::Error { + vm::Error::Wasm(format!("WASM runtime-error: {:?}", err)) } -} +} \ No newline at end of file diff --git a/ethcore/evm/src/wasm/ptr.rs b/ethcore/wasm/src/ptr.rs similarity index 100% rename from ethcore/evm/src/wasm/ptr.rs rename to ethcore/wasm/src/ptr.rs diff --git a/ethcore/evm/src/wasm/result.rs b/ethcore/wasm/src/result.rs similarity index 100% rename from ethcore/evm/src/wasm/result.rs rename to ethcore/wasm/src/result.rs diff --git a/ethcore/evm/src/wasm/runtime.rs b/ethcore/wasm/src/runtime.rs similarity index 62% rename from ethcore/evm/src/wasm/runtime.rs rename to ethcore/wasm/src/runtime.rs index 7beb4c599..e1def857e 100644 --- a/ethcore/evm/src/wasm/runtime.rs +++ b/ethcore/wasm/src/runtime.rs @@ -20,11 +20,11 @@ use std::sync::Arc; use byteorder::{LittleEndian, ByteOrder}; -use ext; - +use vm; use parity_wasm::interpreter; use util::{Address, H256, U256}; +use vm::CallType; use super::ptr::{WasmPtr, Error as PtrError}; use super::call_args::CallArgs; @@ -57,29 +57,49 @@ impl From for Error { } } +pub struct RuntimeContext { + address: Address, + sender: Address, +} + +impl RuntimeContext { + pub fn new(address: Address, sender: Address) -> Self { + RuntimeContext { + address: address, + sender: sender, + } + } +} + /// Runtime enviroment data for wasm contract execution -pub struct Runtime<'a> { +pub struct Runtime<'a, 'b> { gas_counter: u64, gas_limit: u64, dynamic_top: u32, - ext: &'a mut ext::Ext, + ext: &'a mut vm::Ext, memory: Arc, + context: RuntimeContext, + instance: &'b interpreter::ProgramInstance, } -impl<'a> Runtime<'a> { +impl<'a, 'b> Runtime<'a, 'b> { /// New runtime for wasm contract with specified params - pub fn with_params<'b>( - ext: &'b mut ext::Ext, + pub fn with_params<'c, 'd>( + ext: &'c mut vm::Ext, memory: Arc, stack_space: u32, gas_limit: u64, - ) -> Runtime<'b> { + context: RuntimeContext, + program_instance: &'d interpreter::ProgramInstance, + ) -> Runtime<'c, 'd> { Runtime { gas_counter: 0, gas_limit: gas_limit, dynamic_top: stack_space, memory: memory, ext: ext, + context: context, + instance: program_instance, } } @@ -139,13 +159,13 @@ impl<'a> Runtime<'a> { trace!(target: "wasm", "runtime: create contract"); let mut context = context; let result_ptr = context.value_stack.pop_as::()? as u32; - trace!(target: "wasm", " result_ptr: {:?}", result_ptr); + trace!(target: "wasm", "result_ptr: {:?}", result_ptr); let code_len = context.value_stack.pop_as::()? as u32; - trace!(target: "wasm", " code_len: {:?}", code_len); + trace!(target: "wasm", " code_len: {:?}", code_len); let code_ptr = context.value_stack.pop_as::()? as u32; - trace!(target: "wasm", " code_ptr: {:?}", code_ptr); + trace!(target: "wasm", " code_ptr: {:?}", code_ptr); let endowment = self.pop_u256(&mut context)?; - trace!(target: "wasm", " val: {:?}", endowment); + trace!(target: "wasm", " val: {:?}", endowment); let code = self.memory.get(code_ptr, code_len as usize)?; @@ -153,20 +173,141 @@ impl<'a> Runtime<'a> { .map_err(|_| interpreter::Error::Trap("Gas state error".to_owned()))? .into(); - match self.ext.create(&gas_left, &endowment, &code, ext::CreateContractAddress::FromSenderAndCodeHash) { - ext::ContractCreateResult::Created(address, gas_left) => { + match self.ext.create(&gas_left, &endowment, &code, vm::CreateContractAddress::FromSenderAndCodeHash) { + vm::ContractCreateResult::Created(address, gas_left) => { self.memory.set(result_ptr, &*address)?; self.gas_counter = self.gas_limit - gas_left.low_u64(); trace!(target: "wasm", "runtime: create contract success (@{:?})", address); Ok(Some(0i32.into())) }, - ext::ContractCreateResult::Failed => { + vm::ContractCreateResult::Failed => { trace!(target: "wasm", "runtime: create contract fail"); Ok(Some((-1i32).into())) } } } + pub fn call(&mut self, context: interpreter::CallerContext) + -> Result, interpreter::Error> + { + // + // method signature: + // fn ( + // address: *const u8, + // val_ptr: *const u8, + // input_ptr: *const u8, + // input_len: u32, + // result_ptr: *mut u8, + // result_len: u32, + // ) -> i32 + + self.do_call(true, CallType::Call, context) + } + + + fn call_code(&mut self, context: interpreter::CallerContext) + -> Result, interpreter::Error> + { + // + // signature (same as static call): + // fn ( + // address: *const u8, + // input_ptr: *const u8, + // input_len: u32, + // result_ptr: *mut u8, + // result_len: u32, + // ) -> i32 + + self.do_call(false, CallType::CallCode, context) + } + + fn do_call( + &mut self, + use_val: bool, + call_type: CallType, + context: interpreter::CallerContext, + ) + -> Result, interpreter::Error> + { + + trace!(target: "wasm", "runtime: call code"); + let mut context = context; + let result_alloc_len = context.value_stack.pop_as::()? as u32; + trace!(target: "wasm", " result_len: {:?}", result_alloc_len); + + let result_ptr = context.value_stack.pop_as::()? as u32; + trace!(target: "wasm", " result_ptr: {:?}", result_ptr); + + let input_len = context.value_stack.pop_as::()? as u32; + trace!(target: "wasm", " input_len: {:?}", input_len); + + let input_ptr = context.value_stack.pop_as::()? as u32; + trace!(target: "wasm", " input_ptr: {:?}", input_ptr); + + let val = if use_val { Some(self.pop_u256(&mut context)?) } + else { None }; + trace!(target: "wasm", " val: {:?}", val); + + let address = self.pop_address(&mut context)?; + trace!(target: "wasm", " address: {:?}", address); + + if let Some(ref val) = val { + let address_balance = self.ext.balance(&self.context.address) + .map_err(|_| interpreter::Error::Trap("Gas state error".to_owned()))?; + + if &address_balance < val { + trace!(target: "wasm", "runtime: call failed due to balance check"); + return Ok(Some((-1i32).into())); + } + } + + let mut result = Vec::with_capacity(result_alloc_len as usize); + result.resize(result_alloc_len as usize, 0); + let gas = self.gas_left() + .map_err(|_| interpreter::Error::Trap("Gas state error".to_owned()))? + .into(); + // todo: optimize to use memory views once it's in + let payload = self.memory.get(input_ptr, input_len as usize)?; + + let call_result = self.ext.call( + &gas, + &self.context.sender, + &self.context.address, + val, + &payload, + &address, + &mut result[..], + call_type, + ); + + match call_result { + vm::MessageCallResult::Success(gas_left, _) => { + self.gas_counter = self.gas_limit - gas_left.low_u64(); + self.memory.set(result_ptr, &result)?; + Ok(Some(0i32.into())) + }, + vm::MessageCallResult::Failed => { + Ok(Some((-1i32).into())) + } + } + } + + pub fn static_call(&mut self, context: interpreter::CallerContext) + -> Result, interpreter::Error> + { + // signature (same as code call): + // fn ( + // address: *const u8, + // input_ptr: *const u8, + // input_len: u32, + // result_ptr: *mut u8, + // result_len: u32, + // ) -> i32 + + self.do_call(false, CallType::StaticCall, context) + } + + /// Allocate memory using the wasm stack params pub fn malloc(&mut self, context: interpreter::CallerContext) -> Result, interpreter::Error> @@ -311,9 +452,58 @@ impl<'a> Runtime<'a> { Ok(Some(0i32.into())) } + + fn bswap_32(x: u32) -> u32 { + x >> 24 | x >> 8 & 0xff00 | x << 8 & 0xff0000 | x << 24 + } + + fn bitswap_i64(&mut self, context: interpreter::CallerContext) + -> Result, interpreter::Error> + { + let x1 = context.value_stack.pop_as::()?; + let x2 = context.value_stack.pop_as::()?; + + let result = ((Runtime::bswap_32(x2 as u32) as u64) << 32 + | Runtime::bswap_32(x1 as u32) as u64) as i64; + + self.return_i64(result) + } + + fn return_i64(&mut self, val: i64) -> Result, interpreter::Error> { + let uval = val as u64; + let hi = (uval >> 32) as i32; + let lo = (uval << 32 >> 32) as i32; + + let target = self.instance.module("contract") + .ok_or(interpreter::Error::Trap("Error locating main execution entry".to_owned()))?; + target.execute_export( + "setTempRet0", + self.execution_params().add_argument( + interpreter::RuntimeValue::I32(hi).into() + ), + )?; + Ok(Some( + (lo).into() + )) + } + + pub fn execution_params(&mut self) -> interpreter::ExecutionParams { + use super::env; + + let env_instance = self.instance.module("env") + .expect("Env module always exists; qed"); + + interpreter::ExecutionParams::with_external( + "env".into(), + Arc::new( + interpreter::env_native_module(env_instance, env::native_bindings(self)) + .expect("Env module always exists; qed") + ) + ) + } } -impl<'a> interpreter::UserFunctionExecutor for Runtime<'a> { +impl<'a, 'b> interpreter::UserFunctionExecutor for Runtime<'a, 'b> { fn execute(&mut self, name: &str, context: interpreter::CallerContext) -> Result, interpreter::Error> { @@ -338,6 +528,15 @@ impl<'a> interpreter::UserFunctionExecutor for Runtime<'a> { "_create" => { self.create(context) }, + "_ccall" => { + self.call(context) + }, + "_dcall" => { + self.call_code(context) + }, + "_scall" => { + self.static_call(context) + }, "_debug" => { self.debug_log(context) }, @@ -347,8 +546,11 @@ impl<'a> interpreter::UserFunctionExecutor for Runtime<'a> { "_emscripten_memcpy_big" => { self.mem_copy(context) }, + "_llvm_bswap_i64" => { + self.bitswap_i64(context) + }, _ => { - trace!("Unknown env func: '{}'", name); + trace!(target: "wasm", "Trapped due to unhandled function: '{}'", name); self.user_trap(context) } } diff --git a/ethcore/evm/src/wasm/tests.rs b/ethcore/wasm/src/tests.rs similarity index 55% rename from ethcore/evm/src/wasm/tests.rs rename to ethcore/wasm/src/tests.rs index 8ae13daae..df01b8df6 100644 --- a/ethcore/evm/src/wasm/tests.rs +++ b/ethcore/wasm/src/tests.rs @@ -15,20 +15,20 @@ // along with Parity. If not, see . use std::sync::Arc; - -use super::super::tests::{FakeExt, FakeCall, FakeCallType}; -use super::WasmInterpreter; -use evm::{self, Evm, GasLeft}; -use action_params::{ActionParams, ActionValue}; +use byteorder::{LittleEndian, ByteOrder}; use util::{U256, H256, Address}; +use super::WasmInterpreter; +use vm::{self, Vm, GasLeft, ActionParams, ActionValue}; +use vm::tests::{FakeCall, FakeExt, FakeCallType}; + macro_rules! load_sample { ($name: expr) => { - include_bytes!(concat!("../../../res/wasm-tests/compiled/", $name)).to_vec() + include_bytes!(concat!("../../res/wasm-tests/compiled/", $name)).to_vec() } } -fn test_finalize(res: Result) -> Result { +fn test_finalize(res: Result) -> Result { match res { Ok(GasLeft::Known(gas)) => Ok(gas), Ok(GasLeft::NeedsReturn{..}) => unimplemented!(), // since ret is unimplemented. @@ -57,7 +57,7 @@ fn empty() { test_finalize(interpreter.exec(params, &mut ext)).unwrap() }; - assert_eq!(gas_left, U256::from(99_996)); + assert_eq!(gas_left, U256::from(99_992)); } // This test checks if the contract deserializes payload header properly. @@ -85,7 +85,7 @@ fn logger() { }; println!("ext.store: {:?}", ext.store); - assert_eq!(gas_left, U256::from(99581)); + assert_eq!(gas_left, U256::from(99327)); let address_val: H256 = address.into(); assert_eq!( ext.store.get(&"0100000000000000000000000000000000000000000000000000000000000000".parse().unwrap()).expect("storage key to exist"), @@ -136,7 +136,7 @@ fn identity() { } }; - assert_eq!(gas_left, U256::from(99_689)); + assert_eq!(gas_left, U256::from(99_672)); assert_eq!( Address::from_slice(&result), @@ -170,7 +170,7 @@ fn dispersion() { } }; - assert_eq!(gas_left, U256::from(99_402)); + assert_eq!(gas_left, U256::from(99_270)); assert_eq!( result, @@ -199,7 +199,7 @@ fn suicide_not() { } }; - assert_eq!(gas_left, U256::from(99_703)); + assert_eq!(gas_left, U256::from(99_578)); assert_eq!( result, @@ -233,12 +233,14 @@ fn suicide() { } }; - assert_eq!(gas_left, U256::from(99_747)); + assert_eq!(gas_left, U256::from(99_621)); assert!(ext.suicides.contains(&refund)); } #[test] fn create() { + ::ethcore_logger::init_log(); + let mut params = ActionParams::default(); params.gas = U256::from(100_000); params.code = Some(Arc::new(load_sample!("creator.wasm"))); @@ -262,7 +264,7 @@ fn create() { assert!(ext.calls.contains( &FakeCall { call_type: FakeCallType::Create, - gas: U256::from(99_778), + gas: U256::from(99_674), sender_address: None, receive_address: None, value: Some(1_000_000_000.into()), @@ -270,5 +272,179 @@ fn create() { code_address: None, } )); - assert_eq!(gas_left, U256::from(99_768)); + assert_eq!(gas_left, U256::from(99_596)); +} + + +#[test] +fn call_code() { + ::ethcore_logger::init_log(); + + let sender: Address = "01030507090b0d0f11131517191b1d1f21232527".parse().unwrap(); + let receiver: Address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse().unwrap(); + + let mut params = ActionParams::default(); + params.sender = sender.clone(); + params.address = receiver.clone(); + params.gas = U256::from(100_000); + params.code = Some(Arc::new(load_sample!("call_code.wasm"))); + params.data = Some(Vec::new()); + params.value = ActionValue::transfer(1_000_000_000); + + let mut ext = FakeExt::new(); + + let (gas_left, result) = { + let mut interpreter = wasm_interpreter(); + let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors"); + match result { + GasLeft::Known(_) => { panic!("Call test should return payload"); }, + GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()), + } + }; + + trace!(target: "wasm", "fake_calls: {:?}", &ext.calls); + assert!(ext.calls.contains( + &FakeCall { + call_type: FakeCallType::Call, + gas: U256::from(99_069), + sender_address: Some(sender), + receive_address: Some(receiver), + value: None, + data: vec![1u8, 2, 3, 5, 7, 11], + code_address: Some("0d13710000000000000000000000000000000000".parse().unwrap()), + } + )); + assert_eq!(gas_left, U256::from(94144)); + + // siphash result + let res = LittleEndian::read_u32(&result[..]); + assert_eq!(res, 4198595614); +} + +#[test] +fn call_static() { + ::ethcore_logger::init_log(); + + let sender: Address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse().unwrap(); + let receiver: Address = "01030507090b0d0f11131517191b1d1f21232527".parse().unwrap(); + + let mut params = ActionParams::default(); + params.sender = sender.clone(); + params.address = receiver.clone(); + params.gas = U256::from(100_000); + params.code = Some(Arc::new(load_sample!("call_static.wasm"))); + params.data = Some(Vec::new()); + params.value = ActionValue::transfer(1_000_000_000); + + let mut ext = FakeExt::new(); + + let (gas_left, result) = { + let mut interpreter = wasm_interpreter(); + let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors"); + match result { + GasLeft::Known(_) => { panic!("Static call test should return payload"); }, + GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()), + } + }; + + trace!(target: "wasm", "fake_calls: {:?}", &ext.calls); + assert!(ext.calls.contains( + &FakeCall { + call_type: FakeCallType::Call, + gas: U256::from(99_069), + sender_address: Some(sender), + receive_address: Some(receiver), + value: None, + data: vec![1u8, 2, 3, 5, 7, 11], + code_address: Some("13077bfb00000000000000000000000000000000".parse().unwrap()), + } + )); + assert_eq!(gas_left, U256::from(94144)); + + // siphash result + let res = LittleEndian::read_u32(&result[..]); + assert_eq!(res, 317632590); +} + +// Realloc test +#[test] +fn realloc() { + let code = load_sample!("realloc.wasm"); + + let mut params = ActionParams::default(); + params.gas = U256::from(100_000); + params.code = Some(Arc::new(code)); + params.data = Some(vec![0u8]); + let mut ext = FakeExt::new(); + + let (gas_left, result) = { + let mut interpreter = wasm_interpreter(); + let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors"); + match result { + GasLeft::Known(_) => { panic!("Realloc should return payload"); }, + GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()), + } + }; + assert_eq!(gas_left, U256::from(99432)); + assert_eq!(result, vec![0u8; 2]); +} + +// Tests that contract's ability to read from a storage +// Test prepopulates address into storage, than executes a contract which read that address from storage and write this address into result +#[test] +fn storage_read() { + let code = load_sample!("storage_read.wasm"); + let address: Address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse().unwrap(); + + let mut params = ActionParams::default(); + params.gas = U256::from(100_000); + params.code = Some(Arc::new(code)); + let mut ext = FakeExt::new(); + ext.store.insert("0100000000000000000000000000000000000000000000000000000000000000".into(), address.into()); + + let (gas_left, result) = { + let mut interpreter = wasm_interpreter(); + let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors"); + match result { + GasLeft::Known(_) => { panic!("storage_read should return payload"); }, + GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()), + } + }; + + assert_eq!(gas_left, U256::from(99682)); + assert_eq!(Address::from(&result[12..32]), address); +} + + +// Tests that contract's ability to read from a storage +// Test prepopulates address into storage, than executes a contract which read that address from storage and write this address into result +#[test] +fn math_add() { + ::ethcore_logger::init_log(); + let code = load_sample!("math.wasm"); + + let mut params = ActionParams::default(); + params.gas = U256::from(100_000); + params.code = Some(Arc::new(code)); + + let mut args = [0u8; 64]; + let arg_a = U256::from_dec_str("999999999999999999999999999999").unwrap(); + let arg_b = U256::from_dec_str("888888888888888888888888888888").unwrap(); + arg_a.to_big_endian(&mut args[0..32]); + arg_b.to_big_endian(&mut args[32..64]); + params.data = Some(args.to_vec()); + + let (gas_left, result) = { + let mut interpreter = wasm_interpreter(); + let result = interpreter.exec(params, &mut FakeExt::new()).expect("Interpreter to execute without any errors"); + match result { + GasLeft::Known(_) => { panic!("storage_read should return payload"); }, + GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()), + } + }; + + let sum: U256 = (&result[..]).into(); + + assert_eq!(gas_left, U256::from(96284)); + assert_eq!(sum, U256::from_dec_str("1888888888888888888888888888887").unwrap()); } diff --git a/ethcrypto/Cargo.toml b/ethcrypto/Cargo.toml index 8e5131974..a84032f26 100644 --- a/ethcrypto/Cargo.toml +++ b/ethcrypto/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] [dependencies] rust-crypto = "0.2.36" -tiny-keccak = "1.2" +tiny-keccak = "1.3" eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" } ethkey = { path = "../ethkey" } ethcore-bigint = { path = "../util/bigint" } diff --git a/ethkey/Cargo.toml b/ethkey/Cargo.toml index 342410adc..519accadf 100644 --- a/ethkey/Cargo.toml +++ b/ethkey/Cargo.toml @@ -6,7 +6,7 @@ authors = ["Parity Technologies "] [dependencies] rand = "0.3.14" lazy_static = "0.2" -tiny-keccak = "1.2" +tiny-keccak = "1.3" eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" } rustc-hex = "1.0" ethcore-bigint = { path = "../util/bigint" } diff --git a/ethkey/cli/src/main.rs b/ethkey/cli/src/main.rs index 7ad07e295..e60b4583a 100644 --- a/ethkey/cli/src/main.rs +++ b/ethkey/cli/src/main.rs @@ -25,7 +25,7 @@ extern crate panic_hook; use std::{env, fmt, process}; use std::num::ParseIntError; use docopt::Docopt; -use rustc_hex::{FromHex, FromHexError}; +use rustc_hex::{ToHex, FromHex, FromHexError}; use ethkey::{KeyPair, Random, Brain, Prefix, Error as EthkeyError, Generator, sign, verify_public, verify_address}; use std::io; @@ -170,7 +170,7 @@ fn main() { fn display(keypair: KeyPair, mode: DisplayMode) -> String { match mode { DisplayMode::KeyPair => format!("{}", keypair), - DisplayMode::Secret => format!("{:?}", keypair.secret()), + DisplayMode::Secret => format!("{}", keypair.secret().to_hex()), DisplayMode::Public => format!("{:?}", keypair.public()), DisplayMode::Address => format!("{:?}", keypair.address()), } @@ -248,9 +248,9 @@ address: 26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5".to_owned(); .collect::>(); let expected = -"secret: 17d08f5fe8c77af811caa0c9a187e668ce3b74a99acc3f6d976f075fa8e0be55 -public: 689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6e09f3ff04ca2b2a5cd22f62941db103c0356df1a8ed20ce322cab2483db67685afd124 -address: 26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5".to_owned(); +"secret: aa22b54c0cb43ee30a014afe5ef3664b1cde299feabca46cd3167a85a57c39f2 +public: c4c5398da6843632c123f543d714d2d2277716c11ff612b2a2f23c6bda4d6f0327c31cd58c55a9572c3cc141dade0c32747a13b7ef34c241b26c84adbb28fcf4 +address: 006e27b6a72e1f34c626762f3c4761547aff1421".to_owned(); assert_eq!(execute(command).unwrap(), expected); } @@ -261,7 +261,7 @@ address: 26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5".to_owned(); .map(Into::into) .collect::>(); - let expected = "17d08f5fe8c77af811caa0c9a187e668ce3b74a99acc3f6d976f075fa8e0be55".to_owned(); + let expected = "aa22b54c0cb43ee30a014afe5ef3664b1cde299feabca46cd3167a85a57c39f2".to_owned(); assert_eq!(execute(command).unwrap(), expected); } @@ -272,7 +272,7 @@ address: 26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5".to_owned(); .map(Into::into) .collect::>(); - let expected = "689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6e09f3ff04ca2b2a5cd22f62941db103c0356df1a8ed20ce322cab2483db67685afd124".to_owned(); + let expected = "c4c5398da6843632c123f543d714d2d2277716c11ff612b2a2f23c6bda4d6f0327c31cd58c55a9572c3cc141dade0c32747a13b7ef34c241b26c84adbb28fcf4".to_owned(); assert_eq!(execute(command).unwrap(), expected); } @@ -283,7 +283,7 @@ address: 26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5".to_owned(); .map(Into::into) .collect::>(); - let expected = "26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5".to_owned(); + let expected = "006e27b6a72e1f34c626762f3c4761547aff1421".to_owned(); assert_eq!(execute(command).unwrap(), expected); } diff --git a/ethkey/src/secret.rs b/ethkey/src/secret.rs index 982962684..433d8c68e 100644 --- a/ethkey/src/secret.rs +++ b/ethkey/src/secret.rs @@ -17,6 +17,7 @@ use std::fmt; use std::ops::Deref; use std::str::FromStr; +use rustc_hex::ToHex; use secp256k1::key; use bigint::hash::H256; use {Error, SECP256K1}; @@ -26,6 +27,12 @@ pub struct Secret { inner: H256, } +impl ToHex for Secret { + fn to_hex(&self) -> String { + self.inner.to_hex() + } +} + impl fmt::Debug for Secret { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "Secret: 0x{:x}{:x}..{:x}{:x}", self.inner[0], self.inner[1], self.inner[30], self.inner[31]) diff --git a/ethstore/Cargo.toml b/ethstore/Cargo.toml index 117332022..200dec366 100755 --- a/ethstore/Cargo.toml +++ b/ethstore/Cargo.toml @@ -13,7 +13,7 @@ serde_json = "1.0" serde_derive = "1.0" rustc-hex = "1.0" rust-crypto = "0.2.36" -tiny-keccak = "1.0" +tiny-keccak = "1.3" time = "0.1.34" itertools = "0.5" parking_lot = "0.4" diff --git a/ethstore/src/account/safe_account.rs b/ethstore/src/account/safe_account.rs index e0512fe8d..478b796e6 100755 --- a/ethstore/src/account/safe_account.rs +++ b/ethstore/src/account/safe_account.rs @@ -14,7 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use ethkey::{KeyPair, sign, Address, Signature, Message, Public}; +use ethkey::{KeyPair, sign, Address, Signature, Message, Public, Secret}; +use crypto::ecdh::agree; use {json, Error, crypto}; use account::Version; use super::crypto::Crypto; @@ -135,6 +136,12 @@ impl SafeAccount { crypto::ecies::decrypt(&secret, shared_mac, message).map_err(From::from) } + /// Agree on shared key. + pub fn agree(&self, password: &str, other: &Public) -> Result { + let secret = self.crypto.secret(password)?; + agree(&secret, other).map_err(From::from) + } + /// Derive public key. pub fn public(&self, password: &str) -> Result { let secret = self.crypto.secret(password)?; diff --git a/ethstore/src/ethstore.rs b/ethstore/src/ethstore.rs index 246671990..f3bb24071 100755 --- a/ethstore/src/ethstore.rs +++ b/ethstore/src/ethstore.rs @@ -97,6 +97,10 @@ impl SimpleSecretStore for EthStore { self.store.sign_derived(account_ref, password, derivation, message) } + fn agree(&self, account: &StoreAccountRef, password: &str, other: &Public) -> Result { + self.store.agree(account, password, other) + } + fn decrypt(&self, account: &StoreAccountRef, password: &str, shared_mac: &[u8], message: &[u8]) -> Result, Error> { let account = self.get(account)?; account.decrypt(password, shared_mac, message) @@ -495,18 +499,26 @@ impl SimpleSecretStore for EthMultiStore { fn sign(&self, account: &StoreAccountRef, password: &str, message: &Message) -> Result { let accounts = self.get_matching(account, password)?; - for account in accounts { - return account.sign(password, message); + match accounts.first() { + Some(ref account) => account.sign(password, message), + None => Err(Error::InvalidPassword), } - Err(Error::InvalidPassword) } fn decrypt(&self, account: &StoreAccountRef, password: &str, shared_mac: &[u8], message: &[u8]) -> Result, Error> { let accounts = self.get_matching(account, password)?; - for account in accounts { - return account.decrypt(password, shared_mac, message); + match accounts.first() { + Some(ref account) => account.decrypt(password, shared_mac, message), + None => Err(Error::InvalidPassword), + } + } + + fn agree(&self, account: &StoreAccountRef, password: &str, other: &Public) -> Result { + let accounts = self.get_matching(account, password)?; + match accounts.first() { + Some(ref account) => account.agree(password, other), + None => Err(Error::InvalidPassword), } - Err(Error::InvalidPassword) } fn create_vault(&self, name: &str, password: &str) -> Result<(), Error> { diff --git a/ethstore/src/secret_store.rs b/ethstore/src/secret_store.rs index 2deae023e..e364245b7 100755 --- a/ethstore/src/secret_store.rs +++ b/ethstore/src/secret_store.rs @@ -60,6 +60,8 @@ pub trait SimpleSecretStore: Send + Sync { fn sign_derived(&self, account_ref: &StoreAccountRef, password: &str, derivation: Derivation, message: &Message) -> Result; /// Decrypt a messages with given account. fn decrypt(&self, account: &StoreAccountRef, password: &str, shared_mac: &[u8], message: &[u8]) -> Result, Error>; + /// Agree on shared key. + fn agree(&self, account: &StoreAccountRef, password: &str, other: &Public) -> Result; /// Returns all accounts in this secret store. fn accounts(&self) -> Result, Error>; diff --git a/evmbin/Cargo.toml b/evmbin/Cargo.toml index 5e9c50f8f..698646a3c 100644 --- a/evmbin/Cargo.toml +++ b/evmbin/Cargo.toml @@ -16,6 +16,7 @@ serde_derive = "1.0" ethcore = { path = "../ethcore" } ethcore-util = { path = "../util" } evm = { path = "../ethcore/evm" } +vm = { path = "../ethcore/vm" } panic_hook = { path = "../panic_hook" } [features] diff --git a/evmbin/benches/mod.rs b/evmbin/benches/mod.rs index d7d67a551..f4deda88e 100644 --- a/evmbin/benches/mod.rs +++ b/evmbin/benches/mod.rs @@ -31,7 +31,7 @@ extern crate rustc_hex; use self::test::{Bencher, black_box}; use evm::run_vm; -use ethcore::evm::action_params::ActionParams; +use ethcore::vm::ActionParams; use ethcore_util::U256; use rustc_hex::FromHex; diff --git a/evmbin/src/display/json.rs b/evmbin/src/display/json.rs index f12657579..e259eec7a 100644 --- a/evmbin/src/display/json.rs +++ b/evmbin/src/display/json.rs @@ -21,7 +21,7 @@ use std::collections::HashMap; use util::{U256, H256, ToPretty}; use display; -use vm; +use info as vm; /// JSON formatting informant. #[derive(Default)] @@ -116,6 +116,9 @@ impl trace::VMTracer for Informant { self.stack.extend_from_slice(stack_push); if let Some((pos, data)) = mem_diff { + if self.memory.len() < (pos + data.len()) { + self.memory.resize(pos + data.len(), 0); + } self.memory[pos..pos + data.len()].copy_from_slice(data); } diff --git a/evmbin/src/display/simple.rs b/evmbin/src/display/simple.rs index 9f8f7ee14..b03f97c8d 100644 --- a/evmbin/src/display/simple.rs +++ b/evmbin/src/display/simple.rs @@ -20,7 +20,7 @@ use ethcore::trace; use util::ToPretty; use display; -use vm; +use info as vm; /// Simple formatting informant. #[derive(Default)] diff --git a/evmbin/src/vm.rs b/evmbin/src/info.rs similarity index 98% rename from evmbin/src/vm.rs rename to evmbin/src/info.rs index c4530bb9e..617ebc7b9 100644 --- a/evmbin/src/vm.rs +++ b/evmbin/src/info.rs @@ -20,7 +20,7 @@ use std::time::{Instant, Duration}; use util::U256; use ethcore::{trace, spec}; use ethcore::client::{EvmTestClient, EvmTestError}; -use evm::action_params::ActionParams; +use vm::ActionParams; /// VM execution informant pub trait Informant: trace::VMTracer { diff --git a/evmbin/src/main.rs b/evmbin/src/main.rs index 7e89c7c7f..bad0ef1f0 100644 --- a/evmbin/src/main.rs +++ b/evmbin/src/main.rs @@ -25,6 +25,7 @@ extern crate serde; extern crate serde_derive; extern crate docopt; extern crate ethcore_util as util; +extern crate vm; extern crate evm; extern crate panic_hook; @@ -34,27 +35,29 @@ use docopt::Docopt; use rustc_hex::FromHex; use util::{U256, Bytes, Address}; use ethcore::spec; -use evm::action_params::ActionParams; +use vm::{ActionParams, CallType}; -mod vm; +mod info; mod display; -use vm::Informant; +use info::Informant; const USAGE: &'static str = r#" EVM implementation for Parity. Copyright 2016, 2017 Parity Technologies (UK) Ltd Usage: - evmbin stats [options] - evmbin [options] - evmbin [-h | --help] + parity-evm stats [options] + parity-evm [options] + parity-evm [-h | --help] Transaction options: --code CODE Contract code as hex (without 0x). + --to ADDRESS Recipient address (without 0x). --from ADDRESS Sender address (without 0x). --input DATA Input data as hex (without 0x). --gas GAS Supplied gas as hex (without 0x). + --gas-price WEI Supplied gas price as hex (without 0x). General options: --json Display verbose results in JSON. @@ -77,20 +80,30 @@ fn main() { fn run(args: Args, mut informant: T) { let from = arg(args.from(), "--from"); + let to = arg(args.to(), "--to"); let code = arg(args.code(), "--code"); let spec = arg(args.spec(), "--chain"); let gas = arg(args.gas(), "--gas"); + let gas_price = arg(args.gas(), "--gas-price"); let data = arg(args.data(), "--input"); + if code.is_none() && to == Address::default() { + die("Either --code or --to is required."); + } + let mut params = ActionParams::default(); + params.call_type = if code.is_none() { CallType::Call } else { CallType::None }; + params.code_address = to; + params.address = to; params.sender = from; params.origin = from; params.gas = gas; - params.code = Some(Arc::new(code)); + params.gas_price = gas_price; + params.code = code.map(Arc::new); params.data = data; informant.set_gas(gas); - let result = vm::run(&mut informant, spec, params); + let result = info::run(&mut informant, spec, params); informant.finish(result); } @@ -98,10 +111,12 @@ fn run(args: Args, mut informant: T) { struct Args { cmd_stats: bool, flag_from: Option, + flag_to: Option, flag_code: Option, flag_gas: Option, + flag_gas_price: Option, flag_input: Option, - flag_spec: Option, + flag_chain: Option, flag_json: bool, } @@ -113,6 +128,13 @@ impl Args { } } + pub fn gas_price(&self) -> Result { + match self.flag_gas_price { + Some(ref gas_price) => gas_price.parse().map_err(to_string), + None => Ok(U256::zero()), + } + } + pub fn from(&self) -> Result { match self.flag_from { Some(ref from) => from.parse().map_err(to_string), @@ -120,10 +142,17 @@ impl Args { } } - pub fn code(&self) -> Result { + pub fn to(&self) -> Result { + match self.flag_to { + Some(ref to) => to.parse().map_err(to_string), + None => Ok(Address::default()), + } + } + + pub fn code(&self) -> Result, String> { match self.flag_code { - Some(ref code) => code.from_hex().map_err(to_string), - None => Err("Code is required!".into()), + Some(ref code) => code.from_hex().map(Some).map_err(to_string), + None => Ok(None), } } @@ -135,7 +164,7 @@ impl Args { } pub fn spec(&self) -> Result { - Ok(match self.flag_spec { + Ok(match self.flag_chain { Some(ref filename) => { let file = fs::File::open(filename).map_err(|e| format!("{}", e))?; spec::Spec::load(::std::env::temp_dir(), file)? @@ -159,3 +188,37 @@ fn die(msg: T) -> ! { println!("{}", msg); ::std::process::exit(-1) } + +#[cfg(test)] +mod tests { + use docopt::Docopt; + use super::{Args, USAGE}; + + fn run>(args: &[T]) -> Args { + Docopt::new(USAGE).and_then(|d| d.argv(args.into_iter()).deserialize()).unwrap() + } + + #[test] + fn should_parse_all_the_options() { + let args = run(&[ + "parity-evm", + "--json", + "--gas", "1", + "--gas-price", "2", + "--from", "0000000000000000000000000000000000000003", + "--to", "0000000000000000000000000000000000000004", + "--code", "05", + "--input", "06", + "--chain", "./testfile", + ]); + + assert_eq!(args.flag_json, true); + assert_eq!(args.gas(), Ok(1.into())); + assert_eq!(args.gas_price(), Ok(2.into())); + assert_eq!(args.from(), Ok(3.into())); + assert_eq!(args.to(), Ok(4.into())); + assert_eq!(args.code(), Ok(Some(vec![05]))); + assert_eq!(args.data(), Ok(Some(vec![06]))); + assert_eq!(args.flag_chain, Some("./testfile".to_owned())); + } +} diff --git a/evmjit/Cargo.toml b/evmjit/Cargo.toml index e4daf3dae..dbc0cd51a 100644 --- a/evmjit/Cargo.toml +++ b/evmjit/Cargo.toml @@ -7,4 +7,4 @@ authors = ["Parity Technologies "] crate-type = ["dylib"] [dependencies] -tiny-keccak = "1.2" +tiny-keccak = "1.3" diff --git a/hash-fetch/src/client.rs b/hash-fetch/src/client.rs index d52bda7d9..bd773e9b3 100644 --- a/hash-fetch/src/client.rs +++ b/hash-fetch/src/client.rs @@ -188,8 +188,9 @@ fn random_temp_path() -> PathBuf { #[cfg(test)] mod tests { + use rustc_hex::FromHex; use std::sync::{Arc, mpsc}; - use util::{Mutex, FromHex}; + use util::Mutex; use futures::future; use fetch::{self, Fetch}; use parity_reactor::Remote; diff --git a/ipc/hypervisor/src/lib.rs b/ipc/hypervisor/src/lib.rs index 1031905d4..b522122b5 100644 --- a/ipc/hypervisor/src/lib.rs +++ b/ipc/hypervisor/src/lib.rs @@ -260,7 +260,7 @@ mod tests { let client = nanoipc::fast_client::>(url).unwrap(); client.handshake().unwrap(); - client.module_ready(test_module_id); + client.module_ready(test_module_id, url.to_owned()); }); let hypervisor = Hypervisor::with_url(url).local_module(test_module_id); diff --git a/ipfs/src/lib.rs b/ipfs/src/lib.rs index 4821ef59d..104c7db19 100644 --- a/ipfs/src/lib.rs +++ b/ipfs/src/lib.rs @@ -233,7 +233,7 @@ mod tests { let _ = write_chunk(&mut transport, &mut progress, b"foobar"); - assert_eq!(b"foobar".into_vec(), transport); + assert_eq!(b"foobar".to_vec(), transport); assert_eq!(6, progress); } @@ -244,7 +244,7 @@ mod tests { let _ = write_chunk(&mut transport, &mut progress, b"foobar"); - assert_eq!(b"bar".into_vec(), transport); + assert_eq!(b"bar".to_vec(), transport); assert_eq!(6, progress); } diff --git a/js/package-lock.json b/js/package-lock.json new file mode 100644 index 000000000..4e732cbfc --- /dev/null +++ b/js/package-lock.json @@ -0,0 +1,13048 @@ +{ + "name": "parity.js", + "version": "1.8.16", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@parity/wordlist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@parity/wordlist/-/wordlist-1.0.1.tgz", + "integrity": "sha1-wn5A4as2OKCe1TtKLoHVMbXrWjE=" + }, + "abab": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.3.tgz", + "integrity": "sha1-uB3l9ydOxOdW15fNg08wNkJyTl0=", + "dev": true + }, + "abbrev": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz", + "integrity": "sha1-0FVMIlZjbi9W58LlrRg/hZQo2B8=" + }, + "accepts": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz", + "integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=", + "dev": true, + "requires": { + "mime-types": "2.1.16", + "negotiator": "0.6.1" + } + }, + "acorn": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.1.1.tgz", + "integrity": "sha512-vOk6uEMctu0vQrvuSqFdJyqj1Q0S5VTDL79qtjo+DhRr+1mmaD+tluFSCZqhvi/JUhXSzoZN2BhtstaPEeE8cw==", + "dev": true + }, + "acorn-dynamic-import": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz", + "integrity": "sha1-x1K9IQvvZ5UBtsbLf8hPj0cVjMQ=", + "dev": true, + "requires": { + "acorn": "4.0.13" + }, + "dependencies": { + "acorn": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", + "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", + "dev": true + } + } + }, + "acorn-globals": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-3.1.0.tgz", + "integrity": "sha1-/YJw9x+7SZawBPqIDuXUZXOnMb8=", + "dev": true, + "requires": { + "acorn": "4.0.13" + }, + "dependencies": { + "acorn": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", + "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", + "dev": true + } + } + }, + "acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "dev": true, + "requires": { + "acorn": "3.3.0" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "dev": true + } + } + }, + "ajv": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.2.2.tgz", + "integrity": "sha1-R8aNaehvXZUxA7AHSpQw3GPaXjk=", + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.0.0", + "json-schema-traverse": "0.3.1", + "json-stable-stringify": "1.0.1" + }, + "dependencies": { + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + } + } + }, + "ajv-keywords": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", + "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=", + "dev": true + }, + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "requires": { + "kind-of": "3.2.2", + "longest": "1.0.1", + "repeat-string": "1.6.1" + } + }, + "alphanum-sort": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", + "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", + "dev": true + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true + }, + "ansi": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.1.tgz", + "integrity": "sha1-DELU+xcWDVqa8eSEus4cZpIsGyE=" + }, + "ansi-escapes": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-2.0.0.tgz", + "integrity": "sha1-W65SvkJIeN2Xg+iRDj/Cki6DyBs=" + }, + "ansi-html": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", + "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=", + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "any-promise": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-0.1.0.tgz", + "integrity": "sha1-gwtoCqflbzNFHUsEnzvYBESY7ic=", + "dev": true + }, + "anymatch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", + "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "dev": true, + "requires": { + "micromatch": "2.3.11", + "normalize-path": "2.1.1" + } + }, + "append-transform": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-0.4.0.tgz", + "integrity": "sha1-126/jKlNJ24keja61EpLdKthGZE=", + "dev": true, + "requires": { + "default-require-extensions": "1.0.0" + } + }, + "aproba": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.1.2.tgz", + "integrity": "sha512-ZpYajIfO0j2cOFTO955KUMIKNmj6zhX8kVztMAxFsDaMwz+9Z9SV0uou2pC9HJqcfpffOsjnbrDMvkNy+9RXPw==" + }, + "archive-type": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/archive-type/-/archive-type-3.2.0.tgz", + "integrity": "sha1-nNnABpV+vpX62tW9YJiUKoE3N/Y=", + "requires": { + "file-type": "3.9.0" + } + }, + "are-we-there-yet": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", + "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", + "requires": { + "delegates": "1.0.0", + "readable-stream": "2.3.3" + } + }, + "argparse": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", + "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", + "dev": true, + "requires": { + "sprintf-js": "1.0.3" + } + }, + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "requires": { + "arr-flatten": "1.1.0" + } + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" + }, + "array-differ": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", + "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=" + }, + "array-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", + "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", + "dev": true + }, + "array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=" + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", + "dev": true + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "1.0.3" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=" + }, + "array.prototype.find": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/array.prototype.find/-/array.prototype.find-2.0.4.tgz", + "integrity": "sha1-VWpcU2LAhkgyPdrrnenRS8GGTJA=", + "dev": true, + "requires": { + "define-properties": "1.1.2", + "es-abstract": "1.7.0" + } + }, + "arraybuffer-loader": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/arraybuffer-loader/-/arraybuffer-loader-0.2.2.tgz", + "integrity": "sha1-jnKU0VGqyO1wqC53Pq0FWQ23Dik=", + "requires": { + "loader-utils": "0.2.17" + } + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" + }, + "asn1.js": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.9.1.tgz", + "integrity": "sha1-SLokC0WpKA6UdImQull9IWYX/UA=", + "dev": true, + "requires": { + "bn.js": "4.11.7", + "inherits": "2.0.3", + "minimalistic-assert": "1.0.0" + } + }, + "assert": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", + "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", + "dev": true, + "requires": { + "util": "0.10.3" + } + }, + "assert-plus": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=" + }, + "assertion-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.2.tgz", + "integrity": "sha1-E8pRXYYgbaC6xm6DTdOX2HWBCUw=", + "dev": true + }, + "ast-types": { + "version": "0.9.6", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.9.6.tgz", + "integrity": "sha1-ECyenpAF0+fjgpvwxPok7oYu6bk=", + "dev": true + }, + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, + "async-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", + "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "dev": true + }, + "async-each-series": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/async-each-series/-/async-each-series-1.1.0.tgz", + "integrity": "sha1-9C/YFV048hpbjqB8KOBj7RcAsTg=", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "attr-accept": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-1.1.0.tgz", + "integrity": "sha1-tc01In8WOTWo8d4Q7T66FpQfa+Y=" + }, + "autoprefixer": { + "version": "6.7.7", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-6.7.7.tgz", + "integrity": "sha1-Hb0cg1ZY41zj+ZhAmdsAWFx4IBQ=", + "dev": true, + "requires": { + "browserslist": "1.7.7", + "caniuse-db": "1.0.30000708", + "normalize-range": "0.1.2", + "num2fraction": "1.2.2", + "postcss": "5.2.17", + "postcss-value-parser": "3.3.0" + } + }, + "aws-sign2": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=" + }, + "aws4": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=" + }, + "babel-cli": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-cli/-/babel-cli-6.23.0.tgz", + "integrity": "sha1-Uv+UaisPZGRcNee9XuomeqCUjA8=", + "dev": true, + "requires": { + "babel-core": "6.23.1", + "babel-polyfill": "6.23.0", + "babel-register": "6.23.0", + "babel-runtime": "6.23.0", + "chokidar": "1.7.0", + "commander": "2.8.1", + "convert-source-map": "1.5.0", + "fs-readdir-recursive": "1.0.0", + "glob": "7.1.2", + "lodash": "4.17.2", + "output-file-sync": "1.1.2", + "path-is-absolute": "1.0.1", + "slash": "1.0.0", + "source-map": "0.5.6", + "v8flags": "2.1.1" + }, + "dependencies": { + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + } + } + }, + "babel-code-frame": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz", + "integrity": "sha1-AnYgvuVnqIwyVhV05/0IAdMxGOQ=", + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + } + }, + "babel-core": { + "version": "6.23.1", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.23.1.tgz", + "integrity": "sha1-wUPLYhuy9iFxDCIMXVedFbikQt8=", + "dev": true, + "requires": { + "babel-code-frame": "6.22.0", + "babel-generator": "6.25.0", + "babel-helpers": "6.24.1", + "babel-messages": "6.23.0", + "babel-register": "6.23.0", + "babel-runtime": "6.23.0", + "babel-template": "6.25.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0", + "babylon": "6.17.4", + "convert-source-map": "1.5.0", + "debug": "2.6.8", + "json5": "0.5.1", + "lodash": "4.17.2", + "minimatch": "3.0.4", + "path-is-absolute": "1.0.1", + "private": "0.1.7", + "slash": "1.0.0", + "source-map": "0.5.6" + } + }, + "babel-eslint": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-7.1.1.tgz", + "integrity": "sha1-imqITwhapwYK9pz8dzQcL5k3D7I=", + "dev": true, + "requires": { + "babel-code-frame": "6.22.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0", + "babylon": "6.17.4", + "lodash.pickby": "4.6.0" + } + }, + "babel-generator": { + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.25.0.tgz", + "integrity": "sha1-M6GvcNXyiQrrRlpKd5PB32qeqfw=", + "requires": { + "babel-messages": "6.23.0", + "babel-runtime": "6.23.0", + "babel-types": "6.25.0", + "detect-indent": "4.0.0", + "jsesc": "1.3.0", + "lodash": "4.17.2", + "source-map": "0.5.6", + "trim-right": "1.0.1" + }, + "dependencies": { + "jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=" + } + } + }, + "babel-helper-bindify-decorators": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.24.1.tgz", + "integrity": "sha1-FMGeXxQte0fxmlJDHlKxzLxAozA=", + "dev": true, + "requires": { + "babel-runtime": "6.23.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0" + } + }, + "babel-helper-builder-binary-assignment-operator-visitor": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz", + "integrity": "sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=", + "dev": true, + "requires": { + "babel-helper-explode-assignable-expression": "6.24.1", + "babel-runtime": "6.23.0", + "babel-types": "6.25.0" + } + }, + "babel-helper-builder-react-jsx": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.24.1.tgz", + "integrity": "sha1-CteRfjPI11HmRtrKTnfMGTd9LLw=", + "dev": true, + "requires": { + "babel-runtime": "6.23.0", + "babel-types": "6.25.0", + "esutils": "2.0.2" + } + }, + "babel-helper-call-delegate": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", + "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", + "requires": { + "babel-helper-hoist-variables": "6.24.1", + "babel-runtime": "6.23.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0" + } + }, + "babel-helper-define-map": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.24.1.tgz", + "integrity": "sha1-epdH8ljYlH0y1RX2qhx70CIEoIA=", + "requires": { + "babel-helper-function-name": "6.24.1", + "babel-runtime": "6.23.0", + "babel-types": "6.25.0", + "lodash": "4.17.2" + } + }, + "babel-helper-explode-assignable-expression": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz", + "integrity": "sha1-8luCz33BBDPFX3BZLVdGQArCLKo=", + "dev": true, + "requires": { + "babel-runtime": "6.23.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0" + } + }, + "babel-helper-explode-class": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz", + "integrity": "sha1-fcKjkQ3uAHBW4eMdZAztPVTqqes=", + "dev": true, + "requires": { + "babel-helper-bindify-decorators": "6.24.1", + "babel-runtime": "6.23.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0" + } + }, + "babel-helper-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", + "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", + "requires": { + "babel-helper-get-function-arity": "6.24.1", + "babel-runtime": "6.23.0", + "babel-template": "6.25.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0" + } + }, + "babel-helper-get-function-arity": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", + "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", + "requires": { + "babel-runtime": "6.23.0", + "babel-types": "6.25.0" + } + }, + "babel-helper-hoist-variables": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", + "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", + "requires": { + "babel-runtime": "6.23.0", + "babel-types": "6.25.0" + } + }, + "babel-helper-optimise-call-expression": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", + "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", + "requires": { + "babel-runtime": "6.23.0", + "babel-types": "6.25.0" + } + }, + "babel-helper-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.24.1.tgz", + "integrity": "sha1-024i+rEAjXnYhkjjIRaGgShFbOg=", + "requires": { + "babel-runtime": "6.23.0", + "babel-types": "6.25.0", + "lodash": "4.17.2" + } + }, + "babel-helper-remap-async-to-generator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz", + "integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=", + "dev": true, + "requires": { + "babel-helper-function-name": "6.24.1", + "babel-runtime": "6.23.0", + "babel-template": "6.25.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0" + } + }, + "babel-helper-replace-supers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", + "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", + "requires": { + "babel-helper-optimise-call-expression": "6.24.1", + "babel-messages": "6.23.0", + "babel-runtime": "6.23.0", + "babel-template": "6.25.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0" + } + }, + "babel-helpers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", + "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "requires": { + "babel-runtime": "6.23.0", + "babel-template": "6.25.0" + } + }, + "babel-loader": { + "version": "6.3.2", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-6.3.2.tgz", + "integrity": "sha1-GN5FZjhVeMG0+P/my8Zo9eKl7wM=", + "dev": true, + "requires": { + "find-cache-dir": "0.1.1", + "loader-utils": "0.2.17", + "mkdirp": "0.5.1", + "object-assign": "4.1.1" + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "requires": { + "babel-runtime": "6.23.0" + } + }, + "babel-plugin-check-es2015-constants": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", + "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", + "requires": { + "babel-runtime": "6.23.0" + } + }, + "babel-plugin-lodash": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/babel-plugin-lodash/-/babel-plugin-lodash-3.2.11.tgz", + "integrity": "sha1-Icj97J/hg176pzeHPjkCvdZtVwE=", + "dev": true, + "requires": { + "glob": "7.1.2", + "lodash": "4.17.2" + }, + "dependencies": { + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + } + } + }, + "babel-plugin-react-intl": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/babel-plugin-react-intl/-/babel-plugin-react-intl-2.3.1.tgz", + "integrity": "sha1-PUORLoJNoAXgjo6COdW6eEN0uwA=", + "dev": true, + "requires": { + "babel-runtime": "6.23.0", + "intl-messageformat-parser": "1.2.0", + "mkdirp": "0.5.1" + } + }, + "babel-plugin-recharts": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-recharts/-/babel-plugin-recharts-1.1.0.tgz", + "integrity": "sha1-gSzISxPrWN1AWyxjoo6m97JqtKc=", + "dev": true, + "requires": { + "babel-traverse": "6.25.0", + "babel-types": "6.25.0", + "babylon": "6.17.4" + } + }, + "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", + "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=", + "dev": true + }, + "babel-plugin-syntax-async-generators": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz", + "integrity": "sha1-a8lj67FuzLrmuStZbrfzXDQqi5o=", + "dev": true + }, + "babel-plugin-syntax-class-constructor-call": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-constructor-call/-/babel-plugin-syntax-class-constructor-call-6.18.0.tgz", + "integrity": "sha1-nLnTn+Q8hgC+yBRkVt3L1OGnZBY=", + "dev": true + }, + "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", + "integrity": "sha1-1+sjt5oxf4VDlixQW4J8fWysJ94=", + "dev": true + }, + "babel-plugin-syntax-decorators": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz", + "integrity": "sha1-MSVjtNvePMgGzuPkFszurd0RrAs=", + "dev": true + }, + "babel-plugin-syntax-do-expressions": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-do-expressions/-/babel-plugin-syntax-do-expressions-6.13.0.tgz", + "integrity": "sha1-V0d1YTmqJtOQ0JQQsDdEugfkeW0=", + "dev": true + }, + "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", + "integrity": "sha1-jWomIpyDdFqZgqRBBRVyyqF5sdo=", + "dev": true + }, + "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", + "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=", + "dev": true + }, + "babel-plugin-syntax-export-extensions": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz", + "integrity": "sha1-cKFITw+QiaToStRLrDU8lbmxJyE=", + "dev": true + }, + "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", + "integrity": "sha1-TDqyCiryaqIM0lmVw5jE63AxDI0=", + "dev": true + }, + "babel-plugin-syntax-function-bind": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-function-bind/-/babel-plugin-syntax-function-bind-6.13.0.tgz", + "integrity": "sha1-SMSV8Xe98xqYHnMvVa3AvdJgH0Y=", + "dev": true + }, + "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", + "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=", + "dev": true + }, + "babel-plugin-syntax-object-rest-spread": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", + "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=", + "dev": true + }, + "babel-plugin-syntax-trailing-function-commas": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz", + "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=", + "dev": true + }, + "babel-plugin-transform-async-generator-functions": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz", + "integrity": "sha1-8FiQAUX9PpkHpt3yjaWfIVJYpds=", + "dev": true, + "requires": { + "babel-helper-remap-async-to-generator": "6.24.1", + "babel-plugin-syntax-async-generators": "6.13.0", + "babel-runtime": "6.23.0" + } + }, + "babel-plugin-transform-async-to-generator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz", + "integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=", + "dev": true, + "requires": { + "babel-helper-remap-async-to-generator": "6.24.1", + "babel-plugin-syntax-async-functions": "6.13.0", + "babel-runtime": "6.23.0" + } + }, + "babel-plugin-transform-class-constructor-call": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-constructor-call/-/babel-plugin-transform-class-constructor-call-6.24.1.tgz", + "integrity": "sha1-gNwoVQWsBn3LjWxl4vbxGrd2Xvk=", + "dev": true, + "requires": { + "babel-plugin-syntax-class-constructor-call": "6.18.0", + "babel-runtime": "6.23.0", + "babel-template": "6.25.0" + } + }, + "babel-plugin-transform-class-properties": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.23.0.tgz", + "integrity": "sha1-GHt0fuQEOZATVjyZPbA480dUrDs=", + "dev": true, + "requires": { + "babel-helper-function-name": "6.24.1", + "babel-plugin-syntax-class-properties": "6.13.0", + "babel-runtime": "6.23.0", + "babel-template": "6.25.0" + } + }, + "babel-plugin-transform-decorators": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.24.1.tgz", + "integrity": "sha1-eIAT2PjGtSIr33s0Q5Df13Vp4k0=", + "dev": true, + "requires": { + "babel-helper-explode-class": "6.24.1", + "babel-plugin-syntax-decorators": "6.13.0", + "babel-runtime": "6.23.0", + "babel-template": "6.25.0", + "babel-types": "6.25.0" + } + }, + "babel-plugin-transform-decorators-legacy": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-decorators-legacy/-/babel-plugin-transform-decorators-legacy-1.3.4.tgz", + "integrity": "sha1-dBtY9sW86eYCfgiC2cmU8E82aSU=", + "dev": true, + "requires": { + "babel-plugin-syntax-decorators": "6.13.0", + "babel-runtime": "6.23.0", + "babel-template": "6.25.0" + } + }, + "babel-plugin-transform-do-expressions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-do-expressions/-/babel-plugin-transform-do-expressions-6.22.0.tgz", + "integrity": "sha1-KMyvkoEtlJws0SgfaQyP3EaK6bs=", + "dev": true, + "requires": { + "babel-plugin-syntax-do-expressions": "6.13.0", + "babel-runtime": "6.23.0" + } + }, + "babel-plugin-transform-es2015-arrow-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", + "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", + "requires": { + "babel-runtime": "6.23.0" + } + }, + "babel-plugin-transform-es2015-block-scoped-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", + "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", + "requires": { + "babel-runtime": "6.23.0" + } + }, + "babel-plugin-transform-es2015-block-scoping": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.24.1.tgz", + "integrity": "sha1-dsKV3DpHQbFmWt/TFnIV3P8ypXY=", + "requires": { + "babel-runtime": "6.23.0", + "babel-template": "6.25.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0", + "lodash": "4.17.2" + } + }, + "babel-plugin-transform-es2015-classes": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", + "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", + "requires": { + "babel-helper-define-map": "6.24.1", + "babel-helper-function-name": "6.24.1", + "babel-helper-optimise-call-expression": "6.24.1", + "babel-helper-replace-supers": "6.24.1", + "babel-messages": "6.23.0", + "babel-runtime": "6.23.0", + "babel-template": "6.25.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0" + } + }, + "babel-plugin-transform-es2015-computed-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", + "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", + "requires": { + "babel-runtime": "6.23.0", + "babel-template": "6.25.0" + } + }, + "babel-plugin-transform-es2015-destructuring": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", + "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", + "requires": { + "babel-runtime": "6.23.0" + } + }, + "babel-plugin-transform-es2015-duplicate-keys": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", + "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", + "requires": { + "babel-runtime": "6.23.0", + "babel-types": "6.25.0" + } + }, + "babel-plugin-transform-es2015-for-of": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", + "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", + "requires": { + "babel-runtime": "6.23.0" + } + }, + "babel-plugin-transform-es2015-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", + "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", + "requires": { + "babel-helper-function-name": "6.24.1", + "babel-runtime": "6.23.0", + "babel-types": "6.25.0" + } + }, + "babel-plugin-transform-es2015-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", + "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", + "requires": { + "babel-runtime": "6.23.0" + } + }, + "babel-plugin-transform-es2015-modules-amd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", + "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", + "requires": { + "babel-plugin-transform-es2015-modules-commonjs": "6.24.1", + "babel-runtime": "6.23.0", + "babel-template": "6.25.0" + } + }, + "babel-plugin-transform-es2015-modules-commonjs": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.24.1.tgz", + "integrity": "sha1-0+MQtA72ZKNmIiAAl8bUQCmPK/4=", + "requires": { + "babel-plugin-transform-strict-mode": "6.24.1", + "babel-runtime": "6.23.0", + "babel-template": "6.25.0", + "babel-types": "6.25.0" + } + }, + "babel-plugin-transform-es2015-modules-systemjs": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", + "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", + "requires": { + "babel-helper-hoist-variables": "6.24.1", + "babel-runtime": "6.23.0", + "babel-template": "6.25.0" + } + }, + "babel-plugin-transform-es2015-modules-umd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", + "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", + "requires": { + "babel-plugin-transform-es2015-modules-amd": "6.24.1", + "babel-runtime": "6.23.0", + "babel-template": "6.25.0" + } + }, + "babel-plugin-transform-es2015-object-super": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", + "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", + "requires": { + "babel-helper-replace-supers": "6.24.1", + "babel-runtime": "6.23.0" + } + }, + "babel-plugin-transform-es2015-parameters": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", + "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", + "requires": { + "babel-helper-call-delegate": "6.24.1", + "babel-helper-get-function-arity": "6.24.1", + "babel-runtime": "6.23.0", + "babel-template": "6.25.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0" + } + }, + "babel-plugin-transform-es2015-shorthand-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", + "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", + "requires": { + "babel-runtime": "6.23.0", + "babel-types": "6.25.0" + } + }, + "babel-plugin-transform-es2015-spread": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", + "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", + "requires": { + "babel-runtime": "6.23.0" + } + }, + "babel-plugin-transform-es2015-sticky-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", + "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", + "requires": { + "babel-helper-regex": "6.24.1", + "babel-runtime": "6.23.0", + "babel-types": "6.25.0" + } + }, + "babel-plugin-transform-es2015-template-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", + "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", + "requires": { + "babel-runtime": "6.23.0" + } + }, + "babel-plugin-transform-es2015-typeof-symbol": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", + "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", + "requires": { + "babel-runtime": "6.23.0" + } + }, + "babel-plugin-transform-es2015-unicode-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", + "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", + "requires": { + "babel-helper-regex": "6.24.1", + "babel-runtime": "6.23.0", + "regexpu-core": "2.0.0" + } + }, + "babel-plugin-transform-exponentiation-operator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz", + "integrity": "sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=", + "dev": true, + "requires": { + "babel-helper-builder-binary-assignment-operator-visitor": "6.24.1", + "babel-plugin-syntax-exponentiation-operator": "6.13.0", + "babel-runtime": "6.23.0" + } + }, + "babel-plugin-transform-export-extensions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-export-extensions/-/babel-plugin-transform-export-extensions-6.22.0.tgz", + "integrity": "sha1-U3OLR+deghhYnuqUbLvTkQm75lM=", + "dev": true, + "requires": { + "babel-plugin-syntax-export-extensions": "6.13.0", + "babel-runtime": "6.23.0" + } + }, + "babel-plugin-transform-flow-strip-types": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz", + "integrity": "sha1-hMtnKTXUNxT9wyvOhFaNh0Qc988=", + "dev": true, + "requires": { + "babel-plugin-syntax-flow": "6.18.0", + "babel-runtime": "6.23.0" + } + }, + "babel-plugin-transform-function-bind": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-function-bind/-/babel-plugin-transform-function-bind-6.22.0.tgz", + "integrity": "sha1-xvuOlqwpajELjPjqQBRiQH3fapc=", + "dev": true, + "requires": { + "babel-plugin-syntax-function-bind": "6.13.0", + "babel-runtime": "6.23.0" + } + }, + "babel-plugin-transform-object-rest-spread": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.23.0.tgz", + "integrity": "sha1-h11ryb52HFiirj/u5dxIldjH+SE=", + "dev": true, + "requires": { + "babel-plugin-syntax-object-rest-spread": "6.13.0", + "babel-runtime": "6.23.0" + } + }, + "babel-plugin-transform-react-display-name": { + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.25.0.tgz", + "integrity": "sha1-Z+K/Hx6ck6sI25Z5LgU5K/LMKNE=", + "dev": true, + "requires": { + "babel-runtime": "6.23.0" + } + }, + "babel-plugin-transform-react-jsx": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz", + "integrity": "sha1-hAoCjn30YN/DotKfDA2R9jduZqM=", + "dev": true, + "requires": { + "babel-helper-builder-react-jsx": "6.24.1", + "babel-plugin-syntax-jsx": "6.18.0", + "babel-runtime": "6.23.0" + } + }, + "babel-plugin-transform-react-jsx-self": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.22.0.tgz", + "integrity": "sha1-322AqdomEqEh5t3XVYvL7PBuY24=", + "dev": true, + "requires": { + "babel-plugin-syntax-jsx": "6.18.0", + "babel-runtime": "6.23.0" + } + }, + "babel-plugin-transform-react-jsx-source": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.22.0.tgz", + "integrity": "sha1-ZqwSFT9c0tF7PBkmj0vwGX9E7NY=", + "dev": true, + "requires": { + "babel-plugin-syntax-jsx": "6.18.0", + "babel-runtime": "6.23.0" + } + }, + "babel-plugin-transform-react-remove-prop-types": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.3.2.tgz", + "integrity": "sha1-bajYNMbXrYqwL5VlCXkM+qAf/hk=", + "dev": true + }, + "babel-plugin-transform-regenerator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.24.1.tgz", + "integrity": "sha1-uNowWtQ8PJm0hI5P5AN7dw0jxBg=", + "requires": { + "regenerator-transform": "0.9.11" + } + }, + "babel-plugin-transform-runtime": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-runtime/-/babel-plugin-transform-runtime-6.23.0.tgz", + "integrity": "sha1-iEkNRGUC6puOfvsP4J7E2ZR5se4=", + "dev": true, + "requires": { + "babel-runtime": "6.23.0" + } + }, + "babel-plugin-transform-strict-mode": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", + "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", + "requires": { + "babel-runtime": "6.23.0", + "babel-types": "6.25.0" + } + }, + "babel-plugin-webpack-alias": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/babel-plugin-webpack-alias/-/babel-plugin-webpack-alias-2.1.2.tgz", + "integrity": "sha1-BaG6I8KFlWYPtupXNkJPxZa0okc=", + "dev": true, + "requires": { + "babel-types": "6.25.0", + "find-up": "2.1.0", + "lodash.some": "4.6.0", + "lodash.template": "4.4.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "2.0.0" + } + }, + "lodash.template": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.4.0.tgz", + "integrity": "sha1-5zoDhcg1VZF0bgILmWecaQ5o+6A=", + "dev": true, + "requires": { + "lodash._reinterpolate": "3.0.0", + "lodash.templatesettings": "4.1.0" + } + }, + "lodash.templatesettings": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz", + "integrity": "sha1-K01OlbpEDZFf8IvImeRVNmZxMxY=", + "dev": true, + "requires": { + "lodash._reinterpolate": "3.0.0" + } + } + } + }, + "babel-polyfill": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.23.0.tgz", + "integrity": "sha1-g2TKYt+Or7gwSZ9pkXdGbDsDSZ0=", + "dev": true, + "requires": { + "babel-runtime": "6.23.0", + "core-js": "2.4.1", + "regenerator-runtime": "0.10.5" + } + }, + "babel-preset-env": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.1.9.tgz", + "integrity": "sha1-SUQ9zW71K0i3GR6jOGniRZCp60o=", + "dev": true, + "requires": { + "babel-plugin-check-es2015-constants": "6.22.0", + "babel-plugin-syntax-trailing-function-commas": "6.22.0", + "babel-plugin-transform-async-to-generator": "6.24.1", + "babel-plugin-transform-es2015-arrow-functions": "6.22.0", + "babel-plugin-transform-es2015-block-scoped-functions": "6.22.0", + "babel-plugin-transform-es2015-block-scoping": "6.24.1", + "babel-plugin-transform-es2015-classes": "6.24.1", + "babel-plugin-transform-es2015-computed-properties": "6.24.1", + "babel-plugin-transform-es2015-destructuring": "6.23.0", + "babel-plugin-transform-es2015-duplicate-keys": "6.24.1", + "babel-plugin-transform-es2015-for-of": "6.23.0", + "babel-plugin-transform-es2015-function-name": "6.24.1", + "babel-plugin-transform-es2015-literals": "6.22.0", + "babel-plugin-transform-es2015-modules-amd": "6.24.1", + "babel-plugin-transform-es2015-modules-commonjs": "6.24.1", + "babel-plugin-transform-es2015-modules-systemjs": "6.24.1", + "babel-plugin-transform-es2015-modules-umd": "6.24.1", + "babel-plugin-transform-es2015-object-super": "6.24.1", + "babel-plugin-transform-es2015-parameters": "6.24.1", + "babel-plugin-transform-es2015-shorthand-properties": "6.24.1", + "babel-plugin-transform-es2015-spread": "6.22.0", + "babel-plugin-transform-es2015-sticky-regex": "6.24.1", + "babel-plugin-transform-es2015-template-literals": "6.22.0", + "babel-plugin-transform-es2015-typeof-symbol": "6.23.0", + "babel-plugin-transform-es2015-unicode-regex": "6.24.1", + "babel-plugin-transform-exponentiation-operator": "6.24.1", + "babel-plugin-transform-regenerator": "6.24.1", + "browserslist": "1.7.7", + "electron-to-chromium": "1.3.16", + "invariant": "2.2.2" + } + }, + "babel-preset-es2015": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.22.0.tgz", + "integrity": "sha1-r1qY7LNeuK92StiloF6zbcQ4aDU=", + "dev": true, + "requires": { + "babel-plugin-check-es2015-constants": "6.22.0", + "babel-plugin-transform-es2015-arrow-functions": "6.22.0", + "babel-plugin-transform-es2015-block-scoped-functions": "6.22.0", + "babel-plugin-transform-es2015-block-scoping": "6.24.1", + "babel-plugin-transform-es2015-classes": "6.24.1", + "babel-plugin-transform-es2015-computed-properties": "6.24.1", + "babel-plugin-transform-es2015-destructuring": "6.23.0", + "babel-plugin-transform-es2015-duplicate-keys": "6.24.1", + "babel-plugin-transform-es2015-for-of": "6.23.0", + "babel-plugin-transform-es2015-function-name": "6.24.1", + "babel-plugin-transform-es2015-literals": "6.22.0", + "babel-plugin-transform-es2015-modules-amd": "6.24.1", + "babel-plugin-transform-es2015-modules-commonjs": "6.24.1", + "babel-plugin-transform-es2015-modules-systemjs": "6.24.1", + "babel-plugin-transform-es2015-modules-umd": "6.24.1", + "babel-plugin-transform-es2015-object-super": "6.24.1", + "babel-plugin-transform-es2015-parameters": "6.24.1", + "babel-plugin-transform-es2015-shorthand-properties": "6.24.1", + "babel-plugin-transform-es2015-spread": "6.22.0", + "babel-plugin-transform-es2015-sticky-regex": "6.24.1", + "babel-plugin-transform-es2015-template-literals": "6.22.0", + "babel-plugin-transform-es2015-typeof-symbol": "6.23.0", + "babel-plugin-transform-es2015-unicode-regex": "6.24.1", + "babel-plugin-transform-regenerator": "6.24.1" + } + }, + "babel-preset-es2016": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-preset-es2016/-/babel-preset-es2016-6.22.0.tgz", + "integrity": "sha1-sGGqo5g9QMn7rPo3Q7XfN/M2FWw=", + "dev": true, + "requires": { + "babel-plugin-transform-exponentiation-operator": "6.24.1" + } + }, + "babel-preset-es2017": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-preset-es2017/-/babel-preset-es2017-6.22.0.tgz", + "integrity": "sha1-3i+dpaMMUNKT+1SguhXW3cVz8PI=", + "dev": true, + "requires": { + "babel-plugin-syntax-trailing-function-commas": "6.22.0", + "babel-plugin-transform-async-to-generator": "6.24.1" + } + }, + "babel-preset-flow": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz", + "integrity": "sha1-5xIYiHCFrpoktb5Baa/7WZgWxJ0=", + "dev": true, + "requires": { + "babel-plugin-transform-flow-strip-types": "6.22.0" + } + }, + "babel-preset-react": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-preset-react/-/babel-preset-react-6.23.0.tgz", + "integrity": "sha1-63zuTemKP5RQLChWUzLamBlFUZU=", + "dev": true, + "requires": { + "babel-plugin-syntax-jsx": "6.18.0", + "babel-plugin-transform-react-display-name": "6.25.0", + "babel-plugin-transform-react-jsx": "6.24.1", + "babel-plugin-transform-react-jsx-self": "6.22.0", + "babel-plugin-transform-react-jsx-source": "6.22.0", + "babel-preset-flow": "6.23.0" + } + }, + "babel-preset-stage-0": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-preset-stage-0/-/babel-preset-stage-0-6.22.0.tgz", + "integrity": "sha1-cH7rW0Fdp2nv+cQvRUf2RPkpbvk=", + "dev": true, + "requires": { + "babel-plugin-transform-do-expressions": "6.22.0", + "babel-plugin-transform-function-bind": "6.22.0", + "babel-preset-stage-1": "6.24.1" + } + }, + "babel-preset-stage-1": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-preset-stage-1/-/babel-preset-stage-1-6.24.1.tgz", + "integrity": "sha1-dpLNfc1oSZB+auSgqFWJz7niv7A=", + "dev": true, + "requires": { + "babel-plugin-transform-class-constructor-call": "6.24.1", + "babel-plugin-transform-export-extensions": "6.22.0", + "babel-preset-stage-2": "6.24.1" + } + }, + "babel-preset-stage-2": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz", + "integrity": "sha1-2eKWD7PXEYfw5k7sYrwHdnIZvcE=", + "dev": true, + "requires": { + "babel-plugin-syntax-dynamic-import": "6.18.0", + "babel-plugin-transform-class-properties": "6.24.1", + "babel-plugin-transform-decorators": "6.24.1", + "babel-preset-stage-3": "6.24.1" + }, + "dependencies": { + "babel-plugin-transform-class-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz", + "integrity": "sha1-anl2PqYdM9NvN7YRqp3vgagbRqw=", + "dev": true, + "requires": { + "babel-helper-function-name": "6.24.1", + "babel-plugin-syntax-class-properties": "6.13.0", + "babel-runtime": "6.23.0", + "babel-template": "6.25.0" + } + } + } + }, + "babel-preset-stage-3": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz", + "integrity": "sha1-g2raCp56f6N8sTj7kyb4eTSkg5U=", + "dev": true, + "requires": { + "babel-plugin-syntax-trailing-function-commas": "6.22.0", + "babel-plugin-transform-async-generator-functions": "6.24.1", + "babel-plugin-transform-async-to-generator": "6.24.1", + "babel-plugin-transform-exponentiation-operator": "6.24.1", + "babel-plugin-transform-object-rest-spread": "6.23.0" + } + }, + "babel-register": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.23.0.tgz", + "integrity": "sha1-yao9TMqUtR2jSCbEoPnggUXXT/M=", + "dev": true, + "requires": { + "babel-core": "6.23.1", + "babel-runtime": "6.23.0", + "core-js": "2.4.1", + "home-or-tmp": "2.0.0", + "lodash": "4.17.2", + "mkdirp": "0.5.1", + "source-map-support": "0.4.15" + } + }, + "babel-runtime": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz", + "integrity": "sha1-CpSJ8UTecO+zzkMArM2zKeL8VDs=", + "requires": { + "core-js": "2.4.1", + "regenerator-runtime": "0.10.5" + } + }, + "babel-template": { + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.25.0.tgz", + "integrity": "sha1-ZlJBFmt8KqTGGdceGSlpVSsQwHE=", + "requires": { + "babel-runtime": "6.23.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0", + "babylon": "6.17.4", + "lodash": "4.17.2" + } + }, + "babel-traverse": { + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.25.0.tgz", + "integrity": "sha1-IldJfi/NGbie3BPEyROB+VEklvE=", + "requires": { + "babel-code-frame": "6.22.0", + "babel-messages": "6.23.0", + "babel-runtime": "6.23.0", + "babel-types": "6.25.0", + "babylon": "6.17.4", + "debug": "2.6.8", + "globals": "9.18.0", + "invariant": "2.2.2", + "lodash": "4.17.2" + } + }, + "babel-types": { + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz", + "integrity": "sha1-cK+ySNVmDl0Y+BHZHIMDtUE0oY4=", + "requires": { + "babel-runtime": "6.23.0", + "esutils": "2.0.2", + "lodash": "4.17.2", + "to-fast-properties": "1.0.3" + } + }, + "babelify": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", + "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", + "requires": { + "babel-core": "6.25.0", + "object-assign": "4.1.1" + }, + "dependencies": { + "babel-core": { + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.25.0.tgz", + "integrity": "sha1-fdQrBGPHQunVKW3rPsZ6kyLa1yk=", + "requires": { + "babel-code-frame": "6.22.0", + "babel-generator": "6.25.0", + "babel-helpers": "6.24.1", + "babel-messages": "6.23.0", + "babel-register": "6.24.1", + "babel-runtime": "6.23.0", + "babel-template": "6.25.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0", + "babylon": "6.17.4", + "convert-source-map": "1.5.0", + "debug": "2.6.8", + "json5": "0.5.1", + "lodash": "4.17.2", + "minimatch": "3.0.4", + "path-is-absolute": "1.0.1", + "private": "0.1.7", + "slash": "1.0.0", + "source-map": "0.5.6" + } + }, + "babel-register": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.24.1.tgz", + "integrity": "sha1-fhDhOi9xBlvfrVoXh7pFvKbe118=", + "requires": { + "babel-core": "6.25.0", + "babel-runtime": "6.23.0", + "core-js": "2.4.1", + "home-or-tmp": "2.0.0", + "lodash": "4.17.2", + "mkdirp": "0.5.1", + "source-map-support": "0.4.15" + } + } + } + }, + "babylon": { + "version": "6.17.4", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.17.4.tgz", + "integrity": "sha512-kChlV+0SXkjE0vUn9OZ7pBMWRFd8uq3mZe8x1K6jhuNcAFAtEnjchFAqB+dYEXKyd+JpT6eppRR78QAr5gTsUw==" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base32.js": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/base32.js/-/base32.js-0.1.0.tgz", + "integrity": "sha1-tYLexpPC8R6JPPBk7mrFthMaIgI=" + }, + "base64-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz", + "integrity": "sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw==", + "dev": true + }, + "batch-processor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/batch-processor/-/batch-processor-1.0.0.tgz", + "integrity": "sha1-dclcMrdI4IUNEMKxaPa9vpiRrOg=" + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "beeper": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", + "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=" + }, + "big.js": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.1.3.tgz", + "integrity": "sha1-TK2iGTZS6zyp7I5VyQFWacmAaXg=" + }, + "bignumber.js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-3.0.1.tgz", + "integrity": "sha1-gHZS0Q453jfp40lyR+3HmLt0b3Y=" + }, + "bin-build": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/bin-build/-/bin-build-2.2.0.tgz", + "integrity": "sha1-EfjdYfcP/Por3KpbRvXo/t1CIcw=", + "dev": true, + "requires": { + "archive-type": "3.2.0", + "decompress": "3.0.0", + "download": "4.4.3", + "exec-series": "1.0.3", + "rimraf": "2.6.1", + "tempfile": "1.1.1", + "url-regex": "3.2.0" + }, + "dependencies": { + "tempfile": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tempfile/-/tempfile-1.1.1.tgz", + "integrity": "sha1-W8xOrsxKsscH2LwR2ZzMmiyyh/I=", + "dev": true, + "requires": { + "os-tmpdir": "1.0.2", + "uuid": "2.0.3" + } + }, + "uuid": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", + "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=", + "dev": true + } + } + }, + "bin-check": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bin-check/-/bin-check-2.0.0.tgz", + "integrity": "sha1-hvjm9CU4k99g3DFpV/WvAqywWTA=", + "dev": true, + "requires": { + "executable": "1.1.0" + } + }, + "bin-version": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/bin-version/-/bin-version-1.0.4.tgz", + "integrity": "sha1-nrSY7m/Xb3q5p8FgQ2+JV5Q1144=", + "dev": true, + "requires": { + "find-versions": "1.2.1" + } + }, + "bin-version-check": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/bin-version-check/-/bin-version-check-2.1.0.tgz", + "integrity": "sha1-5OXfKQuQaffRETJAMe/BP90RpbA=", + "dev": true, + "requires": { + "bin-version": "1.0.4", + "minimist": "1.2.0", + "semver": "4.3.6", + "semver-truncate": "1.1.2" + }, + "dependencies": { + "semver": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", + "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=", + "dev": true + } + } + }, + "bin-wrapper": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/bin-wrapper/-/bin-wrapper-3.0.2.tgz", + "integrity": "sha1-Z9MwYmLksaXy+I7iNGT2plVneus=", + "dev": true, + "requires": { + "bin-check": "2.0.0", + "bin-version-check": "2.1.0", + "download": "4.4.3", + "each-async": "1.1.1", + "lazy-req": "1.1.0", + "os-filter-obj": "1.0.3" + } + }, + "binary-extensions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.9.0.tgz", + "integrity": "sha1-ZlBsFs5vTWkopbPNajPKQelB43s=", + "dev": true + }, + "bindings": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.3.0.tgz", + "integrity": "sha512-DpLh5EzMR2kzvX1KIlVC0VkC3iZtHKTgdtZ0a3pglBZdaQFjt5S9g9xd1lE+YvXyfd6mtCeRnrUfOLYiTMlNSw==" + }, + "bip66": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/bip66/-/bip66-1.1.5.tgz", + "integrity": "sha1-AfqHSHhcpwlV1QESF9GzE5lpyiI=", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "bl": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.1.tgz", + "integrity": "sha1-ysMo977kVzDUBLaSID/LWQ4XLV4=", + "requires": { + "readable-stream": "2.3.3" + } + }, + "block-stream": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "requires": { + "inherits": "2.0.3" + } + }, + "blockies": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/blockies/-/blockies-0.0.2.tgz", + "integrity": "sha1-Iq1Y2k9rOCvHm/Q4bFggxwBH5O0=" + }, + "bluebird": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", + "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=", + "dev": true + }, + "bn.js": { + "version": "4.11.7", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.7.tgz", + "integrity": "sha512-LxFiV5mefv0ley0SzqkOPR1bC4EbpPx8LkOz5vMe/Yi15t5hzwgO/G+tc7wOtL4PZTYjwHu8JnEiSLumuSjSfA==" + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, + "boom": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "requires": { + "hoek": "2.16.3" + } + }, + "bowser": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-1.7.1.tgz", + "integrity": "sha1-pN6PGKGg3JUx6yqSoVIftqm6lqU=" + }, + "brace": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/brace/-/brace-0.9.0.tgz", + "integrity": "sha1-rQNLrmUiDrZ22UnLKAOD+o4S+nI=", + "requires": { + "w3c-blob": "0.0.1" + } + }, + "brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "requires": { + "expand-range": "1.8.2", + "preserve": "0.2.0", + "repeat-element": "1.1.2" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + }, + "browser-stdout": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", + "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", + "dev": true + }, + "browserify-aes": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.0.6.tgz", + "integrity": "sha1-Xncl297x/Vkw1OurSFZ85FHEigo=", + "requires": { + "buffer-xor": "1.0.3", + "cipher-base": "1.0.4", + "create-hash": "1.1.3", + "evp_bytestokey": "1.0.0", + "inherits": "2.0.3" + } + }, + "browserify-cipher": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.0.tgz", + "integrity": "sha1-mYgkSHS/XtTijalWZtzWasj8Njo=", + "dev": true, + "requires": { + "browserify-aes": "1.0.6", + "browserify-des": "1.0.0", + "evp_bytestokey": "1.0.0" + } + }, + "browserify-des": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.0.tgz", + "integrity": "sha1-2qJ3cXRwki7S/hhZQRihdUOXId0=", + "dev": true, + "requires": { + "cipher-base": "1.0.4", + "des.js": "1.0.0", + "inherits": "2.0.3" + } + }, + "browserify-rsa": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "dev": true, + "requires": { + "bn.js": "4.11.7", + "randombytes": "2.0.5" + } + }, + "browserify-sign": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", + "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", + "dev": true, + "requires": { + "bn.js": "4.11.7", + "browserify-rsa": "4.0.1", + "create-hash": "1.1.3", + "create-hmac": "1.1.6", + "elliptic": "6.4.0", + "inherits": "2.0.3", + "parse-asn1": "5.1.0" + } + }, + "browserify-zlib": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz", + "integrity": "sha1-uzX4pRn2AOD6a4SFJByXnQFB+y0=", + "dev": true, + "requires": { + "pako": "0.2.9" + } + }, + "browserslist": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz", + "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=", + "dev": true, + "requires": { + "caniuse-db": "1.0.30000708", + "electron-to-chromium": "1.3.16" + } + }, + "buffer": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "dev": true, + "requires": { + "base64-js": "1.2.1", + "ieee754": "1.1.8", + "isarray": "1.0.0" + } + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" + }, + "buffer-to-vinyl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-to-vinyl/-/buffer-to-vinyl-1.1.0.tgz", + "integrity": "sha1-APFfruOreh3aLN5tkSG//dB7ImI=", + "requires": { + "file-type": "3.9.0", + "readable-stream": "2.3.3", + "uuid": "2.0.3", + "vinyl": "1.2.0" + }, + "dependencies": { + "uuid": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", + "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=" + } + } + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", + "dev": true + }, + "bytes": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz", + "integrity": "sha1-fZcZb51br39pNeJZhVSe3SpsIzk=" + }, + "caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "dev": true, + "requires": { + "callsites": "0.2.0" + } + }, + "callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "dev": true + }, + "camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", + "dev": true, + "requires": { + "no-case": "2.3.1", + "upper-case": "1.1.3" + } + }, + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" + }, + "camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "requires": { + "camelcase": "2.1.1", + "map-obj": "1.0.1" + } + }, + "caniuse-api": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.6.1.tgz", + "integrity": "sha1-tTTnxzTE+B7F++isoq0kNUuWLGw=", + "dev": true, + "requires": { + "browserslist": "1.7.7", + "caniuse-db": "1.0.30000708", + "lodash.memoize": "4.1.2", + "lodash.uniq": "4.5.0" + } + }, + "caniuse-db": { + "version": "1.0.30000708", + "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000708.tgz", + "integrity": "sha1-wuc2vTt/xfbBTkxt/mK5jtFeils=", + "dev": true + }, + "capture-stack-trace": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz", + "integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0=" + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "caw": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/caw/-/caw-1.2.0.tgz", + "integrity": "sha1-/7Im/n78VHKI3GLuPpcHPCEtEDQ=", + "requires": { + "get-proxy": "1.1.0", + "is-obj": "1.0.1", + "object-assign": "3.0.0", + "tunnel-agent": "0.4.3" + }, + "dependencies": { + "object-assign": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", + "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=" + }, + "tunnel-agent": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", + "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=" + } + } + }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "requires": { + "align-text": "0.1.4", + "lazy-cache": "1.0.4" + } + }, + "chai": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz", + "integrity": "sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=", + "dev": true, + "requires": { + "assertion-error": "1.0.2", + "deep-eql": "0.1.3", + "type-detect": "1.0.0" + } + }, + "chai-as-promised": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-6.0.0.tgz", + "integrity": "sha1-GgKkM6byTa+sY7nJb6FoTbGqjaY=", + "dev": true, + "requires": { + "check-error": "1.0.2" + } + }, + "chai-enzyme": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/chai-enzyme/-/chai-enzyme-0.6.1.tgz", + "integrity": "sha1-WFyWPG6hMxRG79Eu6DkegH11hiA=", + "dev": true, + "requires": { + "html": "1.0.0", + "react-element-to-jsx-string": "5.0.7" + }, + "dependencies": { + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + }, + "react-element-to-jsx-string": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/react-element-to-jsx-string/-/react-element-to-jsx-string-5.0.7.tgz", + "integrity": "sha1-xmOkgAqccSEVwNhRnLAhWkah8PI=", + "dev": true, + "requires": { + "collapse-white-space": "1.0.3", + "is-plain-object": "2.0.4", + "lodash": "4.17.4", + "sortobject": "1.1.1", + "stringify-object": "2.4.0", + "traverse": "0.6.6" + } + }, + "stringify-object": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-2.4.0.tgz", + "integrity": "sha1-xi0RAj6yH+LZsIe+A5om3zsioJ0=", + "dev": true, + "requires": { + "is-plain-obj": "1.1.0", + "is-regexp": "1.0.0" + } + } + } + }, + "chain-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/chain-function/-/chain-function-1.0.0.tgz", + "integrity": "sha1-DUqzfn4Y6tC9xHuSB2QRjOWHM9w=" + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "change-emitter": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/change-emitter/-/change-emitter-0.1.6.tgz", + "integrity": "sha1-6LL+PX8at9aaMhma/5HqaTFAlRU=" + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, + "cheerio": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz", + "integrity": "sha1-qbqoYKP5tZWmuBsahocxIe06Jp4=", + "dev": true, + "requires": { + "css-select": "1.2.0", + "dom-serializer": "0.1.0", + "entities": "1.1.1", + "htmlparser2": "3.9.2", + "lodash.assignin": "4.2.0", + "lodash.bind": "4.2.1", + "lodash.defaults": "4.2.0", + "lodash.filter": "4.6.0", + "lodash.flatten": "4.4.0", + "lodash.foreach": "4.5.0", + "lodash.map": "4.6.0", + "lodash.merge": "4.6.0", + "lodash.pick": "4.4.0", + "lodash.reduce": "4.6.0", + "lodash.reject": "4.6.0", + "lodash.some": "4.6.0" + } + }, + "chokidar": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", + "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", + "dev": true, + "requires": { + "anymatch": "1.3.2", + "async-each": "1.0.1", + "glob-parent": "2.0.0", + "inherits": "2.0.3", + "is-binary-path": "1.0.1", + "is-glob": "2.0.1", + "path-is-absolute": "1.0.1", + "readdirp": "2.1.0" + }, + "dependencies": { + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true, + "requires": { + "is-glob": "2.0.1" + } + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "1.0.0" + } + } + } + }, + "chownr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz", + "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=" + }, + "ci-info": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.0.0.tgz", + "integrity": "sha1-3FKF8rTiUYIWg2gcOBwziPRuxTQ=" + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "requires": { + "inherits": "2.0.3", + "safe-buffer": "5.1.1" + } + }, + "circular-dependency-plugin": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/circular-dependency-plugin/-/circular-dependency-plugin-2.0.0.tgz", + "integrity": "sha1-wQeWyDOQSIqbzdQvAy1uZOmE9mA=", + "dev": true + }, + "circular-json": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", + "dev": true + }, + "clap": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/clap/-/clap-1.2.0.tgz", + "integrity": "sha1-WckP4+E3EEdG/xlGmiemNP9oyFc=", + "dev": true, + "requires": { + "chalk": "1.1.3" + } + }, + "classnames": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.5.tgz", + "integrity": "sha1-+zgB1FNGdknvNgPH1hoCvRKb3m0=" + }, + "clean-css": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.1.7.tgz", + "integrity": "sha1-ua6k+FZ5iJzz6ui0A0nsTr390DI=", + "dev": true, + "requires": { + "source-map": "0.5.6" + } + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "requires": { + "restore-cursor": "2.0.0" + } + }, + "cli-width": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.1.0.tgz", + "integrity": "sha1-sjTKIJsp72b8UY2bmNWEewDt8Ao=" + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wrap-ansi": "2.1.0" + } + }, + "clone": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz", + "integrity": "sha1-Jgt6meux7f4kdTgXX3gyQ8sZ0Uk=" + }, + "clone-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-regexp/-/clone-regexp-1.0.0.tgz", + "integrity": "sha1-6uCiQT9VwJQvgYwin+/OhF1/Oxw=", + "dev": true, + "requires": { + "is-regexp": "1.0.0", + "is-supported-regexp-flag": "1.0.0" + } + }, + "clone-stats": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", + "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=" + }, + "cmd-shim": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-2.0.2.tgz", + "integrity": "sha1-b8vamUg6j9FdfTChlspp1oii79s=", + "requires": { + "graceful-fs": "4.1.11", + "mkdirp": "0.5.1" + } + }, + "co": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/co/-/co-3.1.0.tgz", + "integrity": "sha1-TqVOpaCJOBUxheFSEMaNkJK8G3g=" + }, + "coa": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/coa/-/coa-1.0.4.tgz", + "integrity": "sha1-qe8VNmDWqGqL3sAomlxoTSF0Mv0=", + "dev": true, + "requires": { + "q": "1.5.0" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + }, + "codemirror": { + "version": "5.28.0", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.28.0.tgz", + "integrity": "sha512-E/Z6050shti9v9ivl0dUClVRM4xaH204jsJmEpNYC6KDTlQwAz+5DdhLzn0tjaL/Mp1P0J1uhZokcSP2RFSwlA==" + }, + "collapse-white-space": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.3.tgz", + "integrity": "sha1-S5BvZw5aljqHt2sOFolkM0G2Ajw=" + }, + "color": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/color/-/color-0.11.4.tgz", + "integrity": "sha1-bXtcdPtl6EHNSHkq0e1eB7kE12Q=", + "dev": true, + "requires": { + "clone": "1.0.2", + "color-convert": "1.9.0", + "color-string": "0.3.0" + } + }, + "color-convert": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.0.tgz", + "integrity": "sha1-Gsz5fdc5uYO/mU1W/sj5WFNkG3o=", + "requires": { + "color-name": "1.1.3" + } + }, + "color-diff": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/color-diff/-/color-diff-0.1.7.tgz", + "integrity": "sha1-bbeM2UgqjkWdQIIer0tQMoPcuOI=", + "dev": true + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "color-string": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-0.3.0.tgz", + "integrity": "sha1-J9RvtnAlxcL6JZk7+/V55HhBuZE=", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "colorguard": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/colorguard/-/colorguard-1.2.0.tgz", + "integrity": "sha1-8/rK9cquuk71RlPZ+yW7cxd8DYQ=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "color-diff": "0.1.7", + "log-symbols": "1.0.2", + "object-assign": "4.1.1", + "pipetteur": "2.0.3", + "plur": "2.1.2", + "postcss": "5.2.17", + "postcss-reporter": "1.4.1", + "text-table": "0.2.0", + "yargs": "1.3.3" + }, + "dependencies": { + "postcss-reporter": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-1.4.1.tgz", + "integrity": "sha1-wTbwpbFhkV83ndN2XGEHX357mvI=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "lodash": "4.17.2", + "log-symbols": "1.0.2", + "postcss": "5.2.17" + } + }, + "yargs": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-1.3.3.tgz", + "integrity": "sha1-BU3oth8i7v23IHBZ6u+da4P7kxo=", + "dev": true + } + } + }, + "colormin": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colormin/-/colormin-1.1.2.tgz", + "integrity": "sha1-6i90IKcrlogaOKrlnsEkpvcpgTM=", + "dev": true, + "requires": { + "color": "0.11.4", + "css-color-names": "0.0.4", + "has": "1.0.1" + } + }, + "colors": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", + "dev": true + }, + "combined-stream": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "requires": { + "delayed-stream": "1.0.0" + } + }, + "commander": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", + "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", + "requires": { + "graceful-readlink": "1.0.1" + } + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "commonmark": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/commonmark/-/commonmark-0.24.0.tgz", + "integrity": "sha1-uA3gGCxUY1VkOqFdsSv7KCNoJ48=", + "requires": { + "entities": "1.1.1", + "mdurl": "1.0.1", + "string.prototype.repeat": "0.2.0" + } + }, + "commonmark-react-renderer": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/commonmark-react-renderer/-/commonmark-react-renderer-4.3.3.tgz", + "integrity": "sha1-nEvKE4vIMoe655LM8TNzi+nLxvo=", + "requires": { + "in-publish": "2.0.0", + "lodash.assign": "4.2.0", + "lodash.isplainobject": "4.0.6", + "pascalcase": "0.1.1", + "xss-filters": "1.2.7" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", + "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.3.3", + "typedarray": "0.0.6" + } + }, + "console-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", + "dev": true, + "requires": { + "date-now": "0.1.4" + }, + "dependencies": { + "date-now": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", + "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", + "dev": true + } + } + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + }, + "console-stream": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/console-stream/-/console-stream-0.1.1.tgz", + "integrity": "sha1-oJX+B7IEZZVfL6/Si11yvM2UnUQ=", + "dev": true + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", + "dev": true + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=", + "dev": true + }, + "content-type": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz", + "integrity": "sha1-t9ETrueo3Se9IRM8TcJSnfFyHu0=", + "dev": true + }, + "content-type-parser": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/content-type-parser/-/content-type-parser-1.0.1.tgz", + "integrity": "sha1-w+VpiMU8ZRJ/tG1AMqOpACRv3JQ=", + "dev": true + }, + "convert-source-map": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.0.tgz", + "integrity": "sha1-ms1whRxtXf3ZPZKC5e35SgP/RrU=" + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "dev": true + }, + "copy-to-clipboard": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.0.8.tgz", + "integrity": "sha512-c3GdeY8qxCHGezVb1EFQfHYK/8NZRemgcTIzPq7PuxjHAf/raKibn2QdhHPb/y6q74PMgH6yizaDZlRmw6QyKw==", + "requires": { + "toggle-selection": "1.0.6" + } + }, + "copy-webpack-plugin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-4.0.1.tgz", + "integrity": "sha1-lyjjg7lDFgUNDHRjlY8rhcCqggA=", + "dev": true, + "requires": { + "bluebird": "2.11.0", + "fs-extra": "0.26.7", + "glob": "6.0.4", + "is-glob": "3.1.0", + "loader-utils": "0.2.17", + "lodash": "4.17.2", + "minimatch": "3.0.4", + "node-dir": "0.1.17" + }, + "dependencies": { + "glob": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", + "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "dev": true, + "requires": { + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + } + } + }, + "core-js": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz", + "integrity": "sha1-TekR5mew6ukSTjQlS1OupvxhjT4=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cosmiconfig": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-2.2.2.tgz", + "integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==", + "dev": true, + "requires": { + "is-directory": "0.3.1", + "js-yaml": "3.6.1", + "minimist": "1.2.0", + "object-assign": "4.1.1", + "os-homedir": "1.0.2", + "parse-json": "2.2.0", + "require-from-string": "1.2.1" + } + }, + "coveralls": { + "version": "2.11.16", + "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-2.11.16.tgz", + "integrity": "sha1-2pBhJlFC3e6VT2g3kSK+l76KtLE=", + "dev": true, + "requires": { + "js-yaml": "3.6.1", + "lcov-parse": "0.0.10", + "log-driver": "1.2.5", + "minimist": "1.2.0", + "request": "2.79.0" + }, + "dependencies": { + "caseless": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", + "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=", + "dev": true + }, + "commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", + "dev": true + }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", + "dev": true + }, + "har-validator": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", + "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "commander": "2.11.0", + "is-my-json-valid": "2.16.0", + "pinkie-promise": "2.0.1" + } + }, + "request": { + "version": "2.79.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.79.0.tgz", + "integrity": "sha1-Tf5b9r6LjNw3/Pk+BLZVd3InEN4=", + "dev": true, + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "caseless": "0.11.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "2.0.6", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.16", + "oauth-sign": "0.8.2", + "qs": "6.3.0", + "stringstream": "0.0.5", + "tough-cookie": "2.3.2", + "tunnel-agent": "0.4.3", + "uuid": "3.0.0" + } + }, + "tunnel-agent": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", + "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", + "dev": true + } + } + }, + "create-ecdh": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.0.tgz", + "integrity": "sha1-iIxyNZbN92EvZJgjPuvXo1MBc30=", + "dev": true, + "requires": { + "bn.js": "4.11.7", + "elliptic": "6.4.0" + } + }, + "create-error-class": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", + "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", + "requires": { + "capture-stack-trace": "1.0.0" + } + }, + "create-hash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz", + "integrity": "sha1-YGBCrIuSYnUPSDyt2rD1gZFy2P0=", + "requires": { + "cipher-base": "1.0.4", + "inherits": "2.0.3", + "ripemd160": "2.0.1", + "sha.js": "2.4.8" + } + }, + "create-hmac": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.6.tgz", + "integrity": "sha1-rLniIaThe9sHbpBlfEK5PjcmzwY=", + "requires": { + "cipher-base": "1.0.4", + "create-hash": "1.1.3", + "inherits": "2.0.3", + "ripemd160": "2.0.1", + "safe-buffer": "5.1.1", + "sha.js": "2.4.8" + } + }, + "create-thenable": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/create-thenable/-/create-thenable-1.0.2.tgz", + "integrity": "sha1-4gMXIMzJV12M+jH1wUbnYqgMBTQ=", + "dev": true, + "requires": { + "object.omit": "2.0.1", + "unique-concat": "0.2.2" + } + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "4.1.1", + "shebang-command": "1.2.0", + "which": "1.2.14" + } + }, + "cryptiles": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "requires": { + "boom": "2.10.1" + } + }, + "crypto-browserify": { + "version": "3.11.1", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.11.1.tgz", + "integrity": "sha512-Na7ZlwCOqoaW5RwUK1WpXws2kv8mNhWdTlzob0UXulk6G9BDbyiJaGTYBIX61Ozn9l1EPPJpICZb4DaOpT9NlQ==", + "dev": true, + "requires": { + "browserify-cipher": "1.0.0", + "browserify-sign": "4.0.4", + "create-ecdh": "4.0.0", + "create-hash": "1.1.3", + "create-hmac": "1.1.6", + "diffie-hellman": "5.0.2", + "inherits": "2.0.3", + "pbkdf2": "3.0.12", + "public-encrypt": "4.0.0", + "randombytes": "2.0.5" + } + }, + "crypto-js": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.8.tgz", + "integrity": "sha1-cV8HC/YBTyrpkqmLOSkli3E/CNU=" + }, + "css-color-names": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", + "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", + "dev": true + }, + "css-loader": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-0.26.1.tgz", + "integrity": "sha1-K6fyATG5NZdJaz6btQB4WknNKeo=", + "dev": true, + "requires": { + "babel-code-frame": "6.22.0", + "css-selector-tokenizer": "0.7.0", + "cssnano": "3.10.0", + "loader-utils": "0.2.17", + "lodash.camelcase": "4.3.0", + "object-assign": "4.1.1", + "postcss": "5.2.17", + "postcss-modules-extract-imports": "1.1.0", + "postcss-modules-local-by-default": "1.2.0", + "postcss-modules-scope": "1.1.0", + "postcss-modules-values": "1.3.0", + "source-list-map": "0.1.8" + } + }, + "css-rule-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/css-rule-stream/-/css-rule-stream-1.1.0.tgz", + "integrity": "sha1-N4bnGYmD2WWibjGVfgkHjLt3BaI=", + "dev": true, + "requires": { + "css-tokenize": "1.0.1", + "duplexer2": "0.0.2", + "ldjson-stream": "1.2.1", + "through2": "0.6.5" + }, + "dependencies": { + "duplexer2": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", + "dev": true, + "requires": { + "readable-stream": "1.1.14" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + } + } + }, + "css-select": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", + "dev": true, + "requires": { + "boolbase": "1.0.0", + "css-what": "2.1.0", + "domutils": "1.5.1", + "nth-check": "1.0.1" + } + }, + "css-selector-tokenizer": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz", + "integrity": "sha1-5piEdK6MlTR3v15+/s/OzNnPTIY=", + "dev": true, + "requires": { + "cssesc": "0.1.0", + "fastparse": "1.1.1", + "regexpu-core": "1.0.0" + }, + "dependencies": { + "regexpu-core": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz", + "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=", + "dev": true, + "requires": { + "regenerate": "1.3.2", + "regjsgen": "0.2.0", + "regjsparser": "0.1.5" + } + } + } + }, + "css-tokenize": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/css-tokenize/-/css-tokenize-1.0.1.tgz", + "integrity": "sha1-RiXLHtohwUOFi3+B1oA8HSb8FL4=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "1.1.14" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + } + } + }, + "css-what": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.0.tgz", + "integrity": "sha1-lGfQMsOM+u+58teVASUwYvh/ob0=", + "dev": true + }, + "cssesc": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-0.1.0.tgz", + "integrity": "sha1-yBSQPkViM3GgR3tAEJqq++6t27Q=", + "dev": true + }, + "cssnano": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-3.10.0.tgz", + "integrity": "sha1-Tzj2zqK5sX+gFJDyPx3GjqZcHDg=", + "dev": true, + "requires": { + "autoprefixer": "6.7.7", + "decamelize": "1.2.0", + "defined": "1.0.0", + "has": "1.0.1", + "object-assign": "4.1.1", + "postcss": "5.2.17", + "postcss-calc": "5.3.1", + "postcss-colormin": "2.2.2", + "postcss-convert-values": "2.6.1", + "postcss-discard-comments": "2.0.4", + "postcss-discard-duplicates": "2.1.0", + "postcss-discard-empty": "2.1.0", + "postcss-discard-overridden": "0.1.1", + "postcss-discard-unused": "2.2.3", + "postcss-filter-plugins": "2.0.2", + "postcss-merge-idents": "2.1.7", + "postcss-merge-longhand": "2.0.2", + "postcss-merge-rules": "2.1.2", + "postcss-minify-font-values": "1.0.5", + "postcss-minify-gradients": "1.0.5", + "postcss-minify-params": "1.2.2", + "postcss-minify-selectors": "2.1.1", + "postcss-normalize-charset": "1.1.1", + "postcss-normalize-url": "3.0.8", + "postcss-ordered-values": "2.2.3", + "postcss-reduce-idents": "2.4.0", + "postcss-reduce-initial": "1.0.1", + "postcss-reduce-transforms": "1.0.4", + "postcss-svgo": "2.1.6", + "postcss-unique-selectors": "2.0.2", + "postcss-value-parser": "3.3.0", + "postcss-zindex": "2.2.0" + } + }, + "csso": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/csso/-/csso-2.3.2.tgz", + "integrity": "sha1-3dUsWHAz9J6Utx/FVWnyUuj/X4U=", + "dev": true, + "requires": { + "clap": "1.2.0", + "source-map": "0.5.6" + } + }, + "cssom": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.2.tgz", + "integrity": "sha1-uANhcMefB6kP8vFuIihAJ6JDhIs=", + "dev": true + }, + "cssstyle": { + "version": "0.2.37", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.37.tgz", + "integrity": "sha1-VBCXI0yyUTyDzu06zdwn/yeYfVQ=", + "dev": true, + "requires": { + "cssom": "0.3.2" + } + }, + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "requires": { + "array-find-index": "1.0.2" + } + }, + "d": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", + "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", + "dev": true, + "requires": { + "es5-ext": "0.10.24" + } + }, + "d3-array": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.0.tgz", + "integrity": "sha1-FH0mlyDhdMQFen9CvosPPyulMQg=" + }, + "d3-collection": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.4.tgz", + "integrity": "sha1-NC39EoN8kJdPM/HMCnha6lcNzcI=" + }, + "d3-color": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.0.3.tgz", + "integrity": "sha1-vHZD/KjlOoNH4vva/6I2eWtYUJs=" + }, + "d3-format": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.2.0.tgz", + "integrity": "sha1-a0gLqohohdRlHcJIqPSsnaFtsHo=" + }, + "d3-interpolate": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.1.5.tgz", + "integrity": "sha1-aeCZ/zkhRxblY8muw+qdHqS4p58=", + "requires": { + "d3-color": "1.0.3" + } + }, + "d3-path": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.5.tgz", + "integrity": "sha1-JB6xhJvZ6egCHA0KeZ+KDo5EF2Q=" + }, + "d3-scale": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-1.0.0.tgz", + "integrity": "sha1-C0F1yjHL5l4lRCfkZi3678NzRi0=", + "requires": { + "d3-array": "1.2.0", + "d3-collection": "1.0.4", + "d3-color": "1.0.3", + "d3-format": "1.2.0", + "d3-interpolate": "1.1.5", + "d3-time": "1.0.7", + "d3-time-format": "2.0.5" + } + }, + "d3-shape": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.0.0.tgz", + "integrity": "sha1-zKMySHV55Fc1TIg4oKKDvmOEWbo=", + "requires": { + "d3-path": "1.0.5" + } + }, + "d3-time": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.0.7.tgz", + "integrity": "sha1-lMr27bt4ebuAnQ0fdXK8SEgvcnA=" + }, + "d3-time-format": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.0.5.tgz", + "integrity": "sha1-nXeAIE98kRnJFwsaVttN6aivly4=", + "requires": { + "d3-time": "1.0.7" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "date-difference": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/date-difference/-/date-difference-1.0.0.tgz", + "integrity": "sha1-0+bog8DK0tydv8vxLgYpe5cpiXQ=", + "requires": { + "get-stdin": "3.0.2", + "meow": "3.7.0" + } + }, + "date-now": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/date-now/-/date-now-1.0.1.tgz", + "integrity": "sha1-u30IZDjevkGCpIX7PfP7+5nWFTw=" + }, + "dateformat": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.0.0.tgz", + "integrity": "sha1-J0Pjq7XD/CRi5SfcpEXgTp9N7hc=" + }, + "death": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/death/-/death-1.1.0.tgz", + "integrity": "sha1-AaqcQB7dknUFFEcLgmY5DGbGcxg=" + }, + "debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.0.0.tgz", + "integrity": "sha1-CUivUT0uTOQHkW+FBqQj0/nPctg=", + "requires": { + "date-now": "1.0.1" + } + }, + "debug": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", + "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "decompress": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/decompress/-/decompress-3.0.0.tgz", + "integrity": "sha1-rx3VDQbjv8QyRh033hGzjA2ZG+0=", + "requires": { + "buffer-to-vinyl": "1.1.0", + "concat-stream": "1.6.0", + "decompress-tar": "3.1.0", + "decompress-tarbz2": "3.1.0", + "decompress-targz": "3.1.0", + "decompress-unzip": "3.4.0", + "stream-combiner2": "1.1.1", + "vinyl-assign": "1.2.1", + "vinyl-fs": "2.4.4" + } + }, + "decompress-tar": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-3.1.0.tgz", + "integrity": "sha1-IXx4n5uURQ76rcXF5TeXj8MzxGY=", + "requires": { + "is-tar": "1.0.0", + "object-assign": "2.1.1", + "strip-dirs": "1.1.1", + "tar-stream": "1.5.4", + "through2": "0.6.5", + "vinyl": "0.4.6" + }, + "dependencies": { + "clone": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", + "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=" + }, + "object-assign": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", + "integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo=" + }, + "vinyl": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", + "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", + "requires": { + "clone": "0.2.0", + "clone-stats": "0.0.1" + } + } + } + }, + "decompress-tarbz2": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-3.1.0.tgz", + "integrity": "sha1-iyOTVoE1X58YnYclag+L3ZbZZm0=", + "requires": { + "is-bzip2": "1.0.0", + "object-assign": "2.1.1", + "seek-bzip": "1.0.5", + "strip-dirs": "1.1.1", + "tar-stream": "1.5.4", + "through2": "0.6.5", + "vinyl": "0.4.6" + }, + "dependencies": { + "clone": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", + "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=" + }, + "object-assign": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", + "integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo=" + }, + "vinyl": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", + "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", + "requires": { + "clone": "0.2.0", + "clone-stats": "0.0.1" + } + } + } + }, + "decompress-targz": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-3.1.0.tgz", + "integrity": "sha1-ssE9+YFmJomRtxXWRH9kLpaW9aA=", + "requires": { + "is-gzip": "1.0.0", + "object-assign": "2.1.1", + "strip-dirs": "1.1.1", + "tar-stream": "1.5.4", + "through2": "0.6.5", + "vinyl": "0.4.6" + }, + "dependencies": { + "clone": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", + "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=" + }, + "object-assign": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", + "integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo=" + }, + "vinyl": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", + "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", + "requires": { + "clone": "0.2.0", + "clone-stats": "0.0.1" + } + } + } + }, + "decompress-unzip": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-3.4.0.tgz", + "integrity": "sha1-YUdbQVIGa74/7hL51inRX+ZHjus=", + "requires": { + "is-zip": "1.0.0", + "read-all-stream": "3.1.0", + "stat-mode": "0.2.2", + "strip-dirs": "1.1.1", + "through2": "2.0.3", + "vinyl": "1.2.0", + "yauzl": "2.8.0" + }, + "dependencies": { + "through2": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", + "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", + "requires": { + "readable-stream": "2.3.3", + "xtend": "4.0.1" + } + } + } + }, + "deep-eql": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", + "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=", + "dev": true, + "requires": { + "type-detect": "0.1.1" + }, + "dependencies": { + "type-detect": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", + "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=", + "dev": true + } + } + }, + "deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", + "dev": true + }, + "deep-extend": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz", + "integrity": "sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8=" + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "default-require-extensions": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-1.0.0.tgz", + "integrity": "sha1-836hXT4T/9m0N9M+GnW1+5eHTLg=", + "dev": true, + "requires": { + "strip-bom": "2.0.0" + } + }, + "defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "requires": { + "clone": "1.0.2" + } + }, + "define-properties": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", + "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", + "dev": true, + "requires": { + "foreach": "2.0.5", + "object-keys": "1.0.11" + } + }, + "defined": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", + "dev": true + }, + "del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "dev": true, + "requires": { + "globby": "5.0.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.0", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "rimraf": "2.6.1" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, + "depd": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", + "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=", + "dev": true + }, + "des.js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", + "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "minimalistic-assert": "1.0.0" + } + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "dev": true + }, + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "requires": { + "repeating": "2.0.1" + } + }, + "diff": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", + "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", + "dev": true + }, + "diffie-hellman": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.2.tgz", + "integrity": "sha1-tYNXOScM/ias9jIJn97SoH8gnl4=", + "dev": true, + "requires": { + "bn.js": "4.11.7", + "miller-rabin": "4.0.0", + "randombytes": "2.0.5" + } + }, + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "2.0.2", + "isarray": "1.0.0" + } + }, + "doiuse": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/doiuse/-/doiuse-2.6.0.tgz", + "integrity": "sha1-GJLRC2Gpo1at2/K2FJM+gfi7ODQ=", + "dev": true, + "requires": { + "browserslist": "1.7.7", + "caniuse-db": "1.0.30000708", + "css-rule-stream": "1.1.0", + "duplexer2": "0.0.2", + "jsonfilter": "1.1.2", + "ldjson-stream": "1.2.1", + "lodash": "4.17.2", + "multimatch": "2.1.0", + "postcss": "5.2.17", + "source-map": "0.4.4", + "through2": "0.6.5", + "yargs": "3.32.0" + }, + "dependencies": { + "duplexer2": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", + "dev": true, + "requires": { + "readable-stream": "1.1.14" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, + "requires": { + "amdefine": "1.0.1" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "window-size": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz", + "integrity": "sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY=", + "dev": true + }, + "yargs": { + "version": "3.32.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz", + "integrity": "sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU=", + "dev": true, + "requires": { + "camelcase": "2.1.1", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "os-locale": "1.4.0", + "string-width": "1.0.2", + "window-size": "0.1.4", + "y18n": "3.2.1" + } + } + } + }, + "dom-converter": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.1.4.tgz", + "integrity": "sha1-pF71cnuJDJv/5tfIduexnLDhfzs=", + "dev": true, + "requires": { + "utila": "0.3.3" + }, + "dependencies": { + "utila": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.3.3.tgz", + "integrity": "sha1-1+jn1+MJEHCSsF+NloiCTWM6QiY=", + "dev": true + } + } + }, + "dom-helpers": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.2.1.tgz", + "integrity": "sha1-MgPgf+0he9H0JLAZc1WC/Deyglo=" + }, + "dom-serializer": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", + "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", + "dev": true, + "requires": { + "domelementtype": "1.1.3", + "entities": "1.1.1" + }, + "dependencies": { + "domelementtype": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", + "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", + "dev": true + } + } + }, + "dom-walk": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz", + "integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg=", + "dev": true + }, + "domain-browser": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz", + "integrity": "sha1-hnqksJP6oF8d4IwG9NeyH9+GmLw=", + "dev": true + }, + "domelementtype": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", + "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=", + "dev": true + }, + "domhandler": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.1.tgz", + "integrity": "sha1-iS5HAAqZvlW783dP/qBWHYh5wlk=", + "dev": true, + "requires": { + "domelementtype": "1.3.0" + } + }, + "domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "dev": true, + "requires": { + "dom-serializer": "0.1.0", + "domelementtype": "1.3.0" + } + }, + "download": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/download/-/download-4.4.3.tgz", + "integrity": "sha1-qlX9rTktldS2jowr4D4MKqIbqaw=", + "requires": { + "caw": "1.2.0", + "concat-stream": "1.6.0", + "each-async": "1.1.1", + "filenamify": "1.2.1", + "got": "5.7.1", + "gulp-decompress": "1.2.0", + "gulp-rename": "1.2.2", + "is-url": "1.2.2", + "object-assign": "4.1.1", + "read-all-stream": "3.1.0", + "readable-stream": "2.3.3", + "stream-combiner2": "1.1.1", + "vinyl": "1.2.0", + "vinyl-fs": "2.4.4", + "ware": "1.3.0" + } + }, + "drbg.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/drbg.js/-/drbg.js-1.0.1.tgz", + "integrity": "sha1-Pja2xCs3BDgjzbwzLVjzHiRFSAs=", + "requires": { + "browserify-aes": "1.0.6", + "create-hash": "1.1.3", + "create-hmac": "1.1.6" + } + }, + "duplexer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", + "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", + "dev": true + }, + "duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", + "requires": { + "readable-stream": "2.3.3" + } + }, + "duplexify": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.5.0.tgz", + "integrity": "sha1-GqdzAC4VeEV+nZ1KULDMquvL1gQ=", + "requires": { + "end-of-stream": "1.0.0", + "inherits": "2.0.3", + "readable-stream": "2.3.3", + "stream-shift": "1.0.0" + }, + "dependencies": { + "end-of-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.0.0.tgz", + "integrity": "sha1-1FlucCc0qT5A6a+GQxnqvZn/Lw4=", + "requires": { + "once": "1.3.3" + } + }, + "once": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", + "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", + "requires": { + "wrappy": "1.0.2" + } + } + } + }, + "each-async": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/each-async/-/each-async-1.1.1.tgz", + "integrity": "sha1-3uUim98KtrogEqOV4bhpq/iBNHM=", + "requires": { + "onetime": "1.1.0", + "set-immediate-shim": "1.0.1" + } + }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "editions": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/editions/-/editions-1.3.3.tgz", + "integrity": "sha1-CQcQG92iD6w8vjNMJ8vQaI3Jmls=" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "ejs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-1.0.0.tgz", + "integrity": "sha1-ycYKSKRu5FL7MqccMXuV5aofyz0=", + "dev": true + }, + "ejs-loader": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/ejs-loader/-/ejs-loader-0.3.0.tgz", + "integrity": "sha1-aHNv3CMaSQ7fkZpkRq2dkFWlh74=", + "dev": true, + "requires": { + "loader-utils": "0.2.17", + "lodash": "3.10.1" + }, + "dependencies": { + "lodash": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", + "dev": true + } + } + }, + "ejsify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ejsify/-/ejsify-1.0.0.tgz", + "integrity": "sha1-NxlPWoXBKuQ4QpOVeZ7Ee0O8RT8=", + "dev": true, + "requires": { + "ejs": "1.0.0", + "through": "2.3.8" + } + }, + "electron-to-chromium": { + "version": "1.3.16", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.16.tgz", + "integrity": "sha1-0OAmc1dUdwkBrjAaIWZMukXZL30=", + "dev": true + }, + "element-resize-detector": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/element-resize-detector/-/element-resize-detector-1.1.12.tgz", + "integrity": "sha1-iz/W7t2hf5wAs2Cg6i35knroC6I=", + "requires": { + "batch-processor": "1.0.0" + } + }, + "elliptic": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", + "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", + "requires": { + "bn.js": "4.11.7", + "brorand": "1.1.0", + "hash.js": "1.1.3", + "hmac-drbg": "1.0.1", + "inherits": "2.0.3", + "minimalistic-assert": "1.0.0", + "minimalistic-crypto-utils": "1.0.1" + } + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=" + }, + "empty-module": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/empty-module/-/empty-module-0.0.2.tgz", + "integrity": "sha1-E7TdjUr+3dNeUMGNzXiMUQh/FUU=", + "dev": true + }, + "encodeurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz", + "integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA=", + "dev": true + }, + "encoding": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "requires": { + "iconv-lite": "0.4.18" + } + }, + "end-of-stream": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.0.tgz", + "integrity": "sha1-epDYM+/abPpurA9JSduw+tOmMgY=", + "requires": { + "once": "1.4.0" + } + }, + "enhanced-resolve": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz", + "integrity": "sha1-BCHjOf1xQZs9oT0Smzl5BAIwR24=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "memory-fs": "0.4.1", + "object-assign": "4.1.1", + "tapable": "0.2.7" + } + }, + "entities": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", + "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=" + }, + "enzyme": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/enzyme/-/enzyme-2.7.1.tgz", + "integrity": "sha1-djcOHZnpH3MJG7jEMUt8EozC1iE=", + "dev": true, + "requires": { + "cheerio": "0.22.0", + "function.prototype.name": "1.0.3", + "is-subset": "0.1.1", + "lodash": "4.17.2", + "object-is": "1.0.1", + "object.assign": "4.0.4", + "object.entries": "1.0.4", + "object.values": "1.0.4", + "uuid": "2.0.3" + }, + "dependencies": { + "uuid": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", + "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=", + "dev": true + } + } + }, + "errno": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.4.tgz", + "integrity": "sha1-uJbiOp5ei6M4cfyZar02NfyaHH0=", + "dev": true, + "requires": { + "prr": "0.0.0" + } + }, + "error-ex": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", + "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", + "requires": { + "is-arrayish": "0.2.1" + } + }, + "error-stack-parser": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-1.3.6.tgz", + "integrity": "sha1-4Oc7k+QXE40c18C3RrGkoUhUwpI=", + "dev": true, + "requires": { + "stackframe": "0.3.1" + } + }, + "es-abstract": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.7.0.tgz", + "integrity": "sha1-363ndOAb/Nl/lhgCmMRJyGI/uUw=", + "dev": true, + "requires": { + "es-to-primitive": "1.1.1", + "function-bind": "1.1.0", + "is-callable": "1.1.3", + "is-regex": "1.0.4" + } + }, + "es-to-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz", + "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", + "dev": true, + "requires": { + "is-callable": "1.1.3", + "is-date-object": "1.0.1", + "is-symbol": "1.0.1" + } + }, + "es5-ext": { + "version": "0.10.24", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.24.tgz", + "integrity": "sha1-pVh3yZJLwMjZvTwsvhdJWsFwmxQ=", + "dev": true, + "requires": { + "es6-iterator": "2.0.1", + "es6-symbol": "3.1.1" + } + }, + "es6-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.0.0.tgz", + "integrity": "sha1-8JTHBB9mJZm7EnINoFnWucf/D0A=" + }, + "es6-iterator": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.1.tgz", + "integrity": "sha1-jjGcnwRTv1ddN0lAplWSDlnKVRI=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.24", + "es6-symbol": "3.1.1" + } + }, + "es6-map": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", + "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.24", + "es6-iterator": "2.0.1", + "es6-set": "0.1.5", + "es6-symbol": "3.1.1", + "event-emitter": "0.3.5" + } + }, + "es6-promise": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.0.5.tgz", + "integrity": "sha1-eILzCt3lskDM+n99eMVIMwlRrkI=" + }, + "es6-set": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", + "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.24", + "es6-iterator": "2.0.1", + "es6-symbol": "3.1.1", + "event-emitter": "0.3.5" + } + }, + "es6-symbol": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.24" + } + }, + "es6-templates": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/es6-templates/-/es6-templates-0.2.3.tgz", + "integrity": "sha1-XLmsn7He1usSOTQrgdeSu7QHjuQ=", + "dev": true, + "requires": { + "recast": "0.11.23", + "through": "2.3.8" + } + }, + "es6-weak-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", + "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.24", + "es6-iterator": "2.0.1", + "es6-symbol": "3.1.1" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "escodegen": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", + "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", + "dev": true, + "requires": { + "esprima": "2.7.3", + "estraverse": "1.9.3", + "esutils": "2.0.2", + "optionator": "0.8.2", + "source-map": "0.2.0" + }, + "dependencies": { + "estraverse": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", + "dev": true + }, + "source-map": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", + "dev": true, + "optional": true, + "requires": { + "amdefine": "1.0.1" + } + } + } + }, + "escope": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", + "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", + "dev": true, + "requires": { + "es6-map": "0.1.5", + "es6-weak-map": "2.0.2", + "esrecurse": "4.2.0", + "estraverse": "4.2.0" + } + }, + "eslint": { + "version": "3.16.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-3.16.1.tgz", + "integrity": "sha1-m8MfxzQWks93LoBgdQj2fXEcVgk=", + "dev": true, + "requires": { + "babel-code-frame": "6.22.0", + "chalk": "1.1.3", + "concat-stream": "1.6.0", + "debug": "2.6.8", + "doctrine": "1.5.0", + "escope": "3.6.0", + "espree": "3.4.3", + "estraverse": "4.2.0", + "esutils": "2.0.2", + "file-entry-cache": "2.0.0", + "glob": "7.1.2", + "globals": "9.18.0", + "ignore": "3.3.3", + "imurmurhash": "0.1.4", + "inquirer": "0.12.0", + "is-my-json-valid": "2.16.0", + "is-resolvable": "1.0.0", + "js-yaml": "3.6.1", + "json-stable-stringify": "1.0.1", + "levn": "0.3.0", + "lodash": "4.17.2", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "optionator": "0.8.2", + "path-is-inside": "1.0.2", + "pluralize": "1.2.1", + "progress": "1.1.8", + "require-uncached": "1.0.3", + "shelljs": "0.7.8", + "strip-bom": "3.0.0", + "strip-json-comments": "2.0.1", + "table": "3.8.3", + "text-table": "0.2.0", + "user-home": "2.0.0" + }, + "dependencies": { + "ansi-escapes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", + "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", + "dev": true + }, + "cli-cursor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", + "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", + "dev": true, + "requires": { + "restore-cursor": "1.0.1" + } + }, + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true, + "requires": { + "escape-string-regexp": "1.0.5", + "object-assign": "4.1.1" + } + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "inquirer": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", + "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=", + "dev": true, + "requires": { + "ansi-escapes": "1.4.0", + "ansi-regex": "2.1.1", + "chalk": "1.1.3", + "cli-cursor": "1.0.2", + "cli-width": "2.1.0", + "figures": "1.7.0", + "lodash": "4.17.2", + "readline2": "1.0.1", + "run-async": "0.1.0", + "rx-lite": "3.1.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "through": "2.3.8" + } + }, + "restore-cursor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", + "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", + "dev": true, + "requires": { + "exit-hook": "1.1.1", + "onetime": "1.1.0" + } + }, + "run-async": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", + "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=", + "dev": true, + "requires": { + "once": "1.4.0" + } + }, + "rx-lite": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz", + "integrity": "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=", + "dev": true + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "user-home": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", + "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", + "dev": true, + "requires": { + "os-homedir": "1.0.2" + } + } + } + }, + "eslint-config-semistandard": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-semistandard/-/eslint-config-semistandard-7.0.0.tgz", + "integrity": "sha1-+ANJP1alFy9/WcNa5kg2C0Hy/3E=", + "dev": true + }, + "eslint-config-standard": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-6.2.1.tgz", + "integrity": "sha1-06aKr8cZFjnn7kQec0hzkCY1QpI=", + "dev": true + }, + "eslint-config-standard-jsx": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-3.3.0.tgz", + "integrity": "sha1-yrCAGhWjYL9j+suXqyL73YjYpeA=", + "dev": true + }, + "eslint-config-standard-react": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard-react/-/eslint-config-standard-react-4.2.0.tgz", + "integrity": "sha1-0V/SXoN+IK/w2zL2T7VdEYgOuNA=", + "dev": true, + "requires": { + "eslint-config-standard-jsx": "3.3.0" + } + }, + "eslint-plugin-promise": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.4.2.tgz", + "integrity": "sha1-G+J5Pq/i0YtbEjuBNsJp+AT+cSI=", + "dev": true + }, + "eslint-plugin-react": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-6.10.0.tgz", + "integrity": "sha1-nEi0jRAVVLU1VBPnxkI4q95u8e8=", + "dev": true, + "requires": { + "array.prototype.find": "2.0.4", + "doctrine": "1.5.0", + "has": "1.0.1", + "jsx-ast-utils": "1.4.1", + "object.assign": "4.0.4" + } + }, + "eslint-plugin-standard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-2.0.1.tgz", + "integrity": "sha1-NYlpn/nJF/LCX3apFmh/ZBw2n/M=", + "dev": true + }, + "espree": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.4.3.tgz", + "integrity": "sha1-KRC1zNSc6JPC//+qtP2LOjG4I3Q=", + "dev": true, + "requires": { + "acorn": "5.1.1", + "acorn-jsx": "3.0.1" + } + }, + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "dev": true + }, + "esrecurse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.0.tgz", + "integrity": "sha1-+pVo2Y04I/mkHZHpAtyrnqblsWM=", + "dev": true, + "requires": { + "estraverse": "4.2.0", + "object-assign": "4.1.1" + } + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" + }, + "etag": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.7.0.tgz", + "integrity": "sha1-A9MLX2fdbmMtKUXTDWZScxo01dg=", + "dev": true + }, + "ethereum-common": { + "version": "0.0.18", + "resolved": "https://registry.npmjs.org/ethereum-common/-/ethereum-common-0.0.18.tgz", + "integrity": "sha1-L9w1dvIykDNYl26znaeDIT/5Uj8=" + }, + "ethereumjs-tx": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/ethereumjs-tx/-/ethereumjs-tx-1.2.5.tgz", + "integrity": "sha1-7TbX/+uXvIicYe7xq3b0emE9goY=", + "requires": { + "ethereum-common": "0.0.18", + "ethereumjs-util": "5.1.2" + } + }, + "ethereumjs-util": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.1.2.tgz", + "integrity": "sha1-JboCFcu0wvCxCKb5avKi5i5Fkh8=", + "requires": { + "babel-preset-es2015": "6.24.1", + "babelify": "7.3.0", + "bn.js": "4.11.7", + "create-hash": "1.1.3", + "ethjs-util": "0.1.4", + "keccak": "1.3.0", + "rlp": "2.0.0", + "secp256k1": "3.3.0" + }, + "dependencies": { + "babel-preset-es2015": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz", + "integrity": "sha1-1EBQ1rwsn+6nAqrzjXJ6AhBTiTk=", + "requires": { + "babel-plugin-check-es2015-constants": "6.22.0", + "babel-plugin-transform-es2015-arrow-functions": "6.22.0", + "babel-plugin-transform-es2015-block-scoped-functions": "6.22.0", + "babel-plugin-transform-es2015-block-scoping": "6.24.1", + "babel-plugin-transform-es2015-classes": "6.24.1", + "babel-plugin-transform-es2015-computed-properties": "6.24.1", + "babel-plugin-transform-es2015-destructuring": "6.23.0", + "babel-plugin-transform-es2015-duplicate-keys": "6.24.1", + "babel-plugin-transform-es2015-for-of": "6.23.0", + "babel-plugin-transform-es2015-function-name": "6.24.1", + "babel-plugin-transform-es2015-literals": "6.22.0", + "babel-plugin-transform-es2015-modules-amd": "6.24.1", + "babel-plugin-transform-es2015-modules-commonjs": "6.24.1", + "babel-plugin-transform-es2015-modules-systemjs": "6.24.1", + "babel-plugin-transform-es2015-modules-umd": "6.24.1", + "babel-plugin-transform-es2015-object-super": "6.24.1", + "babel-plugin-transform-es2015-parameters": "6.24.1", + "babel-plugin-transform-es2015-shorthand-properties": "6.24.1", + "babel-plugin-transform-es2015-spread": "6.22.0", + "babel-plugin-transform-es2015-sticky-regex": "6.24.1", + "babel-plugin-transform-es2015-template-literals": "6.22.0", + "babel-plugin-transform-es2015-typeof-symbol": "6.23.0", + "babel-plugin-transform-es2015-unicode-regex": "6.24.1", + "babel-plugin-transform-regenerator": "6.24.1" + } + } + } + }, + "ethjs-util": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.4.tgz", + "integrity": "sha1-HItoeSV0RO9NPz+7rC3tEs2ZfZM=", + "requires": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + } + }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.24" + } + }, + "eventemitter3": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.2.tgz", + "integrity": "sha1-IM5IkZCc6fNbCIyU+rQOLJb0c6w=" + }, + "events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", + "dev": true + }, + "evp_bytestokey": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.0.tgz", + "integrity": "sha1-SXtmrZ/vZc18CKYYCCS6FHa2blM=", + "requires": { + "create-hash": "1.1.3" + } + }, + "exec-buffer": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/exec-buffer/-/exec-buffer-3.2.0.tgz", + "integrity": "sha512-wsiD+2Tp6BWHoVv3B+5Dcx6E7u5zky+hUwOHjuH2hKSLR3dvRmX8fk8UD8uqQixHs4Wk6eDmiegVrMPjKj7wpA==", + "dev": true, + "requires": { + "execa": "0.7.0", + "p-finally": "1.0.0", + "pify": "3.0.0", + "rimraf": "2.6.1", + "tempfile": "2.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "exec-series": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/exec-series/-/exec-series-1.0.3.tgz", + "integrity": "sha1-bSV6m+rEgqhyx3g7yGFYOfx3FDo=", + "dev": true, + "requires": { + "async-each-series": "1.1.0", + "object-assign": "4.1.1" + } + }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "dev": true, + "requires": { + "cross-spawn": "5.1.0", + "get-stream": "3.0.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" + } + }, + "execall": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execall/-/execall-1.0.0.tgz", + "integrity": "sha1-c9CQTjlbPKsGWLCNCewlMH8pu3M=", + "dev": true, + "requires": { + "clone-regexp": "1.0.0" + } + }, + "executable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/executable/-/executable-1.1.0.tgz", + "integrity": "sha1-h3mA6REvM5EGbaNyZd562ENKtNk=", + "dev": true, + "requires": { + "meow": "3.7.0" + } + }, + "exit-hook": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", + "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", + "dev": true + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "requires": { + "is-posix-bracket": "0.1.1" + } + }, + "expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "requires": { + "fill-range": "2.2.3" + } + }, + "expand-template": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-1.0.3.tgz", + "integrity": "sha1-bDAzIxd6YrGyLAcCefeGEoe2mxo=" + }, + "express": { + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.14.1.tgz", + "integrity": "sha1-ZGwjf3ZvFIwhIK/wc4F7nk1+DTM=", + "dev": true, + "requires": { + "accepts": "1.3.3", + "array-flatten": "1.1.1", + "content-disposition": "0.5.2", + "content-type": "1.0.2", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.2.0", + "depd": "1.1.1", + "encodeurl": "1.0.1", + "escape-html": "1.0.3", + "etag": "1.7.0", + "finalhandler": "0.5.1", + "fresh": "0.3.0", + "merge-descriptors": "1.0.1", + "methods": "1.1.2", + "on-finished": "2.3.0", + "parseurl": "1.3.1", + "path-to-regexp": "0.1.7", + "proxy-addr": "1.1.5", + "qs": "6.2.0", + "range-parser": "1.2.0", + "send": "0.14.2", + "serve-static": "1.11.2", + "type-is": "1.6.15", + "utils-merge": "1.0.0", + "vary": "1.1.1" + }, + "dependencies": { + "debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true, + "requires": { + "ms": "0.7.1" + } + }, + "ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", + "dev": true + }, + "qs": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.0.tgz", + "integrity": "sha1-O3hIwDwt7OaalSKw+ujEEm10Xzs=", + "dev": true + } + } + }, + "extend": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-1.2.1.tgz", + "integrity": "sha1-oPX9bPyDpf5J72mNYOyKYk3UV2w=" + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "0.1.1" + } + }, + "external-editor": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.0.4.tgz", + "integrity": "sha1-HtkZnanL/i7y96MbL96LDRI2iXI=", + "requires": { + "iconv-lite": "0.4.18", + "jschardet": "1.5.0", + "tmp": "0.0.31" + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "requires": { + "is-extglob": "1.0.0" + }, + "dependencies": { + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" + } + } + }, + "extract-loader": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/extract-loader/-/extract-loader-0.1.0.tgz", + "integrity": "sha1-ocFGkVJBzEhtUpImPHVV1aoZdm4=", + "dev": true, + "requires": { + "loader-utils": "0.2.17" + } + }, + "extract-text-webpack-plugin": { + "version": "2.0.0-beta.4", + "resolved": "https://registry.npmjs.org/extract-text-webpack-plugin/-/extract-text-webpack-plugin-2.0.0-beta.4.tgz", + "integrity": "sha1-0yOTBp59kMgxjUg5IwJhi1a8G6k=", + "dev": true, + "requires": { + "async": "1.5.2", + "loader-utils": "0.2.17", + "webpack-sources": "0.1.5" + } + }, + "extsprintf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz", + "integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA=" + }, + "fancy-log": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.0.tgz", + "integrity": "sha1-Rb4X0Cu5kX1gzP/UmVyZnmyMmUg=", + "requires": { + "chalk": "1.1.3", + "time-stamp": "1.1.0" + } + }, + "fast-deep-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", + "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=" + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fastparse": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.1.tgz", + "integrity": "sha1-0eJkOzipTXWDtHkGDmxK/8lAcfg=", + "dev": true + }, + "fbjs": { + "version": "0.8.14", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.14.tgz", + "integrity": "sha1-0dviviVMNakeCfMfnNUKQLKg7Rw=", + "requires": { + "core-js": "1.2.7", + "isomorphic-fetch": "2.2.1", + "loose-envify": "1.3.1", + "object-assign": "4.1.1", + "promise": "7.3.1", + "setimmediate": "1.0.5", + "ua-parser-js": "0.7.14" + }, + "dependencies": { + "core-js": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" + } + } + }, + "fd-slicer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", + "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", + "requires": { + "pend": "1.2.0" + } + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "requires": { + "escape-string-regexp": "1.0.5" + } + }, + "file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "dev": true, + "requires": { + "flat-cache": "1.2.2", + "object-assign": "4.1.1" + } + }, + "file-loader": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-0.10.0.tgz", + "integrity": "sha1-u+bbdHSsksf1T9wZfPVH6YtrjhI=", + "dev": true, + "requires": { + "loader-utils": "0.2.17" + } + }, + "file-saver": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-1.3.3.tgz", + "integrity": "sha1-zdTETTqiZOrC9o7BZbx5HDSvEjI=" + }, + "file-type": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", + "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=" + }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=" + }, + "filename-reserved-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-1.0.0.tgz", + "integrity": "sha1-5hz4BfDeHJhFZ9A4bcXfUO5a9+Q=" + }, + "filenamify": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-1.2.1.tgz", + "integrity": "sha1-qfL/0RxQO+0wABUCknI3jx8TZaU=", + "requires": { + "filename-reserved-regex": "1.0.0", + "strip-outer": "1.0.0", + "trim-repeated": "1.0.0" + } + }, + "fileset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz", + "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=", + "dev": true, + "requires": { + "glob": "7.1.2", + "minimatch": "3.0.4" + }, + "dependencies": { + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + } + } + }, + "filesize": { + "version": "3.5.10", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.5.10.tgz", + "integrity": "sha1-/I+iPdtO+eXgq24eZPZ5okpWdh8=", + "dev": true + }, + "fill-range": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", + "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", + "requires": { + "is-number": "2.1.0", + "isobject": "2.1.0", + "randomatic": "1.1.7", + "repeat-element": "1.1.2", + "repeat-string": "1.6.1" + } + }, + "finalhandler": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.5.1.tgz", + "integrity": "sha1-LEANjUUwk1vCMlScX6OF7Afeb80=", + "dev": true, + "requires": { + "debug": "2.2.0", + "escape-html": "1.0.3", + "on-finished": "2.3.0", + "statuses": "1.3.1", + "unpipe": "1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true, + "requires": { + "ms": "0.7.1" + } + }, + "ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true + } + } + }, + "find-cache-dir": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-0.1.1.tgz", + "integrity": "sha1-yN765XyKUqinhPnjHFfHQumToLk=", + "dev": true, + "requires": { + "commondir": "1.0.1", + "mkdirp": "0.5.1", + "pkg-dir": "1.0.0" + } + }, + "find-parent-dir": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/find-parent-dir/-/find-parent-dir-0.3.0.tgz", + "integrity": "sha1-M8RLQpqysvBkYpnF+fcY83b/jVQ=", + "dev": true + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + }, + "find-versions": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-1.2.1.tgz", + "integrity": "sha1-y96fEuOFdaCvG+G5osXV/Y8Ya2I=", + "dev": true, + "requires": { + "array-uniq": "1.0.3", + "get-stdin": "4.0.1", + "meow": "3.7.0", + "semver-regex": "1.0.0" + }, + "dependencies": { + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "dev": true + } + } + }, + "first-chunk-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz", + "integrity": "sha1-Wb+1DNkF9g18OUzT2ayqtOatk04=" + }, + "flat": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat/-/flat-2.0.1.tgz", + "integrity": "sha1-cOKRiKdL4MPIlAnu0fqVd5B64y8=", + "requires": { + "is-buffer": "1.1.5" + } + }, + "flat-cache": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.2.2.tgz", + "integrity": "sha1-+oZxTnLCHbiGAXYezy9VXRq8a5Y=", + "dev": true, + "requires": { + "circular-json": "0.3.3", + "del": "2.2.2", + "graceful-fs": "4.1.11", + "write": "0.2.1" + } + }, + "flatten": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz", + "integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=", + "dev": true + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "requires": { + "for-in": "1.0.2" + } + }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", + "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.16" + } + }, + "format-json": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/format-json/-/format-json-1.0.3.tgz", + "integrity": "sha1-Jo49PhaXkv9Ju1sDDyLIfKHCzZ8=" + }, + "format-number": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/format-number/-/format-number-2.0.1.tgz", + "integrity": "sha1-6SMah0PKZLR9CVVdzkApY0O+Zus=" + }, + "formatio": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.1.1.tgz", + "integrity": "sha1-XtPM1jZVEJc4NGXZlhmRAOhhYek=", + "dev": true, + "requires": { + "samsam": "1.1.2" + } + }, + "forwarded": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.0.tgz", + "integrity": "sha1-Ge+YdMSuHCl7zweP3mOgm2aoQ2M=", + "dev": true + }, + "fresh": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.3.0.tgz", + "integrity": "sha1-ZR+DjiJCTnVm3hYdg1jKoZn4PU8=", + "dev": true + }, + "fs-extra": { + "version": "0.26.7", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.26.7.tgz", + "integrity": "sha1-muH92UiXeY7at20JGM9C0MMYT6k=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "jsonfile": "2.4.0", + "klaw": "1.3.1", + "path-is-absolute": "1.0.1", + "rimraf": "2.6.1" + } + }, + "fs-readdir-recursive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.0.0.tgz", + "integrity": "sha1-jNF0XItPiinIyuw5JHaSG6GV9WA=", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fstream": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", + "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", + "requires": { + "graceful-fs": "4.1.11", + "inherits": "2.0.3", + "mkdirp": "0.5.1", + "rimraf": "2.6.1" + } + }, + "fstream-ignore": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.5.tgz", + "integrity": "sha1-nDHa40dnAY/h0kmyTa2mfQktoQU=", + "requires": { + "fstream": "1.0.11", + "inherits": "2.0.3", + "minimatch": "3.0.4" + } + }, + "function-bind": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.0.tgz", + "integrity": "sha1-FhdnFMgBeY5Ojyz391KUZ7tKV3E=", + "dev": true + }, + "function.prototype.name": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.0.3.tgz", + "integrity": "sha512-5EblxZUdioXi2JiMZ9FUbwYj40eQ9MFHyzFLBSPdlRl3SO8l7SLWuAnQ/at/1Wi4hjJwME/C5WpF2ZfAc8nGNw==", + "dev": true, + "requires": { + "define-properties": "1.1.2", + "function-bind": "1.1.0", + "is-callable": "1.1.3" + } + }, + "gather-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gather-stream/-/gather-stream-1.0.0.tgz", + "integrity": "sha1-szmUr0V6gRVwDUEPMXczy+egkEs=", + "dev": true + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "requires": { + "aproba": "1.1.2", + "console-control-strings": "1.1.0", + "has-unicode": "2.0.1", + "object-assign": "4.1.1", + "signal-exit": "3.0.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wide-align": "1.1.2" + } + }, + "generate-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", + "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", + "dev": true + }, + "generate-object-property": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", + "dev": true, + "requires": { + "is-property": "1.0.2" + } + }, + "geopattern": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/geopattern/-/geopattern-1.2.3.tgz", + "integrity": "sha1-3pZgLkbbqQlcpXdL+zs2MI9+Y/4=", + "requires": { + "extend": "1.2.1" + } + }, + "get-caller-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", + "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=" + }, + "get-own-enumerable-property-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-1.0.1.tgz", + "integrity": "sha1-8dTjrRQC4DmJjlbR6bmqkkwm5IQ=" + }, + "get-proxy": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-proxy/-/get-proxy-1.1.0.tgz", + "integrity": "sha1-iUhUSRvFkbDxR9euVw9cZ4tyVus=", + "requires": { + "rc": "1.2.1" + } + }, + "get-stdin": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-3.0.2.tgz", + "integrity": "sha1-wc7SS5A5s43thb3xYeV3E7bdSr4=" + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "gifsicle": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/gifsicle/-/gifsicle-3.0.4.tgz", + "integrity": "sha1-9Fy17RAWW2ZdySng6TKLbIId+js=", + "dev": true, + "requires": { + "bin-build": "2.2.0", + "bin-wrapper": "3.0.2", + "logalot": "2.1.0" + } + }, + "github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=" + }, + "glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "requires": { + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "requires": { + "glob-parent": "2.0.0", + "is-glob": "2.0.1" + }, + "dependencies": { + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "requires": { + "is-glob": "2.0.1" + } + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "requires": { + "is-extglob": "1.0.0" + } + } + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "requires": { + "is-glob": "3.1.0", + "path-dirname": "1.0.2" + } + }, + "glob-stream": { + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-5.3.5.tgz", + "integrity": "sha1-pVZlqajM3EGRWofHAeMtTgFvrSI=", + "requires": { + "extend": "3.0.1", + "glob": "5.0.15", + "glob-parent": "3.1.0", + "micromatch": "2.3.11", + "ordered-read-streams": "0.3.0", + "through2": "0.6.5", + "to-absolute-glob": "0.1.1", + "unique-stream": "2.2.1" + }, + "dependencies": { + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" + } + } + }, + "global": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/global/-/global-4.3.2.tgz", + "integrity": "sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=", + "dev": true, + "requires": { + "min-document": "2.19.0", + "process": "0.5.2" + } + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==" + }, + "globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "dev": true, + "requires": { + "array-union": "1.0.2", + "arrify": "1.0.1", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + }, + "dependencies": { + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + } + } + }, + "globjoin": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz", + "integrity": "sha1-L0SUrIkZ43Z8XLtpHp9GMyQoXUM=", + "dev": true + }, + "glogg": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.0.tgz", + "integrity": "sha1-f+DxmfV6yQbPUS/urY+Q7kooT8U=", + "requires": { + "sparkles": "1.0.0" + } + }, + "got": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/got/-/got-5.7.1.tgz", + "integrity": "sha1-X4FjWmHkplifGAVp6k44FoClHzU=", + "requires": { + "create-error-class": "3.0.2", + "duplexer2": "0.1.4", + "is-redirect": "1.0.0", + "is-retry-allowed": "1.1.0", + "is-stream": "1.1.0", + "lowercase-keys": "1.0.0", + "node-status-codes": "1.0.0", + "object-assign": "4.1.1", + "parse-json": "2.2.0", + "pinkie-promise": "2.0.1", + "read-all-stream": "3.1.0", + "readable-stream": "2.3.3", + "timed-out": "3.1.3", + "unzip-response": "1.0.2", + "url-parse-lax": "1.0.0" + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + }, + "graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=" + }, + "growl": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", + "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", + "dev": true + }, + "gulp-decompress": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gulp-decompress/-/gulp-decompress-1.2.0.tgz", + "integrity": "sha1-jutlpeAV+O2FMsr+KEVJYGJvDcc=", + "requires": { + "archive-type": "3.2.0", + "decompress": "3.0.0", + "gulp-util": "3.0.8", + "readable-stream": "2.3.3" + } + }, + "gulp-rename": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/gulp-rename/-/gulp-rename-1.2.2.tgz", + "integrity": "sha1-OtRCh2PwXidk3sHGfYaNsnVoeBc=" + }, + "gulp-sourcemaps": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-1.6.0.tgz", + "integrity": "sha1-uG/zSdgBzrVuHZ59x7vLS33uYAw=", + "requires": { + "convert-source-map": "1.5.0", + "graceful-fs": "4.1.11", + "strip-bom": "2.0.0", + "through2": "2.0.3", + "vinyl": "1.2.0" + }, + "dependencies": { + "through2": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", + "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", + "requires": { + "readable-stream": "2.3.3", + "xtend": "4.0.1" + } + } + } + }, + "gulp-util": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", + "integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=", + "requires": { + "array-differ": "1.0.0", + "array-uniq": "1.0.3", + "beeper": "1.1.1", + "chalk": "1.1.3", + "dateformat": "2.0.0", + "fancy-log": "1.3.0", + "gulplog": "1.0.0", + "has-gulplog": "0.1.0", + "lodash._reescape": "3.0.0", + "lodash._reevaluate": "3.0.0", + "lodash._reinterpolate": "3.0.0", + "lodash.template": "3.6.2", + "minimist": "1.2.0", + "multipipe": "0.1.2", + "object-assign": "3.0.0", + "replace-ext": "0.0.1", + "through2": "2.0.3", + "vinyl": "0.5.3" + }, + "dependencies": { + "object-assign": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", + "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=" + }, + "through2": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", + "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", + "requires": { + "readable-stream": "2.3.3", + "xtend": "4.0.1" + } + }, + "vinyl": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", + "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=", + "requires": { + "clone": "1.0.2", + "clone-stats": "0.0.1", + "replace-ext": "0.0.1" + } + } + } + }, + "gulplog": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", + "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", + "requires": { + "glogg": "1.0.0" + } + }, + "handlebars": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.10.tgz", + "integrity": "sha1-PTDHGLCaPZbyPqTMH0A8TTup/08=", + "dev": true, + "requires": { + "async": "1.5.2", + "optimist": "0.6.1", + "source-map": "0.4.4", + "uglify-js": "2.8.16" + }, + "dependencies": { + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, + "requires": { + "amdefine": "1.0.1" + } + } + } + }, + "happypack": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/happypack/-/happypack-3.0.3.tgz", + "integrity": "sha1-IveMh6MlzbeYyVjPTsOD/NTW/cc=", + "dev": true, + "requires": { + "async": "1.5.0", + "json-stringify-safe": "5.0.1", + "loader-utils": "0.2.16", + "mkdirp": "0.5.1" + }, + "dependencies": { + "async": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.0.tgz", + "integrity": "sha1-J5ZkJyNXOFlWVjP8YnRES+4vjOM=", + "dev": true + }, + "loader-utils": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.16.tgz", + "integrity": "sha1-8IYyBm7YKCg13/iN+1JwR2Wt7m0=", + "dev": true, + "requires": { + "big.js": "3.1.3", + "emojis-list": "2.1.0", + "json5": "0.5.1", + "object-assign": "4.1.1" + } + } + } + }, + "har-schema": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", + "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=" + }, + "har-validator": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", + "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", + "requires": { + "ajv": "4.11.8", + "har-schema": "1.0.5" + }, + "dependencies": { + "ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + } + } + }, + "has": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz", + "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", + "dev": true, + "requires": { + "function-bind": "1.1.0" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "2.1.1" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" + }, + "has-gulplog": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz", + "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=", + "requires": { + "sparkles": "1.0.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + }, + "hash-base": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz", + "integrity": "sha1-ZuodhW206KVHDK32/OI65SRO8uE=", + "requires": { + "inherits": "2.0.3" + } + }, + "hash.js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "requires": { + "inherits": "2.0.3", + "minimalistic-assert": "1.0.0" + } + }, + "hawk": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + } + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, + "history": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/history/-/history-3.3.0.tgz", + "integrity": "sha1-/O3M6PEpdTcVRdc1RhAzV5ptrpw=", + "requires": { + "invariant": "2.2.2", + "loose-envify": "1.3.1", + "query-string": "4.3.4", + "warning": "3.0.0" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "requires": { + "hash.js": "1.1.3", + "minimalistic-assert": "1.0.0", + "minimalistic-crypto-utils": "1.0.1" + } + }, + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" + }, + "hoist-non-react-statics": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz", + "integrity": "sha1-qkSM8JhtVcxAdzsXF0t90GbLfPs=" + }, + "home-or-tmp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", + "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, + "hosted-git-info": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", + "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==" + }, + "html": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/html/-/html-1.0.0.tgz", + "integrity": "sha1-pUT6nqVJK/s6LMqCEKEL57WvH2E=", + "dev": true, + "requires": { + "concat-stream": "1.6.0" + } + }, + "html-comment-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.1.tgz", + "integrity": "sha1-ZouTd26q5V696POtRkswekljYl4=", + "dev": true + }, + "html-encoding-sniffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.1.tgz", + "integrity": "sha1-eb96eF6klf5mFl5zQVPzY/9UN9o=", + "dev": true, + "requires": { + "whatwg-encoding": "1.0.1" + } + }, + "html-entities": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz", + "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=", + "dev": true + }, + "html-loader": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/html-loader/-/html-loader-0.4.4.tgz", + "integrity": "sha1-8rW5rNXgNf86tf02nBPJenuwFNo=", + "dev": true, + "requires": { + "es6-templates": "0.2.3", + "fastparse": "1.1.1", + "html-minifier": "3.5.3", + "loader-utils": "0.2.17", + "object-assign": "4.1.1" + } + }, + "html-minifier": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.3.tgz", + "integrity": "sha512-iKRzQQDuTCsq0Ultbi/mfJJnR0D3AdZKTq966Gsp92xkmAPCV4Xi08qhJ0Dl3ZAWemSgJ7qZK+UsZc0gFqK6wg==", + "dev": true, + "requires": { + "camel-case": "3.0.0", + "clean-css": "4.1.7", + "commander": "2.11.0", + "he": "1.1.1", + "ncname": "1.0.0", + "param-case": "2.1.1", + "relateurl": "0.2.7", + "uglify-js": "3.0.27" + }, + "dependencies": { + "commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", + "dev": true + }, + "uglify-js": { + "version": "3.0.27", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.0.27.tgz", + "integrity": "sha512-HD8CmxPXUI62v5tweiulMcP/apAtx1DXGcNZkhKQZyC+MTrTsoCBb8yPAwVrbvpgw3EpRU76bRe6axjIiCYcQg==", + "dev": true, + "requires": { + "commander": "2.11.0", + "source-map": "0.5.6" + } + } + } + }, + "html-tags": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-1.2.0.tgz", + "integrity": "sha1-x43mW1Zjqll5id0rerSSANfk25g=", + "dev": true + }, + "html-webpack-plugin": { + "version": "2.28.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-2.28.0.tgz", + "integrity": "sha1-LnhjtX5f1I/iYzA+L/yTTDBk0Ak=", + "dev": true, + "requires": { + "bluebird": "3.5.0", + "html-minifier": "3.5.3", + "loader-utils": "0.2.17", + "lodash": "4.17.4", + "pretty-error": "2.1.1", + "toposort": "1.0.3" + }, + "dependencies": { + "bluebird": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", + "integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw=", + "dev": true + }, + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + } + } + }, + "htmlparser2": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz", + "integrity": "sha1-G9+HrMoPP55T+k/M6w9LTLsAszg=", + "dev": true, + "requires": { + "domelementtype": "1.3.0", + "domhandler": "2.4.1", + "domutils": "1.5.1", + "entities": "1.1.1", + "inherits": "2.0.3", + "readable-stream": "2.3.3" + } + }, + "http-errors": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.5.1.tgz", + "integrity": "sha1-eIwNLB3iyBuebowBhDtrl+uSB1A=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "setprototypeof": "1.0.2", + "statuses": "1.3.1" + } + }, + "http-proxy": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.16.2.tgz", + "integrity": "sha1-Bt/ykpUr9k2+hHH6nfcwZtTzd0I=", + "dev": true, + "requires": { + "eventemitter3": "1.2.0", + "requires-port": "1.0.0" + }, + "dependencies": { + "eventemitter3": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz", + "integrity": "sha1-HIaZHYFq0eUEdQ5zh0Ik7PO+xQg=", + "dev": true + } + } + }, + "http-proxy-middleware": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.17.3.tgz", + "integrity": "sha1-lAOCFHFJuFYIT1U0dS1bWoFozR0=", + "dev": true, + "requires": { + "http-proxy": "1.16.2", + "is-glob": "3.1.0", + "lodash": "4.17.2", + "micromatch": "2.3.11" + } + }, + "http-signature": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.4.0", + "sshpk": "1.13.1" + } + }, + "https-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-0.0.1.tgz", + "integrity": "sha1-P5E2XKvmC3ftDruiS0VOPgnZWoI=", + "dev": true + }, + "humanize": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/humanize/-/humanize-0.0.9.tgz", + "integrity": "sha1-GZT/rs3+nEQe0r2sdFK3u0yeQaQ=", + "dev": true + }, + "husky": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/husky/-/husky-0.13.1.tgz", + "integrity": "sha1-Ee/G/BDg7E54l3b2WCvjfXG6TM8=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "find-parent-dir": "0.3.0", + "is-ci": "1.0.10", + "normalize-path": "1.0.0" + }, + "dependencies": { + "normalize-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-1.0.0.tgz", + "integrity": "sha1-MtDkcvkf80VwHBWoMRAY07CpA3k=", + "dev": true + } + } + }, + "hyphenate-style-name": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz", + "integrity": "sha1-MRYKNpMK2vH8BMYHT360FGXU7Es=" + }, + "iconv-lite": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.18.tgz", + "integrity": "sha512-sr1ZQph3UwHTR0XftSbK85OvBbxe/abLGzEnPENCQwmHf7sck8Oyu4ob3LgBxWWxRoM+QszeUyl7jbqapu2TqA==" + }, + "icss-replace-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", + "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=", + "dev": true + }, + "ieee754": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz", + "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=", + "dev": true + }, + "ignore": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.3.tgz", + "integrity": "sha1-QyNS5XrM2HqzEQ6C0/6g5HgSFW0=", + "dev": true + }, + "ignore-styles": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ignore-styles/-/ignore-styles-5.0.1.tgz", + "integrity": "sha1-tJ7yJ0va/NikiAqWa/440aC/RnE=", + "dev": true + }, + "image-webpack-loader": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/image-webpack-loader/-/image-webpack-loader-3.2.0.tgz", + "integrity": "sha1-8mMG1gSNOi9ajYROyu3StxSPCk4=", + "dev": true, + "requires": { + "file-loader": "0.9.0", + "imagemin": "5.3.1", + "imagemin-gifsicle": "5.2.0", + "imagemin-mozjpeg": "6.0.0", + "imagemin-optipng": "5.2.1", + "imagemin-pngquant": "5.0.1", + "imagemin-svgo": "5.2.2", + "loader-utils": "0.2.17" + }, + "dependencies": { + "file-loader": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-0.9.0.tgz", + "integrity": "sha1-HS2t3UJM5tGwfP4/eXMb7TYXq0I=", + "dev": true, + "requires": { + "loader-utils": "0.2.17" + } + } + } + }, + "imagemin": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/imagemin/-/imagemin-5.3.1.tgz", + "integrity": "sha1-8Zwu7h5xumxlWMUV+fyWaAGJptQ=", + "dev": true, + "requires": { + "file-type": "4.4.0", + "globby": "6.1.0", + "make-dir": "1.0.0", + "p-pipe": "1.2.0", + "pify": "2.3.0", + "replace-ext": "1.0.0" + }, + "dependencies": { + "file-type": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-4.4.0.tgz", + "integrity": "sha1-G2AOX8ofvcboDApwxxyNul95BsU=", + "dev": true + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "1.0.2", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "replace-ext": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", + "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", + "dev": true + } + } + }, + "imagemin-gifsicle": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/imagemin-gifsicle/-/imagemin-gifsicle-5.2.0.tgz", + "integrity": "sha512-K01m5QuPK+0en8oVhiOOAicF7KjrHlCZxS++mfLI2mV/Ksfq/Y9nCXCWDz6jRv13wwlqe5T7hXT+ji2DnLc2yQ==", + "dev": true, + "requires": { + "exec-buffer": "3.2.0", + "gifsicle": "3.0.4", + "is-gif": "1.0.0" + } + }, + "imagemin-mozjpeg": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/imagemin-mozjpeg/-/imagemin-mozjpeg-6.0.0.tgz", + "integrity": "sha1-caMqRXqhsmEXpo7u8tmxkMLlCR4=", + "dev": true, + "requires": { + "exec-buffer": "3.2.0", + "is-jpg": "1.0.0", + "mozjpeg": "4.1.1" + } + }, + "imagemin-optipng": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/imagemin-optipng/-/imagemin-optipng-5.2.1.tgz", + "integrity": "sha1-0i2kEsCfX/AKQzmWC5ioix2+hpU=", + "dev": true, + "requires": { + "exec-buffer": "3.2.0", + "is-png": "1.1.0", + "optipng-bin": "3.1.4" + } + }, + "imagemin-pngquant": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/imagemin-pngquant/-/imagemin-pngquant-5.0.1.tgz", + "integrity": "sha1-2KMp2lU6+iJrEc5i3r4Lfje0OeY=", + "dev": true, + "requires": { + "exec-buffer": "3.2.0", + "is-png": "1.1.0", + "pngquant-bin": "3.1.1" + } + }, + "imagemin-svgo": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/imagemin-svgo/-/imagemin-svgo-5.2.2.tgz", + "integrity": "sha1-UBaZ9XiXMKV5IrhzbqFcU/e1WDg=", + "dev": true, + "requires": { + "is-svg": "2.1.0", + "svgo": "0.7.2" + } + }, + "immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=" + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + }, + "in-publish": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz", + "integrity": "sha1-4g/146KvwmkDILbcVSaCqcf631E=" + }, + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "requires": { + "repeating": "2.0.1" + } + }, + "indexes-of": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", + "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", + "dev": true + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ini": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", + "integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=" + }, + "inline-style-prefixer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-2.0.5.tgz", + "integrity": "sha1-wVPH6I/YT+9cYC6VqBaLJ3BnH+c=", + "requires": { + "bowser": "1.7.1", + "hyphenate-style-name": "1.0.2" + } + }, + "inquirer": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.2.1.tgz", + "integrity": "sha512-QgW3eiPN8gpj/K5vVpHADJJgrrF0ho/dZGylikGX7iqAdRgC9FVKYKWFLx6hZDBFcOLEoSqINYrVPeFAeG/PdA==", + "requires": { + "ansi-escapes": "2.0.0", + "chalk": "2.0.1", + "cli-cursor": "2.1.0", + "cli-width": "2.1.0", + "external-editor": "2.0.4", + "figures": "2.0.0", + "lodash": "4.17.2", + "mute-stream": "0.0.7", + "run-async": "2.3.0", + "rx-lite": "4.0.8", + "rx-lite-aggregates": "4.0.8", + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "through": "2.3.8" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + }, + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.0.1.tgz", + "integrity": "sha512-Mp+FXEI+FrwY/XYV45b2YD3E8i3HwnEAoFcM0qlZzq/RZ9RwWitt2Y/c7cqRAz70U7hfekqx6qNYthuKFO6K0g==", + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.2.1" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "3.0.0" + } + }, + "supports-color": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.2.1.tgz", + "integrity": "sha512-qxzYsob3yv6U+xMzPrv170y8AwGP7i74g+pbixCfD6rgso8BscLT2qXIuz6TpOaiJZ3mFgT5O9lyT9nMU4LfaA==", + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "interpret": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.0.3.tgz", + "integrity": "sha1-y8NcYu7uc/Gat7EKgBURQBr8D5A=", + "dev": true + }, + "intl-format-cache": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/intl-format-cache/-/intl-format-cache-2.0.5.tgz", + "integrity": "sha1-tITO/Lk1PzdPJd44mjzuoa8Y18k=" + }, + "intl-messageformat": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-1.3.0.tgz", + "integrity": "sha1-99kmre16OrGbLcYB79VOmaS9Tq4=", + "requires": { + "intl-messageformat-parser": "1.2.0" + } + }, + "intl-messageformat-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/intl-messageformat-parser/-/intl-messageformat-parser-1.2.0.tgz", + "integrity": "sha1-WQa3+VOrdHDg3IVJCXtki5kYkv8=" + }, + "intl-relativeformat": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/intl-relativeformat/-/intl-relativeformat-1.3.0.tgz", + "integrity": "sha1-iT3HB2/M04DPCRojAMOA+les5Fs=", + "requires": { + "intl-messageformat": "1.3.0" + } + }, + "invariant": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz", + "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=", + "requires": { + "loose-envify": "1.3.1" + } + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" + }, + "ip-regex": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-1.0.3.tgz", + "integrity": "sha1-3FiQdvZZ9BnCIgOaMzFvHHOH7/0=", + "dev": true + }, + "ipaddr.js": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.4.0.tgz", + "integrity": "sha1-KWrKh4qCGBbluF0KKFqZvP9FgvA=", + "dev": true + }, + "irregular-plurals": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-1.3.0.tgz", + "integrity": "sha512-njf5A+Mxb3kojuHd1DzISjjIl+XhyzovXEOyPPSzdQozq/Lf2tN27mOrAAsxEPZxpn6I4MGzs1oo9TxXxPFpaA==", + "dev": true + }, + "is-absolute": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.1.7.tgz", + "integrity": "sha1-hHSREZ/MtftDYhfMc39/qtUPYD8=", + "requires": { + "is-relative": "0.1.3" + } + }, + "is-absolute-url": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", + "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "1.9.0" + } + }, + "is-buffer": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz", + "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw=" + }, + "is-builtin-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "requires": { + "builtin-modules": "1.1.1" + } + }, + "is-bzip2": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-bzip2/-/is-bzip2-1.0.0.tgz", + "integrity": "sha1-XuWOqlounIDiFAe+3yOuWsCRs/w=" + }, + "is-callable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz", + "integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI=", + "dev": true + }, + "is-ci": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.0.10.tgz", + "integrity": "sha1-9zkzayYyNlBhqdSCcM1WrjNpMY4=", + "requires": { + "ci-info": "1.0.0" + } + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, + "is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "dev": true + }, + "is-dom": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/is-dom/-/is-dom-1.0.9.tgz", + "integrity": "sha1-SDgy1SlyBz3hK5/j9gMghw2oNw0=" + }, + "is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=" + }, + "is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "requires": { + "is-primitive": "2.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-gif": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-gif/-/is-gif-1.0.0.tgz", + "integrity": "sha1-ptKumIkwB7/6l6HYwB1jIFgyCX4=", + "dev": true + }, + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "requires": { + "is-extglob": "2.1.1" + } + }, + "is-gzip": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-gzip/-/is-gzip-1.0.0.tgz", + "integrity": "sha1-bKiwe5nHeZgCWQDlVc7Y7YCHmoM=" + }, + "is-hex-prefixed": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", + "integrity": "sha1-fY035q135dEnFIkTxXPggtd39VQ=" + }, + "is-jpg": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-jpg/-/is-jpg-1.0.0.tgz", + "integrity": "sha1-KVnBfnNDDbOCZNp1uQ3VTy2G2hw=", + "dev": true + }, + "is-my-json-valid": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz", + "integrity": "sha1-8Hndm/2uZe4gOKrorLyGqxCeNpM=", + "dev": true, + "requires": { + "generate-function": "2.0.0", + "generate-object-property": "1.2.0", + "jsonpointer": "4.0.1", + "xtend": "4.0.1" + } + }, + "is-natural-number": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-2.1.1.tgz", + "integrity": "sha1-fUxXKDd+84bD4ZSpkRv1fG3DNec=" + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "requires": { + "kind-of": "3.2.2" + } + }, + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" + }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true + }, + "is-path-in-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", + "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", + "dev": true, + "requires": { + "is-path-inside": "1.0.0" + } + }, + "is-path-inside": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz", + "integrity": "sha1-/AbloWg/vaE95mev9xe7wQpI838=", + "dev": true, + "requires": { + "path-is-inside": "1.0.2" + } + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=" + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "requires": { + "isobject": "3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + } + } + }, + "is-png": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-png/-/is-png-1.1.0.tgz", + "integrity": "sha1-1XSxK/J1wDUEVVcLDltXqwYgd84=", + "dev": true + }, + "is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=" + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=" + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" + }, + "is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", + "dev": true + }, + "is-redirect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", + "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=" + }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "requires": { + "has": "1.0.1" + } + }, + "is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=" + }, + "is-relative": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-0.1.3.tgz", + "integrity": "sha1-kF/uiuhvRbPsYUvDwVyGnfCHboI=" + }, + "is-resolvable": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz", + "integrity": "sha1-jfV8YeouPFAUCNEA+wE8+NbgzGI=", + "dev": true, + "requires": { + "tryit": "1.0.3" + } + }, + "is-retry-allowed": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", + "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=" + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + }, + "is-subset": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-subset/-/is-subset-0.1.1.tgz", + "integrity": "sha1-ilkRfZMt4d4A8kX83TnOQ/HpOaY=", + "dev": true + }, + "is-supported-regexp-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-supported-regexp-flag/-/is-supported-regexp-flag-1.0.0.tgz", + "integrity": "sha1-i1IMhfrnolM4LUsCZS4EVXbhO7g=", + "dev": true + }, + "is-svg": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-2.1.0.tgz", + "integrity": "sha1-z2EJDaDZ77yrhyLeum8DIgjbsOk=", + "dev": true, + "requires": { + "html-comment-regex": "1.1.1" + } + }, + "is-symbol": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz", + "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=", + "dev": true + }, + "is-tar": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-tar/-/is-tar-1.0.0.tgz", + "integrity": "sha1-L2suF5LB9bs2UZrKqdZcDSb+hT0=" + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "is-url": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.2.tgz", + "integrity": "sha1-SYkFpZO/R8wtnn9zg3K792lsfyY=" + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" + }, + "is-valid-glob": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-0.3.0.tgz", + "integrity": "sha1-1LVcafUYhvm2XHDWwmItN+KfSP4=" + }, + "is-zip": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-zip/-/is-zip-1.0.0.tgz", + "integrity": "sha1-R7Co/004p2QxzP2ZqOFaTIa6IyU=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "requires": { + "isarray": "1.0.0" + } + }, + "isomorphic-fetch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", + "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", + "requires": { + "node-fetch": "1.7.1", + "whatwg-fetch": "2.0.1" + } + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "istanbul": { + "version": "1.0.0-alpha.2", + "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-1.0.0-alpha.2.tgz", + "integrity": "sha1-BglrwI6Yuq10Sq5Gli2N+frGPQg=", + "dev": true, + "requires": { + "abbrev": "1.0.9", + "async": "1.5.2", + "istanbul-api": "1.1.11", + "js-yaml": "3.6.1", + "mkdirp": "0.5.1", + "nopt": "3.0.6", + "which": "1.2.14", + "wordwrap": "1.0.0" + }, + "dependencies": { + "abbrev": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", + "dev": true + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + } + } + }, + "istanbul-api": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-1.1.11.tgz", + "integrity": "sha1-/MC0YeKzvaceMFFVE4I4doJX2d4=", + "dev": true, + "requires": { + "async": "2.5.0", + "fileset": "2.0.3", + "istanbul-lib-coverage": "1.1.1", + "istanbul-lib-hook": "1.0.7", + "istanbul-lib-instrument": "1.7.4", + "istanbul-lib-report": "1.1.1", + "istanbul-lib-source-maps": "1.2.1", + "istanbul-reports": "1.1.1", + "js-yaml": "3.9.1", + "mkdirp": "0.5.1", + "once": "1.4.0" + }, + "dependencies": { + "async": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/async/-/async-2.5.0.tgz", + "integrity": "sha512-e+lJAJeNWuPCNyxZKOBdaJGyLGHugXVQtrAwtuAe2vhxTYxFTKE73p8JuTmdH0qdQZtDvI4dhJwjZc5zsfIsYw==", + "dev": true, + "requires": { + "lodash": "4.17.2" + } + }, + "esprima": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", + "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", + "dev": true + }, + "js-yaml": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.9.1.tgz", + "integrity": "sha512-CbcG379L1e+mWBnLvHWWeLs8GyV/EMw862uLI3c+GxVyDHWZcjZinwuBd3iW2pgxgIlksW/1vNJa4to+RvDOww==", + "dev": true, + "requires": { + "argparse": "1.0.9", + "esprima": "4.0.0" + } + } + } + }, + "istanbul-lib-coverage": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.1.tgz", + "integrity": "sha512-0+1vDkmzxqJIn5rcoEqapSB4DmPxE31EtI2dF2aCkV5esN9EWHxZ0dwgDClivMXJqE7zaYQxq30hj5L0nlTN5Q==", + "dev": true + }, + "istanbul-lib-hook": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.0.7.tgz", + "integrity": "sha512-3U2HB9y1ZV9UmFlE12Fx+nPtFqIymzrqCksrXujm3NVbAZIJg/RfYgO1XiIa0mbmxTjWpVEVlkIZJ25xVIAfkQ==", + "dev": true, + "requires": { + "append-transform": "0.4.0" + } + }, + "istanbul-lib-instrument": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.7.4.tgz", + "integrity": "sha1-6f2SDkdn89Ge3HZeLWs/XMvQ7qg=", + "dev": true, + "requires": { + "babel-generator": "6.25.0", + "babel-template": "6.25.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0", + "babylon": "6.17.4", + "istanbul-lib-coverage": "1.1.1", + "semver": "5.4.1" + } + }, + "istanbul-lib-report": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz", + "integrity": "sha512-tvF+YmCmH4thnez6JFX06ujIA19WPa9YUiwjc1uALF2cv5dmE3It8b5I8Ob7FHJ70H9Y5yF+TDkVa/mcADuw1Q==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "1.1.1", + "mkdirp": "0.5.1", + "path-parse": "1.0.5", + "supports-color": "3.2.3" + }, + "dependencies": { + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "1.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.1.tgz", + "integrity": "sha512-mukVvSXCn9JQvdJl8wP/iPhqig0MRtuWuD4ZNKo6vB2Ik//AmhAKe3QnPN02dmkRe3lTudFk3rzoHhwU4hb94w==", + "dev": true, + "requires": { + "debug": "2.6.8", + "istanbul-lib-coverage": "1.1.1", + "mkdirp": "0.5.1", + "rimraf": "2.6.1", + "source-map": "0.5.6" + } + }, + "istanbul-reports": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.1.1.tgz", + "integrity": "sha512-P8G873A0kW24XRlxHVGhMJBhQ8gWAec+dae7ZxOBzxT4w+a9ATSPvRVK3LB1RAJ9S8bg2tOyWHAGW40Zd2dKfw==", + "dev": true, + "requires": { + "handlebars": "4.0.10" + } + }, + "js-base64": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.1.9.tgz", + "integrity": "sha1-8OgK4DmkvWVLXygfyT8EqRSn/M4=", + "dev": true + }, + "js-sha3": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.5.tgz", + "integrity": "sha1-uvDA6MVK1ZA0R9+Wreekobynmko=" + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" + }, + "js-yaml": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.6.1.tgz", + "integrity": "sha1-bl/mfYsgXOTSL60Ft3geja3MSzA=", + "dev": true, + "requires": { + "argparse": "1.0.9", + "esprima": "2.7.3" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "optional": true + }, + "jschardet": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-1.5.0.tgz", + "integrity": "sha512-+Q8JsoEQbrdE+a/gg1F9XO92gcKXgpE5UACqr0sIubjDmBEkd+OOWPGzQeMrWSLxd73r4dHxBeRW7edHu5LmJQ==" + }, + "jsdom": { + "version": "9.11.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-9.11.0.tgz", + "integrity": "sha1-qVsDBOUhospaY8bqR793CKeoRZE=", + "dev": true, + "requires": { + "abab": "1.0.3", + "acorn": "4.0.13", + "acorn-globals": "3.1.0", + "array-equal": "1.0.0", + "content-type-parser": "1.0.1", + "cssom": "0.3.2", + "cssstyle": "0.2.37", + "escodegen": "1.8.1", + "html-encoding-sniffer": "1.0.1", + "nwmatcher": "1.4.1", + "parse5": "1.5.1", + "request": "2.81.0", + "sax": "1.2.4", + "symbol-tree": "3.2.2", + "tough-cookie": "2.3.2", + "webidl-conversions": "4.0.1", + "whatwg-encoding": "1.0.1", + "whatwg-url": "4.8.0", + "xml-name-validator": "2.0.1" + }, + "dependencies": { + "acorn": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", + "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", + "dev": true + } + } + }, + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" + }, + "json-loader": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.4.tgz", + "integrity": "sha1-i6oTZaYy9Yo8RtIBdfxgAsluN94=", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "requires": { + "jsonify": "0.0.0" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "json3": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", + "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", + "dev": true + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" + }, + "jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11" + } + }, + "jsonfilter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/jsonfilter/-/jsonfilter-1.1.2.tgz", + "integrity": "sha1-Ie987cdRk4E8dZMulqmL4gW6WhE=", + "dev": true, + "requires": { + "JSONStream": "0.8.4", + "minimist": "1.2.0", + "stream-combiner": "0.2.2", + "through2": "0.6.5" + } + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" + }, + "jsonparse": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-0.0.5.tgz", + "integrity": "sha1-MwVCrT8KZUZlt3jz6y2an6UHrGQ=", + "dev": true + }, + "jsonpointer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", + "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", + "dev": true + }, + "JSONStream": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-0.8.4.tgz", + "integrity": "sha1-kWV9/m/4V0gwZhMrRhi2Lo9Ih70=", + "dev": true, + "requires": { + "jsonparse": "0.0.5", + "through": "2.3.8" + } + }, + "jsprim": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.0.tgz", + "integrity": "sha1-o7h+QCmNjDgFUtjMdiigu5WiKRg=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.0.2", + "json-schema": "0.2.3", + "verror": "1.3.6" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "jsqr": { + "version": "git+https://github.com/JodusNodus/jsQR.git#5ba1acefa1cbb9b2bc92b49f503f2674e2ec212b" + }, + "jsx-ast-utils": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz", + "integrity": "sha1-OGchPo3Xm/Ho8jAMDPwe+xgsDfE=", + "dev": true + }, + "keccak": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-1.3.0.tgz", + "integrity": "sha512-JgsKPxYhcJxKrV+TrCyg/GwZbOjhpRPrz2kG8xbAsUaIDelUlKjm08YcwBO9Fm8sqf/Kg8ZWkk6nWujhLykfvw==", + "requires": { + "bindings": "1.3.0", + "inherits": "2.0.3", + "nan": "2.6.2", + "prebuild-install": "2.2.1", + "safe-buffer": "5.1.1" + } + }, + "keycode": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/keycode/-/keycode-2.1.9.tgz", + "integrity": "sha1-lkojxU5IiUBbSGGlyfBIDUUUHfo=" + }, + "keythereum": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/keythereum/-/keythereum-0.4.6.tgz", + "integrity": "sha1-D97Hz5OK455eMGGy9uFmd7dmxdo=", + "requires": { + "elliptic": "6.4.0", + "ethereumjs-util": "5.1.1", + "sjcl": "1.0.6", + "uuid": "3.0.0", + "validator": "4.0.2" + }, + "dependencies": { + "ethereumjs-util": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.1.1.tgz", + "integrity": "sha1-Ei+zjep0fcYrOuv8Nl0b1Ivktz4=", + "requires": { + "bn.js": "4.11.7", + "create-hash": "1.1.3", + "ethjs-util": "0.1.4", + "keccak": "1.3.0", + "rlp": "2.0.0", + "secp256k1": "3.3.0" + } + }, + "validator": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/validator/-/validator-4.0.2.tgz", + "integrity": "sha1-cKHCUl7EdE5AmXHBspiqaadTQlE=" + } + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "1.1.5" + } + }, + "klaw": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11" + } + }, + "known-css-properties": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.0.6.tgz", + "integrity": "sha1-caC4/eG240McRx77w9lzP667z78=", + "dev": true + }, + "laggard": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/laggard/-/laggard-0.1.0.tgz", + "integrity": "sha1-Lv1kX38tjz0nrICAOcqGqO40EHU=", + "dev": true, + "requires": { + "minimist": "1.2.0", + "pixrem": "3.0.2", + "postcss": "5.2.17", + "postcss-color-rgba-fallback": "2.2.0", + "postcss-opacity": "3.0.0", + "postcss-pseudoelements": "3.0.0", + "postcss-reporter": "1.4.1", + "postcss-vmin": "2.0.0", + "postcss-will-change": "1.1.0", + "read-file-stdin": "0.2.1", + "write-file-stdout": "0.0.2" + }, + "dependencies": { + "postcss-opacity": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-opacity/-/postcss-opacity-3.0.0.tgz", + "integrity": "sha1-eHm8xzRAW/dKpsgcORdiBS/FWyk=", + "dev": true, + "requires": { + "postcss": "5.2.17" + } + }, + "postcss-reporter": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-1.4.1.tgz", + "integrity": "sha1-wTbwpbFhkV83ndN2XGEHX357mvI=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "lodash": "4.17.2", + "log-symbols": "1.0.2", + "postcss": "5.2.17" + } + } + } + }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=" + }, + "lazy-req": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/lazy-req/-/lazy-req-1.1.0.tgz", + "integrity": "sha1-va6+rTD42CQDnODOFJ1Nqge6H6w=", + "dev": true + }, + "lazystream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", + "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", + "requires": { + "readable-stream": "2.3.3" + } + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "requires": { + "invert-kv": "1.0.0" + } + }, + "lcov-parse": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-0.0.10.tgz", + "integrity": "sha1-GwuP+ayceIklBYK3C3ExXZ2m2aM=", + "dev": true + }, + "ldjson-stream": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ldjson-stream/-/ldjson-stream-1.2.1.tgz", + "integrity": "sha1-kb7O2lrE7SsX5kn7d356v6AYnCs=", + "dev": true, + "requires": { + "split2": "0.2.1", + "through2": "0.6.5" + } + }, + "leven": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", + "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=" + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "1.1.2", + "type-check": "0.3.2" + } + }, + "lie": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz", + "integrity": "sha1-mkNrLMd0bKWd56QfpGmz77dr2H4=", + "requires": { + "immediate": "3.0.6" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "strip-bom": "2.0.0" + } + }, + "loader-runner": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.3.0.tgz", + "integrity": "sha1-9IKuqC1UPgeSFwDVpG7yb9rGuKI=", + "dev": true + }, + "loader-utils": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", + "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", + "requires": { + "big.js": "3.1.3", + "emojis-list": "2.1.0", + "json5": "0.5.1", + "object-assign": "4.1.1" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "2.0.0", + "path-exists": "3.0.0" + }, + "dependencies": { + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, + "lodash": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.2.tgz", + "integrity": "sha1-NKMFW6vgTOQkZ7YH1wAHLH/2v0I=" + }, + "lodash-es": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.4.tgz", + "integrity": "sha1-3MHXVS4VCgZABzupyzHXDwMpUOc=" + }, + "lodash._baseassign": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", + "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", + "dev": true, + "requires": { + "lodash._basecopy": "3.0.1", + "lodash.keys": "3.1.2" + } + }, + "lodash._basecopy": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=" + }, + "lodash._basecreate": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz", + "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=", + "dev": true + }, + "lodash._basetostring": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", + "integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=" + }, + "lodash._basevalues": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", + "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=" + }, + "lodash._getnative": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=" + }, + "lodash._isiterateecall": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", + "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=" + }, + "lodash._reescape": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", + "integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=" + }, + "lodash._reevaluate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", + "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=" + }, + "lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=" + }, + "lodash._root": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", + "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=" + }, + "lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=" + }, + "lodash.assignin": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz", + "integrity": "sha1-uo31+4QesKPoBEIysOJjqNxqKKI=", + "dev": true + }, + "lodash.bind": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz", + "integrity": "sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU=", + "dev": true + }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=", + "dev": true + }, + "lodash.create": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", + "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", + "dev": true, + "requires": { + "lodash._baseassign": "3.2.0", + "lodash._basecreate": "3.0.3", + "lodash._isiterateecall": "3.0.9" + } + }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" + }, + "lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=", + "dev": true + }, + "lodash.escape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", + "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", + "requires": { + "lodash._root": "3.0.1" + } + }, + "lodash.filter": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.filter/-/lodash.filter-4.6.0.tgz", + "integrity": "sha1-ZosdSYFgOuHMWm+nYBQ+SAtMSs4=", + "dev": true + }, + "lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=", + "dev": true + }, + "lodash.foreach": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz", + "integrity": "sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM=", + "dev": true + }, + "lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=" + }, + "lodash.isarray": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=" + }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "requires": { + "lodash._getnative": "3.9.1", + "lodash.isarguments": "3.1.0", + "lodash.isarray": "3.0.4" + } + }, + "lodash.map": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", + "integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=", + "dev": true + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, + "lodash.merge": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.0.tgz", + "integrity": "sha1-aYhLoUSsM/5plzemCG3v+t0PicU=" + }, + "lodash.pad": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/lodash.pad/-/lodash.pad-4.5.1.tgz", + "integrity": "sha1-QzCUmoM6fI2iLMIPaibE1Z3runA=" + }, + "lodash.padend": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.padend/-/lodash.padend-4.6.1.tgz", + "integrity": "sha1-U8y6BH0G4VjTEfRdpiX05J5vFm4=" + }, + "lodash.padstart": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.padstart/-/lodash.padstart-4.6.1.tgz", + "integrity": "sha1-0uPuv/DZ05rVD1y9G1KnvOa7YRs=" + }, + "lodash.pick": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", + "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=", + "dev": true + }, + "lodash.pickby": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz", + "integrity": "sha1-feoh2MGNdwOifHBMFdO4SmfjOv8=", + "dev": true + }, + "lodash.reduce": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz", + "integrity": "sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs=", + "dev": true + }, + "lodash.reject": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.reject/-/lodash.reject-4.6.0.tgz", + "integrity": "sha1-gNZJLcFHCGS79YNTO2UfQqn1JBU=", + "dev": true + }, + "lodash.restparam": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", + "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=" + }, + "lodash.some": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz", + "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=", + "dev": true + }, + "lodash.template": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", + "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", + "requires": { + "lodash._basecopy": "3.0.1", + "lodash._basetostring": "3.0.1", + "lodash._basevalues": "3.0.0", + "lodash._isiterateecall": "3.0.9", + "lodash._reinterpolate": "3.0.0", + "lodash.escape": "3.2.0", + "lodash.keys": "3.1.2", + "lodash.restparam": "3.6.1", + "lodash.templatesettings": "3.1.1" + } + }, + "lodash.templatesettings": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", + "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", + "requires": { + "lodash._reinterpolate": "3.0.0", + "lodash.escape": "3.2.0" + } + }, + "lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=" + }, + "lodash.toarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", + "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=" + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", + "dev": true + }, + "log-driver": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.5.tgz", + "integrity": "sha1-euTsJXMC/XkNVXyxDJcQDYV7AFY=", + "dev": true + }, + "log-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", + "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", + "dev": true, + "requires": { + "chalk": "1.1.3" + } + }, + "logalot": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/logalot/-/logalot-2.1.0.tgz", + "integrity": "sha1-X46MkNME7fElMJUaVVSruMXj9VI=", + "dev": true, + "requires": { + "figures": "1.7.0", + "squeak": "1.3.0" + }, + "dependencies": { + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true, + "requires": { + "escape-string-regexp": "1.0.5", + "object-assign": "4.1.1" + } + } + } + }, + "loglevel": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.4.1.tgz", + "integrity": "sha1-lbOD+Ro8J1b9SrCTZn5DCRYfK80=" + }, + "lolex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.3.2.tgz", + "integrity": "sha1-fD2mL/yzDw9agKJWbKJORdigHzE=", + "dev": true + }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=" + }, + "loose-envify": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", + "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", + "requires": { + "js-tokens": "3.0.2" + } + }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "requires": { + "currently-unhandled": "0.4.1", + "signal-exit": "3.0.2" + } + }, + "lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", + "dev": true + }, + "lowercase-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz", + "integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY=" + }, + "lpad-align": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/lpad-align/-/lpad-align-1.1.2.tgz", + "integrity": "sha1-IfYArBwwlcPG5JfuZyce4ISB/p4=", + "dev": true, + "requires": { + "get-stdin": "4.0.1", + "indent-string": "2.1.0", + "longest": "1.0.1", + "meow": "3.7.0" + }, + "dependencies": { + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "dev": true + } + } + }, + "lru-cache": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", + "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", + "dev": true, + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" + } + }, + "macaddress": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/macaddress/-/macaddress-0.2.8.tgz", + "integrity": "sha1-WQTcU3w57G2+/q6QIycTX6hRHxI=", + "dev": true + }, + "make-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.0.0.tgz", + "integrity": "sha1-l6ARdR6R3YfPre9Ygy67BJNt6Xg=", + "dev": true, + "requires": { + "pify": "2.3.0" + } + }, + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=" + }, + "markdown-loader": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-loader/-/markdown-loader-2.0.0.tgz", + "integrity": "sha1-Qhhi04xCJP02FetkgBfqOFtWLXg=", + "dev": true, + "requires": { + "loader-utils": "0.2.17", + "marked": "0.3.6" + } + }, + "marked": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.6.tgz", + "integrity": "sha1-ssbGGPzOzk74bE/Gy4p8v1rtqNc=" + }, + "material-ui": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/material-ui/-/material-ui-0.16.5.tgz", + "integrity": "sha1-u4ZhqsfKyMsiOj529PV+4YpK78E=", + "requires": { + "babel-runtime": "6.23.0", + "inline-style-prefixer": "2.0.5", + "keycode": "2.1.9", + "lodash.merge": "4.6.0", + "lodash.throttle": "4.1.1", + "react-addons-create-fragment": "15.6.0", + "react-addons-transition-group": "15.6.0", + "react-event-listener": "0.4.1", + "recompose": "0.20.2", + "simple-assign": "0.1.0", + "warning": "3.0.0" + } + }, + "material-ui-chip-input": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/material-ui-chip-input/-/material-ui-chip-input-0.11.1.tgz", + "integrity": "sha1-6Sssxcl0HNddaxgi8cd3GtTObBA=" + }, + "math-expression-evaluator": { + "version": "1.2.17", + "resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz", + "integrity": "sha1-3oGf282E3M2PrlnGrreWFbnSZqw=" + }, + "mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dev": true, + "requires": { + "errno": "0.1.4", + "readable-stream": "2.3.3" + } + }, + "memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=" + }, + "meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "requires": { + "camelcase-keys": "2.1.0", + "decamelize": "1.2.0", + "loud-rejection": "1.6.0", + "map-obj": "1.0.1", + "minimist": "1.2.0", + "normalize-package-data": "2.4.0", + "object-assign": "4.1.1", + "read-pkg-up": "1.0.1", + "redent": "1.0.0", + "trim-newlines": "1.0.0" + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", + "dev": true + }, + "merge-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz", + "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=", + "requires": { + "readable-stream": "2.3.3" + } + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "dev": true + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "requires": { + "arr-diff": "2.0.0", + "array-unique": "0.2.1", + "braces": "1.8.5", + "expand-brackets": "0.1.5", + "extglob": "0.3.2", + "filename-regex": "2.0.1", + "is-extglob": "1.0.0", + "is-glob": "2.0.1", + "kind-of": "3.2.2", + "normalize-path": "2.1.1", + "object.omit": "2.0.1", + "parse-glob": "3.0.4", + "regex-cache": "0.4.3" + }, + "dependencies": { + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "requires": { + "is-extglob": "1.0.0" + } + } + } + }, + "miller-rabin": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.0.tgz", + "integrity": "sha1-SmL7HUKTPAVYOYL0xxb2+55sbT0=", + "dev": true, + "requires": { + "bn.js": "4.11.7", + "brorand": "1.1.0" + } + }, + "mime": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz", + "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM=", + "dev": true + }, + "mime-db": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.29.0.tgz", + "integrity": "sha1-SNJtI1WJZRcErFkWygYAGRQmaHg=" + }, + "mime-types": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.16.tgz", + "integrity": "sha1-K4WKUuXs1RbbiXrCvodIeDBpjiM=", + "requires": { + "mime-db": "1.29.0" + } + }, + "mimic-fn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz", + "integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg=" + }, + "min-document": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", + "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", + "dev": true, + "requires": { + "dom-walk": "0.1.1" + } + }, + "minimalistic-assert": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz", + "integrity": "sha1-cCvi3aazf0g2vLP121ZkG2Sh09M=" + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "requires": { + "brace-expansion": "1.1.8" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + } + } + }, + "mobx": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/mobx/-/mobx-2.6.4.tgz", + "integrity": "sha1-4FqRpbLJfaw/2rNAJOa3Sn9DEas=" + }, + "mobx-react": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/mobx-react/-/mobx-react-4.0.3.tgz", + "integrity": "sha1-QOsx0l4LjWMEjtojdsxWv6vRT3U=", + "requires": { + "hoist-non-react-statics": "1.2.0" + } + }, + "mobx-react-devtools": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/mobx-react-devtools/-/mobx-react-devtools-4.2.10.tgz", + "integrity": "sha1-eSdL2NRLoE2VByhzihRFQfoqYBI=" + }, + "mocha": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-3.2.0.tgz", + "integrity": "sha1-fcT0XlCIB1FxpoiWgU5q6et6heM=", + "dev": true, + "requires": { + "browser-stdout": "1.3.0", + "commander": "2.9.0", + "debug": "2.2.0", + "diff": "1.4.0", + "escape-string-regexp": "1.0.5", + "glob": "7.0.5", + "growl": "1.9.2", + "json3": "3.3.2", + "lodash.create": "3.1.1", + "mkdirp": "0.5.1", + "supports-color": "3.1.2" + }, + "dependencies": { + "commander": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "dev": true, + "requires": { + "graceful-readlink": "1.0.1" + } + }, + "debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true, + "requires": { + "ms": "0.7.1" + } + }, + "glob": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.5.tgz", + "integrity": "sha1-tCAqaQmbu00pKnwblbZoK2fr3JU=", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true + }, + "supports-color": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", + "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", + "dev": true, + "requires": { + "has-flag": "1.0.0" + } + } + } + }, + "mock-local-storage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mock-local-storage/-/mock-local-storage-1.0.2.tgz", + "integrity": "sha1-plplzdq0cHQz1Suk6fa2MIS4wpg=", + "dev": true, + "requires": { + "core-js": "0.8.4" + }, + "dependencies": { + "core-js": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-0.8.4.tgz", + "integrity": "sha1-wiZl8eDRucPF4bCNq9HxCGleT88=", + "dev": true + } + } + }, + "mock-socket": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/mock-socket/-/mock-socket-6.0.4.tgz", + "integrity": "sha1-hfWKCqg7wdtMp9FLQtj53WY+dWk=", + "dev": true + }, + "moment": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.17.0.tgz", + "integrity": "sha1-pMKS4CqsXd77Kabu0k9Rk43Tt08=" + }, + "mozjpeg": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/mozjpeg/-/mozjpeg-4.1.1.tgz", + "integrity": "sha1-hZAwsk9omlPbm0DwFg2JGVuI/VA=", + "dev": true, + "requires": { + "bin-build": "2.2.0", + "bin-wrapper": "3.0.2", + "logalot": "2.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "multimatch": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-2.1.0.tgz", + "integrity": "sha1-nHkGoi+0wCkZ4vX3UWG0zb1LKis=", + "dev": true, + "requires": { + "array-differ": "1.0.0", + "array-union": "1.0.2", + "arrify": "1.0.1", + "minimatch": "3.0.4" + } + }, + "multipipe": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", + "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=", + "requires": { + "duplexer2": "0.0.2" + }, + "dependencies": { + "duplexer2": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", + "requires": { + "readable-stream": "1.1.14" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" + }, + "nan": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.6.2.tgz", + "integrity": "sha1-5P805slf37WuzAjeZZb0NgWn20U=" + }, + "napa": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/napa/-/napa-2.3.0.tgz", + "integrity": "sha1-QZZUbRoLa7lPNwQgU8xd3XlzHlM=", + "requires": { + "download": "4.4.3", + "extend": "3.0.1", + "load-json-file": "1.1.0", + "minimist": "1.2.0", + "mkdirp": "0.5.1", + "npm-cache-filename": "1.0.2", + "npmlog": "2.0.4", + "rimraf": "2.6.1", + "tar-pack": "3.4.0", + "write-json-file": "1.2.0" + }, + "dependencies": { + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" + }, + "gauge": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-1.2.7.tgz", + "integrity": "sha1-6c7FSD09TuDvRLYKfZnkk14TbZM=", + "requires": { + "ansi": "0.3.1", + "has-unicode": "2.0.1", + "lodash.pad": "4.5.1", + "lodash.padend": "4.6.1", + "lodash.padstart": "4.6.1" + } + }, + "npmlog": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-2.0.4.tgz", + "integrity": "sha1-mLUlMPJRTKkNCexbIsiEZyI3VpI=", + "requires": { + "ansi": "0.3.1", + "are-we-there-yet": "1.1.4", + "gauge": "1.2.7" + } + } + } + }, + "native-promise-only": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz", + "integrity": "sha1-IKMYwwy0X3H+et+/eyHJnBRy7xE=", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "ncname": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ncname/-/ncname-1.0.0.tgz", + "integrity": "sha1-W1etGLHKCShk72Kwse2BlPODtxw=", + "dev": true, + "requires": { + "xml-char-classes": "1.0.0" + } + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", + "dev": true + }, + "no-case": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.1.tgz", + "integrity": "sha1-euuhxzpSGEJlVUt9wDuvcg34AIE=", + "dev": true, + "requires": { + "lower-case": "1.1.4" + } + }, + "nock": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/nock/-/nock-9.0.7.tgz", + "integrity": "sha1-zJNIG7FfOL7Co5xEQr4HglI1saE=", + "dev": true, + "requires": { + "chai": "3.5.0", + "debug": "2.6.8", + "deep-equal": "1.0.1", + "json-stringify-safe": "5.0.1", + "lodash": "4.17.2", + "mkdirp": "0.5.1", + "propagate": "0.4.0", + "qs": "6.3.0" + } + }, + "node-abi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.1.0.tgz", + "integrity": "sha512-AbW35CPRE4vdieOse46V+16dKispLNv3PQwgqlcfg7GQeQHcLu3gvp3fbU2gTh7d8NfGjp5CJh+j4Hpyb0XzaA==" + }, + "node-dir": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", + "integrity": "sha1-X1Zl2TNRM1yqvvjxxVRRbPXx5OU=", + "dev": true, + "requires": { + "minimatch": "3.0.4" + } + }, + "node-emoji": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.8.1.tgz", + "integrity": "sha512-+ktMAh1Jwas+TnGodfCfjUbJKoANqPaJFN0z0iqh41eqD8dvguNzcitVSBSVK1pidz0AqGbLKcoVuVLRVZ/aVg==", + "requires": { + "lodash.toarray": "4.4.0" + } + }, + "node-fetch": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.1.tgz", + "integrity": "sha512-j8XsFGCLw79vWXkZtMSmmLaOk9z5SQ9bV/tkbZVCqvgwzrjAGq66igobLofHtF63NvMTp2WjytpsNTGKa+XRIQ==", + "requires": { + "encoding": "0.1.12", + "is-stream": "1.1.0" + } + }, + "node-gyp": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.6.2.tgz", + "integrity": "sha1-m/vlRWIoYoSDjnUOrAUpWFP6HGA=", + "requires": { + "fstream": "1.0.11", + "glob": "7.1.2", + "graceful-fs": "4.1.11", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "nopt": "3.0.6", + "npmlog": "4.1.2", + "osenv": "0.1.4", + "request": "2.81.0", + "rimraf": "2.6.1", + "semver": "5.3.0", + "tar": "2.2.1", + "which": "1.2.14" + }, + "dependencies": { + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=" + } + } + }, + "node-libs-browser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.0.0.tgz", + "integrity": "sha1-o6WeyXAkmFtG6Vg3lkb5bEthZkY=", + "dev": true, + "requires": { + "assert": "1.4.1", + "browserify-zlib": "0.1.4", + "buffer": "4.9.1", + "console-browserify": "1.1.0", + "constants-browserify": "1.0.0", + "crypto-browserify": "3.11.1", + "domain-browser": "1.1.7", + "events": "1.1.1", + "https-browserify": "0.0.1", + "os-browserify": "0.2.1", + "path-browserify": "0.0.0", + "process": "0.11.10", + "punycode": "1.4.1", + "querystring-es3": "0.2.1", + "readable-stream": "2.3.3", + "stream-browserify": "2.0.1", + "stream-http": "2.7.2", + "string_decoder": "0.10.31", + "timers-browserify": "2.0.3", + "tty-browserify": "0.0.0", + "url": "0.11.0", + "util": "0.10.3", + "vm-browserify": "0.0.4" + }, + "dependencies": { + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + } + } + }, + "node-status-codes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-status-codes/-/node-status-codes-1.0.0.tgz", + "integrity": "sha1-WuVUHQJGRdMqWPzdyc7s6nrjrC8=" + }, + "noop-logger": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", + "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=" + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "requires": { + "abbrev": "1.1.0" + } + }, + "normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "requires": { + "hosted-git-info": "2.5.0", + "is-builtin-module": "1.0.0", + "semver": "5.4.1", + "validate-npm-package-license": "3.0.1" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "requires": { + "remove-trailing-separator": "1.0.2" + } + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "dev": true + }, + "normalize-selector": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/normalize-selector/-/normalize-selector-0.2.0.tgz", + "integrity": "sha1-0LFF62kRicY6eNIB3E/bEpPvDAM=", + "dev": true + }, + "normalize-url": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz", + "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=", + "dev": true, + "requires": { + "object-assign": "4.1.1", + "prepend-http": "1.0.4", + "query-string": "4.3.4", + "sort-keys": "1.1.2" + } + }, + "npm-cache-filename": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/npm-cache-filename/-/npm-cache-filename-1.0.2.tgz", + "integrity": "sha1-3tMGxbC/yHCp6fr4I7xfKD4FrhE=" + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "2.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "requires": { + "are-we-there-yet": "1.1.4", + "console-control-strings": "1.1.0", + "gauge": "2.7.4", + "set-blocking": "2.0.0" + } + }, + "nth-check": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz", + "integrity": "sha1-mSms32KPwsQQmN6rgqxYDPFJquQ=", + "dev": true, + "requires": { + "boolbase": "1.0.0" + } + }, + "num2fraction": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", + "dev": true + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "nwmatcher": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.4.1.tgz", + "integrity": "sha1-eumwew6oBNt+JfBctf5Al9TklJ8=", + "dev": true + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-is": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.1.tgz", + "integrity": "sha1-CqYOyZiaCz7Xlc9NBvYs8a1lObY=", + "dev": true + }, + "object-keys": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", + "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=", + "dev": true + }, + "object-path": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.11.4.tgz", + "integrity": "sha1-NwrnUvvzfePqcKhhwju6iRVpGUk=" + }, + "object.assign": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.0.4.tgz", + "integrity": "sha1-scnMBE7xuf5jYG/BQau7MuFHMMw=", + "dev": true, + "requires": { + "define-properties": "1.1.2", + "function-bind": "1.1.0", + "object-keys": "1.0.11" + } + }, + "object.entries": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.0.4.tgz", + "integrity": "sha1-G/mk3SKI9bM/Opk9JXZh8F0WGl8=", + "dev": true, + "requires": { + "define-properties": "1.1.2", + "es-abstract": "1.7.0", + "function-bind": "1.1.0", + "has": "1.0.1" + } + }, + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "requires": { + "for-own": "0.1.5", + "is-extendable": "0.1.1" + } + }, + "object.values": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.0.4.tgz", + "integrity": "sha1-5STaCbT2b/Bd9FdUbscqyZ8TBpo=", + "dev": true, + "requires": { + "define-properties": "1.1.2", + "es-abstract": "1.7.0", + "function-bind": "1.1.0", + "has": "1.0.1" + } + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1.0.2" + } + }, + "onecolor": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/onecolor/-/onecolor-3.0.4.tgz", + "integrity": "sha1-daRvgNpseqpbTarhekcZi9llJJQ=", + "dev": true + }, + "onetime": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", + "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=" + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "0.0.10", + "wordwrap": "0.0.2" + }, + "dependencies": { + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", + "dev": true + } + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" + }, + "dependencies": { + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + } + } + }, + "optipng-bin": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/optipng-bin/-/optipng-bin-3.1.4.tgz", + "integrity": "sha1-ldNPLEiHBPb9cGBr/qDGWfHZXYQ=", + "dev": true, + "requires": { + "bin-build": "2.2.0", + "bin-wrapper": "3.0.2", + "logalot": "2.1.0" + } + }, + "ordered-read-streams": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.3.0.tgz", + "integrity": "sha1-cTfmmzKYuzQiR6G77jiByA4v14s=", + "requires": { + "is-stream": "1.1.0", + "readable-stream": "2.3.3" + } + }, + "os-browserify": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.2.1.tgz", + "integrity": "sha1-Y/xMzuXS13Y9Jrv4YBB45sLgBE8=", + "dev": true + }, + "os-filter-obj": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/os-filter-obj/-/os-filter-obj-1.0.3.tgz", + "integrity": "sha1-WRUzDZDs7VV9LZOKMcbdIU2cY60=", + "dev": true + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "requires": { + "lcid": "1.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "osenv": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz", + "integrity": "sha1-Qv5tWVPfBsgGS+bxdsPQWqqjRkQ=", + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, + "output-file-sync": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/output-file-sync/-/output-file-sync-1.1.2.tgz", + "integrity": "sha1-0KM+7+YaIF+suQCS6CZZjVJFznY=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "mkdirp": "0.5.1", + "object-assign": "4.1.1" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-limit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.1.0.tgz", + "integrity": "sha1-sH/y2aXYi+yAYDWJWiurZqJ5iLw=", + "dev": true + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "1.1.0" + } + }, + "p-pipe": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/p-pipe/-/p-pipe-1.2.0.tgz", + "integrity": "sha1-SxoROZoRUgpneQ7loMHViB1r7+k=", + "dev": true + }, + "pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=", + "dev": true + }, + "param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", + "dev": true, + "requires": { + "no-case": "2.3.1" + } + }, + "parse-asn1": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.0.tgz", + "integrity": "sha1-N8T5t+06tlx0gXtfJICTf7+XxxI=", + "dev": true, + "requires": { + "asn1.js": "4.9.1", + "browserify-aes": "1.0.6", + "create-hash": "1.1.3", + "evp_bytestokey": "1.0.0", + "pbkdf2": "3.0.12" + } + }, + "parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "requires": { + "glob-base": "0.3.0", + "is-dotfile": "1.0.3", + "is-extglob": "1.0.0", + "is-glob": "2.0.1" + }, + "dependencies": { + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "requires": { + "is-extglob": "1.0.0" + } + } + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "requires": { + "error-ex": "1.3.1" + } + }, + "parse5": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz", + "integrity": "sha1-m387DeMr543CQBsXVzzK8Pb1nZQ=", + "dev": true + }, + "parseurl": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.1.tgz", + "integrity": "sha1-yKuMkiO6NIiKpkopeyiFO+wY2lY=", + "dev": true + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" + }, + "path-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", + "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=" + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "requires": { + "pinkie-promise": "2.0.1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", + "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", + "dev": true + }, + "path-to-regexp": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", + "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", + "requires": { + "isarray": "0.0.1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + } + } + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "requires": { + "graceful-fs": "4.1.11", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "pbkdf2": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.12.tgz", + "integrity": "sha1-vjZ4XFBn6kjYBv+SMojF91C2uKI=", + "dev": true, + "requires": { + "create-hash": "1.1.3", + "create-hmac": "1.1.6", + "ripemd160": "2.0.1", + "safe-buffer": "5.1.1", + "sha.js": "2.4.8" + } + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "phoneformat.js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/phoneformat.js/-/phoneformat.js-1.0.3.tgz", + "integrity": "sha1-Eb40dOdkdFQP43NMwz8aZYQdX4c=" + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "requires": { + "pinkie": "2.0.4" + } + }, + "pipetteur": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pipetteur/-/pipetteur-2.0.3.tgz", + "integrity": "sha1-GVV2CVno0aEcsqUOyD7sRwYz5J8=", + "dev": true, + "requires": { + "onecolor": "3.0.4", + "synesthesia": "1.0.1" + } + }, + "pixrem": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pixrem/-/pixrem-3.0.2.tgz", + "integrity": "sha1-MNG6+0w73Ojpu0vVahOYVhkyDDQ=", + "dev": true, + "requires": { + "browserslist": "1.7.7", + "postcss": "5.2.17", + "reduce-css-calc": "1.3.0" + } + }, + "pkg-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", + "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", + "dev": true, + "requires": { + "find-up": "1.1.2" + } + }, + "plur": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/plur/-/plur-2.1.2.tgz", + "integrity": "sha1-dIJFLBoPUI4+NE6uwxLJHCncZVo=", + "dev": true, + "requires": { + "irregular-plurals": "1.3.0" + } + }, + "pluralize": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz", + "integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=", + "dev": true + }, + "pngquant-bin": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/pngquant-bin/-/pngquant-bin-3.1.1.tgz", + "integrity": "sha1-0STZinWpSH9AwWQLTb/Lsr1aH9E=", + "dev": true, + "requires": { + "bin-build": "2.2.0", + "bin-wrapper": "3.0.2", + "logalot": "2.1.0" + } + }, + "postcss": { + "version": "5.2.17", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.17.tgz", + "integrity": "sha1-z09Ze4ZNZcikkrLqvp1wbIecOIs=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "js-base64": "2.1.9", + "source-map": "0.5.6", + "supports-color": "3.2.3" + }, + "dependencies": { + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "1.0.0" + } + } + } + }, + "postcss-alias": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postcss-alias/-/postcss-alias-1.0.0.tgz", + "integrity": "sha1-Bwxh7hGXr27l63XSat9IiZudL3s=", + "dev": true, + "requires": { + "postcss": "5.2.17" + } + }, + "postcss-calc": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-5.3.1.tgz", + "integrity": "sha1-d7rnypKK2FcW4v2kLyYb98HWW14=", + "dev": true, + "requires": { + "postcss": "5.2.17", + "postcss-message-helpers": "2.0.0", + "reduce-css-calc": "1.3.0" + } + }, + "postcss-clearfix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postcss-clearfix/-/postcss-clearfix-1.0.0.tgz", + "integrity": "sha1-r+xqDgHSXaw2pUrbif/Uv+HSGa8=", + "dev": true, + "requires": { + "postcss": "5.2.17" + } + }, + "postcss-color-rgba-fallback": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/postcss-color-rgba-fallback/-/postcss-color-rgba-fallback-2.2.0.tgz", + "integrity": "sha1-bSlJG+WZCpMXPUfnx29YELCUAro=", + "dev": true, + "requires": { + "postcss": "5.2.17", + "postcss-value-parser": "3.3.0", + "rgb-hex": "1.0.0" + } + }, + "postcss-colormin": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-2.2.2.tgz", + "integrity": "sha1-ZjFBfV8OkJo9fsJrJMio0eT5bks=", + "dev": true, + "requires": { + "colormin": "1.1.2", + "postcss": "5.2.17", + "postcss-value-parser": "3.3.0" + } + }, + "postcss-convert-values": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz", + "integrity": "sha1-u9hZPFwf0uPRwyK7kl3K6Nrk1i0=", + "dev": true, + "requires": { + "postcss": "5.2.17", + "postcss-value-parser": "3.3.0" + } + }, + "postcss-discard-comments": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz", + "integrity": "sha1-vv6J+v1bPazlzM5Rt2uBUUvgDj0=", + "dev": true, + "requires": { + "postcss": "5.2.17" + } + }, + "postcss-discard-duplicates": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-2.1.0.tgz", + "integrity": "sha1-uavye4isGIFYpesSq8riAmO5GTI=", + "dev": true, + "requires": { + "postcss": "5.2.17" + } + }, + "postcss-discard-empty": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz", + "integrity": "sha1-0rS9nVztXr2Nyt52QMfXzX9PkrU=", + "dev": true, + "requires": { + "postcss": "5.2.17" + } + }, + "postcss-discard-overridden": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz", + "integrity": "sha1-ix6vVU9ob7KIzYdMVWZ7CqNmjVg=", + "dev": true, + "requires": { + "postcss": "5.2.17" + } + }, + "postcss-discard-unused": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz", + "integrity": "sha1-vOMLLMWR/8Y0Mitfs0ZLbZNPRDM=", + "dev": true, + "requires": { + "postcss": "5.2.17", + "uniqs": "2.0.0" + } + }, + "postcss-easings": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/postcss-easings/-/postcss-easings-0.3.0.tgz", + "integrity": "sha1-I9zL+XWH4o1doZw7rktQaYxarV4=", + "dev": true, + "requires": { + "postcss": "5.2.17" + } + }, + "postcss-filter-plugins": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/postcss-filter-plugins/-/postcss-filter-plugins-2.0.2.tgz", + "integrity": "sha1-bYWGJTTXNaxCDkqFgG4fXUKG2Ew=", + "dev": true, + "requires": { + "postcss": "5.2.17", + "uniqid": "4.1.1" + } + }, + "postcss-fontpath": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/postcss-fontpath/-/postcss-fontpath-0.3.0.tgz", + "integrity": "sha1-KBQqed0Y8snwv1yH96PreUxTkp4=", + "dev": true, + "requires": { + "object-assign": "4.1.1", + "postcss": "5.2.17" + } + }, + "postcss-hexrgba": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/postcss-hexrgba/-/postcss-hexrgba-0.2.1.tgz", + "integrity": "sha1-XGGrukOcCjjknn+8CzzZNhGewiU=", + "dev": true, + "requires": { + "postcss": "5.2.17" + } + }, + "postcss-import": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-9.1.0.tgz", + "integrity": "sha1-lf6YdqHnmvSfvcNYnwH+WqfMHoA=", + "dev": true, + "requires": { + "object-assign": "4.1.1", + "postcss": "5.2.17", + "postcss-value-parser": "3.3.0", + "promise-each": "2.2.0", + "read-cache": "1.0.0", + "resolve": "1.4.0" + } + }, + "postcss-input-style": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/postcss-input-style/-/postcss-input-style-0.3.0.tgz", + "integrity": "sha1-47T9sKpEG+0ZMMu0TYrVY0zzhUA=", + "dev": true, + "requires": { + "postcss": "5.2.17" + } + }, + "postcss-less": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/postcss-less/-/postcss-less-0.14.0.tgz", + "integrity": "sha1-xjGwicbM5CK5oQ86lY0r7dOBkyQ=", + "dev": true, + "requires": { + "postcss": "5.2.17" + } + }, + "postcss-load-config": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-1.2.0.tgz", + "integrity": "sha1-U56a/J3chiASHr+djDZz4M5Q0oo=", + "dev": true, + "requires": { + "cosmiconfig": "2.2.2", + "object-assign": "4.1.1", + "postcss-load-options": "1.2.0", + "postcss-load-plugins": "2.3.0" + } + }, + "postcss-load-options": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postcss-load-options/-/postcss-load-options-1.2.0.tgz", + "integrity": "sha1-sJixVZ3awt8EvAuzdfmaXP4rbYw=", + "dev": true, + "requires": { + "cosmiconfig": "2.2.2", + "object-assign": "4.1.1" + } + }, + "postcss-load-plugins": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/postcss-load-plugins/-/postcss-load-plugins-2.3.0.tgz", + "integrity": "sha1-dFdoEWWZrKLwCfrUJrABdQSdjZI=", + "dev": true, + "requires": { + "cosmiconfig": "2.2.2", + "object-assign": "4.1.1" + } + }, + "postcss-loader": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-1.3.2.tgz", + "integrity": "sha1-xWi2HC5I4nThwiSiWH+1ZvTsJvU=", + "dev": true, + "requires": { + "loader-utils": "1.1.0", + "object-assign": "4.1.1", + "postcss": "5.2.17", + "postcss-load-config": "1.2.0" + }, + "dependencies": { + "loader-utils": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", + "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", + "dev": true, + "requires": { + "big.js": "3.1.3", + "emojis-list": "2.1.0", + "json5": "0.5.1" + } + } + } + }, + "postcss-media-query-parser": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", + "integrity": "sha1-J7Ocb02U+Bsac7j3Y1HGCeXO8kQ=", + "dev": true + }, + "postcss-merge-idents": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz", + "integrity": "sha1-TFUwMTwI4dWzu/PSu8dH4njuonA=", + "dev": true, + "requires": { + "has": "1.0.1", + "postcss": "5.2.17", + "postcss-value-parser": "3.3.0" + } + }, + "postcss-merge-longhand": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz", + "integrity": "sha1-I9kM0Sewp3mUkVMyc5A0oaTz1lg=", + "dev": true, + "requires": { + "postcss": "5.2.17" + } + }, + "postcss-merge-rules": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz", + "integrity": "sha1-0d9d+qexrMO+VT8OnhDofGG19yE=", + "dev": true, + "requires": { + "browserslist": "1.7.7", + "caniuse-api": "1.6.1", + "postcss": "5.2.17", + "postcss-selector-parser": "2.2.3", + "vendors": "1.0.1" + } + }, + "postcss-message-helpers": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz", + "integrity": "sha1-pPL0+rbk/gAvCu0ABHjN9S+bpg4=", + "dev": true + }, + "postcss-minify-font-values": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz", + "integrity": "sha1-S1jttWZB66fIR0qzUmyv17vey2k=", + "dev": true, + "requires": { + "object-assign": "4.1.1", + "postcss": "5.2.17", + "postcss-value-parser": "3.3.0" + } + }, + "postcss-minify-gradients": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz", + "integrity": "sha1-Xb2hE3NwP4PPtKPqOIHY11/15uE=", + "dev": true, + "requires": { + "postcss": "5.2.17", + "postcss-value-parser": "3.3.0" + } + }, + "postcss-minify-params": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz", + "integrity": "sha1-rSzgcTc7lDs9kwo/pZo1jCjW8fM=", + "dev": true, + "requires": { + "alphanum-sort": "1.0.2", + "postcss": "5.2.17", + "postcss-value-parser": "3.3.0", + "uniqs": "2.0.0" + } + }, + "postcss-minify-selectors": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz", + "integrity": "sha1-ssapjAByz5G5MtGkllCBFDEXNb8=", + "dev": true, + "requires": { + "alphanum-sort": "1.0.2", + "has": "1.0.1", + "postcss": "5.2.17", + "postcss-selector-parser": "2.2.3" + } + }, + "postcss-modules-extract-imports": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.1.0.tgz", + "integrity": "sha1-thTJcgvmgW6u41+zpfqh26agXds=", + "dev": true, + "requires": { + "postcss": "6.0.8" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.0.1.tgz", + "integrity": "sha512-Mp+FXEI+FrwY/XYV45b2YD3E8i3HwnEAoFcM0qlZzq/RZ9RwWitt2Y/c7cqRAz70U7hfekqx6qNYthuKFO6K0g==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.2.1" + } + }, + "postcss": { + "version": "6.0.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.8.tgz", + "integrity": "sha512-G6WnRmdTt2jvJvY+aY+M0AO4YlbxE+slKPZb+jG2P2U9Tyxi3h1fYZ/DgiFU6DC6bv3XIEJoZt+f/kNh8BrWFw==", + "dev": true, + "requires": { + "chalk": "2.0.1", + "source-map": "0.5.6", + "supports-color": "4.2.1" + } + }, + "supports-color": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.2.1.tgz", + "integrity": "sha512-qxzYsob3yv6U+xMzPrv170y8AwGP7i74g+pbixCfD6rgso8BscLT2qXIuz6TpOaiJZ3mFgT5O9lyT9nMU4LfaA==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-modules-local-by-default": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz", + "integrity": "sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk=", + "dev": true, + "requires": { + "css-selector-tokenizer": "0.7.0", + "postcss": "6.0.8" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.0.1.tgz", + "integrity": "sha512-Mp+FXEI+FrwY/XYV45b2YD3E8i3HwnEAoFcM0qlZzq/RZ9RwWitt2Y/c7cqRAz70U7hfekqx6qNYthuKFO6K0g==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.2.1" + } + }, + "postcss": { + "version": "6.0.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.8.tgz", + "integrity": "sha512-G6WnRmdTt2jvJvY+aY+M0AO4YlbxE+slKPZb+jG2P2U9Tyxi3h1fYZ/DgiFU6DC6bv3XIEJoZt+f/kNh8BrWFw==", + "dev": true, + "requires": { + "chalk": "2.0.1", + "source-map": "0.5.6", + "supports-color": "4.2.1" + } + }, + "supports-color": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.2.1.tgz", + "integrity": "sha512-qxzYsob3yv6U+xMzPrv170y8AwGP7i74g+pbixCfD6rgso8BscLT2qXIuz6TpOaiJZ3mFgT5O9lyT9nMU4LfaA==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-modules-scope": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz", + "integrity": "sha1-1upkmUx5+XtipytCb75gVqGUu5A=", + "dev": true, + "requires": { + "css-selector-tokenizer": "0.7.0", + "postcss": "6.0.8" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.0.1.tgz", + "integrity": "sha512-Mp+FXEI+FrwY/XYV45b2YD3E8i3HwnEAoFcM0qlZzq/RZ9RwWitt2Y/c7cqRAz70U7hfekqx6qNYthuKFO6K0g==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.2.1" + } + }, + "postcss": { + "version": "6.0.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.8.tgz", + "integrity": "sha512-G6WnRmdTt2jvJvY+aY+M0AO4YlbxE+slKPZb+jG2P2U9Tyxi3h1fYZ/DgiFU6DC6bv3XIEJoZt+f/kNh8BrWFw==", + "dev": true, + "requires": { + "chalk": "2.0.1", + "source-map": "0.5.6", + "supports-color": "4.2.1" + } + }, + "supports-color": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.2.1.tgz", + "integrity": "sha512-qxzYsob3yv6U+xMzPrv170y8AwGP7i74g+pbixCfD6rgso8BscLT2qXIuz6TpOaiJZ3mFgT5O9lyT9nMU4LfaA==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-modules-values": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz", + "integrity": "sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA=", + "dev": true, + "requires": { + "icss-replace-symbols": "1.1.0", + "postcss": "6.0.8" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.0.1.tgz", + "integrity": "sha512-Mp+FXEI+FrwY/XYV45b2YD3E8i3HwnEAoFcM0qlZzq/RZ9RwWitt2Y/c7cqRAz70U7hfekqx6qNYthuKFO6K0g==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.2.1" + } + }, + "postcss": { + "version": "6.0.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.8.tgz", + "integrity": "sha512-G6WnRmdTt2jvJvY+aY+M0AO4YlbxE+slKPZb+jG2P2U9Tyxi3h1fYZ/DgiFU6DC6bv3XIEJoZt+f/kNh8BrWFw==", + "dev": true, + "requires": { + "chalk": "2.0.1", + "source-map": "0.5.6", + "supports-color": "4.2.1" + } + }, + "supports-color": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.2.1.tgz", + "integrity": "sha512-qxzYsob3yv6U+xMzPrv170y8AwGP7i74g+pbixCfD6rgso8BscLT2qXIuz6TpOaiJZ3mFgT5O9lyT9nMU4LfaA==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-nested": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-1.0.0.tgz", + "integrity": "sha1-0Ta9S1dr1WMt8ULBKyGYqcz3lN8=", + "dev": true, + "requires": { + "postcss": "5.2.17" + } + }, + "postcss-normalize-charset": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz", + "integrity": "sha1-757nEhLX/nWceO0WL2HtYrXLk/E=", + "dev": true, + "requires": { + "postcss": "5.2.17" + } + }, + "postcss-normalize-url": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz", + "integrity": "sha1-EI90s/L82viRov+j6kWSJ5/HgiI=", + "dev": true, + "requires": { + "is-absolute-url": "2.1.0", + "normalize-url": "1.9.1", + "postcss": "5.2.17", + "postcss-value-parser": "3.3.0" + } + }, + "postcss-opacity": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-opacity/-/postcss-opacity-4.0.0.tgz", + "integrity": "sha1-qlYgQ9ozlMlKOs7c9D8MMj0JhqE=", + "dev": true, + "requires": { + "postcss": "5.2.17" + } + }, + "postcss-ordered-values": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz", + "integrity": "sha1-7sbCpntsQSqNsgQud/6NpD+VwR0=", + "dev": true, + "requires": { + "postcss": "5.2.17", + "postcss-value-parser": "3.3.0" + } + }, + "postcss-position": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/postcss-position/-/postcss-position-0.5.0.tgz", + "integrity": "sha1-hlPU8LhP+wflRPt/fq4IxlUbc6A=", + "dev": true, + "requires": { + "postcss": "5.2.17" + } + }, + "postcss-pseudoelements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-pseudoelements/-/postcss-pseudoelements-3.0.0.tgz", + "integrity": "sha1-bGghd8eQC6BTtt8X+MWQKEx7i7w=", + "dev": true, + "requires": { + "postcss": "5.2.17" + } + }, + "postcss-quantity-queries": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/postcss-quantity-queries/-/postcss-quantity-queries-0.4.0.tgz", + "integrity": "sha1-vhNwp76TEqFzY5wIaapCECRPhs4=", + "dev": true, + "requires": { + "balanced-match": "0.2.1", + "postcss": "5.2.17" + }, + "dependencies": { + "balanced-match": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.2.1.tgz", + "integrity": "sha1-e8ZYtL7WHu5CStdPdfXD4sTfPMc=", + "dev": true + } + } + }, + "postcss-reduce-idents": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz", + "integrity": "sha1-wsbSDMlYKE9qv75j92Cb9AkFmtM=", + "dev": true, + "requires": { + "postcss": "5.2.17", + "postcss-value-parser": "3.3.0" + } + }, + "postcss-reduce-initial": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz", + "integrity": "sha1-aPgGlfBF0IJjqHmtJA343WT2ROo=", + "dev": true, + "requires": { + "postcss": "5.2.17" + } + }, + "postcss-reduce-transforms": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz", + "integrity": "sha1-/3b02CEkN7McKYpC0uFEQCV3GuE=", + "dev": true, + "requires": { + "has": "1.0.1", + "postcss": "5.2.17", + "postcss-value-parser": "3.3.0" + } + }, + "postcss-reporter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-2.0.0.tgz", + "integrity": "sha1-0l50un/OkR4qpy7BrlkvrebsNnE=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "lodash": "4.17.2", + "log-symbols": "1.0.2", + "postcss": "5.2.17" + } + }, + "postcss-resolve-nested-selector": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz", + "integrity": "sha1-Kcy8fDfe36wwTp//C/FZaz9qDk4=", + "dev": true + }, + "postcss-responsive-type": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/postcss-responsive-type/-/postcss-responsive-type-0.5.1.tgz", + "integrity": "sha1-J0EzvARjWeVCpYu8YhhH0ED9EOY=", + "dev": true, + "requires": { + "postcss": "5.2.17" + } + }, + "postcss-scss": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-0.4.1.tgz", + "integrity": "sha1-rXcbgfD3L19IRdCKpg+TVXZT1Uw=", + "dev": true, + "requires": { + "postcss": "5.2.17" + } + }, + "postcss-selector-parser": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz", + "integrity": "sha1-+UN3iGBsPJrO4W/+jYsWKX8nu5A=", + "dev": true, + "requires": { + "flatten": "1.0.2", + "indexes-of": "1.0.1", + "uniq": "1.0.1" + } + }, + "postcss-simple-vars": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-simple-vars/-/postcss-simple-vars-3.0.0.tgz", + "integrity": "sha1-H6TMtLcVHZ8NUvuOoZoVwTGVmdY=", + "dev": true, + "requires": { + "postcss": "5.2.17" + } + }, + "postcss-svgo": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-2.1.6.tgz", + "integrity": "sha1-tt8YqmE7Zm4TPwittSGcJoSsEI0=", + "dev": true, + "requires": { + "is-svg": "2.1.0", + "postcss": "5.2.17", + "postcss-value-parser": "3.3.0", + "svgo": "0.7.2" + } + }, + "postcss-unique-selectors": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz", + "integrity": "sha1-mB1X0p3csz57Hf4f1DuGSfkzyh0=", + "dev": true, + "requires": { + "alphanum-sort": "1.0.2", + "postcss": "5.2.17", + "uniqs": "2.0.0" + } + }, + "postcss-value-parser": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz", + "integrity": "sha1-h/OPnxj3dKSrTIojL1xc6IcqnRU=", + "dev": true + }, + "postcss-vmin": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-vmin/-/postcss-vmin-2.0.0.tgz", + "integrity": "sha1-UyfCEZE3ElaGj9enOZF/FHTVf+4=", + "dev": true, + "requires": { + "postcss": "5.2.17" + } + }, + "postcss-will-change": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/postcss-will-change/-/postcss-will-change-1.1.0.tgz", + "integrity": "sha1-plHdWoHoLEEtOabPkKkrsyaa8Yw=", + "dev": true, + "requires": { + "postcss": "5.2.17" + } + }, + "postcss-zindex": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-2.2.0.tgz", + "integrity": "sha1-0hCd3AVbka9n/EyzsCWUZjnSryI=", + "dev": true, + "requires": { + "has": "1.0.1", + "postcss": "5.2.17", + "uniqs": "2.0.0" + } + }, + "prebuild-install": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-2.2.1.tgz", + "integrity": "sha512-y/sgNJ49vjXQ3qYdSI/jTRZq6D7g5Q2euK6x0/L8dvwK1EGvNLidtg2t4PZzTgkR6LahkzpYVshOmHKYtp0AlQ==", + "requires": { + "expand-template": "1.0.3", + "github-from-package": "0.0.0", + "minimist": "1.2.0", + "mkdirp": "0.5.1", + "node-abi": "2.1.0", + "noop-logger": "0.1.1", + "npmlog": "4.1.2", + "os-homedir": "1.0.2", + "pump": "1.0.2", + "rc": "1.2.1", + "simple-get": "1.4.3", + "tar-fs": "1.15.3", + "tunnel-agent": "0.6.0", + "xtend": "4.0.1" + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" + }, + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=" + }, + "pretty-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.1.tgz", + "integrity": "sha1-X0+HyPkeWuPzuoerTPXgOxoX8aM=", + "dev": true, + "requires": { + "renderkid": "2.0.1", + "utila": "0.4.0" + } + }, + "private": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.7.tgz", + "integrity": "sha1-aM5eih7woju1cMwoU3tTMqumPvE=" + }, + "process": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz", + "integrity": "sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8=", + "dev": true + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" + }, + "progress": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", + "dev": true + }, + "progress-bar-webpack-plugin": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/progress-bar-webpack-plugin/-/progress-bar-webpack-plugin-1.9.3.tgz", + "integrity": "sha1-gfuL2OONpu2vmiC+7Xm9l43WPCo=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "object.assign": "4.0.4", + "progress": "1.1.8" + } + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "requires": { + "asap": "2.0.6" + } + }, + "promise-each": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/promise-each/-/promise-each-2.2.0.tgz", + "integrity": "sha1-M1MXTv8mlEgQN+BOAfd6oPttG2A=", + "dev": true, + "requires": { + "any-promise": "0.1.0" + } + }, + "promise-worker": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/promise-worker/-/promise-worker-1.1.1.tgz", + "integrity": "sha1-wrddBF0kliXAImTi3/mtIuAxxps=", + "requires": { + "is-promise": "2.1.0", + "lie": "3.1.1" + } + }, + "prop-types": { + "version": "15.5.10", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.5.10.tgz", + "integrity": "sha1-J5ffwxJhguOpXj37suiT3ddFYVQ=", + "requires": { + "fbjs": "0.8.14", + "loose-envify": "1.3.1" + } + }, + "propagate": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/propagate/-/propagate-0.4.0.tgz", + "integrity": "sha1-8/zKCm/gZzanulcpZgaWF8EwtIE=", + "dev": true + }, + "proper-lockfile": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-2.0.1.tgz", + "integrity": "sha1-FZ+wYZPTIAP0s2kd0uwaY0qoDR0=", + "requires": { + "graceful-fs": "4.1.11", + "retry": "0.10.1" + } + }, + "proxy-addr": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.5.tgz", + "integrity": "sha1-ccDuOxAt4/IC87ZPYI0XP8uhqRg=", + "dev": true, + "requires": { + "forwarded": "0.1.0", + "ipaddr.js": "1.4.0" + } + }, + "prr": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/prr/-/prr-0.0.0.tgz", + "integrity": "sha1-GoS4WQgyVQFBGFPQCB7j+obikmo=", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "public-encrypt": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.0.tgz", + "integrity": "sha1-OfaZ86RlYN1eusvKaTyvfGXBjMY=", + "dev": true, + "requires": { + "bn.js": "4.11.7", + "browserify-rsa": "4.0.1", + "create-hash": "1.1.3", + "parse-asn1": "5.1.0", + "randombytes": "2.0.5" + } + }, + "pump": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.2.tgz", + "integrity": "sha1-Oz7mUS+U8OV1U4wXmV+fFpkKXVE=", + "requires": { + "end-of-stream": "1.4.0", + "once": "1.4.0" + } + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "push.js": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/push.js/-/push.js-0.0.11.tgz", + "integrity": "sha1-T606n5CEQhLiqmfQc6I9Rw4yqJE=" + }, + "q": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.0.tgz", + "integrity": "sha1-3QG6ydBtMObyGa7LglPunr3DCPE=", + "dev": true + }, + "qs": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.3.0.tgz", + "integrity": "sha1-9AOyZPI7wBIox0ExtAfxjV6l1EI=" + }, + "query-string": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", + "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", + "requires": { + "object-assign": "4.1.1", + "strict-uri-encode": "1.1.0" + } + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "dev": true + }, + "raf": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.3.2.tgz", + "integrity": "sha1-DBO+C1tJtG921maSSNUnzysC/ic=", + "requires": { + "performance-now": "2.1.0" + } + }, + "randomatic": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", + "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", + "requires": { + "is-number": "3.0.0", + "kind-of": "4.0.0" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "randombytes": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.5.tgz", + "integrity": "sha512-8T7Zn1AhMsQ/HI1SjcCfT/t4ii3eAqco3yOcSzS4mozsOz69lHLsoMXmF9nZgnFanYscnSlUSgs8uZyKzpE6kg==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", + "dev": true + }, + "raw-loader": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-0.5.1.tgz", + "integrity": "sha1-DD0L6u2KAclm2Xh793goElKpeao=", + "dev": true + }, + "rc": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.1.tgz", + "integrity": "sha1-LgPo5C7kULjLPc5lvhv4l04d/ZU=", + "requires": { + "deep-extend": "0.4.2", + "ini": "1.3.4", + "minimist": "1.2.0", + "strip-json-comments": "2.0.1" + } + }, + "react": { + "version": "15.4.2", + "resolved": "https://registry.npmjs.org/react/-/react-15.4.2.tgz", + "integrity": "sha1-QfeZGyYYU5K6m66WyIiefgGDl+8=", + "requires": { + "fbjs": "0.8.14", + "loose-envify": "1.3.1", + "object-assign": "4.1.1" + } + }, + "react-ace": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/react-ace/-/react-ace-4.1.0.tgz", + "integrity": "sha1-ZZ+qAQ0XP2DWqJQPCzJcXkIsq1Q=", + "requires": { + "brace": "0.8.0", + "lodash.isequal": "4.5.0" + }, + "dependencies": { + "brace": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/brace/-/brace-0.8.0.tgz", + "integrity": "sha1-6CbG1QVMrl9getexyBI23SzwGXg=", + "requires": { + "w3c-blob": "0.0.1" + } + } + } + }, + "react-addons-create-fragment": { + "version": "15.6.0", + "resolved": "https://registry.npmjs.org/react-addons-create-fragment/-/react-addons-create-fragment-15.6.0.tgz", + "integrity": "sha1-r5GiKx+wld0B8a+6Q7/Q71idiyA=", + "requires": { + "fbjs": "0.8.14", + "loose-envify": "1.3.1", + "object-assign": "4.1.1" + } + }, + "react-addons-css-transition-group": { + "version": "15.4.2", + "resolved": "https://registry.npmjs.org/react-addons-css-transition-group/-/react-addons-css-transition-group-15.4.2.tgz", + "integrity": "sha1-t4KINN+hQin+B3UOMx6KjLb7d0U=", + "requires": { + "fbjs": "0.8.14", + "object-assign": "4.1.1" + } + }, + "react-addons-perf": { + "version": "15.4.2", + "resolved": "https://registry.npmjs.org/react-addons-perf/-/react-addons-perf-15.4.2.tgz", + "integrity": "sha1-EQvc9cRZxPd8uF7WNLzTOXU2ODs=", + "dev": true, + "requires": { + "fbjs": "0.8.14", + "object-assign": "4.1.1" + } + }, + "react-addons-shallow-compare": { + "version": "15.6.0", + "resolved": "https://registry.npmjs.org/react-addons-shallow-compare/-/react-addons-shallow-compare-15.6.0.tgz", + "integrity": "sha1-t6Tl/58nBMIM9obdigXdCLJt4lI=", + "requires": { + "fbjs": "0.8.14", + "object-assign": "4.1.1" + } + }, + "react-addons-test-utils": { + "version": "15.4.2", + "resolved": "https://registry.npmjs.org/react-addons-test-utils/-/react-addons-test-utils-15.4.2.tgz", + "integrity": "sha1-k7yqcY/K5zYNQuj7HAl1bMNjAqI=", + "dev": true, + "requires": { + "fbjs": "0.8.14", + "object-assign": "4.1.1" + } + }, + "react-addons-transition-group": { + "version": "15.6.0", + "resolved": "https://registry.npmjs.org/react-addons-transition-group/-/react-addons-transition-group-15.6.0.tgz", + "integrity": "sha1-DyILn5WX2zqAqI29b+gF/GRM4hw=", + "requires": { + "react-transition-group": "1.2.0" + } + }, + "react-codemirror": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/react-codemirror/-/react-codemirror-0.3.0.tgz", + "integrity": "sha1-zWvW70WOweA1z9iz/nswyMeIPGw=", + "requires": { + "classnames": "2.2.5", + "codemirror": "5.28.0", + "lodash.debounce": "4.0.8" + } + }, + "react-container-dimensions": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/react-container-dimensions/-/react-container-dimensions-1.2.0.tgz", + "integrity": "sha1-v7XnDhCqgtLsukkUfRS7TCLK/ao=", + "requires": { + "element-resize-detector": "1.1.12", + "invariant": "2.2.2" + } + }, + "react-copy-to-clipboard": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/react-copy-to-clipboard/-/react-copy-to-clipboard-4.2.3.tgz", + "integrity": "sha1-JoxaD73pqV2WFFAU5/hRELDn+44=", + "requires": { + "copy-to-clipboard": "3.0.8" + } + }, + "react-deep-force-update": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/react-deep-force-update/-/react-deep-force-update-2.0.1.tgz", + "integrity": "sha1-T39sEsPn3kLzRZkqPFGCNvoeytM=", + "dev": true + }, + "react-dom": { + "version": "15.4.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-15.4.2.tgz", + "integrity": "sha1-AVNj8FsKH9Uq6e/dOgBg2QaVII8=", + "requires": { + "fbjs": "0.8.14", + "loose-envify": "1.3.1", + "object-assign": "4.1.1" + } + }, + "react-dropzone": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-3.7.3.tgz", + "integrity": "sha1-eFK2ZSpDr8f6ByAh8zaRI+pKYeA=", + "requires": { + "attr-accept": "1.1.0" + } + }, + "react-element-to-jsx-string": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/react-element-to-jsx-string/-/react-element-to-jsx-string-6.0.0.tgz", + "integrity": "sha1-8sFRR27o3YF4ke01K+Ss6fs2McI=", + "requires": { + "collapse-white-space": "1.0.3", + "is-plain-object": "2.0.4", + "lodash": "4.17.4", + "sortobject": "1.1.1", + "stringify-object": "3.2.0", + "traverse": "0.6.6" + }, + "dependencies": { + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" + } + } + }, + "react-event-listener": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/react-event-listener/-/react-event-listener-0.4.1.tgz", + "integrity": "sha1-hrU5dMPfZRhXdmt7F3aC7Xx8gxg=", + "requires": { + "babel-runtime": "6.23.0", + "react-addons-shallow-compare": "15.6.0", + "warning": "3.0.0" + } + }, + "react-hot-loader": { + "version": "3.0.0-beta.6", + "resolved": "https://registry.npmjs.org/react-hot-loader/-/react-hot-loader-3.0.0-beta.6.tgz", + "integrity": "sha1-Rj+sC/yLY6g4UlivIMkWNqvOdfQ=", + "dev": true, + "requires": { + "babel-template": "6.25.0", + "global": "4.3.2", + "react-deep-force-update": "2.0.1", + "react-proxy": "3.0.0-alpha.1", + "redbox-react": "1.4.3", + "source-map": "0.4.4" + }, + "dependencies": { + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, + "requires": { + "amdefine": "1.0.1" + } + } + } + }, + "react-inspector": { + "version": "github:paritytech/react-inspector#73b5214261a5131821eb9088f58d7e5f31210c23", + "requires": { + "babel-runtime": "6.23.0", + "is-dom": "1.0.9" + } + }, + "react-intl": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/react-intl/-/react-intl-2.1.5.tgz", + "integrity": "sha1-+Xleo0t5DctdDY73Bg3dvoW/h2M=", + "requires": { + "intl-format-cache": "2.0.5", + "intl-messageformat": "1.3.0", + "intl-relativeformat": "1.3.0", + "invariant": "2.2.2" + } + }, + "react-intl-aggregate-webpack-plugin": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/react-intl-aggregate-webpack-plugin/-/react-intl-aggregate-webpack-plugin-0.0.1.tgz", + "integrity": "sha1-wplYhg17zfpvRg3sefVa4CIEiMY=", + "dev": true, + "requires": { + "mkdirp": "0.5.1" + } + }, + "react-markdown": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-2.4.4.tgz", + "integrity": "sha1-JtglQ40pLnym4pL+diAeHb8s/u4=", + "requires": { + "commonmark": "0.24.0", + "commonmark-react-renderer": "4.3.3", + "in-publish": "2.0.0" + } + }, + "react-portal": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/react-portal/-/react-portal-3.0.0.tgz", + "integrity": "sha1-kwT86DbooyFrIliPjckbRHco8K4=" + }, + "react-proxy": { + "version": "3.0.0-alpha.1", + "resolved": "https://registry.npmjs.org/react-proxy/-/react-proxy-3.0.0-alpha.1.tgz", + "integrity": "sha1-RABCa8+oDKpnJMd1VpUxUgn6Swc=", + "dev": true, + "requires": { + "lodash": "4.17.2" + } + }, + "react-qr-reader": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/react-qr-reader/-/react-qr-reader-1.1.3.tgz", + "integrity": "sha1-dDmnZvyZPLj17u/HLCnblh1AswI=", + "requires": { + "jsqr": "git+https://github.com/JodusNodus/jsQR.git#5ba1acefa1cbb9b2bc92b49f503f2674e2ec212b", + "prop-types": "15.5.10", + "webrtc-adapter": "2.1.0" + } + }, + "react-redux": { + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-4.4.6.tgz", + "integrity": "sha1-S50ymFMHoRCWot1hVhmABE/MYgk=", + "requires": { + "hoist-non-react-statics": "1.2.0", + "invariant": "2.2.2", + "lodash": "4.17.2", + "loose-envify": "1.3.1" + } + }, + "react-router": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-3.0.0.tgz", + "integrity": "sha1-PzE+Tbr1cEjEjdCow8rCTZNmff8=", + "requires": { + "history": "3.3.0", + "hoist-non-react-statics": "1.2.0", + "invariant": "2.2.2", + "loose-envify": "1.3.1", + "warning": "3.0.0" + } + }, + "react-router-redux": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/react-router-redux/-/react-router-redux-4.0.7.tgz", + "integrity": "sha1-mx/eTnAQbFD0chThK92IjPuW4qY=" + }, + "react-smooth": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-0.1.11.tgz", + "integrity": "sha1-84n45Yy7VGq7SSHKDL57B5vFGg0=", + "requires": { + "lodash": "4.13.1", + "raf": "3.3.2", + "react-addons-transition-group": "15.6.0" + }, + "dependencies": { + "lodash": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.13.1.tgz", + "integrity": "sha1-g+SxCRP0hJbU0W/sSlYK8u50S2g=" + } + } + }, + "react-tap-event-plugin": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/react-tap-event-plugin/-/react-tap-event-plugin-2.0.1.tgz", + "integrity": "sha1-MWvrO8ZVbinshppyk+icgmqQdNI=", + "requires": { + "fbjs": "0.8.14" + } + }, + "react-tooltip": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-3.2.2.tgz", + "integrity": "sha1-OlmcDqu9nrlZeqLXKyF/17o1h2c=", + "requires": { + "classnames": "2.2.5" + } + }, + "react-transition-group": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-1.2.0.tgz", + "integrity": "sha1-tR/JIbDDg1p+98Vxx5/ILHPpIE8=", + "requires": { + "chain-function": "1.0.0", + "dom-helpers": "3.2.1", + "loose-envify": "1.3.1", + "prop-types": "15.5.10", + "warning": "3.0.0" + } + }, + "read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", + "requires": { + "mute-stream": "0.0.7" + } + }, + "read-all-stream": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/read-all-stream/-/read-all-stream-3.1.0.tgz", + "integrity": "sha1-NcPhd/IHjveJ7kv6+kNzB06u9Po=", + "requires": { + "pinkie-promise": "2.0.1", + "readable-stream": "2.3.3" + } + }, + "read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha1-5mTvMRYRZsl1HNvo28+GtftY93Q=", + "dev": true, + "requires": { + "pify": "2.3.0" + } + }, + "read-file-stdin": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/read-file-stdin/-/read-file-stdin-0.2.1.tgz", + "integrity": "sha1-JezP86FTtoCa+ssj7hU4fbng7mE=", + "dev": true, + "requires": { + "gather-stream": "1.0.0" + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "requires": { + "load-json-file": "1.1.0", + "normalize-package-data": "2.4.0", + "path-type": "1.1.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "requires": { + "find-up": "1.1.2", + "read-pkg": "1.1.0" + } + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "readdirp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", + "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "minimatch": "3.0.4", + "readable-stream": "2.3.3", + "set-immediate-shim": "1.0.1" + } + }, + "readline2": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz", + "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=", + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "mute-stream": "0.0.5" + }, + "dependencies": { + "mute-stream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz", + "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=", + "dev": true + } + } + }, + "recast": { + "version": "0.11.23", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.11.23.tgz", + "integrity": "sha1-RR/TAEqx5N+bTktmN2sqIZEkYtM=", + "dev": true, + "requires": { + "ast-types": "0.9.6", + "esprima": "3.1.3", + "private": "0.1.7", + "source-map": "0.5.6" + }, + "dependencies": { + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "dev": true + } + } + }, + "recharts": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-0.15.2.tgz", + "integrity": "sha1-Y28ho0HwCzHJJXOe1K73CttV2A8=", + "requires": { + "classnames": "2.2.5", + "core-js": "2.4.0", + "d3-scale": "1.0.0", + "d3-shape": "1.0.0", + "lodash": "4.13.1", + "react-container-dimensions": "1.2.0", + "react-smooth": "0.1.11", + "recharts-scale": "0.2.1", + "reduce-css-calc": "1.3.0" + }, + "dependencies": { + "core-js": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.0.tgz", + "integrity": "sha1-30CKtG0Br/kcAcPnlxk11CLFT4E=" + }, + "lodash": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.13.1.tgz", + "integrity": "sha1-g+SxCRP0hJbU0W/sSlYK8u50S2g=" + } + } + }, + "recharts-scale": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.2.1.tgz", + "integrity": "sha1-N49UPtF8MkXk2a+xCq9imCQNL8s=" + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, + "requires": { + "resolve": "1.4.0" + } + }, + "recompose": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/recompose/-/recompose-0.20.2.tgz", + "integrity": "sha1-ET1qx+KcpmTP/+wWtoHd3fFSULw=", + "requires": { + "change-emitter": "0.1.6", + "fbjs": "0.8.14", + "hoist-non-react-statics": "1.2.0", + "symbol-observable": "0.2.4" + } + }, + "redbox-react": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/redbox-react/-/redbox-react-1.4.3.tgz", + "integrity": "sha512-P/N+y57/FVUQWbgpfTf/2wjgxEhxQuA6FRLv0ipZKLFv5v8mp6qs5inFyBwJQYAgaMrntZRCvKdz1vGwkCNs7A==", + "dev": true, + "requires": { + "error-stack-parser": "1.3.6", + "object-assign": "4.1.1", + "prop-types": "15.5.10", + "sourcemapped-stacktrace": "1.1.7" + } + }, + "redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "requires": { + "indent-string": "2.1.0", + "strip-indent": "1.0.1" + } + }, + "reduce-css-calc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz", + "integrity": "sha1-dHyRTgSWFKTJz7umKYca0dKSdxY=", + "requires": { + "balanced-match": "0.4.2", + "math-expression-evaluator": "1.2.17", + "reduce-function-call": "1.0.2" + }, + "dependencies": { + "balanced-match": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=" + } + } + }, + "reduce-function-call": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/reduce-function-call/-/reduce-function-call-1.0.2.tgz", + "integrity": "sha1-WiAL+S4ON3UXUv5FsKszD9S2vpk=", + "requires": { + "balanced-match": "0.4.2" + }, + "dependencies": { + "balanced-match": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=" + } + } + }, + "reduce-reducers": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/reduce-reducers/-/reduce-reducers-0.1.2.tgz", + "integrity": "sha1-+htHGLxSkqcd3R5dg5yb6pdw8Us=" + }, + "redux": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/redux/-/redux-3.6.0.tgz", + "integrity": "sha1-iHwrPQub2G7KK+cFccJ2VMGeGI0=", + "requires": { + "lodash": "4.17.2", + "lodash-es": "4.17.4", + "loose-envify": "1.3.1", + "symbol-observable": "1.0.4" + }, + "dependencies": { + "symbol-observable": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.4.tgz", + "integrity": "sha1-Kb9hXUqnEhvdiYsi1LP5vE4qoD0=" + } + } + }, + "redux-actions": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/redux-actions/-/redux-actions-1.1.0.tgz", + "integrity": "sha1-347HkdniZ1ROWKi6K3L8XDCvujs=", + "requires": { + "invariant": "2.2.2", + "lodash": "4.17.2", + "reduce-reducers": "0.1.2" + } + }, + "redux-thunk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.1.0.tgz", + "integrity": "sha1-xyS/7nXb41LaLjupvBQwK63Ympg=" + }, + "regenerate": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.2.tgz", + "integrity": "sha1-0ZQcZ7rUN+G+dkM63Vs4X5WxkmA=" + }, + "regenerator-runtime": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", + "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=" + }, + "regenerator-transform": { + "version": "0.9.11", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.9.11.tgz", + "integrity": "sha1-On0GdSDLe3F2dp61/4aGkb7+EoM=", + "requires": { + "babel-runtime": "6.23.0", + "babel-types": "6.25.0", + "private": "0.1.7" + } + }, + "regex-cache": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz", + "integrity": "sha1-mxpsNdTQ3871cRrmUejp09cRQUU=", + "requires": { + "is-equal-shallow": "0.1.3", + "is-primitive": "2.0.0" + } + }, + "regexpu-core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", + "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", + "requires": { + "regenerate": "1.3.2", + "regjsgen": "0.2.0", + "regjsparser": "0.1.5" + } + }, + "regjsgen": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=" + }, + "regjsparser": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "requires": { + "jsesc": "0.5.0" + } + }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", + "dev": true + }, + "remove-trailing-separator": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.0.2.tgz", + "integrity": "sha1-abBi2XhyetFNxrVrpKt3L9jXBRE=" + }, + "renderkid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.1.tgz", + "integrity": "sha1-iYyr/Ivt5Le5ETWj/9Mj5YwNsxk=", + "dev": true, + "requires": { + "css-select": "1.2.0", + "dom-converter": "0.1.4", + "htmlparser2": "3.3.0", + "strip-ansi": "3.0.1", + "utila": "0.3.3" + }, + "dependencies": { + "domhandler": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.1.0.tgz", + "integrity": "sha1-0mRvXlf2w7qxHPbLBdPArPdBJZQ=", + "dev": true, + "requires": { + "domelementtype": "1.3.0" + } + }, + "domutils": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.1.6.tgz", + "integrity": "sha1-vdw94Jm5ou+sxRxiPyj0FuzFdIU=", + "dev": true, + "requires": { + "domelementtype": "1.3.0" + } + }, + "htmlparser2": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.3.0.tgz", + "integrity": "sha1-zHDQWln2VC5D8OaFyYLhTJJKnv4=", + "dev": true, + "requires": { + "domelementtype": "1.3.0", + "domhandler": "2.1.0", + "domutils": "1.1.6", + "readable-stream": "1.0.34" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "utila": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.3.3.tgz", + "integrity": "sha1-1+jn1+MJEHCSsF+NloiCTWM6QiY=", + "dev": true + } + } + }, + "repeat-element": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", + "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=" + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "requires": { + "is-finite": "1.0.2" + } + }, + "replace-ext": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", + "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=" + }, + "request": { + "version": "2.81.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", + "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "4.2.1", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.16", + "oauth-sign": "0.8.2", + "performance-now": "0.2.0", + "qs": "6.4.0", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.2", + "tunnel-agent": "0.6.0", + "uuid": "3.0.0" + }, + "dependencies": { + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" + }, + "performance-now": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", + "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=" + }, + "qs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", + "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=" + } + } + }, + "request-capture-har": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/request-capture-har/-/request-capture-har-1.2.2.tgz", + "integrity": "sha1-zWks+yzHRP2EozWKrG7lFSjPcg0=" + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "require-from-string": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-1.2.1.tgz", + "integrity": "sha1-UpyczvJzgK3+yaL5ZbZJu+5jZBg=" + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" + }, + "require-uncached": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "dev": true, + "requires": { + "caller-path": "0.1.0", + "resolve-from": "1.0.1" + } + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "resolve": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.4.0.tgz", + "integrity": "sha512-aW7sVKPufyHqOmyyLzg/J+8606v5nevBgaliIlV7nUpVMsDnoBGV/cbSLNjZAg9q0Cfd/+easKVKQ8vOu8fn1Q==", + "dev": true, + "requires": { + "path-parse": "1.0.5" + } + }, + "resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "dev": true + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "requires": { + "onetime": "2.0.1", + "signal-exit": "3.0.2" + }, + "dependencies": { + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "requires": { + "mimic-fn": "1.1.0" + } + } + } + }, + "retry": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", + "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=" + }, + "rgb-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rgb-hex/-/rgb-hex-1.0.0.tgz", + "integrity": "sha1-v6+M2c2RZLWibXHrTxWgllMks8E=", + "dev": true + }, + "right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "requires": { + "align-text": "0.1.4" + } + }, + "rimraf": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", + "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=", + "requires": { + "glob": "7.1.2" + }, + "dependencies": { + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + } + } + }, + "ripemd160": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz", + "integrity": "sha1-D0WEKVxTo2KK9+bXmsohzlfRxuc=", + "requires": { + "hash-base": "2.0.2", + "inherits": "2.0.3" + } + }, + "rlp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.0.0.tgz", + "integrity": "sha1-nbOE/0uJqPYVY9kjldhiWxjzr7A=" + }, + "roadrunner": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/roadrunner/-/roadrunner-1.1.0.tgz", + "integrity": "sha1-EYCjDWThlw2PVd2MsNqP/M7K1x4=" + }, + "rucksack-css": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/rucksack-css/-/rucksack-css-0.9.1.tgz", + "integrity": "sha1-2n66TGe9BbAMv0yDQwXF/lU3XeE=", + "dev": true, + "requires": { + "autoprefixer": "6.7.7", + "laggard": "0.1.0", + "minimist": "1.2.0", + "postcss": "5.2.17", + "postcss-alias": "1.0.0", + "postcss-clearfix": "1.0.0", + "postcss-color-rgba-fallback": "2.2.0", + "postcss-easings": "0.3.0", + "postcss-fontpath": "0.3.0", + "postcss-hexrgba": "0.2.1", + "postcss-input-style": "0.3.0", + "postcss-opacity": "4.0.0", + "postcss-position": "0.5.0", + "postcss-pseudoelements": "3.0.0", + "postcss-quantity-queries": "0.4.0", + "postcss-reporter": "2.0.0", + "postcss-responsive-type": "0.5.1", + "postcss-vmin": "2.0.0", + "read-file-stdin": "0.2.1", + "write-file-stdout": "0.0.2" + } + }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "requires": { + "is-promise": "2.1.0" + } + }, + "rx-lite": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", + "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=" + }, + "rx-lite-aggregates": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", + "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", + "requires": { + "rx-lite": "4.0.8" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + }, + "samsam": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.1.2.tgz", + "integrity": "sha1-vsEf3IOp/aBjQBIQ5AF2wwJNFWc=", + "dev": true + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "schema-utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz", + "integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=", + "requires": { + "ajv": "5.2.2" + } + }, + "script-ext-html-webpack-plugin": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/script-ext-html-webpack-plugin/-/script-ext-html-webpack-plugin-1.7.1.tgz", + "integrity": "sha1-rpwOJtd2fUqnk8duNVA0TsCLbRA=", + "dev": true, + "requires": { + "debug": "2.6.8" + } + }, + "scryptsy": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/scryptsy/-/scryptsy-2.0.0.tgz", + "integrity": "sha1-Jiw28CMc+nZU4jY/o5TNLexm83g=" + }, + "sdp": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/sdp/-/sdp-1.5.4.tgz", + "integrity": "sha1-jgOPbdsUvXZa4fS1IW4SCUUR4NA=" + }, + "secp256k1": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-3.3.0.tgz", + "integrity": "sha512-CbrQoeGG5V0kQ1ohEMGI+J7oKerapLTpivLICBaXR0R4HyQcN3kM9itLsV5fdpV1UR1bD14tOkJ1xughmlDIiQ==", + "requires": { + "bindings": "1.3.0", + "bip66": "1.1.5", + "bn.js": "4.11.7", + "create-hash": "1.1.3", + "drbg.js": "1.0.1", + "elliptic": "6.4.0", + "nan": "2.6.2", + "prebuild-install": "2.2.1", + "safe-buffer": "5.1.1" + } + }, + "seek-bzip": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.5.tgz", + "integrity": "sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w=", + "requires": { + "commander": "2.8.1" + } + }, + "semver": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", + "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==" + }, + "semver-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-1.0.0.tgz", + "integrity": "sha1-kqSWkGX5xwxpR1PVUkj8aPj2Usk=", + "dev": true + }, + "semver-truncate": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/semver-truncate/-/semver-truncate-1.1.2.tgz", + "integrity": "sha1-V/Qd5pcHpicJp+AQS6IRcQnqR+g=", + "dev": true, + "requires": { + "semver": "5.4.1" + } + }, + "send": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.14.2.tgz", + "integrity": "sha1-ObBDiz9RC+Xcb2Z6EfcWiTaM3u8=", + "dev": true, + "requires": { + "debug": "2.2.0", + "depd": "1.1.1", + "destroy": "1.0.4", + "encodeurl": "1.0.1", + "escape-html": "1.0.3", + "etag": "1.7.0", + "fresh": "0.3.0", + "http-errors": "1.5.1", + "mime": "1.3.4", + "ms": "0.7.2", + "on-finished": "2.3.0", + "range-parser": "1.2.0", + "statuses": "1.3.1" + }, + "dependencies": { + "debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true, + "requires": { + "ms": "0.7.1" + }, + "dependencies": { + "ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true + } + } + }, + "ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", + "dev": true + } + } + }, + "serve-static": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.11.2.tgz", + "integrity": "sha1-LPmIm9RDWjIMw2iVyapXvWYuasc=", + "dev": true, + "requires": { + "encodeurl": "1.0.1", + "escape-html": "1.0.3", + "parseurl": "1.3.1", + "send": "0.14.2" + } + }, + "serviceworker-cache-polyfill": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serviceworker-cache-polyfill/-/serviceworker-cache-polyfill-4.0.0.tgz", + "integrity": "sha1-3hnuc77yGrPAdAo3sz22JGS6ves=" + }, + "serviceworker-webpack-plugin": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/serviceworker-webpack-plugin/-/serviceworker-webpack-plugin-0.2.0.tgz", + "integrity": "sha1-beneyC7RRMdUxvFbND57h2SsWyg=", + "dev": true, + "requires": { + "minimatch": "3.0.4" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "set-immediate-shim": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", + "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=" + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + }, + "setprototypeof": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.2.tgz", + "integrity": "sha1-gaVSFB7BBLiOic44MQOtXGZWTQg=", + "dev": true + }, + "sha.js": { + "version": "2.4.8", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.8.tgz", + "integrity": "sha1-NwaMLEdra69ALRSknGf1l5IfY08=", + "requires": { + "inherits": "2.0.3" + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "shelljs": { + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz", + "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=", + "dev": true, + "requires": { + "glob": "7.1.2", + "interpret": "1.0.3", + "rechoir": "0.6.2" + }, + "dependencies": { + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + } + } + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + }, + "simple-assign": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/simple-assign/-/simple-assign-0.1.0.tgz", + "integrity": "sha1-F/0wZqXz13OPUDIbsPFMooHMS6o=" + }, + "simple-get": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-1.4.3.tgz", + "integrity": "sha1-6XVe2kB+ltpAxeUVjJ6jezO+y+s=", + "requires": { + "once": "1.4.0", + "unzip-response": "1.0.2", + "xtend": "4.0.1" + } + }, + "sinon": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-1.17.7.tgz", + "integrity": "sha1-RUKk9JugxFwF6y6d2dID4rjv4L8=", + "dev": true, + "requires": { + "formatio": "1.1.1", + "lolex": "1.3.2", + "samsam": "1.1.2", + "util": "0.10.3" + } + }, + "sinon-as-promised": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/sinon-as-promised/-/sinon-as-promised-4.0.2.tgz", + "integrity": "sha1-Eg6c4DPao5ZI3EKQYv5mC+G1tBI=", + "dev": true, + "requires": { + "create-thenable": "1.0.2", + "native-promise-only": "0.8.1" + } + }, + "sinon-chai": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-2.8.0.tgz", + "integrity": "sha1-Qyqbv9Uab8AHmPTSUmqCnAYGh6w=", + "dev": true + }, + "sjcl": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/sjcl/-/sjcl-1.0.6.tgz", + "integrity": "sha1-ZBVGKmPMDUIVxJuuydP6DBtTUg8=" + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" + }, + "slice-ansi": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", + "dev": true + }, + "slide": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", + "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=" + }, + "sntp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "requires": { + "hoek": "2.16.3" + } + }, + "solc": { + "version": "github:ngotchac/solc-js#04eb38cc3003fba8cb3656653a7941ed36408818", + "requires": { + "memorystream": "0.3.1", + "require-from-string": "1.2.1", + "yargs": "4.8.1" + }, + "dependencies": { + "yargs": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", + "integrity": "sha1-wMQpJMpKqmsObaFznfshZDn53cA=", + "requires": { + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.2", + "lodash.assign": "4.2.0", + "os-locale": "1.4.0", + "read-pkg-up": "1.0.1", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "1.0.2", + "which-module": "1.0.0", + "window-size": "0.2.0", + "y18n": "3.2.1", + "yargs-parser": "2.4.1" + } + } + } + }, + "sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", + "requires": { + "is-plain-obj": "1.1.0" + } + }, + "sortobject": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/sortobject/-/sortobject-1.1.1.tgz", + "integrity": "sha1-T2ldTUTtCkwGSCw0wlgqLc3CqzQ=", + "requires": { + "editions": "1.3.3" + } + }, + "source-list-map": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-0.1.8.tgz", + "integrity": "sha1-xVCyq1Qn9rPyH1r+rYjE9Vh7IQY=", + "dev": true + }, + "source-map": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=" + }, + "source-map-support": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.15.tgz", + "integrity": "sha1-AyAt9lwG0r2MfsI2KhkwVv7407E=", + "requires": { + "source-map": "0.5.6" + } + }, + "sourcemapped-stacktrace": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/sourcemapped-stacktrace/-/sourcemapped-stacktrace-1.1.7.tgz", + "integrity": "sha512-pgHNUACbafkQ+M5zR00NSOtSKBc/i40prgN+SY07J/pghClwVNWNTTMa0JuXj4lriR2TvMKcPAHw5KN9tVFRhA==", + "dev": true, + "requires": { + "source-map": "0.5.6" + } + }, + "sparkles": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.0.tgz", + "integrity": "sha1-Gsu/tZJDbRC76PeFt8xvgoFQEsM=" + }, + "spdx-correct": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", + "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", + "requires": { + "spdx-license-ids": "1.2.2" + } + }, + "spdx-expression-parse": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", + "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=" + }, + "spdx-license-ids": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", + "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=" + }, + "specificity": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/specificity/-/specificity-0.3.1.tgz", + "integrity": "sha1-8bBoQkzjF64HR42V3jwhz4Xo1Wc=", + "dev": true + }, + "split2": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/split2/-/split2-0.2.1.tgz", + "integrity": "sha1-At2smtwD7Au3jBKC7Aecpuha6QA=", + "dev": true, + "requires": { + "through2": "0.6.5" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "squeak": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/squeak/-/squeak-1.3.0.tgz", + "integrity": "sha1-MwRQN7ZDiLVnZ0uEMiplIQc5FsM=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "console-stream": "0.1.1", + "lpad-align": "1.1.2" + } + }, + "sshpk": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", + "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "stackframe": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-0.3.1.tgz", + "integrity": "sha1-M6qE8Rd6VUjIk1Uzy/6zQgl19aQ=", + "dev": true + }, + "stat-mode": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-0.2.2.tgz", + "integrity": "sha1-5sgLYjEj19gM8TLOU480YokHJQI=" + }, + "statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=", + "dev": true + }, + "store": { + "version": "1.3.20", + "resolved": "https://registry.npmjs.org/store/-/store-1.3.20.tgz", + "integrity": "sha1-E+p+P7LWwjmGgmXWhrHYTpnFvj4=" + }, + "stream-browserify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", + "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.3.3" + } + }, + "stream-combiner": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", + "integrity": "sha1-rsjLrBd7Vrb0+kec7YwZEs7lKFg=", + "dev": true, + "requires": { + "duplexer": "0.1.1", + "through": "2.3.8" + } + }, + "stream-combiner2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", + "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=", + "requires": { + "duplexer2": "0.1.4", + "readable-stream": "2.3.3" + } + }, + "stream-http": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.7.2.tgz", + "integrity": "sha512-c0yTD2rbQzXtSsFSVhtpvY/vS6u066PcXOX9kBB3mSO76RiUQzL340uJkGBWnlBg4/HZzqiUXtaVA7wcRcJgEw==", + "dev": true, + "requires": { + "builtin-status-codes": "3.0.0", + "inherits": "2.0.3", + "readable-stream": "2.3.3", + "to-arraybuffer": "1.0.1", + "xtend": "4.0.1" + } + }, + "stream-shift": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", + "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" + }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "string.prototype.repeat": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-0.2.0.tgz", + "integrity": "sha1-q6Nt4I3O5qWjN9SbLqHaGyj8Ds8=" + }, + "stringify-object": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.2.0.tgz", + "integrity": "sha1-lDcKE15BvASDWIE7+ZSB8TFcaqY=", + "requires": { + "get-own-enumerable-property-symbols": "1.0.1", + "is-obj": "1.0.1", + "is-regexp": "1.0.0" + } + }, + "stringstream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "requires": { + "is-utf8": "0.2.1" + } + }, + "strip-bom-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-1.0.0.tgz", + "integrity": "sha1-5xRDmFd9Uaa+0PoZlPoF9D/ZiO4=", + "requires": { + "first-chunk-stream": "1.0.0", + "strip-bom": "2.0.0" + } + }, + "strip-dirs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-1.1.1.tgz", + "integrity": "sha1-lgu9EoeETzl1pFWKoQOoJV4kVqA=", + "requires": { + "chalk": "1.1.3", + "get-stdin": "4.0.1", + "is-absolute": "0.1.7", + "is-natural-number": "2.1.1", + "minimist": "1.2.0", + "sum-up": "1.0.3" + }, + "dependencies": { + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=" + } + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-hex-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", + "integrity": "sha1-DF8VX+8RUTczd96du1iNoFUA428=", + "requires": { + "is-hex-prefixed": "1.0.0" + } + }, + "strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "requires": { + "get-stdin": "4.0.1" + }, + "dependencies": { + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=" + } + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + }, + "strip-outer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.0.tgz", + "integrity": "sha1-qsC6YNLpDF1PJ1/Yhp/ZotMQ/7g=", + "requires": { + "escape-string-regexp": "1.0.5" + } + }, + "style-loader": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.13.1.tgz", + "integrity": "sha1-RoKA77wEcwI806bNVuM7Wh1/w6k=", + "dev": true, + "requires": { + "loader-utils": "0.2.17" + } + }, + "style-search": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz", + "integrity": "sha1-eVjHk+R+MuB9K1yv5cC/jhLneQI=", + "dev": true + }, + "stylehacks": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-2.3.2.tgz", + "integrity": "sha1-ZMg+BDimjJ7fRJ6MVSp9mrYAmws=", + "dev": true, + "requires": { + "browserslist": "1.7.7", + "chalk": "1.1.3", + "log-symbols": "1.0.2", + "minimist": "1.2.0", + "plur": "2.1.2", + "postcss": "5.2.17", + "postcss-reporter": "1.4.1", + "postcss-selector-parser": "2.2.3", + "read-file-stdin": "0.2.1", + "text-table": "0.2.0", + "write-file-stdout": "0.0.2" + }, + "dependencies": { + "postcss-reporter": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-1.4.1.tgz", + "integrity": "sha1-wTbwpbFhkV83ndN2XGEHX357mvI=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "lodash": "4.17.2", + "log-symbols": "1.0.2", + "postcss": "5.2.17" + } + } + } + }, + "stylelint": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-7.9.0.tgz", + "integrity": "sha1-uNnqIPiHqzUQdcat7ZUo3iRQkyc=", + "dev": true, + "requires": { + "autoprefixer": "6.7.7", + "balanced-match": "0.4.2", + "chalk": "1.1.3", + "colorguard": "1.2.0", + "cosmiconfig": "2.2.2", + "doiuse": "2.6.0", + "execall": "1.0.0", + "get-stdin": "5.0.1", + "globby": "6.1.0", + "globjoin": "0.1.4", + "html-tags": "1.2.0", + "ignore": "3.3.3", + "known-css-properties": "0.0.6", + "lodash": "4.17.4", + "log-symbols": "1.0.2", + "meow": "3.7.0", + "micromatch": "2.3.11", + "normalize-selector": "0.2.0", + "postcss": "5.2.17", + "postcss-less": "0.14.0", + "postcss-media-query-parser": "0.2.3", + "postcss-reporter": "3.0.0", + "postcss-resolve-nested-selector": "0.1.1", + "postcss-scss": "0.4.1", + "postcss-selector-parser": "2.2.3", + "postcss-value-parser": "3.3.0", + "resolve-from": "2.0.0", + "specificity": "0.3.1", + "string-width": "2.1.1", + "style-search": "0.1.0", + "stylehacks": "2.3.2", + "sugarss": "0.2.0", + "svg-tags": "1.0.0", + "table": "4.0.1" + }, + "dependencies": { + "ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "dev": true, + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + } + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "balanced-match": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=", + "dev": true + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "get-stdin": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.1.tgz", + "integrity": "sha1-Ei4WFZHiH/TFJTAwVpPyDmOTo5g=", + "dev": true + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "1.0.2", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + }, + "postcss-reporter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-3.0.0.tgz", + "integrity": "sha1-CeoPN6RExWk4eGBuCbAY6+/3z48=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "lodash": "4.17.4", + "log-symbols": "1.0.2", + "postcss": "5.2.17" + } + }, + "resolve-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", + "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + }, + "table": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/table/-/table-4.0.1.tgz", + "integrity": "sha1-qBFsEz+sLGH0pCCrbN9cTWHw5DU=", + "dev": true, + "requires": { + "ajv": "4.11.8", + "ajv-keywords": "1.5.1", + "chalk": "1.1.3", + "lodash": "4.17.4", + "slice-ansi": "0.0.4", + "string-width": "2.1.1" + } + } + } + }, + "stylelint-config-standard": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-16.0.0.tgz", + "integrity": "sha1-u3OHv/HX3XGGpSs+v4hbJAXWkb8=", + "dev": true + }, + "sugarss": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/sugarss/-/sugarss-0.2.0.tgz", + "integrity": "sha1-rDQjdWMyfG/4l7ZHQr9q7BkK054=", + "dev": true, + "requires": { + "postcss": "5.2.17" + } + }, + "sum-up": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sum-up/-/sum-up-1.0.3.tgz", + "integrity": "sha1-HGYfZnBX9jvLeHWqFDi8FiUlFW4=", + "requires": { + "chalk": "1.1.3" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + }, + "svg-tags": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", + "integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=", + "dev": true + }, + "svgo": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-0.7.2.tgz", + "integrity": "sha1-n1dyQTlSE1xv779Ar+ak+qiLS7U=", + "dev": true, + "requires": { + "coa": "1.0.4", + "colors": "1.1.2", + "csso": "2.3.2", + "js-yaml": "3.7.0", + "mkdirp": "0.5.1", + "sax": "1.2.4", + "whet.extend": "0.9.9" + }, + "dependencies": { + "js-yaml": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz", + "integrity": "sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A=", + "dev": true, + "requires": { + "argparse": "1.0.9", + "esprima": "2.7.3" + } + } + } + }, + "sw-toolbox": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/sw-toolbox/-/sw-toolbox-3.6.0.tgz", + "integrity": "sha1-Jt8dHHA0hljk3qKIQxkUm3sxg7U=", + "requires": { + "path-to-regexp": "1.7.0", + "serviceworker-cache-polyfill": "4.0.0" + } + }, + "symbol-observable": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-0.2.4.tgz", + "integrity": "sha1-lag9smGG1q9+ehjb2XYKL4bQj0A=" + }, + "symbol-tree": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz", + "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=", + "dev": true + }, + "synesthesia": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/synesthesia/-/synesthesia-1.0.1.tgz", + "integrity": "sha1-XvlepUjA1cbm+btLDQcx3/hkp3c=", + "dev": true, + "requires": { + "css-color-names": "0.0.3" + }, + "dependencies": { + "css-color-names": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.3.tgz", + "integrity": "sha1-3gzvFvTYqoIioyDVttfpu62nufY=", + "dev": true + } + } + }, + "table": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz", + "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=", + "dev": true, + "requires": { + "ajv": "4.11.8", + "ajv-keywords": "1.5.1", + "chalk": "1.1.3", + "lodash": "4.17.2", + "slice-ansi": "0.0.4", + "string-width": "2.1.1" + }, + "dependencies": { + "ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "dev": true, + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + } + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + } + } + }, + "tapable": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.7.tgz", + "integrity": "sha1-5GwNqsuyuKmLmwzqD0BSEFgX7Vw=", + "dev": true + }, + "tar": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", + "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", + "requires": { + "block-stream": "0.0.9", + "fstream": "1.0.11", + "inherits": "2.0.3" + } + }, + "tar-fs": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.15.3.tgz", + "integrity": "sha1-7M+TXpQUk9gVECjmNuUc5MPKfyA=", + "requires": { + "chownr": "1.0.1", + "mkdirp": "0.5.1", + "pump": "1.0.2", + "tar-stream": "1.5.4" + } + }, + "tar-pack": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/tar-pack/-/tar-pack-3.4.0.tgz", + "integrity": "sha1-I74tf2cagzk3bL2wuP4/3r8xeYQ=", + "requires": { + "debug": "2.6.8", + "fstream": "1.0.11", + "fstream-ignore": "1.0.5", + "once": "1.4.0", + "readable-stream": "2.3.3", + "rimraf": "2.6.1", + "tar": "2.2.1", + "uid-number": "0.0.6" + } + }, + "tar-stream": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.5.4.tgz", + "integrity": "sha1-NlSc8E7RrumyowwBQyUiONr5QBY=", + "requires": { + "bl": "1.2.1", + "end-of-stream": "1.4.0", + "readable-stream": "2.3.3", + "xtend": "4.0.1" + } + }, + "temp-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz", + "integrity": "sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0=", + "dev": true + }, + "tempfile": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tempfile/-/tempfile-2.0.0.tgz", + "integrity": "sha1-awRGhWqbERTRhW/8vlCczLCXcmU=", + "dev": true, + "requires": { + "temp-dir": "1.0.0", + "uuid": "3.1.0" + }, + "dependencies": { + "uuid": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", + "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==", + "dev": true + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "through2": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "requires": { + "readable-stream": "1.0.34", + "xtend": "4.0.1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, + "through2-filter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-2.0.0.tgz", + "integrity": "sha1-YLxVoNrLdghdsfna6Zq0P4PWIuw=", + "requires": { + "through2": "2.0.3", + "xtend": "4.0.1" + }, + "dependencies": { + "through2": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", + "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", + "requires": { + "readable-stream": "2.3.3", + "xtend": "4.0.1" + } + } + } + }, + "time-stamp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", + "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=" + }, + "timed-out": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-3.1.3.tgz", + "integrity": "sha1-lYYL/MXHbCd/j4Mm/Q9bLiDrohc=" + }, + "timers-browserify": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.3.tgz", + "integrity": "sha512-+JAqyNgg+M8+gXIrq2EeUr4kZqRz47Ysco7X5QKRGScRE9HIHckyHD1asozSFGeqx2nmPCgA8T5tIGVO0ML7/w==", + "dev": true, + "requires": { + "global": "4.3.2", + "setimmediate": "1.0.5" + } + }, + "tmp": { + "version": "0.0.31", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.31.tgz", + "integrity": "sha1-jzirlDjhcxXl29izZX6L+yd65Kc=", + "requires": { + "os-tmpdir": "1.0.2" + } + }, + "to-absolute-glob": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-0.1.1.tgz", + "integrity": "sha1-HN+kcqnvUMI57maZm2YsoOs5k38=", + "requires": { + "extend-shallow": "2.0.1" + } + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", + "dev": true + }, + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=" + }, + "to-source": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/to-source/-/to-source-2.0.3.tgz", + "integrity": "sha1-U4f4JZzzV2Kz4+m1wtzY49uaLRU=", + "dev": true + }, + "toggle-selection": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", + "integrity": "sha1-bkWxJj8gF/oKzH2J14sVuL932jI=" + }, + "toposort": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.3.tgz", + "integrity": "sha1-8CzYp0vYvi/A6YYRw7rLlaFxhpw=", + "dev": true + }, + "tough-cookie": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", + "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=", + "requires": { + "punycode": "1.4.1" + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", + "dev": true + }, + "traverse": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", + "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=" + }, + "trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=" + }, + "trim-repeated": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", + "integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=", + "requires": { + "escape-string-regexp": "1.0.5" + } + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=" + }, + "tryit": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz", + "integrity": "sha1-OTvnMKlEb9Hq1tpZoBQwjzbCics=", + "dev": true + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "optional": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "1.1.2" + } + }, + "type-detect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz", + "integrity": "sha1-diIXzAbbJY7EiQihKY6LlRIejqI=", + "dev": true + }, + "type-is": { + "version": "1.6.15", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", + "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "2.1.16" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "typedarray-to-buffer": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.2.tgz", + "integrity": "sha1-EBezLZhP9VbroQD1AViauhrOLgQ=", + "dev": true, + "requires": { + "is-typedarray": "1.0.0" + } + }, + "u2f-api": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/u2f-api/-/u2f-api-0.0.9.tgz", + "integrity": "sha1-ve1Fe6Wpqe6bWLPeKR+MH4/qy3o=" + }, + "u2f-api-polyfill": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/u2f-api-polyfill/-/u2f-api-polyfill-0.4.3.tgz", + "integrity": "sha1-t60WWm+WJVhReoZ8XEv5OZ/Pfpg=" + }, + "ua-parser-js": { + "version": "0.7.14", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.14.tgz", + "integrity": "sha1-EQ1T+kw/MmwSEpK76skE0uAzh8o=" + }, + "uglify-js": { + "version": "2.8.16", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.16.tgz", + "integrity": "sha1-0oYZC27vxv1l6w7KxlUeCw6IOaQ=", + "requires": { + "source-map": "0.5.6", + "uglify-to-browserify": "1.0.2", + "yargs": "3.10.0" + }, + "dependencies": { + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=" + }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "requires": { + "center-align": "0.1.3", + "right-align": "0.1.3", + "wordwrap": "0.0.2" + } + }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=" + }, + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "requires": { + "camelcase": "1.2.1", + "cliui": "2.1.0", + "decamelize": "1.2.0", + "window-size": "0.1.0" + } + } + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "optional": true + }, + "uid-number": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz", + "integrity": "sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=" + }, + "uniq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", + "dev": true + }, + "uniqid": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/uniqid/-/uniqid-4.1.1.tgz", + "integrity": "sha1-iSIN32t1GuUrX3JISGNShZa7hME=", + "dev": true, + "requires": { + "macaddress": "0.2.8" + } + }, + "uniqs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", + "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=", + "dev": true + }, + "unique-concat": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/unique-concat/-/unique-concat-0.2.2.tgz", + "integrity": "sha1-khD5vcqsxeHjkpSQ18AZ35bxhxI=", + "dev": true + }, + "unique-stream": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.2.1.tgz", + "integrity": "sha1-WqADz76Uxf+GbE59ZouxxNuts2k=", + "requires": { + "json-stable-stringify": "1.0.1", + "through2-filter": "2.0.0" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, + "unzip-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-1.0.2.tgz", + "integrity": "sha1-uYTwh3/AqJwsdzzB73tbIytbBv4=" + }, + "upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=", + "dev": true + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + } + } + }, + "url-loader": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-0.5.7.tgz", + "integrity": "sha1-Z+h3l1n4AA2nSZSQZoDJQ6mwkl0=", + "dev": true, + "requires": { + "loader-utils": "0.2.17", + "mime": "1.2.11" + }, + "dependencies": { + "mime": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", + "integrity": "sha1-WCA+7Ybjpe8XrtK32evUfwpg3RA=", + "dev": true + } + } + }, + "url-parse-lax": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", + "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "requires": { + "prepend-http": "1.0.4" + } + }, + "url-regex": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/url-regex/-/url-regex-3.2.0.tgz", + "integrity": "sha1-260eDJ4p4QXdCx8J9oYvf9tIJyQ=", + "dev": true, + "requires": { + "ip-regex": "1.0.3" + } + }, + "user-home": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", + "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=", + "dev": true + }, + "useragent.js": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/useragent.js/-/useragent.js-0.5.6.tgz", + "integrity": "sha1-p2rvEB4kg3AlI/9vtYpACvd+Iqk=" + }, + "utf8": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.2.tgz", + "integrity": "sha1-H6DZJw6b6FDZsFAn9jUZv0ZFfZY=" + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "requires": { + "inherits": "2.0.1" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=", + "dev": true + }, + "utils-merge": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz", + "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg=", + "dev": true + }, + "uuid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.0.0.tgz", + "integrity": "sha1-Zyj8BFnEUNeWqZwxg3VpvfZy1yg=" + }, + "v8flags": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-2.1.1.tgz", + "integrity": "sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=", + "dev": true, + "requires": { + "user-home": "1.1.1" + } + }, + "vali-date": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/vali-date/-/vali-date-1.0.0.tgz", + "integrity": "sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY=" + }, + "valid-url": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/valid-url/-/valid-url-1.0.9.tgz", + "integrity": "sha1-HBRHm0DxOXp1eC8RXkCGRHQzogA=" + }, + "validate-npm-package-license": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", + "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", + "requires": { + "spdx-correct": "1.0.2", + "spdx-expression-parse": "1.0.4" + } + }, + "validator": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-6.2.0.tgz", + "integrity": "sha1-sszNxJ/w9LjuTmHbot3T3eE/I+c=" + }, + "vary": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.1.tgz", + "integrity": "sha1-Z1Neu2lMHVIldFeYRmUyP1h+jTc=", + "dev": true + }, + "vendors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.1.tgz", + "integrity": "sha1-N61zyO5Bf7PVgOeFMSMH0nSEfyI=", + "dev": true + }, + "verror": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz", + "integrity": "sha1-z/XfEpRtKX0rqu+qJoniW+AcAFw=", + "requires": { + "extsprintf": "1.0.2" + } + }, + "vinyl": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", + "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", + "requires": { + "clone": "1.0.2", + "clone-stats": "0.0.1", + "replace-ext": "0.0.1" + } + }, + "vinyl-assign": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/vinyl-assign/-/vinyl-assign-1.2.1.tgz", + "integrity": "sha1-TRmIkbVRWRHXcajNnFSApGoHSkU=", + "requires": { + "object-assign": "4.1.1", + "readable-stream": "2.3.3" + } + }, + "vinyl-fs": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-2.4.4.tgz", + "integrity": "sha1-vm/zJwy1Xf19MGNkDegfJddTIjk=", + "requires": { + "duplexify": "3.5.0", + "glob-stream": "5.3.5", + "graceful-fs": "4.1.11", + "gulp-sourcemaps": "1.6.0", + "is-valid-glob": "0.3.0", + "lazystream": "1.0.0", + "lodash.isequal": "4.5.0", + "merge-stream": "1.0.1", + "mkdirp": "0.5.1", + "object-assign": "4.1.1", + "readable-stream": "2.3.3", + "strip-bom": "2.0.0", + "strip-bom-stream": "1.0.0", + "through2": "2.0.3", + "through2-filter": "2.0.0", + "vali-date": "1.0.0", + "vinyl": "1.2.0" + }, + "dependencies": { + "through2": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", + "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", + "requires": { + "readable-stream": "2.3.3", + "xtend": "4.0.1" + } + } + } + }, + "vm-browserify": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", + "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", + "dev": true, + "requires": { + "indexof": "0.0.1" + } + }, + "w3c-blob": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/w3c-blob/-/w3c-blob-0.0.1.tgz", + "integrity": "sha1-sM01KhpQ9RVWNCD/1YYflQ8dhbg=" + }, + "ware": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ware/-/ware-1.3.0.tgz", + "integrity": "sha1-0bFPOdLiy0q4xAmPdW/ksWTkc9Q=", + "requires": { + "wrap-fn": "0.1.5" + } + }, + "warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", + "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=", + "requires": { + "loose-envify": "1.3.1" + } + }, + "watchpack": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.4.0.tgz", + "integrity": "sha1-ShRyvLuVK9Cpu0A2gB+VTfs5+qw=", + "dev": true, + "requires": { + "async": "2.5.0", + "chokidar": "1.7.0", + "graceful-fs": "4.1.11" + }, + "dependencies": { + "async": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/async/-/async-2.5.0.tgz", + "integrity": "sha512-e+lJAJeNWuPCNyxZKOBdaJGyLGHugXVQtrAwtuAe2vhxTYxFTKE73p8JuTmdH0qdQZtDvI4dhJwjZc5zsfIsYw==", + "dev": true, + "requires": { + "lodash": "4.17.2" + } + } + } + }, + "web3": { + "version": "0.17.0-beta", + "resolved": "https://registry.npmjs.org/web3/-/web3-0.17.0-beta.tgz", + "integrity": "sha1-V684JFv/ejIJn3zleA+tW7wA2ls=", + "requires": { + "bignumber.js": "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2", + "crypto-js": "3.1.8", + "utf8": "2.1.2", + "xmlhttprequest": "1.8.0" + }, + "dependencies": { + "bignumber.js": { + "version": "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2" + } + } + }, + "webidl-conversions": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.1.tgz", + "integrity": "sha1-gBWherg+fhsxFjhIas6B2mziBqA=", + "dev": true + }, + "webpack": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-2.2.1.tgz", + "integrity": "sha1-e7HXKuIIfdGkr1Jq/sFe7RfdpHU=", + "dev": true, + "requires": { + "acorn": "4.0.13", + "acorn-dynamic-import": "2.0.2", + "ajv": "4.11.8", + "ajv-keywords": "1.5.1", + "async": "2.5.0", + "enhanced-resolve": "3.4.1", + "interpret": "1.0.3", + "json-loader": "0.5.4", + "loader-runner": "2.3.0", + "loader-utils": "0.2.17", + "memory-fs": "0.4.1", + "mkdirp": "0.5.1", + "node-libs-browser": "2.0.0", + "source-map": "0.5.6", + "supports-color": "3.2.3", + "tapable": "0.2.7", + "uglify-js": "2.8.16", + "watchpack": "1.4.0", + "webpack-sources": "0.1.5", + "yargs": "6.6.0" + }, + "dependencies": { + "acorn": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", + "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", + "dev": true + }, + "ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "dev": true, + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + } + }, + "async": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/async/-/async-2.5.0.tgz", + "integrity": "sha512-e+lJAJeNWuPCNyxZKOBdaJGyLGHugXVQtrAwtuAe2vhxTYxFTKE73p8JuTmdH0qdQZtDvI4dhJwjZc5zsfIsYw==", + "dev": true, + "requires": { + "lodash": "4.17.2" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "1.0.0" + } + } + } + }, + "webpack-bundle-size-analyzer": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/webpack-bundle-size-analyzer/-/webpack-bundle-size-analyzer-2.5.0.tgz", + "integrity": "sha1-k56kZeRVk1Op/OQK9RGCDyFqnIA=", + "dev": true, + "requires": { + "commander": "2.8.1", + "filesize": "3.5.10", + "humanize": "0.0.9" + } + }, + "webpack-dev-middleware": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-1.10.1.tgz", + "integrity": "sha1-xrTPQoE5zxrvvgagwA/bT42i+JM=", + "dev": true, + "requires": { + "memory-fs": "0.4.1", + "mime": "1.3.4", + "path-is-absolute": "1.0.1", + "range-parser": "1.2.0" + } + }, + "webpack-error-notification": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/webpack-error-notification/-/webpack-error-notification-0.1.6.tgz", + "integrity": "sha1-6/y9TvRrg0ZrWcEv3oeQFo9Holc=", + "dev": true + }, + "webpack-hot-middleware": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/webpack-hot-middleware/-/webpack-hot-middleware-2.17.1.tgz", + "integrity": "sha1-DI+/b5P/KcCV1oSwerbWwPL5Udc=", + "dev": true, + "requires": { + "ansi-html": "0.0.7", + "html-entities": "1.2.1", + "querystring": "0.2.0", + "strip-ansi": "3.0.1" + } + }, + "webpack-sources": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-0.1.5.tgz", + "integrity": "sha1-qh86vw8NdNtxEcQOUAuE+WZkB1A=", + "dev": true, + "requires": { + "source-list-map": "0.1.8", + "source-map": "0.5.6" + } + }, + "webrtc-adapter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-2.1.0.tgz", + "integrity": "sha1-YStbxs6Oc8nQZgA4oh+SVahnvz4=", + "requires": { + "sdp": "1.5.4" + } + }, + "websocket": { + "version": "1.0.24", + "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.24.tgz", + "integrity": "sha1-dJA+dfJUW2suHeFCW8HJBZF6GJA=", + "dev": true, + "requires": { + "debug": "2.6.8", + "nan": "2.6.2", + "typedarray-to-buffer": "3.1.2", + "yaeti": "0.0.6" + } + }, + "whatwg-encoding": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.1.tgz", + "integrity": "sha1-PGxFGhmO567FWx7GHQkgxngBpfQ=", + "dev": true, + "requires": { + "iconv-lite": "0.4.13" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.13", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", + "integrity": "sha1-H4irpKsLFQjoMSrMOTRfNumS4vI=", + "dev": true + } + } + }, + "whatwg-fetch": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.1.tgz", + "integrity": "sha1-B4uUYbvpHOpzy86LsSKgX56St3I=" + }, + "whatwg-url": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-4.8.0.tgz", + "integrity": "sha1-0pgaqRSMHgCkHFphMRZqtGg7vMA=", + "dev": true, + "requires": { + "tr46": "0.0.3", + "webidl-conversions": "3.0.1" + }, + "dependencies": { + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", + "dev": true + } + } + }, + "whet.extend": { + "version": "0.9.9", + "resolved": "https://registry.npmjs.org/whet.extend/-/whet.extend-0.9.9.tgz", + "integrity": "sha1-+HfVv2SMl+WqVC+twW1qJZucEaE=", + "dev": true + }, + "which": { + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", + "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", + "requires": { + "isexe": "2.0.0" + } + }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=" + }, + "wide-align": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", + "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", + "requires": { + "string-width": "1.0.2" + } + }, + "window-size": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", + "integrity": "sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU=" + }, + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=" + }, + "worker-loader": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/worker-loader/-/worker-loader-0.8.1.tgz", + "integrity": "sha1-6OmVMx6jTfW/aCloJL+38K1XjUM=", + "requires": { + "loader-utils": "1.1.0", + "schema-utils": "0.3.0" + }, + "dependencies": { + "loader-utils": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", + "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", + "requires": { + "big.js": "3.1.3", + "emojis-list": "2.1.0", + "json5": "0.5.1" + } + } + } + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1" + } + }, + "wrap-fn": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/wrap-fn/-/wrap-fn-0.1.5.tgz", + "integrity": "sha1-8htuQQFv9KfjFyDbxjoJAWvfmEU=", + "requires": { + "co": "3.1.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "dev": true, + "requires": { + "mkdirp": "0.5.1" + } + }, + "write-file-atomic": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz", + "integrity": "sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=", + "requires": { + "graceful-fs": "4.1.11", + "imurmurhash": "0.1.4", + "slide": "1.1.6" + } + }, + "write-file-stdout": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/write-file-stdout/-/write-file-stdout-0.0.2.tgz", + "integrity": "sha1-wlLXx8WxtAKJdjDjRTx7/mkNnKE=", + "dev": true + }, + "write-json-file": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/write-json-file/-/write-json-file-1.2.0.tgz", + "integrity": "sha1-LV3+lqvDyIkFfJOXGqQAXvtUgTQ=", + "requires": { + "graceful-fs": "4.1.11", + "mkdirp": "0.5.1", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "sort-keys": "1.1.2", + "write-file-atomic": "1.3.4" + } + }, + "xml-char-classes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/xml-char-classes/-/xml-char-classes-1.0.0.tgz", + "integrity": "sha1-ZGV4SKIP/F31g6Qq2KJ3tFErvE0=", + "dev": true + }, + "xml-name-validator": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz", + "integrity": "sha1-TYuPHszTQZqjYgYb7O9RXh5VljU=", + "dev": true + }, + "xmlhttprequest": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", + "integrity": "sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw=" + }, + "xss-filters": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/xss-filters/-/xss-filters-1.2.7.tgz", + "integrity": "sha1-Wfod4gHzby80cNysX1jMwoMLCpo=" + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" + }, + "yaeti": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", + "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=", + "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "yargs": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz", + "integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=", + "dev": true, + "requires": { + "camelcase": "3.0.0", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.2", + "os-locale": "1.4.0", + "read-pkg-up": "1.0.1", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "1.0.2", + "which-module": "1.0.0", + "y18n": "3.2.1", + "yargs-parser": "4.2.1" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true + }, + "yargs-parser": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz", + "integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=", + "dev": true, + "requires": { + "camelcase": "3.0.0" + } + } + } + }, + "yargs-parser": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", + "integrity": "sha1-hVaN488VD/SfpRgl8DqMiA3cxcQ=", + "requires": { + "camelcase": "3.0.0", + "lodash.assign": "4.2.0" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" + } + } + }, + "yarn": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/yarn/-/yarn-0.21.3.tgz", + "integrity": "sha1-jdo6Y8eYs4PPpXdFLCs8s+Sqh+A=", + "requires": { + "babel-runtime": "6.23.0", + "bytes": "2.4.0", + "camelcase": "3.0.0", + "chalk": "1.1.3", + "cmd-shim": "2.0.2", + "commander": "2.11.0", + "death": "1.1.0", + "debug": "2.6.8", + "defaults": "1.0.3", + "detect-indent": "5.0.0", + "ini": "1.3.4", + "inquirer": "3.2.1", + "invariant": "2.2.2", + "is-builtin-module": "1.0.0", + "is-ci": "1.0.10", + "leven": "2.1.0", + "loud-rejection": "1.6.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "node-emoji": "1.8.1", + "node-gyp": "3.6.2", + "object-path": "0.11.4", + "proper-lockfile": "2.0.1", + "read": "1.0.7", + "request": "2.81.0", + "request-capture-har": "1.2.2", + "rimraf": "2.6.1", + "roadrunner": "1.1.0", + "semver": "5.4.1", + "strip-bom": "3.0.0", + "tar": "2.2.1", + "tar-stream": "1.5.4", + "validate-npm-package-license": "3.0.1" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" + }, + "commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==" + }, + "detect-indent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz", + "integrity": "sha1-OHHMCmoALow+Wzz38zYmRnXwa50=" + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" + } + } + }, + "yauzl": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.8.0.tgz", + "integrity": "sha1-eUUK/yKyqcWkHvVOAtuQfM+/nuI=", + "requires": { + "buffer-crc32": "0.2.13", + "fd-slicer": "1.0.1" + } + }, + "zxcvbn": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/zxcvbn/-/zxcvbn-4.4.1.tgz", + "integrity": "sha1-I4Gq3X8HiiWoayFTJ1YmR7gKqKw=" + } + } +} diff --git a/js/package.json b/js/package.json index 612d7c1d8..41388a127 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "parity.js", - "version": "1.8.7", + "version": "1.8.16", "main": "release/index.js", "jsnext:main": "src/index.js", "author": "Parity Team ", diff --git a/js/src/api/local/accounts/account.js b/js/src/api/local/accounts/account.js index 0bb069c8b..224a05cd9 100644 --- a/js/src/api/local/accounts/account.js +++ b/js/src/api/local/accounts/account.js @@ -31,6 +31,10 @@ export default class Account { } isValidPassword (password) { + if (!this._keyObject) { + return false; + } + return decryptPrivateKey(this._keyObject, password) .then((privateKey) => { if (!privateKey) { diff --git a/js/src/api/local/accounts/accounts.js b/js/src/api/local/accounts/accounts.js index 823ab3624..d11ea2bad 100644 --- a/js/src/api/local/accounts/accounts.js +++ b/js/src/api/local/accounts/accounts.js @@ -168,6 +168,12 @@ export default class Accounts { return false; } + if (!account.uuid) { + this.removeUnsafe(address); + + return true; + } + return account .isValidPassword(password) .then((isValid) => { diff --git a/js/src/api/local/localAccountsMiddleware.js b/js/src/api/local/localAccountsMiddleware.js index c8e767f89..c452f541a 100644 --- a/js/src/api/local/localAccountsMiddleware.js +++ b/js/src/api/local/localAccountsMiddleware.js @@ -206,6 +206,10 @@ export default class LocalAccountsMiddleware extends Middleware { return accounts.remove(address, password); }); + register('parity_removeAddress', ([address]) => { + return accounts.remove(address, null); + }); + register('parity_testPassword', ([address, password]) => { const account = accounts.get(address); diff --git a/js/src/api/rpc/parity/parity.js b/js/src/api/rpc/parity/parity.js index 4fdaf5b1b..c2681b3fb 100644 --- a/js/src/api/rpc/parity/parity.js +++ b/js/src/api/rpc/parity/parity.js @@ -95,6 +95,11 @@ export default class Parity { .execute('parity_dappsList'); } + dappsRefresh () { + return this._transport + .execute('parity_dappsRefresh'); + } + dappsUrl () { return this._transport .execute('parity_dappsUrl'); diff --git a/js/src/api/rpc/shh/shh.js b/js/src/api/rpc/shh/shh.js index 9312df6c1..c58754abf 100644 --- a/js/src/api/rpc/shh/shh.js +++ b/js/src/api/rpc/shh/shh.js @@ -14,58 +14,78 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -export default class Personal { +export default class Shh { constructor (transport) { this._transport = transport; } - addToGroup (identity) { + info () { return this._transport - .execute('shh_addToGroup', identity); + .execute('shh_info'); } - getFilterChanges (filterId) { + newKeyPair () { return this._transport - .execute('shh_getFilterChanges', filterId); + .execute('shh_newKeyPair'); } - getMessages (filterId) { + addPrivateKey (privKey) { return this._transport - .execute('shh_getMessages', filterId); + .execute('shh_addPrivateKey', privKey); } - hasIdentity (identity) { + newSymKey () { return this._transport - .execute('shh_hasIdentity', identity); + .execute('shh_newSymKey'); } - newFilter (options) { + getPublicKey (identity) { return this._transport - .execute('shh_newFilter', options); + .execute('shh_getPublicKey', identity); } - newGroup () { + getPrivateKey (identity) { return this._transport - .execute('shh_newGroup'); + .execute('shh_getPrivateKey', identity); } - newIdentity () { + getSymKey (identity) { return this._transport - .execute('shh_newIdentity'); + .execute('shh_getSymKey', identity); } - post (options) { + deleteKey (identity) { return this._transport - .execute('shh_post', options); + .execute('shh_deleteKey', identity); } - uninstallFilter (filterId) { + post (messageObj) { return this._transport - .execute('shh_uninstallFilter', filterId); + .execute('shh_post', messageObj); } - version () { + newMessageFilter (filterObj) { return this._transport - .execute('shh_version'); + .execute('shh_newMessageFilter', filterObj); + } + + getFilterMessages (filterId) { + return this._transport + .execute('shh_getFilterMessages', filterId); + } + + deleteMessageFilter (filterId) { + return this._transport + .execute('shh_deleteMessageFilter', filterId); + } + + subscribe (filterObj, callback) { + return this._transport + .subscribe('shh', callback, filterObj); + } + + unsubscribe (subscriptionId) { + return this._transport + .unsubscribe(subscriptionId); } } diff --git a/js/src/api/transport/ws/ws.js b/js/src/api/transport/ws/ws.js index 3c642d5f8..9c276772d 100644 --- a/js/src/api/transport/ws/ws.js +++ b/js/src/api/transport/ws/ws.js @@ -29,7 +29,7 @@ export default class Ws extends JsonRpcBase { this._url = url; this._token = token; this._messages = {}; - this._subscriptions = { 'eth_subscription': [], 'parity_subscription': [] }; + this._subscriptions = { 'eth_subscription': [], 'parity_subscription': [], 'shh_subscription': [] }; this._sessionHash = null; this._connecting = false; diff --git a/js/src/api/util/format.js b/js/src/api/util/format.js index 61fc9d32c..6a4a81d40 100644 --- a/js/src/api/util/format.js +++ b/js/src/api/util/format.js @@ -75,7 +75,10 @@ export function bytesToAscii (bytes) { } export function asciiToHex (string) { - return '0x' + string.split('').map((s) => s.charCodeAt(0).toString(16)).join(''); + return '0x' + string.split('') + .map(s => s.charCodeAt(0)) + .map(s => s < 0x10 ? '0' + s.toString(16) : s.toString(16)) + .join(''); } export function padRight (input, length) { diff --git a/js/src/api/util/format.spec.js b/js/src/api/util/format.spec.js index c37205569..ba7a3994e 100644 --- a/js/src/api/util/format.spec.js +++ b/js/src/api/util/format.spec.js @@ -67,6 +67,7 @@ describe('api/util/format', () => { it('correctly converts a non-empty string', () => { expect(asciiToHex('abc')).to.equal('0x616263'); + expect(asciiToHex('a\nb')).to.equal('0x610a62'); }); }); diff --git a/js/src/api/util/index.js b/js/src/api/util/index.js index cc8fc9b93..30328856b 100644 --- a/js/src/api/util/index.js +++ b/js/src/api/util/index.js @@ -17,7 +17,7 @@ import { isAddress as isAddressValid, toChecksumAddress } from '../../abi/util/address'; import { abiDecode, decodeCallData, decodeMethodInput, methodToAbi } from './decode'; import { abiEncode, abiUnencode, abiSignature, encodeMethodCallAbi } from './encode'; -import { bytesToHex, hexToAscii, asciiToHex, cleanupValue } from './format'; +import { bytesToHex, hexToAscii, hexToBytes, asciiToHex, cleanupValue } from './format'; import { fromWei, toWei } from './wei'; import { sha3 } from './sha3'; import { isArray, isFunction, isHex, isInstanceOf, isString } from './types'; @@ -37,6 +37,7 @@ export default { isString, bytesToHex, hexToAscii, + hexToBytes, asciiToHex, createIdentityImg, decodeCallData, diff --git a/js/src/contracts/abi/consensys-multisig-wallet.json b/js/src/contracts/abi/consensys-multisig-wallet.json new file mode 100644 index 000000000..79623637d --- /dev/null +++ b/js/src/contracts/abi/consensys-multisig-wallet.json @@ -0,0 +1,510 @@ +[ + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "uint256" + } + ], + "name": "owners", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "removeOwner", + "outputs": [], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "transactionId", + "type": "uint256" + } + ], + "name": "revokeConfirmation", + "outputs": [], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "isOwner", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "address" + } + ], + "name": "confirmations", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "pending", + "type": "bool" + }, + { + "name": "executed", + "type": "bool" + } + ], + "name": "getTransactionCount", + "outputs": [ + { + "name": "count", + "type": "uint256" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + } + ], + "name": "addOwner", + "outputs": [], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "transactionId", + "type": "uint256" + } + ], + "name": "isConfirmed", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "transactionId", + "type": "uint256" + } + ], + "name": "getConfirmationCount", + "outputs": [ + { + "name": "count", + "type": "uint256" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "uint256" + } + ], + "name": "transactions", + "outputs": [ + { + "name": "destination", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + }, + { + "name": "data", + "type": "bytes" + }, + { + "name": "executed", + "type": "bool" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getOwners", + "outputs": [ + { + "name": "", + "type": "address[]" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "from", + "type": "uint256" + }, + { + "name": "to", + "type": "uint256" + }, + { + "name": "pending", + "type": "bool" + }, + { + "name": "executed", + "type": "bool" + } + ], + "name": "getTransactionIds", + "outputs": [ + { + "name": "_transactionIds", + "type": "uint256[]" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "transactionId", + "type": "uint256" + } + ], + "name": "getConfirmations", + "outputs": [ + { + "name": "_confirmations", + "type": "address[]" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "transactionCount", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_required", + "type": "uint256" + } + ], + "name": "changeRequirement", + "outputs": [], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "transactionId", + "type": "uint256" + } + ], + "name": "confirmTransaction", + "outputs": [], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "destination", + "type": "address" + }, + { + "name": "value", + "type": "uint256" + }, + { + "name": "data", + "type": "bytes" + } + ], + "name": "submitTransaction", + "outputs": [ + { + "name": "transactionId", + "type": "uint256" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MAX_OWNER_COUNT", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "required", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner", + "type": "address" + }, + { + "name": "newOwner", + "type": "address" + } + ], + "name": "replaceOwner", + "outputs": [], + "payable": false, + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "transactionId", + "type": "uint256" + } + ], + "name": "executeTransaction", + "outputs": [], + "payable": false, + "type": "function" + }, + { + "inputs": [ + { + "name": "_owners", + "type": "address[]" + }, + { + "name": "_required", + "type": "uint256" + } + ], + "payable": false, + "type": "constructor" + }, + { + "payable": true, + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "name": "transactionId", + "type": "uint256" + } + ], + "name": "Confirmation", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "name": "transactionId", + "type": "uint256" + } + ], + "name": "Revocation", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "transactionId", + "type": "uint256" + } + ], + "name": "Submission", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "transactionId", + "type": "uint256" + } + ], + "name": "Execution", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "transactionId", + "type": "uint256" + } + ], + "name": "ExecutionFailure", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Deposit", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + } + ], + "name": "OwnerAddition", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + } + ], + "name": "OwnerRemoval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "required", + "type": "uint256" + } + ], + "name": "RequirementChange", + "type": "event" + } +] diff --git a/js/src/contracts/abi/wallet.json b/js/src/contracts/abi/foundation-multisig-wallet.json similarity index 100% rename from js/src/contracts/abi/wallet.json rename to js/src/contracts/abi/foundation-multisig-wallet.json diff --git a/js/src/contracts/abi/index.js b/js/src/contracts/abi/index.js index 8985d869e..f475cce07 100644 --- a/js/src/contracts/abi/index.js +++ b/js/src/contracts/abi/index.js @@ -28,4 +28,4 @@ export registry2 from './registry2.json'; export signaturereg from './signaturereg.json'; export smsverification from './sms-verification.json'; export tokenreg from './tokenreg.json'; -export wallet from './wallet.json'; +export foundationWallet from './foundation-multisig-wallet.json'; diff --git a/js/src/dapps/localtx/Application/application.js b/js/src/dapps/localtx/Application/application.js index 8efadcf1a..27dc41b3e 100644 --- a/js/src/dapps/localtx/Application/application.js +++ b/js/src/dapps/localtx/Application/application.js @@ -151,7 +151,7 @@ export default class Application extends Component { if (!transactions.length) { return ( -

The queue seems is empty.

+

The queue seems empty.

); } diff --git a/js/src/embed.js b/js/src/embed.js index 5e8bf7ffe..0413fb466 100644 --- a/js/src/embed.js +++ b/js/src/embed.js @@ -64,14 +64,19 @@ class FakeTransport { class FrameSecureApi extends SecureApi { constructor (transport) { - super(transport.uiUrl, null, () => { - return transport; - }); + super( + transport.uiUrl, + null, + () => transport, + () => 'http:' + ); } connect () { // Do nothing - this API does not need connecting this.emit('connecting'); + // Fetch settings + this._fetchSettings(); // Fire connected event with some delay. setTimeout(() => { this.emit('connected'); diff --git a/js/src/jsonrpc/interfaces/eth.js b/js/src/jsonrpc/interfaces/eth.js index d54c57325..30756e8c6 100644 --- a/js/src/jsonrpc/interfaces/eth.js +++ b/js/src/jsonrpc/interfaces/eth.js @@ -566,9 +566,9 @@ The following options are possible for the \`defaultBlock\` parameter: type: Hash, desc: 'public key of the signer.' }, - networkId: { + chainId: { type: Quantity, - desc: 'the network id of the transaction, if any.' + desc: 'the chain id of the transaction, if any.' }, creates: { type: Hash, @@ -1111,9 +1111,9 @@ The following options are possible for the \`defaultBlock\` parameter: type: Hash, desc: 'public key of the signer.' }, - networkId: { + chainId: { type: Quantity, - desc: 'the network id of the transaction, if any.' + desc: 'the chain id of the transaction, if any.' }, creates: { type: Hash, diff --git a/js/src/jsonrpc/interfaces/parity.js b/js/src/jsonrpc/interfaces/parity.js index d1ade602b..a1e6246e4 100644 --- a/js/src/jsonrpc/interfaces/parity.js +++ b/js/src/jsonrpc/interfaces/parity.js @@ -164,6 +164,17 @@ export default { } }, + dappsRefresh: { + subdoc: SUBDOC_SET, + desc: 'Returns a boolean value upon success and error upon failure', + params: [], + returns: { + type: Boolean, + desc: 'True for success. error details for failure', + example: true + } + }, + dappsUrl: { section: SECTION_NODE, desc: 'Returns the hostname and the port of dapps/rpc server, error if not enabled.', @@ -392,7 +403,7 @@ export default { condition: { block: 1 }, - networkId: null, + chainId: null, nonce: '0x0', publicKey: '0x3fa8c08c65a83f6b4ea3e04e1cc70cbe3cd391499e3e05ab7dedf28aff9afc538200ff93e3f2b2cb5029f03c7ebee820d63a4c5a9541c83acebe293f54cacf0e', raw: '0xf868808502d20cff33830e57e09400a289b43e1e4825dbedf2a78ba60a640634dc40830fffff801ca034c333b0b91cd832a3414d628e3fea29a00055cebf5ba59f7038c188404c0cf3a0524fd9b35be170439b5ffe89694ae0cfc553cb49d1d8b643239e353351531532', @@ -615,7 +626,7 @@ export default { condition: { block: 1 }, - networkId: 1, + chainId: 1, nonce: '0x5', publicKey: '0x96157302dade55a1178581333e57d60ffe6fdf5a99607890456a578b4e6b60e335037d61ed58aa4180f9fd747dc50d44a7924aa026acbfb988b5062b629d6c36', r: '0x92e8beb19af2bad0511d516a86e77fa73004c0811b2173657a55797bdf8558e1', @@ -677,7 +688,7 @@ export default { condition: { block: 1 }, - networkId: 1, + chainId: 1, nonce: '0x5', publicKey: '0x96157302dade55a1178581333e57d60ffe6fdf5a99607890456a578b4e6b60e335037d61ed58aa4180f9fd747dc50d44a7924aa026acbfb988b5062b629d6c36', r: '0x92e8beb19af2bad0511d516a86e77fa73004c0811b2173657a55797bdf8558e1', @@ -969,7 +980,7 @@ export default { creates: null, raw: '0xf86c018504a817c80082520894f5d405530dabfbd0c1cab7a5812f008aa5559adf882efc004ac03a49968025a0b40c6967a7e8bbdfd99a25fd306b9ef23b80e719514aeb7ddd19e2303d6fc139a06bf770ab08119e67dc29817e1412a0e3086f43da308c314db1b3bca9fb6d32bd', publicKey: '0xeba33fd74f06236e17475bc5b6d1bac718eac048350d77d3fc8fbcbd85782a57c821255623c4fd1ebc9d555d07df453b2579ee557b7203fc256ca3b3401e4027', - networkId: 1, + chainId: 1, standardV: '0x0', v: '0x25', r: '0xb40c6967a7e8bbdfd99a25fd306b9ef23b80e719514aeb7ddd19e2303d6fc139', diff --git a/js/src/jsonrpc/interfaces/shh.js b/js/src/jsonrpc/interfaces/shh.js index 801c965d0..7084aa3bf 100644 --- a/js/src/jsonrpc/interfaces/shh.js +++ b/js/src/jsonrpc/interfaces/shh.js @@ -14,21 +14,37 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -import { Data, Quantity } from '../types'; +import { Data, Quantity, Float } from '../types'; export default { - version: { - nodoc: 'Not present in Rust code', + info: { desc: 'Returns the current whisper protocol version.', params: [], returns: { - type: String, - desc: 'The current whisper protocol version' + type: Object, + desc: 'The current whisper protocol version', + details: { + minPow: { + type: Float, + desc: 'required PoW threshold for a message to be accepted into the local pool, or null if there is empty space in the pool.' + }, + messages: { + type: Quantity, + desc: 'Number of messages in the pool.' + }, + memory: { + type: Quantity, + desc: 'Amount of memory used by messages in the pool.' + }, + targetMemory: { + type: Quantity, + desc: 'Target amount of memory for the pool.' + } + } } }, post: { - nodoc: 'Not present in Rust code', desc: 'Sends a whisper message.', params: [ { @@ -63,79 +79,122 @@ export default { } }, - newIdentity: { - nodoc: 'Not present in Rust code', - desc: 'Creates new whisper identity in the client.', + newKeyPair: { + desc: 'Generate a new key pair (identity) for asymmetric encryption.', params: [], returns: { type: Data, - desc: '60 Bytes - the address of the new identiy' + desc: '32 Bytes - the address of the new identiy' } }, - hasIdentity: { - nodoc: 'Not present in Rust code', - desc: 'Checks if the client hold the private keys for a given identity.', + addPrivateKey: { + desc: 'Import a private key to use for asymmetric decryption.', params: [ { type: Data, - desc: '60 Bytes - The identity address to check' + desc: '32 Bytes - The private key to import' } ], returns: { - type: Boolean, - desc: '`true` if the client holds the privatekey for that identity, otherwise `false`' + type: Data, + desc: '`32 Bytes` A unique identity to refer to this keypair by.' } }, - newGroup: { - nodoc: 'Not present in Rust code', - desc: '(?)', + newSymKey: { + desc: 'Generate a key pair(identity) for symmetric encryption.', params: [], returns: { - type: Data, desc: '60 Bytes - the address of the new group. (?)' + type: Data, + desc: '32 Bytes - the address of the new identiy' } }, - addToGroup: { - nodoc: 'Not present in Rust code', - desc: '(?)', + getPublicKey: { + desc: 'Get the public key associated with an asymmetric identity.', params: [ { type: Data, - desc: '60 Bytes - The identity address to add to a group (?)' + desc: '32 Bytes - The identity to fetch the public key for.' } ], returns: { - type: Boolean, - desc: '`true` if the identity was successfully added to the group, otherwise `false` (?)' + type: Data, + desc: '`64 Bytes` - The public key of the asymmetric identity.' } }, - newFilter: { - nodoc: 'Not present in Rust code', - desc: 'Creates filter to notify, when client receives whisper message matching the filter options.', + getPrivateKey: { + desc: 'Get the private key associated with an asymmetric identity.', + params: [ + { + type: Data, + desc: '32 Bytes - The identity to fetch the private key for.' + } + ], + returns: { + type: Data, + desc: '`32 Bytes` - The private key of the asymmetric identity.' + } + }, + + getSymKey: { + desc: 'Get the key associated with a symmetric identity.', + params: [ + { + type: Data, + desc: '`32 Bytes` - The identity to fetch the key for.' + } + ], + returns: { + type: Data, + desc: '`64 Bytes` - The key of the asymmetric identity.' + } + }, + + deleteKey: { + desc: 'Delete the key or key pair denoted by the given identity.', + params: [ + { + type: Data, + desc: '`32 Bytes` - The identity to remove.' + } + ], + returns: { + type: Data, + desc: '`true` on successful removal, `false` on unkown identity' + } + }, + + newMessageFilter: { + desc: 'Create a new polled filter for messages.', params: [ { type: Object, desc: 'The filter options:', details: { - to: { - type: Data, desc: '60 Bytes - Identity of the receiver. *When present it will try to decrypt any incoming message if the client holds the private key to this identity.*', + decryptWith: { + type: Data, + desc: '`32 bytes` - Identity of key used for description. null if listening for broadcasts.' + }, + from: { + type: Data, desc: '`32 Bytes` - if present, only accept messages signed by this key.', optional: true }, topics: { - type: Array, desc: 'Array of `Data` topics which the incoming message\'s topics should match. You can use the following combinations' + type: Array, + desc: 'Array of `Data`. Only accept messages matching these topics. Should be non-empty.' } } } ], returns: { - type: Quantity, - desc: 'The newly created filter' + type: Data, + desc: '`32 bytes` - Unique identity for this filter.' } }, - uninstallFilter: { + getFilterMesssages: { nodoc: 'Not present in Rust code', desc: 'Uninstalls a filter with given id. Should always be called when watch is no longer needed.\nAdditonally Filters timeout when they aren\'t requested with [shh_getFilterChanges](#shh_getfilterchanges) for a period of time.', params: [ @@ -150,30 +209,83 @@ export default { } }, - getFilterChanges: { - nodoc: 'Not present in Rust code', + getFilterMessages: { desc: 'Polling method for whisper filters. Returns new messages since the last call of this method.\n**Note** calling the [shh_getMessages](#shh_getmessages) method, will reset the buffer for this method, so that you won\'t receive duplicate messages.', params: [ { - type: Quantity, - desc: 'The filter id' + type: Data, + desc: '`32 bytes` - Unique identity to fetch changes for.' } ], returns: { type: Array, - desc: 'Array of messages received since last poll' + desc: 'Array of `messages` received since last poll', + details: { + from: { + type: Data, + desc: '`64 bytes` - Public key that signed this message or null' + }, + recipient: { + type: Data, + desc: '`32 bytes` - local identity which decrypted this message, or null if broadcast.' + }, + ttl: { + type: Quantity, + desc: 'time to live of the message in seconds.' + }, + topics: { + type: Array, + desc: 'Array of `Data` - Topics which matched the filter' + }, + timestamp: { + type: Quantity, + desc: 'Unix timestamp of the message' + }, + payload: { + type: Data, + desc: 'The message body' + }, + padding: { + type: Data, + desc: 'Optional padding which was decoded.' + } + } } }, - getMessages: { - nodoc: 'Not present in Rust code', - desc: 'Get all messages matching a filter. Unlike `shh_getFilterChanges` this returns all messages.', + deleteMessageFilter: { + desc: 'Delete a message filter by identifier', params: [ { - type: Quantity, - desc: 'The filter id' + type: Data, + desc: '`32 bytes` - The identity of the filter to delete.' } ], - returns: 'See [shh_getFilterChanges](#shh_getfilterchanges)' + returns: { + type: Boolean, + desc: '`true` on deletion, `false` on unrecognized ID.' + } + }, + subscribe: { + desc: 'Open a subscription to a filter.', + params: [{ + type: Data, + desc: 'See [shh_newMessageFilter](#shh_newmessagefilter)' + }], + returns: { + type: Quantity, + desc: 'Unique subscription identifier' + } + }, + unsubscribe: { + desc: 'Close a subscribed filter', + params: [{ + type: Quantity, + desc: 'Unique subscription identifier' + }], + returns: { + type: Boolean, + desc: '`true` on success, `false` on unkown subscription ID.' + } } }; diff --git a/js/src/jsonrpc/types.js b/js/src/jsonrpc/types.js index 52e79019e..bd69cc863 100644 --- a/js/src/jsonrpc/types.js +++ b/js/src/jsonrpc/types.js @@ -22,6 +22,8 @@ export class Hash {} export class Integer {} +export class Float {} + export class Quantity {} export class BlockNumber { @@ -171,9 +173,9 @@ export class TransactionResponse { type: Data, desc: 'Public key of the signer.' }, - networkId: { + chainId: { type: Quantity, - desc: 'The network id of the transaction, if any.' + desc: 'The chain id of the transaction, if any.' }, standardV: { type: Quantity, diff --git a/js/src/lib.rs.in b/js/src/lib.rs.in index 220811656..b811c1066 100644 --- a/js/src/lib.rs.in +++ b/js/src/lib.rs.in @@ -51,5 +51,5 @@ impl WebApp for App { #[test] fn test_js() { - parity_dapps_glue::js::build(env!("CARGO_MANIFEST_DIR")); + parity_dapps_glue::js::build(env!("CARGO_MANIFEST_DIR"), "build"); } diff --git a/js/src/modals/AddContract/types.js b/js/src/modals/AddContract/types.js index b229fc7ac..dd1e20fbc 100644 --- a/js/src/modals/AddContract/types.js +++ b/js/src/modals/AddContract/types.js @@ -17,7 +17,7 @@ import React from 'react'; import { FormattedMessage } from 'react-intl'; -import { eip20, wallet } from '~/contracts/abi'; +import { eip20, foundationWallet } from '~/contracts/abi'; const ABI_TYPES = [ { @@ -72,7 +72,7 @@ const ABI_TYPES = [ ), readOnly: true, type: 'multisig', - value: JSON.stringify(wallet) + value: JSON.stringify(foundationWallet) }, { description: ( diff --git a/js/src/modals/CreateWallet/createWalletStore.js b/js/src/modals/CreateWallet/createWalletStore.js index d614e8041..26ed5816c 100644 --- a/js/src/modals/CreateWallet/createWalletStore.js +++ b/js/src/modals/CreateWallet/createWalletStore.js @@ -21,7 +21,7 @@ import { FormattedMessage } from 'react-intl'; import Contract from '~/api/contract'; import Contracts from '~/contracts'; -import { wallet as walletAbi } from '~/contracts/abi'; +import { foundationWallet as walletAbi } from '~/contracts/abi'; import { wallet as walletCode, walletLibrary as walletLibraryCode, walletLibraryRegKey, fullWalletCode } from '~/contracts/code/wallet'; import { validateUint, validateAddress, validateName } from '~/util/validation'; @@ -163,11 +163,11 @@ export default class CreateWalletStore { WalletsUtils.fetchOwners(walletContract), WalletsUtils.fetchDailylimit(walletContract) ]) - .then(([ require, owners, dailylimit ]) => { + .then(([ require, owners, daylimit ]) => { transaction(() => { this.wallet.owners = owners; this.wallet.required = require.toNumber(); - this.wallet.dailylimit = dailylimit.limit; + this.wallet.daylimit = daylimit.limit; this.wallet = this.getWalletWithMeta(this.wallet); }); diff --git a/js/src/modals/Transfer/store.js b/js/src/modals/Transfer/store.js index 737bab778..eaccf4f40 100644 --- a/js/src/modals/Transfer/store.js +++ b/js/src/modals/Transfer/store.js @@ -18,12 +18,12 @@ import { noop } from 'lodash'; import { observable, computed, action, transaction } from 'mobx'; import BigNumber from 'bignumber.js'; -import { eip20 as tokenAbi, wallet as walletAbi } from '~/contracts/abi'; +import { eip20 as tokenAbi } from '~/contracts/abi'; import { fromWei } from '~/api/util/wei'; -import Contract from '~/api/contract'; import ERRORS from './errors'; -import { DEFAULT_GAS, DEFAULT_GASPRICE, MAX_GAS_ESTIMATION } from '~/util/constants'; +import { DEFAULT_GAS } from '~/util/constants'; import { ETH_TOKEN } from '~/util/tokens'; +import { getTxOptions } from '~/util/tx'; import GasPriceStore from '~/ui/GasPriceEditor/store'; import { getLogger, LOG_KEYS } from '~/config'; @@ -92,7 +92,6 @@ export default class TransferStore { if (this.isWallet) { this.wallet = props.wallet; - this.walletContract = new Contract(this.api, walletAbi); } if (senders) { @@ -115,19 +114,13 @@ export default class TransferStore { @computed get isValid () { const detailsValid = !this.recipientError && !this.valueError && !this.totalError && !this.senderError; const extrasValid = !this.gasStore.errorGas && !this.gasStore.errorPrice && !this.gasStore.conditionBlockError && !this.totalError; - const verifyValid = !this.passwordError; switch (this.stage) { case 0: return detailsValid; case 1: - return this.extras - ? extrasValid - : verifyValid; - - case 2: - return verifyValid; + return extrasValid; } } @@ -263,16 +256,21 @@ export default class TransferStore { if (this.isWallet && !valueError) { const { last, limit, spent } = this.wallet.dailylimit; - const remains = fromWei(limit.minus(spent)); - const today = Math.round(Date.now() / (24 * 3600 * 1000)); - const isResetable = last.lt(today); - if ((!isResetable && remains.lt(value)) || fromWei(limit).lt(value)) { - // already spent too much today - this.walletWarning = WALLET_WARNING_SPENT_TODAY_LIMIT; - } else if (this.walletWarning) { - // all ok - this.walletWarning = null; + // Don't show a warning if the limit is 0 + // (will always need confirmations) + if (limit.gt(0)) { + const remains = fromWei(limit.minus(spent)); + const today = Math.round(Date.now() / (24 * 3600 * 1000)); + const willResetLimit = last.lt(today); + + if ((!willResetLimit && remains.lt(value)) || fromWei(limit).lt(value)) { + // already spent too much today + this.walletWarning = WALLET_WARNING_SPENT_TODAY_LIMIT; + } else if (this.walletWarning) { + // all ok + this.walletWarning = null; + } } } @@ -312,24 +310,16 @@ export default class TransferStore { }); } - getBalance (forceSender = false) { - if (this.isWallet && !forceSender) { - return this.balance; - } - - const balance = this.senders - ? this.sendersBalances[this.sender] - : this.balance; - - return balance; - } - /** * Return the balance of the selected token * (in WEI for ETH, without formating for other tokens) */ - getTokenBalance (token = this.token, forceSender = false) { - return new BigNumber(this.balance[token.id] || 0); + getTokenBalance (token = this.token, address = this.account.address) { + const balance = address === this.account.address + ? this.balance + : this.sendersBalances[address]; + + return new BigNumber(balance[token.id] || 0); } getTokenValue (token = this.token, value = this.value, inverse = false) { @@ -348,54 +338,30 @@ export default class TransferStore { return _value.mul(token.format); } - getValues (_gasTotal) { - const gasTotal = new BigNumber(_gasTotal || 0); + getValue () { const { valueAll, isEth, isWallet } = this; - log.debug('@getValues', 'gas', gasTotal.toFormat()); - if (!valueAll) { const value = this.getTokenValue(); - // If it's a token or a wallet, eth is the estimated gas, - // and value is the user input - if (!isEth || isWallet) { - return { - eth: gasTotal, - token: value - }; - } - - // Otherwise, eth is the sum of the gas and the user input - const totalEthValue = gasTotal.plus(value); - - return { - eth: totalEthValue, - token: value - }; + return value; } - // If it's the total balance that needs to be sent, send the total balance - // if it's not a proper ETH transfer + const balance = this.getTokenBalance(); + if (!isEth || isWallet) { - const tokenBalance = this.getTokenBalance(); - - return { - eth: gasTotal, - token: tokenBalance - }; + return balance; } - // Otherwise, substract the gas estimate - const availableEth = this.getTokenBalance(ETH_TOKEN); - const totalEthValue = availableEth.gt(gasTotal) - ? availableEth.minus(gasTotal) + // substract the gas estimate + const gasTotal = new BigNumber(this.gasStore.price || 0) + .mul(new BigNumber(this.gasStore.gas || 0)); + + const totalEthValue = balance.gt(gasTotal) + ? balance.minus(gasTotal) : new BigNumber(0); - return { - eth: totalEthValue.plus(gasTotal), - token: totalEthValue - }; + return totalEthValue; } getFormattedTokenValue (tokenValue) { @@ -403,160 +369,125 @@ export default class TransferStore { } @action recalculate = (redo = false) => { - const { account } = this; + const { account, balance } = this; - if (!account || !this.balance) { + if (!account || !balance) { return; } - const balance = this.getBalance(); + return this.getTransactionOptions() + .then((options) => { + const gasTotal = options.gas.mul(options.gasPrice); - if (!balance) { - return; - } + const tokenValue = this.getValue(); + const ethValue = options.value.add(gasTotal); - const gasTotal = new BigNumber(this.gasStore.price || 0).mul(new BigNumber(this.gasStore.gas || 0)); + const tokenBalance = this.getTokenBalance(); + const ethBalance = this.getTokenBalance(ETH_TOKEN, options.from); - const ethBalance = this.getTokenBalance(ETH_TOKEN, true); - const tokenBalance = this.getTokenBalance(); - const { eth, token } = this.getValues(gasTotal); + let totalError = null; + let valueError = null; - let totalError = null; - let valueError = null; + if (tokenValue.gt(tokenBalance)) { + valueError = ERRORS.largeAmount; + } - if (eth.gt(ethBalance)) { - totalError = ERRORS.largeAmount; - } + if (ethValue.gt(ethBalance)) { + totalError = ERRORS.largeAmount; + } - if (token && token.gt(tokenBalance)) { - valueError = ERRORS.largeAmount; - } + log.debug('@recalculate', { + eth: ethValue.toFormat(), + token: tokenValue.toFormat(), + ethBalance: ethBalance.toFormat(), + tokenBalance: tokenBalance.toFormat(), + gasTotal: gasTotal.toFormat() + }); - log.debug('@recalculate', { - eth: eth.toFormat(), - token: token.toFormat(), - ethBalance: ethBalance.toFormat(), - tokenBalance: tokenBalance.toFormat(), - gasTotal: gasTotal.toFormat() - }); + transaction(() => { + this.totalError = totalError; + this.valueError = valueError; + this.gasStore.setErrorTotal(totalError); + this.gasStore.setEthValue(options.value); - transaction(() => { - this.totalError = totalError; - this.valueError = valueError; - this.gasStore.setErrorTotal(totalError); - this.gasStore.setEthValue(eth.sub(gasTotal)); + this.total = fromWei(ethValue).toFixed(); - this.total = this.api.util.fromWei(eth).toFixed(); + const nextValue = this.getFormattedTokenValue(tokenValue); + let prevValue; - const nextValue = this.getFormattedTokenValue(token); - let prevValue; + try { + prevValue = new BigNumber(this.value || 0); + } catch (error) { + prevValue = new BigNumber(0); + } - try { - prevValue = new BigNumber(this.value || 0); - } catch (error) { - prevValue = new BigNumber(0); - } + // Change the input only if necessary + if (!nextValue.eq(prevValue)) { + this.value = nextValue.toString(); + } - // Change the input only if necessary - if (!nextValue.eq(prevValue)) { - this.value = nextValue.toString(); - } - - // Re Calculate gas once more to be sure - if (redo) { - return this.recalculateGas(false); - } - }); - } - - send () { - const { options, values } = this._getTransferParams(); - - log.debug('@send', 'transfer value', options.value && options.value.toFormat()); - - return this._getTransferMethod().postTransaction(options, values); - } - - _estimateGas (forceToken = false) { - const { options, values } = this._getTransferParams(true, forceToken); - - return this._getTransferMethod(true, forceToken).estimateGas(options, values); + // Re Calculate gas once more to be sure + if (redo) { + return this.recalculateGas(false); + } + }); + }); } estimateGas () { - return this._estimateGas(); + return this.getTransactionOptions() + .then((options) => { + return this.api.eth.estimateGas(options); + }); } - _getTransferMethod (gas = false, forceToken = false) { - const { isEth, isWallet } = this; + send () { + return this.getTransactionOptions() + .then((options) => { + log.debug('@send', 'transfer value', options.value && options.value.toFormat()); - if (isEth && !isWallet && !forceToken) { - return gas ? this.api.eth : this.api.parity; - } - - if (isWallet && !forceToken) { - return this.wallet.instance.execute; - } - - return this.tokenContract.at(this.token.address).instance.transfer; + return this.api.parity.postTransaction(options); + }); } - _getData (gas = false) { - const { isEth, isWallet } = this; + getTransactionOptions () { + const [ func, options, values ] = this._getTransactionArgs(); - if (!isWallet || isEth) { - return this.data && this.data.length ? this.data : ''; - } - - const func = this._getTransferMethod(gas, true); - const { options, values } = this._getTransferParams(gas, true); - - return this.tokenContract.at(this.token.address).getCallData(func, options, values); + return getTxOptions(this.api, func, options, values) + .then((_options) => { + delete _options.sender; + return _options; + }); } - _getTransferParams (gas = false, forceToken = false) { - const { isEth, isWallet } = this; - - const to = (isEth && !isWallet) ? this.recipient - : (this.isWallet ? this.wallet.address : this.token.address); + _getTransactionArgs () { + const { isEth } = this; + const value = this.getValue(); const options = this.gasStore.overrideTransaction({ - from: this.sender || this.account.address, - to + from: this.account.address, + sender: this.sender }); - if (gas) { - options.gas = MAX_GAS_ESTIMATION; - } - - const gasTotal = new BigNumber(options.gas || DEFAULT_GAS).mul(options.gasPrice || DEFAULT_GASPRICE); - const { token } = this.getValues(gasTotal); - - if (isEth && !isWallet && !forceToken) { - options.value = token; - options.data = this._getData(gas); - - return { options, values: [] }; - } - - if (isWallet && !forceToken) { - const to = isEth ? this.recipient : this.token.address; - const value = isEth ? token : new BigNumber(0); - - const values = [ - to, value, - this._getData(gas) - ]; - - return { options, values }; + // A simple ETH transfer + if (isEth) { + options.value = value; + options.data = this.data || ''; + options.to = this.recipient; + + return [ null, options ]; } + // A token transfer + const tokenContract = this.tokenContract.at(this.token.address); const values = [ this.recipient, - token.toFixed(0) + value ]; - return { options, values }; + options.to = this.token.address; + + return [ tokenContract.instance.transfer, options, values ]; } _validatePositiveNumber (num) { diff --git a/js/src/modals/WalletSettings/walletSettingsStore.js b/js/src/modals/WalletSettings/walletSettingsStore.js index d31ec9eb2..c3adb812e 100644 --- a/js/src/modals/WalletSettings/walletSettingsStore.js +++ b/js/src/modals/WalletSettings/walletSettingsStore.js @@ -20,6 +20,7 @@ import BigNumber from 'bignumber.js'; import { validateUint, validateAddress } from '~/util/validation'; import { DEFAULT_GAS, MAX_GAS_ESTIMATION } from '~/util/constants'; +import WalletsUtils from '~/util/wallets'; const STEPS = { EDIT: { title: 'wallet settings' }, @@ -220,8 +221,6 @@ export default class WalletSettingsStore { this.api = api; this.step = this.stepsKeys[0]; - this.walletInstance = wallet.instance; - this.initialWallet = { address: wallet.address, owners: wallet.owners, @@ -280,72 +279,43 @@ export default class WalletSettingsStore { @action send = () => { const changes = this.changes; - const walletInstance = this.walletInstance; - Promise.all(changes.map((change) => this.sendChange(change, walletInstance))); + Promise.all(changes.map((change) => this.sendChange(change))); this.onClose(); } - @action sendChange = (change, walletInstance) => { - const { method, values } = this.getChangeMethod(change, walletInstance); + @action sendChange = (change) => { + const { api, initialWallet } = this; - const options = { - from: this.wallet.sender, - to: this.initialWallet.address, - gas: MAX_GAS_ESTIMATION - }; - - return method - .estimateGas(options, values) - .then((gasEst) => { - let gas = gasEst; - - if (gas.gt(DEFAULT_GAS)) { - gas = gas.mul(1.2); + WalletsUtils.getChangeMethod(api, initialWallet.address, change) + .then((changeMethod) => { + if (!changeMethod) { + return; } - options.gas = gas; - return method.postTransaction(options, values); + const { method, values } = changeMethod; + + const options = { + from: this.wallet.sender, + to: initialWallet.address, + gas: MAX_GAS_ESTIMATION + }; + + return method + .estimateGas(options, values) + .then((gasEst) => { + let gas = gasEst; + + if (gas.gt(DEFAULT_GAS)) { + gas = gas.mul(1.2); + } + options.gas = gas; + + return method.postTransaction(options, values); + }); }); } - getChangeMethod = (change, walletInstance) => { - if (change.type === 'require') { - return { - method: walletInstance.changeRequirement, - values: [ change.value ] - }; - } - - if (change.type === 'dailylimit') { - return { - method: walletInstance.setDailyLimit, - values: [ change.value ] - }; - } - - if (change.type === 'add_owner') { - return { - method: walletInstance.addOwner, - values: [ change.value ] - }; - } - - if (change.type === 'change_owner') { - return { - method: walletInstance.changeOwner, - values: [ change.value.from, change.value.to ] - }; - } - - if (change.type === 'remove_owner') { - return { - method: walletInstance.removeOwner, - values: [ change.value ] - }; - } - } - @action validateWallet = (_wallet) => { const senderValidation = validateAddress(_wallet.sender); const requireValidation = validateUint(_wallet.require); diff --git a/js/src/redux/providers/personalActions.js b/js/src/redux/providers/personalActions.js index 6200537c3..f747fa92e 100644 --- a/js/src/redux/providers/personalActions.js +++ b/js/src/redux/providers/personalActions.js @@ -23,7 +23,7 @@ import { attachWallets } from './walletActions'; import Contract from '~/api/contract'; import MethodDecodingStore from '~/ui/MethodDecoding/methodDecodingStore'; import WalletsUtils from '~/util/wallets'; -import { wallet as WalletAbi } from '~/contracts/abi'; +import { foundationWallet as WalletAbi } from '~/contracts/abi'; export function personalAccountsInfo (accountsInfo) { const accounts = {}; diff --git a/js/src/redux/providers/status.js b/js/src/redux/providers/status.js index fc5dc38ba..e58fcf6c1 100644 --- a/js/src/redux/providers/status.js +++ b/js/src/redux/providers/status.js @@ -227,12 +227,12 @@ export default class Status { } _overallStatus = (health) => { - const all = [health.peers, health.sync, health.time].filter(x => x); - const allNoTime = [health.peers, health.sync].filter(x => x); + const allWithTime = [health.peers, health.sync, health.time].filter(x => x); + const all = [health.peers, health.sync].filter(x => x); const statuses = all.map(x => x.status); const bad = statuses.find(x => x === STATUS_BAD); - const needsAttention = allNoTime.map(x => x.status).find(x => x === STATUS_WARN); - const message = all.map(x => x.message).filter(x => x); + const needsAttention = statuses.find(x => x === STATUS_WARN); + const message = allWithTime.map(x => x.message).filter(x => x); if (all.length) { return { diff --git a/js/src/redux/providers/walletActions.js b/js/src/redux/providers/walletActions.js index b31a2b35b..58a8faca6 100644 --- a/js/src/redux/providers/walletActions.js +++ b/js/src/redux/providers/walletActions.js @@ -17,19 +17,17 @@ import { isEqual, uniq } from 'lodash'; import Contract from '~/api/contract'; -import { bytesToHex, toHex } from '~/api/util/format'; import { ERROR_CODES } from '~/api/transport/error'; -import { wallet as WALLET_ABI } from '~/contracts/abi'; -import { MAX_GAS_ESTIMATION } from '~/util/constants'; +import { foundationWallet as WALLET_ABI } from '~/contracts/abi'; import WalletsUtils from '~/util/wallets'; - import { newError } from '~/ui/Errors/actions'; - -const UPDATE_OWNERS = 'owners'; -const UPDATE_REQUIRE = 'require'; -const UPDATE_DAILYLIMIT = 'dailylimit'; -const UPDATE_TRANSACTIONS = 'transactions'; -const UPDATE_CONFIRMATIONS = 'confirmations'; +import { + UPDATE_OWNERS, + UPDATE_REQUIRE, + UPDATE_DAILYLIMIT, + UPDATE_TRANSACTIONS, + UPDATE_CONFIRMATIONS +} from '~/util/wallets/updates'; export function confirmOperation (address, owner, operation) { return modifyOperation('confirm', address, owner, operation); @@ -39,41 +37,25 @@ export function revokeOperation (address, owner, operation) { return modifyOperation('revoke', address, owner, operation); } -function modifyOperation (method, address, owner, operation) { +function modifyOperation (modification, address, owner, operation) { return (dispatch, getState) => { const { api } = getState(); - const contract = new Contract(api, WALLET_ABI).at(address); - - const options = { - from: owner, - gas: MAX_GAS_ESTIMATION - }; - - const values = [ operation ]; dispatch(setOperationPendingState(address, operation, true)); - contract.instance[method] - .estimateGas(options, values) - .then((gas) => { - options.gas = gas.mul(1.2); - return contract.instance[method].postTransaction(options, values); - }) + WalletsUtils.postModifyOperation(api, address, modification, owner, operation) .then((requestId) => { - return api - .pollMethod('parity_checkRequest', requestId) - .catch((e) => { - dispatch(setOperationPendingState(address, operation, false)); - if (e.code === ERROR_CODES.REQUEST_REJECTED) { - return; - } - - throw e; - }); + return api.pollMethod('parity_checkRequest', requestId); }) .catch((error) => { - dispatch(setOperationPendingState(address, operation, false)); + if (error.code === ERROR_CODES.REQUEST_REJECTED) { + return; + } + dispatch(newError(error)); + }) + .then(() => { + dispatch(setOperationPendingState(address, operation, false)); }); }; } @@ -97,14 +79,18 @@ export function attachWallets (_wallets) { return dispatch(updateWallets({ wallets: {}, walletsAddresses: [], filterSubId: null })); } - const filterOptions = { - fromBlock: 0, - toBlock: 'latest', - address: nextAddresses - }; - + // Filter the logs from the current block api.eth - .newFilter(filterOptions) + .blockNumber() + .then((block) => { + const filterOptions = { + fromBlock: block, + toBlock: 'latest', + address: nextAddresses + }; + + return api.eth.newFilter(filterOptions); + }) .then((filterId) => { dispatch(updateWallets({ wallets: _wallets, walletsAddresses: nextAddresses, filterSubId: filterId })); }) @@ -142,7 +128,6 @@ export function load (api) { api.eth .getFilterChanges(filterSubId) - .then((logs) => contract.parseEventLogs(logs)) .then((logs) => { parseLogs(logs)(dispatch, getState); }) @@ -292,202 +277,57 @@ function fetchWalletDailylimit (contract) { } function fetchWalletConfirmations (contract, _operations, _owners = null, _transactions = null, getState) { - const walletInstance = contract.instance; - const wallet = getState().wallet.wallets[contract.address]; const owners = _owners || (wallet && wallet.owners) || null; const transactions = _transactions || (wallet && wallet.transactions) || null; - // Full load if no operations given, or if the one given aren't loaded yet - const fullLoad = !Array.isArray(_operations) || _operations - .filter((op) => !wallet.confirmations.find((conf) => conf.operation === op)) - .length > 0; + const cache = { owners, transactions }; - let promise; - - if (fullLoad) { - promise = walletInstance - .ConfirmationNeeded - .getAllLogs() - .then((logs) => { - return logs.map((log) => ({ - initiator: log.params.initiator.value, - to: log.params.to.value, - data: log.params.data.value, - value: log.params.value.value, - operation: bytesToHex(log.params.operation.value), - transactionIndex: log.transactionIndex, - transactionHash: log.transactionHash, - blockNumber: log.blockNumber, - confirmedBy: [] - })); - }) - .then((logs) => { - return logs.sort((logA, logB) => { - const comp = logA.blockNumber.comparedTo(logB.blockNumber); - - if (comp !== 0) { - return comp; - } - - return logA.transactionIndex.comparedTo(logB.transactionIndex); - }); - }) - .then((confirmations) => { - if (confirmations.length === 0) { - return confirmations; - } - - // Only fetch confirmations for operations not - // yet confirmed (ie. not yet a transaction) - if (transactions) { - const operations = transactions - .filter((t) => t.operation) - .map((t) => t.operation); - - return confirmations.filter((confirmation) => { - return !operations.includes(confirmation.operation); - }); - } - - return confirmations; - }); - } else { - const { confirmations } = wallet; - const nextConfirmations = confirmations - .filter((conf) => _operations.includes(conf.operation)); - - promise = Promise.resolve(nextConfirmations); - } - - return promise + return WalletsUtils.fetchPendingTransactions(contract, cache) .then((confirmations) => { - if (confirmations.length === 0) { - return confirmations; - } - - const uniqConfirmations = Object.values( - confirmations.reduce((confirmations, confirmation) => { - confirmations[confirmation.operation] = confirmation; - return confirmations; - }, {}) - ); - - const operations = uniqConfirmations.map((conf) => conf.operation); - - return Promise - .all(operations.map((op) => fetchOperationConfirmations(contract, op, owners))) - .then((confirmedBys) => { - uniqConfirmations.forEach((_, index) => { - uniqConfirmations[index].confirmedBy = confirmedBys[index]; - }); - - return uniqConfirmations; - }); - }) - .then((confirmations) => { - const prevConfirmations = wallet.confirmations || []; - const nextConfirmations = prevConfirmations - .filter((conA) => !confirmations.find((conB) => conB.operation === conA.operation)) - .concat(confirmations) - .map((conf) => ({ - ...conf, - pending: false - })); - return { key: UPDATE_CONFIRMATIONS, - value: nextConfirmations + value: confirmations }; }); } -function fetchOperationConfirmations (contract, operation, owners = null) { - if (!owners) { - console.warn('[fetchOperationConfirmations] try to provide the owners for the Wallet', contract.address); - } - - const walletInstance = contract.instance; - - const promise = owners - ? Promise.resolve({ value: owners }) - : fetchWalletOwners(contract); - - return promise - .then((result) => { - const owners = result.value; - - return Promise - .all(owners.map((owner) => walletInstance.hasConfirmed.call({}, [ operation, owner ]))) - .then((data) => { - return owners.filter((owner, index) => data[index]); - }); - }); -} - function parseLogs (logs) { return (dispatch, getState) => { if (!logs || logs.length === 0) { return; } - const WalletSignatures = WalletsUtils.getWalletSignatures(); - + const { api } = getState(); const updates = {}; - logs.forEach((log) => { - const { address, topics } = log; - const eventSignature = toHex(topics[0]); - const prev = updates[address] || { - [ UPDATE_DAILYLIMIT ]: true, - address - }; + const promises = logs.map((log) => { + const { address } = log; - switch (eventSignature) { - case WalletSignatures.OwnerChanged: - case WalletSignatures.OwnerAdded: - case WalletSignatures.OwnerRemoved: - updates[address] = { - ...prev, - [ UPDATE_OWNERS ]: true + return WalletsUtils.logToUpdate(api, address, log) + .then((update) => { + const prev = updates[address] || { + [ UPDATE_DAILYLIMIT ]: true, + address }; - return; - case WalletSignatures.RequirementChanged: - updates[address] = { - ...prev, - [ UPDATE_REQUIRE ]: true - }; - return; + if (update[UPDATE_CONFIRMATIONS]) { + const operations = (prev[UPDATE_CONFIRMATIONS] || []).concat(update[UPDATE_CONFIRMATIONS]); - case WalletSignatures.ConfirmationNeeded: - case WalletSignatures.Confirmation: - case WalletSignatures.Revoke: - const operation = bytesToHex(log.params.operation.value); + update[UPDATE_CONFIRMATIONS] = uniq(operations); + } updates[address] = { ...prev, - [ UPDATE_CONFIRMATIONS ]: uniq( - (prev[UPDATE_CONFIRMATIONS] || []).concat(operation) - ) + ...update }; - - return; - - case WalletSignatures.Deposit: - case WalletSignatures.SingleTransact: - case WalletSignatures.MultiTransact: - case WalletSignatures.Old.SingleTransact: - case WalletSignatures.Old.MultiTransact: - updates[address] = { - ...prev, - [ UPDATE_TRANSACTIONS ]: true - }; - return; - } + }); }); - fetchWalletsInfo(updates)(dispatch, getState); + return Promise.all(promises) + .then(() => { + fetchWalletsInfo(updates)(dispatch, getState); + }); }; } diff --git a/js/src/secureApi.js b/js/src/secureApi.js index c34f71dd9..76b7eadf8 100644 --- a/js/src/secureApi.js +++ b/js/src/secureApi.js @@ -325,7 +325,8 @@ export default class SecureApi extends Api { _fetchSettings () { return Promise .all([ - this._uiApi.parity.dappsUrl(), + // ignore dapps disabled errors + this._uiApi.parity.dappsUrl().catch(() => null), this._uiApi.parity.wsUrl() ]) .then(([dappsUrl, wsUrl]) => { diff --git a/js/src/util/tx.js b/js/src/util/tx.js index 9ab8b6599..e325e6024 100644 --- a/js/src/util/tx.js +++ b/js/src/util/tx.js @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +import BigNumber from 'bignumber.js'; + import WalletsUtils from '~/util/wallets'; /** @@ -71,11 +73,14 @@ const isValidReceipt = (receipt) => { return receipt && receipt.blockNumber && receipt.blockNumber.gt(0); }; -function getTxArgs (func, options, values = []) { - const { contract } = func; - const { api } = contract; +export function getTxOptions (api, func, _options, values = []) { + const options = { ..._options }; const address = options.from; + if (func && func.contract) { + options.to = options.to || func.contract.address; + } + if (!address) { return Promise.resolve({ func, options, values }); } @@ -87,8 +92,9 @@ function getTxArgs (func, options, values = []) { return { func, options, values }; } - options.data = contract.getCallData(func, options, values); - options.to = options.to || contract.address; + if (func && func.contract) { + options.data = func.contract.getCallData(func, options, values); + } if (!options.to) { return { func, options, values }; @@ -103,24 +109,35 @@ function getTxArgs (func, options, values = []) { return callArgs; }); + }) + .then(({ func, options, values }) => { + if (func) { + options.data = func.contract.getCallData(func, options, values); + } + + if (!options.value) { + options.value = new BigNumber(0); + } + + return options; }); } export function estimateGas (_func, _options, _values = []) { - return getTxArgs(_func, _options, _values) - .then((callArgs) => { - const { func, options, values } = callArgs; + const { api } = _func.contract; - return func._estimateGas(options, values); + return getTxOptions(api, _func, _options, _values) + .then((options) => { + return api.eth.estimateGas(options); }); } export function postTransaction (_func, _options, _values = []) { - return getTxArgs(_func, _options, _values) - .then((callArgs) => { - const { func, options, values } = callArgs; + const { api } = _func.contract; - return func._postTransaction(options, values); + return getTxOptions(api, _func, _options, _values) + .then((options) => { + return api.parity.postTransaction(options); }); } @@ -182,42 +199,35 @@ export function deploy (contract, options, values, skipGasEstimate = false) { } export function parseTransactionReceipt (api, options, receipt) { - const { metadata } = options; - const address = options.from; - if (receipt.gasUsed.eq(options.gas)) { const error = new Error(`Contract not deployed, gasUsed == ${options.gas.toFixed(0)}`); return Promise.reject(error); } - const logs = WalletsUtils.parseLogs(api, receipt.logs || []); + // If regular contract creation, only validate the contract + if (receipt.contractAddress) { + return validateContract(api, receipt.contractAddress); + } - const confirmationLog = logs.find((log) => log.event === 'ConfirmationNeeded'); - const transactionLog = logs.find((log) => log.event === 'SingleTransact'); + // Otherwise, needs to check for a contract deployment + // from a multisig wallet + const walletResult = WalletsUtils.parseTransactionLogs(api, options, receipt.logs || []); - if (!confirmationLog && !transactionLog && !receipt.contractAddress) { + if (!walletResult) { const error = new Error('Something went wrong in the contract deployment...'); return Promise.reject(error); } - // Confirmations are needed from the other owners - if (confirmationLog) { - const operationHash = api.util.bytesToHex(confirmationLog.params.operation.value); - - // Add the contract to pending contracts - WalletsUtils.addPendingContract(address, operationHash, metadata); + if (walletResult.pending) { return Promise.resolve(null); } - if (transactionLog) { - // Set the contract address in the receipt - receipt.contractAddress = transactionLog.params.created.value; - } - - const contractAddress = receipt.contractAddress; + return validateContract(api, walletResult.contractAddress); +} +function validateContract (api, contractAddress) { return api.eth .getCode(contractAddress) .then((code) => { diff --git a/js/src/util/wallets.js b/js/src/util/wallets.js index e90f4115f..6b1c29d01 100644 --- a/js/src/util/wallets.js +++ b/js/src/util/wallets.js @@ -15,95 +15,96 @@ // along with Parity. If not, see . import BigNumber from 'bignumber.js'; -import { intersection, range, uniq } from 'lodash'; -import store from 'store'; +import { intersection } from 'lodash'; -import Abi from '~/abi'; -import Contract from '~/api/contract'; -import { bytesToHex, toHex } from '~/api/util/format'; -import { validateAddress } from '~/util/validation'; -import WalletAbi from '~/contracts/abi/wallet.json'; -import OldWalletAbi from '~/contracts/abi/old-wallet.json'; +import ConsensysWalletUtils from './wallets/consensys-wallet'; +import FoundationWalletUtils from './wallets/foundation-wallet'; -const LS_PENDING_CONTRACTS_KEY = '_parity::wallets::pendingContracts'; +const CONSENSYS_WALLET = 'CONSENSYS_WALLET'; +const FOUNDATION_WALLET = 'FOUNDATION_WALLET'; const _cachedWalletLookup = {}; +const _cachedWalletTypes = {}; let _cachedAccounts = {}; -const walletAbi = new Abi(WalletAbi); -const oldWalletAbi = new Abi(OldWalletAbi); - -const walletEvents = walletAbi.events.reduce((events, event) => { - events[event.name] = event; - return events; -}, {}); - -const oldWalletEvents = oldWalletAbi.events.reduce((events, event) => { - events[event.name] = event; - return events; -}, {}); - -const WalletSignatures = { - OwnerChanged: toHex(walletEvents.OwnerChanged.signature), - OwnerAdded: toHex(walletEvents.OwnerAdded.signature), - OwnerRemoved: toHex(walletEvents.OwnerRemoved.signature), - RequirementChanged: toHex(walletEvents.RequirementChanged.signature), - Confirmation: toHex(walletEvents.Confirmation.signature), - Revoke: toHex(walletEvents.Revoke.signature), - Deposit: toHex(walletEvents.Deposit.signature), - SingleTransact: toHex(walletEvents.SingleTransact.signature), - MultiTransact: toHex(walletEvents.MultiTransact.signature), - ConfirmationNeeded: toHex(walletEvents.ConfirmationNeeded.signature), - - Old: { - SingleTransact: toHex(oldWalletEvents.SingleTransact.signature), - MultiTransact: toHex(oldWalletEvents.MultiTransact.signature) - } -}; - export default class WalletsUtils { - static getWalletSignatures () { - return WalletSignatures; - } - - static getPendingContracts () { - return store.get(LS_PENDING_CONTRACTS_KEY) || {}; - } - - static setPendingContracts (contracts = {}) { - return store.set(LS_PENDING_CONTRACTS_KEY, contracts); - } - - static removePendingContract (operationHash) { - const nextContracts = WalletsUtils.getPendingContracts(); - - delete nextContracts[operationHash]; - WalletsUtils.setPendingContracts(nextContracts); - } - - static addPendingContract (address, operationHash, metadata) { - const nextContracts = { - ...WalletsUtils.getPendingContracts(), - [ operationHash ]: { - address, - metadata, - operationHash - } - }; - - WalletsUtils.setPendingContracts(nextContracts); - } - static cacheAccounts (accounts) { _cachedAccounts = accounts; } - static getCallArgs (api, options, values = []) { - const walletContract = new Contract(api, WalletAbi); - const walletAddress = options.from; + static delegateCall (api, address, method, args = []) { + return WalletsUtils.getWalletType(api, address) + .then((walletType) => { + if (walletType === CONSENSYS_WALLET) { + return ConsensysWalletUtils[method].apply(null, args); + } + + return FoundationWalletUtils[method].apply(null, args); + }); + } + + static fetchDailylimit (walletContract) { + const { api } = walletContract; return WalletsUtils - .fetchOwners(walletContract.at(walletAddress)) + .delegateCall(api, walletContract.address, 'fetchDailylimit', [ walletContract ]); + } + + static fetchOwners (walletContract) { + const { api } = walletContract; + + return WalletsUtils + .delegateCall(api, walletContract.address, 'fetchOwners', [ walletContract ]); + } + + static fetchRequire (walletContract) { + const { api } = walletContract; + + return WalletsUtils + .delegateCall(api, walletContract.address, 'fetchRequire', [ walletContract ]); + } + + static fetchPendingTransactions (walletContract, cache) { + const { api } = walletContract; + + return WalletsUtils + .delegateCall(api, walletContract.address, 'fetchPendingTransactions', [ walletContract, cache ]); + } + + static fetchTransactions (walletContract) { + const { api } = walletContract; + + return WalletsUtils + .delegateCall(api, walletContract.address, 'fetchTransactions', [ walletContract ]) + .then((transactions) => { + return transactions.sort((txA, txB) => { + const comp = txB.blockNumber.comparedTo(txA.blockNumber); + + if (comp !== 0) { + return comp; + } + + return txB.transactionIndex.comparedTo(txA.transactionIndex); + }); + }); + } + + static getCallArgs (api, options, values = []) { + const walletAddress = options.from; + let walletContract; + let submitMethod; + + return Promise + .all([ + WalletsUtils.getWalletContract(api, walletAddress), + WalletsUtils.delegateCall(api, walletAddress, 'getSubmitMethod') + ]) + .then(([ _walletContract, _submitMethod ]) => { + walletContract = _walletContract; + submitMethod = _submitMethod; + + return WalletsUtils.fetchOwners(walletContract); + }) .then((owners) => { const addresses = Object.keys(_cachedAccounts); const ownerAddress = intersection(addresses, owners).pop(); @@ -121,12 +122,12 @@ export default class WalletsUtils { const nextValues = [ to, value, data ]; const nextOptions = { ..._options, - from: ownerAddress, + from: options.sender || ownerAddress, to: walletAddress, value: new BigNumber(0) }; - const execFunc = walletContract.instance.execute; + const execFunc = walletContract.instance[submitMethod]; const callArgs = { func: execFunc, options: nextOptions, values: nextValues }; if (!account.wallet) { @@ -139,6 +140,11 @@ export default class WalletsUtils { }); } + static getChangeMethod (api, address, change) { + return WalletsUtils + .delegateCall(api, address, 'getChangeMethod', [ api, address, change ]); + } + static getDeployArgs (contract, options, values) { const { api } = contract; const func = contract.constructors[0]; @@ -158,10 +164,41 @@ export default class WalletsUtils { }); } - static parseLogs (api, logs = []) { - const walletContract = new Contract(api, WalletAbi); + static getWalletContract (api, address) { + return WalletsUtils + .delegateCall(api, address, 'getWalletContract', [ api ]) + .then((walletContract) => { + return walletContract.at(address); + }); + } - return walletContract.parseEventLogs(logs); + static getWalletType (api, address) { + if (_cachedWalletTypes[address] === undefined) { + _cachedWalletTypes[address] = Promise.resolve(null) + .then((result) => { + if (result) { + return result; + } + + return FoundationWalletUtils.isWallet(api, address) + .then((isWallet) => isWallet && FOUNDATION_WALLET); + }) + .then((result) => { + if (result) { + return result; + } + + return ConsensysWalletUtils.isWallet(api, address) + .then((isWallet) => isWallet && CONSENSYS_WALLET); + }) + .then((result) => { + _cachedWalletTypes[address] = result || null; + + return _cachedWalletTypes[address]; + }); + } + + return Promise.resolve(_cachedWalletTypes[address]); } /** @@ -175,20 +212,8 @@ export default class WalletsUtils { } if (!_cachedWalletLookup[address]) { - const walletContract = new Contract(api, WalletAbi); - - _cachedWalletLookup[address] = walletContract - .at(address) - .instance - .m_numOwners - .call() - .then((result) => { - if (!result || result.equals(0)) { - return false; - } - - return true; - }) + _cachedWalletLookup[address] = WalletsUtils.getWalletType(api, address) + .then((walletType) => walletType !== null) .then((bool) => { _cachedWalletLookup[address] = Promise.resolve(bool); return bool; @@ -198,207 +223,34 @@ export default class WalletsUtils { return _cachedWalletLookup[address]; } - static fetchRequire (walletContract) { - return walletContract.instance.m_required.call(); - } - - static fetchOwners (walletContract) { - const walletInstance = walletContract.instance; - - return walletInstance - .m_numOwners.call() - .then((mNumOwners) => { - const promises = range(mNumOwners.toNumber()) - .map((idx) => walletInstance.getOwner.call({}, [ idx ])); - - return Promise - .all(promises) - .then((owners) => { - const uniqOwners = uniq(owners); - - // If all owners are the zero account : must be Mist wallet contract - if (uniqOwners.length === 1 && /^(0x)?0*$/.test(owners[0])) { - return WalletsUtils.fetchMistOwners(walletContract, mNumOwners.toNumber()); - } - - return owners; - }) - .then((owners) => uniq(owners)); - }); - } - - static fetchMistOwners (walletContract, mNumOwners) { - const walletAddress = walletContract.address; - + static logToUpdate (api, address, log) { return WalletsUtils - .getMistOwnersOffset(walletContract) - .then((result) => { - if (!result || result.offset === -1) { - return []; - } - - const owners = [ result.address ]; - - if (mNumOwners === 1) { - return owners; - } - - const initOffset = result.offset + 1; - let promise = Promise.resolve(); - - range(initOffset, initOffset + mNumOwners - 1).forEach((offset) => { - promise = promise - .then(() => { - return walletContract.api.eth.getStorageAt(walletAddress, offset); - }) - .then((result) => { - const resultAddress = '0x' + (result || '').slice(-40); - const { address } = validateAddress(resultAddress); - - owners.push(address); - }); - }); - - return promise.then(() => owners); - }); + .delegateCall(api, address, 'logToUpdate', [ log ]); } - static getMistOwnersOffset (walletContract, offset = 3) { - return walletContract.api.eth - .getStorageAt(walletContract.address, offset) - .then((result) => { - if (result && !/^(0x)?0*$/.test(result)) { - const resultAddress = '0x' + result.slice(-40); - const { address, addressError } = validateAddress(resultAddress); - - if (!addressError) { - return { offset, address }; - } - } - - if (offset >= 100) { - return { offset: -1 }; - } - - return WalletsUtils.getMistOwnersOffset(walletContract, offset + 1); - }); + static parseTransactionLogs (api, options, rawLogs) { + return WalletsUtils + .delegateCall(api, options.from, 'parseTransactionLogs', [ api, options, rawLogs ]); } - static fetchDailylimit (walletContract) { - const walletInstance = walletContract.instance; + static postModifyOperation (api, walletAddress, modification, owner, operation) { + const options = { from: owner }; + const values = [ operation ]; return Promise .all([ - walletInstance.m_dailyLimit.call(), - walletInstance.m_spentToday.call(), - walletInstance.m_lastDay.call() + WalletsUtils + .getWalletContract(api, walletAddress), + WalletsUtils + .delegateCall(api, walletAddress, 'getModifyOperationMethod', [ modification ]) ]) - .then(([ limit, spent, last ]) => ({ - limit, spent, last - })); - } - - static fetchTransactions (walletContract) { - const { api } = walletContract; - const pendingContracts = WalletsUtils.getPendingContracts(); - - return walletContract - .getAllLogs({ - topics: [ [ - WalletSignatures.SingleTransact, - WalletSignatures.MultiTransact, - WalletSignatures.Deposit, - WalletSignatures.Old.SingleTransact, - WalletSignatures.Old.MultiTransact - ] ] - }) - .then((logs) => { - return logs.sort((logA, logB) => { - const comp = logB.blockNumber.comparedTo(logA.blockNumber); - - if (comp !== 0) { - return comp; - } - - return logB.transactionIndex.comparedTo(logA.transactionIndex); - }); - }) - .then((logs) => { - const transactions = logs.map((log) => { - const signature = toHex(log.topics[0]); - - const value = log.params.value.value; - const from = signature === WalletSignatures.Deposit - ? log.params['_from'].value - : walletContract.address; - - const to = signature === WalletSignatures.Deposit - ? walletContract.address - : log.params.to.value; - - const transaction = { - transactionHash: log.transactionHash, - blockNumber: log.blockNumber, - from, to, value - }; - - if (log.params.created && log.params.created.value && !/^(0x)?0*$/.test(log.params.created.value)) { - transaction.creates = log.params.created.value; - delete transaction.to; - } - - if (log.params.operation) { - const operation = bytesToHex(log.params.operation.value); - - // Add the pending contract to the contracts - if (pendingContracts[operation]) { - const { metadata } = pendingContracts[operation]; - const contractName = metadata.name; - - metadata.blockNumber = log.blockNumber; - - // The contract creation might not be in the same log, - // but must be in the same transaction (eg. Contract creation - // from Wallet within a Wallet) - api.eth - .getTransactionReceipt(log.transactionHash) - .then((transactionReceipt) => { - const transactionLogs = WalletsUtils.parseLogs(api, transactionReceipt.logs); - const creationLog = transactionLogs.find((log) => { - return log.params.created && !/^(0x)?0*$/.test(log.params.created.value); - }); - - if (!creationLog) { - return false; - } - - const contractAddress = creationLog.params.created.value; - - return Promise - .all([ - api.parity.setAccountName(contractAddress, contractName), - api.parity.setAccountMeta(contractAddress, metadata) - ]) - .then(() => { - WalletsUtils.removePendingContract(operation); - }); - }) - .catch((error) => { - console.error('adding wallet contract', error); - }); - } - - transaction.operation = operation; - } - - if (log.params.data) { - transaction.data = log.params.data.value; - } - - return transaction; - }); - - return transactions; + .then(([ wallet, method ]) => { + return wallet.instance[method] + .estimateGas(options, values) + .then((gas) => { + options.gas = gas.mul(1.5); + return wallet.instance[method].postTransaction(options, values); + }); }); } } diff --git a/js/src/util/wallets/consensys-wallet.js b/js/src/util/wallets/consensys-wallet.js new file mode 100644 index 000000000..9f9f9d5fa --- /dev/null +++ b/js/src/util/wallets/consensys-wallet.js @@ -0,0 +1,354 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import BigNumber from 'bignumber.js'; + +import Abi from '~/abi'; +import Contract from '~/api/contract'; +import { toHex } from '~/api/util/format'; + +import WalletAbi from '~/contracts/abi/consensys-multisig-wallet.json'; + +import { + UPDATE_OWNERS, + UPDATE_REQUIRE, + UPDATE_TRANSACTIONS, + UPDATE_CONFIRMATIONS +} from './updates'; + +const WALLET_CONTRACT = new Contract({}, WalletAbi); +const WALLET_ABI = new Abi(WalletAbi); + +const walletEvents = WALLET_ABI.events.reduce((events, event) => { + events[event.name] = event; + return events; +}, {}); + +const WalletSignatures = { + Confirmation: toHex(walletEvents.Confirmation.signature), + Revocation: toHex(walletEvents.Revocation.signature), + Deposit: toHex(walletEvents.Deposit.signature), + Execution: toHex(walletEvents.Execution.signature), + OwnerAddition: toHex(walletEvents.OwnerAddition.signature), + OwnerRemoval: toHex(walletEvents.OwnerRemoval.signature), + RequirementChange: toHex(walletEvents.RequirementChange.signature), + Submission: toHex(walletEvents.Submission.signature) +}; + +export default class ConsensysWalletUtils { + static fetchOwners (inWallet) { + const wallet = new Contract(inWallet.api, WalletAbi).at(inWallet.address); + + return wallet.instance.getOwners.call() + .then((owners) => { + return owners.map((token) => token.value); + }); + } + + static fetchPendingTransactions (inWallet) { + const wallet = new Contract(inWallet.api, WalletAbi).at(inWallet.address); + + let transactions; + let txIds; + + // Get pending and not exectued transactions + return wallet.instance.getTransactionCount + .call({}, [ true, false ]) + .then((txCount) => { + // Get all the pending transactions + const fromId = 0; + const toId = txCount; + + return wallet.instance.getTransactionIds + .call({}, [ fromId, toId, true, false ]); + }) + .then((_txIds) => { + txIds = _txIds.map((token) => token.value); + + const promises = txIds.map((txId) => { + return wallet.instance.transactions + .call({}, [ txId ]); + }); + + return Promise.all(promises); + }) + .then((transactions) => { + return transactions.map((transaction, index) => { + const [ destination, value, data ] = transaction; + const id = toHex(txIds[index]); + + return { + to: destination, + data, + value, + operation: id + }; + }); + }) + .then((_transactions) => { + transactions = _transactions; + + return wallet + .getAllLogs({ + topics: [ + WalletSignatures.Submission, + txIds.map((txId) => toHex(txId)) + ] + }); + }) + .then((logs) => { + transactions.forEach((tx) => { + const log = logs + .find((log) => { + const id = toHex(log.params.transactionId.value); + + return id === tx.operation; + }); + + if (!log) { + console.warn('could not find a Submission log for this operation', tx); + return; + } + + tx.transactionIndex = log.transactionIndex; + tx.transactionHash = log.transactionHash; + tx.blockNumber = log.blockNumber; + }); + + const confirmationsPromises = transactions.map((tx) => { + return wallet.instance.getConfirmations + .call({}, [ tx.operation ]) + .then((owners) => { + return owners.map((token) => token.value); + }); + }); + + return Promise.all(confirmationsPromises); + }) + .then((confirmations) => { + transactions.forEach((tx, index) => { + tx.confirmedBy = confirmations[index]; + }); + + return transactions; + }); + } + + static fetchRequire (inWallet) { + const wallet = new Contract(inWallet.api, WalletAbi).at(inWallet.address); + + return wallet.instance.required.call(); + } + + static fetchTransactions (inWallet) { + const wallet = new Contract(inWallet.api, WalletAbi).at(inWallet.address); + + let transactions; + let txIds; + + return wallet.instance.getTransactionCount + .call({}, [ false, true ]) + .then((txCount) => { + // Get the 20 last transactions + const fromId = Math.max(0, txCount - 20); + const toId = txCount; + + return wallet.instance.getTransactionIds + .call({}, [ fromId, toId, false, true ]); + }) + .then((_txIds) => { + txIds = _txIds.map((token) => token.value); + + const promises = txIds.map((txId) => { + return wallet.instance.transactions + .call({}, [ txId ]); + }); + + return Promise.all(promises); + }) + .then((transactions) => { + return transactions.map((transaction, index) => { + const [ destination, value, data, executed ] = transaction; + const id = toHex(txIds[index]); + + return { + destination, value, data, executed, id + }; + }); + }) + .then((_transactions) => { + transactions = _transactions; + + const depositLogs = wallet + .getAllLogs({ + topics: [ WalletSignatures.Deposit ] + }); + + const executionLogs = wallet + .getAllLogs({ + topics: [ WalletSignatures.Execution, txIds ] + }); + + return Promise.all([ depositLogs, executionLogs ]); + }) + .then(([ depositLogs, executionLogs ]) => { + const logs = [].concat(depositLogs, executionLogs); + + return logs.map((log) => { + const signature = toHex(log.topics[0]); + + const transaction = { + transactionHash: log.transactionHash, + blockNumber: log.blockNumber + }; + + if (signature === WalletSignatures.Deposit) { + transaction.from = log.params.sender.value; + transaction.value = log.params.value.value; + transaction.to = wallet.address; + } else { + const txId = toHex(log.params.transactionId.value); + const tx = transactions.find((tx) => tx.id === txId); + + transaction.from = wallet.address; + transaction.to = tx.destination; + transaction.value = tx.value; + transaction.data = tx.data; + transaction.operation = toHex(tx.id); + } + + return transaction; + }); + }); + } + + static getChangeMethod (api, address, change) { + const wallet = new Contract(api, WalletAbi).at(address); + const walletInstance = wallet.instance; + + let data = ''; + + if (change.type === 'require') { + const func = walletInstance.changeRequirement; + + data = wallet.getCallData(func, {}, [ change.value ]); + } + + if (change.type === 'add_owner') { + const func = walletInstance.addOwner; + + data = wallet.getCallData(func, {}, [ change.value ]); + } + + if (change.type === 'change_owner') { + const func = walletInstance.replaceOwner; + + data = wallet.getCallData(func, {}, [ change.value.from, change.value.to ]); + } + + if (change.type === 'remove_owner') { + const func = walletInstance.removeOwner; + + data = wallet.getCallData(func, {}, [ change.value ]); + } + + const method = walletInstance.submitTransaction; + const values = [ address, 0, data ]; + + return { method, values }; + } + + static getModifyOperationMethod (modification) { + switch (modification) { + case 'confirm': + return 'confirmTransaction'; + + case 'revoke': + return 'revokeConfirmation'; + + default: + return ''; + } + } + + static getSubmitMethod () { + return 'submitTransaction'; + } + + static getWalletContract (api) { + return new Contract(api, WalletAbi); + } + + static getWalletSignatures () { + return WalletSignatures; + } + + static fetchDailylimit () { + return { + last: new BigNumber(0), + limit: new BigNumber(0), + spent: new BigNumber(0) + }; + } + + static isWallet (api, address) { + const wallet = new Contract(api, WalletAbi).at(address); + + return ConsensysWalletUtils.fetchRequire(wallet) + .then((result) => { + if (!result || result.equals(0)) { + return false; + } + + return true; + }); + } + + static logToUpdate (log) { + const eventSignature = toHex(log.topics[0]); + + switch (eventSignature) { + case WalletSignatures.OwnerAddition: + case WalletSignatures.OwnerRemoval: + return { [ UPDATE_OWNERS ]: true }; + + case WalletSignatures.RequirementChange: + return { [ UPDATE_REQUIRE ]: true }; + + case WalletSignatures.Deposit: + case WalletSignatures.Execution: + return { [ UPDATE_TRANSACTIONS ]: true }; + + case WalletSignatures.Submission: + case WalletSignatures.Confirmation: + case WalletSignatures.Revocation: + const parsedLog = WALLET_CONTRACT.parseEventLogs([ log ])[0]; + const operation = toHex(parsedLog.params.transactionId.value); + + return { [ UPDATE_CONFIRMATIONS ]: operation }; + + default: + return {}; + } + } + + /** + * This type of wallet cannot create any contract... + */ + static parseTransactionLogs (api, options, rawLogs) { + return null; + } +} diff --git a/js/src/util/wallets/foundation-wallet.js b/js/src/util/wallets/foundation-wallet.js new file mode 100644 index 000000000..4fb1cfe22 --- /dev/null +++ b/js/src/util/wallets/foundation-wallet.js @@ -0,0 +1,500 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import { range, uniq } from 'lodash'; + +import Abi from '~/abi'; +import Contract from '~/api/contract'; +import { bytesToHex, toHex } from '~/api/util/format'; +import { validateAddress } from '~/util/validation'; + +import WalletAbi from '~/contracts/abi/foundation-multisig-wallet.json'; +import OldWalletAbi from '~/contracts/abi/old-wallet.json'; + +import PendingContracts from './pending-contracts'; +import { + UPDATE_OWNERS, + UPDATE_REQUIRE, + UPDATE_TRANSACTIONS, + UPDATE_CONFIRMATIONS +} from './updates'; + +const WALLET_CONTRACT = new Contract({}, WalletAbi); +const WALLET_ABI = new Abi(WalletAbi); +const OLD_WALLET_ABI = new Abi(OldWalletAbi); + +const walletEvents = WALLET_ABI.events.reduce((events, event) => { + events[event.name] = event; + return events; +}, {}); + +const oldWalletEvents = OLD_WALLET_ABI.events.reduce((events, event) => { + events[event.name] = event; + return events; +}, {}); + +const WalletSignatures = { + OwnerChanged: toHex(walletEvents.OwnerChanged.signature), + OwnerAdded: toHex(walletEvents.OwnerAdded.signature), + OwnerRemoved: toHex(walletEvents.OwnerRemoved.signature), + RequirementChanged: toHex(walletEvents.RequirementChanged.signature), + Confirmation: toHex(walletEvents.Confirmation.signature), + Revoke: toHex(walletEvents.Revoke.signature), + Deposit: toHex(walletEvents.Deposit.signature), + SingleTransact: toHex(walletEvents.SingleTransact.signature), + MultiTransact: toHex(walletEvents.MultiTransact.signature), + ConfirmationNeeded: toHex(walletEvents.ConfirmationNeeded.signature), + + Old: { + SingleTransact: toHex(oldWalletEvents.SingleTransact.signature), + MultiTransact: toHex(oldWalletEvents.MultiTransact.signature) + } +}; + +export default class FoundationWalletUtils { + static fetchConfirmations (walletContract, operation, _owners = null) { + const ownersPromise = _owners + ? Promise.resolve(_owners) + : FoundationWalletUtils.fetchOwners(walletContract); + + return ownersPromise + .then((owners) => { + const promises = owners.map((owner) => { + return walletContract.instance.hasConfirmed.call({}, [ operation, owner ]); + }); + + return Promise + .all(promises) + .then((data) => { + return owners.filter((_, index) => data[index]); + }); + }); + } + + static fetchDailylimit (walletContract) { + const walletInstance = walletContract.instance; + + return Promise + .all([ + walletInstance.m_dailyLimit.call(), + walletInstance.m_spentToday.call(), + walletInstance.m_lastDay.call() + ]) + .then(([ limit, spent, last ]) => ({ + limit, spent, last + })); + } + + static fetchOwners (walletContract) { + const walletInstance = walletContract.instance; + + return walletInstance + .m_numOwners.call() + .then((mNumOwners) => { + const promises = range(mNumOwners.toNumber()) + .map((idx) => walletInstance.getOwner.call({}, [ idx ])); + + return Promise + .all(promises) + .then((_owners) => { + const owners = validateOwners(_owners); + + // If all owners are the zero account : must be Mist wallet contract + if (!owners) { + return fetchMistOwners(walletContract, mNumOwners.toNumber()); + } + + return owners; + }); + }); + } + + static fetchPendingTransactions (walletContract, cache = {}) { + const { owners, transactions } = cache; + + return walletContract + .instance + .ConfirmationNeeded + .getAllLogs() + .then((logs) => { + return logs.map((log) => ({ + initiator: log.params.initiator.value, + to: log.params.to.value, + data: log.params.data.value, + value: log.params.value.value, + operation: bytesToHex(log.params.operation.value), + transactionIndex: log.transactionIndex, + transactionHash: log.transactionHash, + blockNumber: log.blockNumber, + confirmedBy: [] + })); + }) + .then((logs) => { + return logs.sort((logA, logB) => { + const comp = logA.blockNumber.comparedTo(logB.blockNumber); + + if (comp !== 0) { + return comp; + } + + return logA.transactionIndex.comparedTo(logB.transactionIndex); + }); + }) + .then((pendingTxs) => { + if (pendingTxs.length === 0) { + return pendingTxs; + } + + // Only fetch confirmations for operations not + // yet confirmed (ie. not yet a transaction) + if (transactions) { + const operations = transactions + .filter((t) => t.operation) + .map((t) => t.operation); + + return pendingTxs.filter((pendingTx) => { + return !operations.includes(pendingTx.operation); + }); + } + + return pendingTxs; + }) + .then((pendingTxs) => { + const promises = pendingTxs.map((tx) => { + return FoundationWalletUtils + .fetchConfirmations(walletContract, tx.operation, owners) + .then((confirmedBy) => { + tx.confirmedBy = confirmedBy; + + return tx; + }); + }); + + return Promise.all(promises); + }); + } + + static fetchRequire (wallet) { + return wallet.instance.m_required.call(); + } + + static fetchTransactions (walletContract) { + const { api } = walletContract; + + return walletContract + .getAllLogs({ + topics: [ [ + WalletSignatures.SingleTransact, + WalletSignatures.MultiTransact, + WalletSignatures.Deposit, + WalletSignatures.Old.SingleTransact, + WalletSignatures.Old.MultiTransact + ] ] + }) + .then((logs) => { + const transactions = logs.map((log) => { + const signature = toHex(log.topics[0]); + + const value = log.params.value.value; + const from = signature === WalletSignatures.Deposit + ? log.params['_from'].value + : walletContract.address; + + const to = signature === WalletSignatures.Deposit + ? walletContract.address + : log.params.to.value; + + const transaction = { + transactionHash: log.transactionHash, + blockNumber: log.blockNumber, + from, to, value + }; + + if (log.params.created && log.params.created.value && !/^(0x)?0*$/.test(log.params.created.value)) { + transaction.creates = log.params.created.value; + delete transaction.to; + } + + if (log.params.operation) { + transaction.operation = bytesToHex(log.params.operation.value); + checkPendingOperation(api, log, transaction.operation); + } + + if (log.params.data) { + transaction.data = log.params.data.value; + } + + return transaction; + }); + + return transactions; + }); + } + + static getChangeMethod (api, address, change) { + const wallet = new Contract(api, WalletAbi).at(address); + const walletInstance = wallet.instance; + + if (change.type === 'require') { + return { + method: walletInstance.changeRequirement, + values: [ change.value ] + }; + } + + if (change.type === 'dailylimit') { + return { + method: walletInstance.setDailyLimit, + values: [ change.value ] + }; + } + + if (change.type === 'add_owner') { + return { + method: walletInstance.addOwner, + values: [ change.value ] + }; + } + + if (change.type === 'change_owner') { + return { + method: walletInstance.changeOwner, + values: [ change.value.from, change.value.to ] + }; + } + + if (change.type === 'remove_owner') { + return { + method: walletInstance.removeOwner, + values: [ change.value ] + }; + } + } + + static getModifyOperationMethod (modification) { + switch (modification) { + case 'confirm': + return 'confirm'; + + case 'revoke': + return 'revoke'; + + default: + return ''; + } + } + + static getSubmitMethod () { + return 'execute'; + } + + static getWalletContract (api) { + return new Contract(api, WalletAbi); + } + + static getWalletSignatures () { + return WalletSignatures; + } + + static isWallet (api, address) { + const walletContract = new Contract(api, WalletAbi); + + return walletContract + .at(address) + .instance + .m_numOwners + .call() + .then((result) => { + if (!result || result.equals(0)) { + return false; + } + + return true; + }); + } + + static logToUpdate (log) { + const eventSignature = toHex(log.topics[0]); + + switch (eventSignature) { + case WalletSignatures.OwnerChanged: + case WalletSignatures.OwnerAdded: + case WalletSignatures.OwnerRemoved: + return { [ UPDATE_OWNERS ]: true }; + + case WalletSignatures.RequirementChanged: + return { [ UPDATE_REQUIRE ]: true }; + + case WalletSignatures.ConfirmationNeeded: + case WalletSignatures.Confirmation: + case WalletSignatures.Revoke: + const parsedLog = WALLET_CONTRACT.parseEventLogs([ log ])[0]; + const operation = bytesToHex(parsedLog.params.operation.value); + + return { [ UPDATE_CONFIRMATIONS ]: operation }; + + case WalletSignatures.Deposit: + case WalletSignatures.SingleTransact: + case WalletSignatures.MultiTransact: + case WalletSignatures.Old.SingleTransact: + case WalletSignatures.Old.MultiTransact: + return { [ UPDATE_TRANSACTIONS ]: true }; + + default: + return {}; + } + } + + static parseLogs (api, logs = []) { + const walletContract = new Contract(api, WalletAbi); + + return walletContract.parseEventLogs(logs); + } + + static parseTransactionLogs (api, options, rawLogs) { + const { metadata } = options; + const address = options.from; + const logs = FoundationWalletUtils.parseLogs(api, rawLogs); + + const confirmationLog = logs.find((log) => log.event === 'ConfirmationNeeded'); + const transactionLog = logs.find((log) => log.event === 'SingleTransact'); + + if (!confirmationLog && !transactionLog) { + return null; + } + + // Confirmations are needed from the other owners + if (confirmationLog) { + const operationHash = bytesToHex(confirmationLog.params.operation.value); + + // Add the contract to pending contracts + PendingContracts.addPendingContract(address, operationHash, metadata); + + return { pending: true }; + } + + return { contractAddress: transactionLog.params.created.value }; + } +} + +function checkPendingOperation (api, log, operation) { + const pendingContracts = PendingContracts.getPendingContracts(); + + // Add the pending contract to the contracts + if (pendingContracts[operation]) { + const { metadata } = pendingContracts[operation]; + const contractName = metadata.name; + + metadata.blockNumber = log.blockNumber; + + // The contract creation might not be in the same log, + // but must be in the same transaction (eg. Contract creation + // from Wallet within a Wallet) + api.eth + .getTransactionReceipt(log.transactionHash) + .then((transactionReceipt) => { + const transactionLogs = FoundationWalletUtils.parseLogs(api, transactionReceipt.logs); + const creationLog = transactionLogs.find((log) => { + return log.params.created && !/^(0x)?0*$/.test(log.params.created.value); + }); + + if (!creationLog) { + return false; + } + + const contractAddress = creationLog.params.created.value; + + return Promise + .all([ + api.parity.setAccountName(contractAddress, contractName), + api.parity.setAccountMeta(contractAddress, metadata) + ]) + .then(() => { + PendingContracts.removePendingContract(operation); + }); + }) + .catch((error) => { + console.error('adding wallet contract', error); + }); + } +} + +function fetchMistOwners (walletContract, mNumOwners) { + const walletAddress = walletContract.address; + + return getMistOwnersOffset(walletContract) + .then((result) => { + if (!result || result.offset === -1) { + return []; + } + + const owners = [ result.address ]; + + if (mNumOwners === 1) { + return owners; + } + + const initOffset = result.offset + 1; + let promise = Promise.resolve(); + + range(initOffset, initOffset + mNumOwners - 1).forEach((offset) => { + promise = promise + .then(() => { + return walletContract.api.eth.getStorageAt(walletAddress, offset); + }) + .then((result) => { + const resultAddress = '0x' + (result || '').slice(-40); + const { address } = validateAddress(resultAddress); + + owners.push(address); + }); + }); + + return promise.then(() => owners); + }); +} + +function getMistOwnersOffset (walletContract, offset = 3) { + return walletContract.api.eth + .getStorageAt(walletContract.address, offset) + .then((result) => { + if (result && !/^(0x)?0*$/.test(result)) { + const resultAddress = '0x' + result.slice(-40); + const { address, addressError } = validateAddress(resultAddress); + + if (!addressError) { + return { offset, address }; + } + } + + if (offset >= 100) { + return { offset: -1 }; + } + + return getMistOwnersOffset(walletContract, offset + 1); + }); +} + +function validateOwners (owners) { + const uniqOwners = uniq(owners); + + // If all owners are the zero account : must be Mist wallet contract + if (uniqOwners.length === 1 && /^(0x)?0*$/.test(owners[0])) { + return null; + } + + return uniqOwners; +} diff --git a/js/src/util/wallets/pending-contracts.js b/js/src/util/wallets/pending-contracts.js new file mode 100644 index 000000000..8eef273e2 --- /dev/null +++ b/js/src/util/wallets/pending-contracts.js @@ -0,0 +1,49 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import store from 'store'; + +const LS_PENDING_CONTRACTS_KEY = '_parity::wallets::pendingContracts'; + +export default class PendingContracts { + static getPendingContracts () { + return store.get(LS_PENDING_CONTRACTS_KEY) || {}; + } + + static setPendingContracts (contracts = {}) { + return store.set(LS_PENDING_CONTRACTS_KEY, contracts); + } + + static removePendingContract (operationHash) { + const nextContracts = PendingContracts.getPendingContracts(); + + delete nextContracts[operationHash]; + PendingContracts.setPendingContracts(nextContracts); + } + + static addPendingContract (address, operationHash, metadata) { + const nextContracts = { + ...PendingContracts.getPendingContracts(), + [ operationHash ]: { + address, + metadata, + operationHash + } + }; + + PendingContracts.setPendingContracts(nextContracts); + } +} diff --git a/js/src/util/wallets/updates.js b/js/src/util/wallets/updates.js new file mode 100644 index 000000000..a739652fc --- /dev/null +++ b/js/src/util/wallets/updates.js @@ -0,0 +1,21 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +export const UPDATE_OWNERS = 'owners'; +export const UPDATE_REQUIRE = 'require'; +export const UPDATE_DAILYLIMIT = 'dailylimit'; +export const UPDATE_TRANSACTIONS = 'transactions'; +export const UPDATE_CONFIRMATIONS = 'confirmations'; diff --git a/js/src/views/Accounts/accounts.js b/js/src/views/Accounts/accounts.js index 2d37b7a4b..c8828cff6 100644 --- a/js/src/views/Accounts/accounts.js +++ b/js/src/views/Accounts/accounts.js @@ -373,10 +373,6 @@ class Accounts extends Component { } renderNewWalletButton () { - if (this.props.availability !== 'personal') { - return null; - } - return (