From 9a7abcde6122c1fdefa6a20c616219e2902cd615 Mon Sep 17 00:00:00 2001 From: mduske Date: Sun, 24 Jun 2018 19:45:28 -0400 Subject: [PATCH 1/3] changes --- src/__tests__/index.test.js | 26 + src/colonyClient.js | 213 + src/createColonyWindow.html | 82 + src/create_colony.js | 67 + src/create_task.js | 25 + src/css/extraStyle.css | 123 + src/ecp.js | 44 + src/etherClient.js | 3 + src/genericCode.js | 23 + src/index.js | 8 + src/lib/colonyNetwork/.babelrc | 4 + src/lib/colonyNetwork/.circleci/config.yml | 102 + src/lib/colonyNetwork/.eslintignore | 8 + src/lib/colonyNetwork/.eslintrc | 21 + src/lib/colonyNetwork/.gitattributes | 1 + src/lib/colonyNetwork/.gitignore | 15 + src/lib/colonyNetwork/.gitmodules | 3 + src/lib/colonyNetwork/.nvmrc | 1 + src/lib/colonyNetwork/.solcover.js | 12 + src/lib/colonyNetwork/.soliumignore | 7 + src/lib/colonyNetwork/.soliumrc.json | 14 + src/lib/colonyNetwork/.yarnrc | 1 + src/lib/colonyNetwork/LICENSE | 674 + src/lib/colonyNetwork/contracts/Authority.sol | 49 + src/lib/colonyNetwork/contracts/Colony.sol | 166 + .../colonyNetwork/contracts/ColonyFunding.sol | 311 + .../colonyNetwork/contracts/ColonyNetwork.sol | 243 + .../contracts/ColonyNetworkAuction.sol | 216 + .../contracts/ColonyNetworkStaking.sol | 138 + .../contracts/ColonyNetworkStorage.sol | 73 + .../colonyNetwork/contracts/ColonyStorage.sol | 190 + .../colonyNetwork/contracts/ColonyTask.sol | 411 + .../colonyNetwork/contracts/ERC20Extended.sol | 31 + .../colonyNetwork/contracts/EtherRouter.sol | 66 + src/lib/colonyNetwork/contracts/IColony.sol | 416 + .../contracts/IColonyNetwork.sol | 188 + .../contracts/IReputationMiningCycle.sol | 153 + .../colonyNetwork/contracts/Migrations.sol | 26 + .../contracts/PatriciaTree/Bits.sol | 44 + .../contracts/PatriciaTree/Data.sol | 145 + .../contracts/PatriciaTree/IPatriciaTree.sol | 37 + .../contracts/PatriciaTree/PatriciaTree.sol | 71 + .../PatriciaTree/PatriciaTreeProofs.sol | 33 + .../contracts/ReputationMiningCycle.sol | 740 + src/lib/colonyNetwork/contracts/Resolver.sol | 40 + src/lib/colonyNetwork/contracts/SafeMath.sol | 49 + src/lib/colonyNetwork/contracts/Token.sol | 53 + .../contracts/gnosis/MultiSigWallet.sol | 370 + src/lib/colonyNetwork/docs/CODE_OF_CONDUCT.md | 46 + src/lib/colonyNetwork/docs/CONTRIBUTING.md | 31 + src/lib/colonyNetwork/docs/ISSUE_TEMPLATE.md | 33 + .../docs/PULL_REQUEST_TEMPLATE.md | 6 + src/lib/colonyNetwork/docs/README.md | 43 + src/lib/colonyNetwork/docs/_Docs_Colony.md | 65 + src/lib/colonyNetwork/docs/_Docs_Disputes.md | 38 + .../colonyNetwork/docs/_Docs_DomainsSkills.md | 47 + .../colonyNetwork/docs/_Docs_GetStarted.md | 88 + src/lib/colonyNetwork/docs/_Docs_Glossary.md | 62 + .../colonyNetwork/docs/_Docs_MetaColony.md | 25 + .../docs/_Docs_NetworkOverview.md | 35 + src/lib/colonyNetwork/docs/_Docs_Pots.md | 46 + .../colonyNetwork/docs/_Docs_Reputation.md | 53 + .../docs/_Docs_ReputationMining.md | 63 + src/lib/colonyNetwork/docs/_Docs_Tasks.md | 67 + src/lib/colonyNetwork/docs/_Docs_Upgrades.md | 27 + src/lib/colonyNetwork/docs/doc.config.json | 6 + .../colonyNetwork/docs/img/Colony_Header.png | Bin 0 -> 79796 bytes .../colonyNetwork/docs/img/EtherRouter.svg | 1 + .../docs/img/colonyNetwork_combomark.svg | 1 + .../docs/img/colonyNetwork_wordmark.svg | 48 + src/lib/colonyNetwork/docs/img/domains_r1.svg | 1 + src/lib/colonyNetwork/gasCosts/gasCosts.js | 330 + src/lib/colonyNetwork/genesis.json | 35 + src/lib/colonyNetwork/helpers/constants.js | 53 + .../helpers/test-data-generator.js | 197 + src/lib/colonyNetwork/helpers/test-helper.js | 247 + .../helpers/upgradable-contracts.js | 97 + .../migrations/1_initial_migration.js | 6 + .../migrations/2_deploy_contracts.js | 29 + .../migrations/3_setup_colony_network.js | 45 + .../4_setup_colony_version_resolver.js | 55 + .../migrations/5_setup_meta_colony.js | 43 + src/lib/colonyNetwork/package-lock.json | 3054 ++++ src/lib/colonyNetwork/package.json | 85 + .../colony-contract-loader-network/.gitignore | 1 + .../colony-contract-loader-network/Readme.md | 20 + .../config.json | 4 + .../contracts/static/EtherRouter.json | 129 + .../contracts/static/Token.json | 388 + .../versioned/rinkeby-v1/Authority.json | 325 + .../versioned/rinkeby-v1/IColony.json | 1074 ++ .../versioned/rinkeby-v1/IColonyNetwork.json | 531 + .../jest.conf.json | 3 + .../package.json | 24 + .../src/NetworkLoader.js | 58 + .../src/__tests__/NetworkLoader.test.js | 66 + .../src/index.js | 1 + .../reputation-miner/ReputationMiner.js | 576 + .../reputation-miner/ReputationMinerClient.js | 140 + .../packages/reputation-miner/bin/index.js | 25 + .../packages/reputation-miner/package.json | 26 + .../test/MaliciousReputationMinerExtraRep.js | 21 + .../test/MaliciousReputationMinerReuseUID.js | 33 + .../test/MaliciousReputationMinerWrongUID.js | 23 + .../parity-genesis.template.json | 42 + .../colonyNetwork/scripts/check-storage.js | 47 + src/lib/colonyNetwork/scripts/eslint.sh | 8 + .../scripts/generate-test-contracts.sh | 20 + src/lib/colonyNetwork/scripts/resetParity.sh | 26 + src/lib/colonyNetwork/scripts/solium.sh | 10 + .../scripts/start-blockchain-client.sh | 63 + .../scripts/stop-blockchain-client.sh | 6 + .../scripts/version-contracts.sh | 5 + src/lib/colonyNetwork/test/colony-funding.js | 811 + .../test/colony-network-auction.js | 448 + .../test/colony-network-mining.js | 1696 +++ src/lib/colonyNetwork/test/colony-network.js | 278 + .../test/colony-task-work-rating.js | 289 + src/lib/colonyNetwork/test/colony.js | 844 ++ src/lib/colonyNetwork/test/meta-colony.js | 471 + .../colonyNetwork/test/reputation-update.js | 217 + src/lib/colonyNetwork/test/router-resolver.js | 66 + src/lib/colonyNetwork/truffle.js | 41 + .../upgrade-test/colony-network-upgrade.js | 53 + .../upgrade-test/colony-upgrade.js | 103 + src/lib/colonyNetwork/yarn.lock | 9133 ++++++++++++ src/lib/materialize/LICENSE | 21 + src/lib/materialize/README.md | 90 + src/lib/materialize/css/materialize.css | 9039 ++++++++++++ src/lib/materialize/css/materialize.min.css | 13 + src/lib/materialize/js/materialize.js | 12255 ++++++++++++++++ src/lib/materialize/js/materialize.min.js | 6 + src/main.js | 583 + src/mainWindow.html | 283 + src/researchWindow.html | 145 + src/selectAccountWindow.html | 78 + src/selectColonyWindow.html | 80 + src/store.js | 52 + src/taskWindow.html | 86 + 139 files changed, 51720 insertions(+) create mode 100644 src/__tests__/index.test.js create mode 100644 src/colonyClient.js create mode 100644 src/createColonyWindow.html create mode 100644 src/create_colony.js create mode 100644 src/create_task.js create mode 100644 src/css/extraStyle.css create mode 100644 src/ecp.js create mode 100644 src/etherClient.js create mode 100644 src/genericCode.js create mode 100644 src/index.js create mode 100644 src/lib/colonyNetwork/.babelrc create mode 100644 src/lib/colonyNetwork/.circleci/config.yml create mode 100644 src/lib/colonyNetwork/.eslintignore create mode 100644 src/lib/colonyNetwork/.eslintrc create mode 100644 src/lib/colonyNetwork/.gitattributes create mode 100644 src/lib/colonyNetwork/.gitignore create mode 100644 src/lib/colonyNetwork/.gitmodules create mode 100644 src/lib/colonyNetwork/.nvmrc create mode 100644 src/lib/colonyNetwork/.solcover.js create mode 100644 src/lib/colonyNetwork/.soliumignore create mode 100644 src/lib/colonyNetwork/.soliumrc.json create mode 100644 src/lib/colonyNetwork/.yarnrc create mode 100644 src/lib/colonyNetwork/LICENSE create mode 100644 src/lib/colonyNetwork/contracts/Authority.sol create mode 100755 src/lib/colonyNetwork/contracts/Colony.sol create mode 100755 src/lib/colonyNetwork/contracts/ColonyFunding.sol create mode 100644 src/lib/colonyNetwork/contracts/ColonyNetwork.sol create mode 100644 src/lib/colonyNetwork/contracts/ColonyNetworkAuction.sol create mode 100644 src/lib/colonyNetwork/contracts/ColonyNetworkStaking.sol create mode 100644 src/lib/colonyNetwork/contracts/ColonyNetworkStorage.sol create mode 100755 src/lib/colonyNetwork/contracts/ColonyStorage.sol create mode 100755 src/lib/colonyNetwork/contracts/ColonyTask.sol create mode 100644 src/lib/colonyNetwork/contracts/ERC20Extended.sol create mode 100644 src/lib/colonyNetwork/contracts/EtherRouter.sol create mode 100644 src/lib/colonyNetwork/contracts/IColony.sol create mode 100644 src/lib/colonyNetwork/contracts/IColonyNetwork.sol create mode 100644 src/lib/colonyNetwork/contracts/IReputationMiningCycle.sol create mode 100644 src/lib/colonyNetwork/contracts/Migrations.sol create mode 100644 src/lib/colonyNetwork/contracts/PatriciaTree/Bits.sol create mode 100644 src/lib/colonyNetwork/contracts/PatriciaTree/Data.sol create mode 100644 src/lib/colonyNetwork/contracts/PatriciaTree/IPatriciaTree.sol create mode 100644 src/lib/colonyNetwork/contracts/PatriciaTree/PatriciaTree.sol create mode 100644 src/lib/colonyNetwork/contracts/PatriciaTree/PatriciaTreeProofs.sol create mode 100644 src/lib/colonyNetwork/contracts/ReputationMiningCycle.sol create mode 100644 src/lib/colonyNetwork/contracts/Resolver.sol create mode 100644 src/lib/colonyNetwork/contracts/SafeMath.sol create mode 100644 src/lib/colonyNetwork/contracts/Token.sol create mode 100644 src/lib/colonyNetwork/contracts/gnosis/MultiSigWallet.sol create mode 100644 src/lib/colonyNetwork/docs/CODE_OF_CONDUCT.md create mode 100644 src/lib/colonyNetwork/docs/CONTRIBUTING.md create mode 100644 src/lib/colonyNetwork/docs/ISSUE_TEMPLATE.md create mode 100644 src/lib/colonyNetwork/docs/PULL_REQUEST_TEMPLATE.md create mode 100644 src/lib/colonyNetwork/docs/README.md create mode 100644 src/lib/colonyNetwork/docs/_Docs_Colony.md create mode 100644 src/lib/colonyNetwork/docs/_Docs_Disputes.md create mode 100644 src/lib/colonyNetwork/docs/_Docs_DomainsSkills.md create mode 100644 src/lib/colonyNetwork/docs/_Docs_GetStarted.md create mode 100644 src/lib/colonyNetwork/docs/_Docs_Glossary.md create mode 100644 src/lib/colonyNetwork/docs/_Docs_MetaColony.md create mode 100644 src/lib/colonyNetwork/docs/_Docs_NetworkOverview.md create mode 100644 src/lib/colonyNetwork/docs/_Docs_Pots.md create mode 100644 src/lib/colonyNetwork/docs/_Docs_Reputation.md create mode 100644 src/lib/colonyNetwork/docs/_Docs_ReputationMining.md create mode 100644 src/lib/colonyNetwork/docs/_Docs_Tasks.md create mode 100644 src/lib/colonyNetwork/docs/_Docs_Upgrades.md create mode 100644 src/lib/colonyNetwork/docs/doc.config.json create mode 100644 src/lib/colonyNetwork/docs/img/Colony_Header.png create mode 100644 src/lib/colonyNetwork/docs/img/EtherRouter.svg create mode 100644 src/lib/colonyNetwork/docs/img/colonyNetwork_combomark.svg create mode 100644 src/lib/colonyNetwork/docs/img/colonyNetwork_wordmark.svg create mode 100644 src/lib/colonyNetwork/docs/img/domains_r1.svg create mode 100644 src/lib/colonyNetwork/gasCosts/gasCosts.js create mode 100644 src/lib/colonyNetwork/genesis.json create mode 100644 src/lib/colonyNetwork/helpers/constants.js create mode 100644 src/lib/colonyNetwork/helpers/test-data-generator.js create mode 100644 src/lib/colonyNetwork/helpers/test-helper.js create mode 100644 src/lib/colonyNetwork/helpers/upgradable-contracts.js create mode 100644 src/lib/colonyNetwork/migrations/1_initial_migration.js create mode 100644 src/lib/colonyNetwork/migrations/2_deploy_contracts.js create mode 100644 src/lib/colonyNetwork/migrations/3_setup_colony_network.js create mode 100644 src/lib/colonyNetwork/migrations/4_setup_colony_version_resolver.js create mode 100644 src/lib/colonyNetwork/migrations/5_setup_meta_colony.js create mode 100644 src/lib/colonyNetwork/package-lock.json create mode 100644 src/lib/colonyNetwork/package.json create mode 100644 src/lib/colonyNetwork/packages/colony-contract-loader-network/.gitignore create mode 100644 src/lib/colonyNetwork/packages/colony-contract-loader-network/Readme.md create mode 100644 src/lib/colonyNetwork/packages/colony-contract-loader-network/config.json create mode 100644 src/lib/colonyNetwork/packages/colony-contract-loader-network/contracts/static/EtherRouter.json create mode 100644 src/lib/colonyNetwork/packages/colony-contract-loader-network/contracts/static/Token.json create mode 100644 src/lib/colonyNetwork/packages/colony-contract-loader-network/contracts/versioned/rinkeby-v1/Authority.json create mode 100644 src/lib/colonyNetwork/packages/colony-contract-loader-network/contracts/versioned/rinkeby-v1/IColony.json create mode 100644 src/lib/colonyNetwork/packages/colony-contract-loader-network/contracts/versioned/rinkeby-v1/IColonyNetwork.json create mode 100644 src/lib/colonyNetwork/packages/colony-contract-loader-network/jest.conf.json create mode 100644 src/lib/colonyNetwork/packages/colony-contract-loader-network/package.json create mode 100644 src/lib/colonyNetwork/packages/colony-contract-loader-network/src/NetworkLoader.js create mode 100644 src/lib/colonyNetwork/packages/colony-contract-loader-network/src/__tests__/NetworkLoader.test.js create mode 100644 src/lib/colonyNetwork/packages/colony-contract-loader-network/src/index.js create mode 100644 src/lib/colonyNetwork/packages/reputation-miner/ReputationMiner.js create mode 100644 src/lib/colonyNetwork/packages/reputation-miner/ReputationMinerClient.js create mode 100644 src/lib/colonyNetwork/packages/reputation-miner/bin/index.js create mode 100644 src/lib/colonyNetwork/packages/reputation-miner/package.json create mode 100644 src/lib/colonyNetwork/packages/reputation-miner/test/MaliciousReputationMinerExtraRep.js create mode 100644 src/lib/colonyNetwork/packages/reputation-miner/test/MaliciousReputationMinerReuseUID.js create mode 100644 src/lib/colonyNetwork/packages/reputation-miner/test/MaliciousReputationMinerWrongUID.js create mode 100644 src/lib/colonyNetwork/parity-genesis.template.json create mode 100644 src/lib/colonyNetwork/scripts/check-storage.js create mode 100644 src/lib/colonyNetwork/scripts/eslint.sh create mode 100644 src/lib/colonyNetwork/scripts/generate-test-contracts.sh create mode 100644 src/lib/colonyNetwork/scripts/resetParity.sh create mode 100644 src/lib/colonyNetwork/scripts/solium.sh create mode 100644 src/lib/colonyNetwork/scripts/start-blockchain-client.sh create mode 100644 src/lib/colonyNetwork/scripts/stop-blockchain-client.sh create mode 100644 src/lib/colonyNetwork/scripts/version-contracts.sh create mode 100755 src/lib/colonyNetwork/test/colony-funding.js create mode 100644 src/lib/colonyNetwork/test/colony-network-auction.js create mode 100755 src/lib/colonyNetwork/test/colony-network-mining.js create mode 100755 src/lib/colonyNetwork/test/colony-network.js create mode 100644 src/lib/colonyNetwork/test/colony-task-work-rating.js create mode 100755 src/lib/colonyNetwork/test/colony.js create mode 100644 src/lib/colonyNetwork/test/meta-colony.js create mode 100755 src/lib/colonyNetwork/test/reputation-update.js create mode 100644 src/lib/colonyNetwork/test/router-resolver.js create mode 100644 src/lib/colonyNetwork/truffle.js create mode 100644 src/lib/colonyNetwork/upgrade-test/colony-network-upgrade.js create mode 100644 src/lib/colonyNetwork/upgrade-test/colony-upgrade.js create mode 100644 src/lib/colonyNetwork/yarn.lock create mode 100644 src/lib/materialize/LICENSE create mode 100644 src/lib/materialize/README.md create mode 100644 src/lib/materialize/css/materialize.css create mode 100644 src/lib/materialize/css/materialize.min.css create mode 100644 src/lib/materialize/js/materialize.js create mode 100644 src/lib/materialize/js/materialize.min.js create mode 100644 src/main.js create mode 100644 src/mainWindow.html create mode 100644 src/researchWindow.html create mode 100644 src/selectAccountWindow.html create mode 100644 src/selectColonyWindow.html create mode 100644 src/store.js create mode 100644 src/taskWindow.html diff --git a/src/__tests__/index.test.js b/src/__tests__/index.test.js new file mode 100644 index 0000000..8ffc29b --- /dev/null +++ b/src/__tests__/index.test.js @@ -0,0 +1,26 @@ +const createColony = require('../create_colony'); +const createTask = require('../create_task'); + +describe('Starter project', () => { + test('Example logs successful results', async () => { + jest.spyOn(console, 'log'); + + const colonyClient = await createColony(); + await createTask(colonyClient); + + const logs = console.log.mock.calls.map(args => args[0]); + + const expected = [ + expect.stringContaining('Token address'), + expect.stringContaining('Colony ID'), + expect.stringContaining('Colony address'), + expect.stringContaining('Meta Colony address'), + expect.stringContaining('Specification hash'), + expect.objectContaining({ + cancelled: false + }), + ]; + + expect(logs).toEqual(expect.arrayContaining(expected)); + }, 20000); +}); diff --git a/src/colonyClient.js b/src/colonyClient.js new file mode 100644 index 0000000..78c77ac --- /dev/null +++ b/src/colonyClient.js @@ -0,0 +1,213 @@ +/* +Connector for Colony API +*/ + +// Import the prerequisites +const { providers, Wallet } = require('ethers'); +const { default: EthersAdapter } = require('@colony/colony-js-adapter-ethers'); +const { TrufflepigLoader } = require('@colony/colony-js-contract-loader-http'); + +// Import the ColonyNetworkClient +const { default: ColonyNetworkClient } = require('@colony/colony-js-client'); + +// Create an instance of the Trufflepig contract loader +const loader = new TrufflepigLoader(); + +// Create a provider for local TestRPC (Ganache) +const provider = new providers.JsonRpcProvider('http://localhost:8545/'); + +//Existing Colonies +let knownColoniesCache = []; + +/** + * Create a brand new Colony using its own ERC20 Token + * @param {*} _accountNumber + * @param {*} _tokenName + * @param {*} _tokenSymbol + */ +exports.createColony = async function (_accountNumber, _tokenName, _tokenSymbol) { + console.log("createColony"); + + // Get the private key from the selected account from the ganache-accounts + // through trufflepig + const { privateKey } = await loader.getAccount(_accountNumber); + + // Create a wallet with the private key (so we have a balance we can use) + const wallet = new Wallet(privateKey, provider); + + // Create an adapter (powered by ethers) + const adapter = new EthersAdapter({ + loader, + provider, + wallet, + }); + + // Connect to ColonyNetwork with the adapter! + const networkClient = new ColonyNetworkClient({ adapter }); + await networkClient.init(); + + // Let's deploy a new ERC20 token for our Colony. + // You could also skip this step and use a pre-existing/deployed contract. + const tokenAddress = await networkClient.createToken({ + name: _tokenName, + symbol: _tokenSymbol, + }); + console.log('Token address: ' + tokenAddress); + + // Create a cool Colony! + const { + eventData: { colonyId, colonyAddress }, + } = await networkClient.createColony.send({ tokenAddress }); + + // Congrats, you've created a Colony! + console.log('Colony ID: ' + colonyId); + console.log('Colony address: ' + colonyAddress); + + // For a colony that exists already, you just need its ID: + const colonyClient = await networkClient.getColonyClient(colonyId); + + const colonyData = await exports.gatherColonyData(colonyClient, colonyId); + + return {"colonyClient": colonyClient, "colonyData": colonyData}; +}; + +exports.openColony = async function (_accountNumber, _colonyId, _colonyAddress) { + console.log("openColony " +_accountNumber + ", " + _colonyId + ", " + _colonyAddress); + + // Get the private key from the selected account from the ganache-accounts + // through trufflepig + const { privateKey } = await loader.getAccount(_accountNumber); + + // Create a wallet with the private key (so we have a balance we can use) + const wallet = new Wallet(privateKey, provider); + + // Create an adapter (powered by ethers) + const adapter = new EthersAdapter({ + loader, + provider, + wallet, + }); + + // Connect to ColonyNetwork with the adapter! + const networkClient = new ColonyNetworkClient({ adapter }); + await networkClient.init(); + + console.log("openColony2 " +_accountNumber + ", " + _colonyId + ", " + _colonyAddress); + + // For a colony that exists already, you just need its ID: + //const colonyClient = await networkClient.getColonyClient(_colonyId); + const colonyClient = await networkClient.getColonyClientByAddress(_colonyAddress); + + console.log("openColony3 " +_accountNumber + ", " + _colonyId + ", " + _colonyAddress); + const colonyData = await exports.gatherColonyData(colonyClient, _colonyId); + + console.log("openColony4 " +_accountNumber + ", " + _colonyId + ", " + _colonyAddress); + return {"colonyClient": colonyClient, "colonyData": colonyData}; +}; + +/** + * List all known colonies + * TODO: Process Colonies in parallel + * @param {*} _accountNumber + */ +exports.listColonies = async function (_accountNumber) { + console.log("listColonies " + _accountNumber); + const colonies = []; + + if (knownColoniesCache.length > 0) { + console.log("reading from Cache with " + knownColoniesCache.length + " entries."); + tempColonyList = []; + + for (colony in knownColoniesCache) { + tempColonyList.push(knownColoniesCache[colony]); + } + return tempColonyList; + } + + // Get the private key from the selected account from the ganache-accounts + // through trufflepig + const { privateKey } = await loader.getAccount(_accountNumber); + + // Create a wallet with the private key (so we have a balance we can use) + const wallet = new Wallet(privateKey, provider); + + // Create an adapter (powered by ethers) + const adapter = new EthersAdapter({ + loader, + provider, + wallet, + }); + + // Connect to ColonyNetwork with the adapter! + const networkClient = new ColonyNetworkClient({ adapter }); + await networkClient.init(); + + // You can also get the Meta Colony: + //const metaColonyClient = await networkClient.getMetaColonyClient(); + //console.log('Meta Colony address: ' + metaColonyClient.contract.address); + + //List Colonies + try { + const colonyClientPromises = []; + const totalColonyCount = (await networkClient.getColonyCount.call()).count; + for (x = 1; x <= totalColonyCount; x++) { + console.log("Extracting Colony Data " + x); + const colonyClient = await networkClient.getColonyClient(x); + + colonyData = await exports.gatherColonyData(colonyClient, x); + + console.log(colonyData); + + colonies.push(colonyData); + + //break; //REMOVE + } + } catch (e) { + console.log(e); + } + + return colonies; +}; + +/** + * Gathers simply and consistent represenation of the Colony + * @param {*} _colonyClient + */ +exports.gatherColonyData = async function (_colonyClient, _id) { + console.log("gatherColonyData " + _id); + const colonyTokenInfo = await _colonyClient.token.getTokenInfo.call(); + const colonyDomainCount = (await _colonyClient.getDomainCount.call()).count; + const colonyTaskCount = (await _colonyClient.getTaskCount.call()).count; + const colonyContractAddress = _colonyClient.contract.address; + const colonyId = _id; + + //Gather data + const colonyData = { + "token": colonyTokenInfo, + "domainCount": colonyDomainCount, + "taskCount": colonyDomainCount, + "address": colonyContractAddress, + "id": colonyId + }; + + return colonyData; +} + +/** + * List Existing Accounts + */ +exports.listAccounts = async function () { + let addressList = []; + // Get the addresses from all local accounts through trufflepig + try { + while (true) { + const { address } = await loader.getAccount(addressList.length); + + addressList.push(address); + } + } catch (e) { + console.log("Finished Loading Accounts. Found " + addressList.length + " accounts. " + e); + } + + return addressList; +}; \ No newline at end of file diff --git a/src/createColonyWindow.html b/src/createColonyWindow.html new file mode 100644 index 0000000..156e1d1 --- /dev/null +++ b/src/createColonyWindow.html @@ -0,0 +1,82 @@ + + + + + DDSC - Creating New Decentralized Data Science Colony + + + + + + + + + + + + +
+
+
+
+
+
+ + +
+
+ + +
+
+
+
+
+
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/src/create_colony.js b/src/create_colony.js new file mode 100644 index 0000000..503e6e2 --- /dev/null +++ b/src/create_colony.js @@ -0,0 +1,67 @@ +// Import the prerequisites + +const { providers, Wallet } = require('ethers'); +const { default: EthersAdapter } = require('@colony/colony-js-adapter-ethers'); +const { TrufflepigLoader } = require('@colony/colony-js-contract-loader-http'); + +// Import the ColonyNetworkClient +const { default: ColonyNetworkClient } = require('@colony/colony-js-client'); + +// Create an instance of the Trufflepig contract loader +const loader = new TrufflepigLoader(); + +// Create a provider for local TestRPC (Ganache) +const provider = new providers.JsonRpcProvider('http://localhost:8545/'); + +// The following methods use Promises +const example = async () => { + + // Get the private key from the first account from the ganache-accounts + // through trufflepig + const { privateKey } = await loader.getAccount(0); + + // Create a wallet with the private key (so we have a balance we can use) + const wallet = new Wallet(privateKey, provider); + + // Create an adapter (powered by ethers) + const adapter = new EthersAdapter({ + loader, + provider, + wallet, + }); + + // Connect to ColonyNetwork with the adapter! + const networkClient = new ColonyNetworkClient({ adapter }); + await networkClient.init(); + + // Let's deploy a new ERC20 token for our Colony. + // You could also skip this step and use a pre-existing/deployed contract. + const tokenAddress = await networkClient.createToken({ + name: 'Cool Colony Token', + symbol: 'COLNY', + }); + console.log('Token address: ' + tokenAddress); + + // Create a cool Colony! + const { + eventData: { colonyId, colonyAddress }, + } = await networkClient.createColony.send({ tokenAddress }); + + // Congrats, you've created a Colony! + console.log('Colony ID: ' + colonyId); + console.log('Colony address: ' + colonyAddress); + + // For a colony that exists already, you just need its ID: + const colonyClient = await networkClient.getColonyClient(colonyId); + + // Or alternatively, just its address: + // const colonyClient = await networkClient.getColonyClientByAddress(colonyAddress); + + // You can also get the Meta Colony: + const metaColonyClient = await networkClient.getMetaColonyClient(); + console.log('Meta Colony address: ' + metaColonyClient.contract.address); + + return colonyClient; +}; + +module.exports = example; diff --git a/src/create_task.js b/src/create_task.js new file mode 100644 index 0000000..239e689 --- /dev/null +++ b/src/create_task.js @@ -0,0 +1,25 @@ +const ecp = require('./ecp'); + +const example = async (colonyClient) => { + // Initialise the Extended Colony Protocol + + await ecp.init(); + + // Create a task! + const specificationHash = await ecp.saveTaskSpecification({ title: 'Cool task', description: 'Create this cool thing.' }); + + // Unique, immutable hash on IPFS + console.log('Specification hash', specificationHash); + + // Create a task in the root domain + const { eventData: { taskId }} = await colonyClient.createTask.send({ specificationHash, domainId: 1 }); + + // Let's take a look at the newly created task + const task = await colonyClient.getTask.call({ taskId }) + console.log(task); + + // Do some cleanup + await ecp.stop(); +} + +module.exports = example; diff --git a/src/css/extraStyle.css b/src/css/extraStyle.css new file mode 100644 index 0000000..9cbc45b --- /dev/null +++ b/src/css/extraStyle.css @@ -0,0 +1,123 @@ +/* Required for the sticky footer */ +body { + display: flex; + min-height: 100vh; + flex-direction: column; + overflow: hidden; +} + +main { + flex: 1 0 auto; +} + +/* Override of MaterializedCSS classes */ + +.container { + margin: 0 auto; + max-width: 2280px; + width: 100%; +} + +/* Customization to individual Elements */ + +/* Main Window - BEGIN */ +.currentResearch { + min-height: 30vh; + max-height: 78vh; + overflow: auto; + padding-top: 5px; + padding-bottom: 1px; +} + +.fundingPots { + min-height: 50vh; + max-height: 50vh; + overflow: auto; + padding-top: 5px; + padding-bottom: 1px; +} + +/* On screens that are 992px or less, set the background color to blue */ +@media screen and (max-height: 900px) { + .fundingPots { + min-height: 30vh; + max-height: 30vh; + } + .currentResearch { + max-height: 70vh; + } +} +/* Main Window - END */ + +/* Research Window - BEGIN */ + +.researchTaskCard { + min-height: 15vh; + max-height: 78vh; + overflow: auto; + padding-top: 5px; + padding-bottom: 1px; +} + +.researchDocsCard { + min-height: 50vh; + max-height: 50vh; + overflow: auto; + padding-top: 5px; + padding-bottom: 1px; +} + +/* On screens that are 992px or less, set the background color to blue */ +@media screen and (max-height: 900px) { + .researchDocsCard { + min-height: 39vh; + max-height: 39vh; + } + .researchTaskCard { + max-height: 70vh; + } +} +/* Research Window - END */ + +/* Task Window - END */ +.taskTextCard { + height: 400px; + min-width: 100vw; + max-width: 100vw; + overflow: auto; +} + +.taskButtonCard { + height: 200px; + min-width: 100vw; + max-width: 100vw; + overflow: hidden; +} +/* Task Window - END */ + +/* Create New Colony - END */ +.colonyTextCard { + height: 400px; + min-width: 100vw; + max-width: 100vw; + overflow: auto; +} + +.colonyButtonCard { + height: 200px; + min-width: 100vw; + max-width: 100vw; + overflow: hidden; +} +/* Create New Colony Window - END */ + + +.minimumPadding { + padding-top: 5px; + padding-bottom: 1px; +} + +.minimumPadding > * { + padding-top: 1px; + padding-bottom: 1px; +} diff --git a/src/ecp.js b/src/ecp.js new file mode 100644 index 0000000..2c2ada1 --- /dev/null +++ b/src/ecp.js @@ -0,0 +1,44 @@ +// This is what will become a part of ColonyJS - The Extended Colony Protocol + +// It will make the Colony Network more human usable with functionality for +// non-consensus-relevant contexts by enriching the data stored on chain with +// metadata (which might be too expensive to store on chain). +// It helps developers building on the Colony Network provide a web 2.0 like +// user experience, without compromising decentralisation. + +const IPFS = require('ipfs'); +const { Buffer } = require('buffer'); + +let node; + +const waitForIPFS = () => { + node = new IPFS({ start: false }); + return new Promise((resolve, reject) => { + node.on('ready', () => resolve(true)); + node.on('error', err => reject(err)); + }) +}; + +exports.init = async () => { + await waitForIPFS(); + return node.start(); +} + +exports.saveTaskSpecification = async (spec) => { + const data = Buffer.from(JSON.stringify(spec)); + const result = await node.files.add(data); + return result[0].hash; +} + +exports.getTaskSpecification = async (hash) => { + const buf = await node.files.cat(`/ipfs/${hash}`); + let spec; + try { + spec = JSON.parse(buf.toString()); + } catch (e) { + throw new Error(`Could not get task specification for hash ${hash}`); + } + return spec; +} + +exports.stop = () => node.stop(); diff --git a/src/etherClient.js b/src/etherClient.js new file mode 100644 index 0000000..791f6a6 --- /dev/null +++ b/src/etherClient.js @@ -0,0 +1,3 @@ +/* +Client for Ethereum Blockchain +*/ \ No newline at end of file diff --git a/src/genericCode.js b/src/genericCode.js new file mode 100644 index 0000000..0b45278 --- /dev/null +++ b/src/genericCode.js @@ -0,0 +1,23 @@ +/* + + Code used on multiple windows + +*/ + +const electron = require("electron"); +const {ipcRenderer,remote} = electron; + +function showProcessingPopUp() { + +} + +/* + * Show a toast on the current window + */ +ipcRenderer.on("toast:show", function (e, _message, options) { + let effectiveOptions = (options == null) ? {} : options; + + effectiveOptions["html"] = _message; + + M.toast(effectiveOptions); +}); \ No newline at end of file diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..a64840d --- /dev/null +++ b/src/index.js @@ -0,0 +1,8 @@ +const createColony = require('./create_colony'); +const createTask = require('./create_task'); + +createColony() + .then(createTask) + // We're exiting hard here as the providers keep polling otherwise + .then(() => process.exit()) + .catch(err => console.error(err)); diff --git a/src/lib/colonyNetwork/.babelrc b/src/lib/colonyNetwork/.babelrc new file mode 100644 index 0000000..92a444b --- /dev/null +++ b/src/lib/colonyNetwork/.babelrc @@ -0,0 +1,4 @@ +{ + "presets": ["es2015", "stage-2"], + "plugins": ["babel-plugin-transform-runtime"], +} diff --git a/src/lib/colonyNetwork/.circleci/config.yml b/src/lib/colonyNetwork/.circleci/config.yml new file mode 100644 index 0000000..33a6754 --- /dev/null +++ b/src/lib/colonyNetwork/.circleci/config.yml @@ -0,0 +1,102 @@ +version: 2 + +jobs: + lint-and-unit-test: + docker: + - image: circleci/node:9.1.0 + working_directory: ~/colonyNetwork + steps: + - checkout + - restore_cache: + keys: + - node-modules-{{ checksum "yarn.lock" }} + - node-modules- + - run: + name: "Set up global packages" + command: | + yarn global add greenkeeper-lockfile@1 + yarn --pure-lockfile + git submodule update --init + - run: + name: "Setup parity" + command: | + wget https://parity-downloads-mirror.parity.io/v1.8.3/x86_64-unknown-linux-gnu/parity_1.8.3_amd64.deb + sudo dpkg -i parity_1.8.3_amd64.deb + echo "password" > parityPassword + cp ./parity-genesis.template.json ./parity-genesis.json + sed -i "s/wwwww/$(parity --keys-path ./keys --password ./parityPassword account new)/g" ./parity-genesis.json + sed -i "s/xxxxx/$(parity --keys-path ./keys --password ./parityPassword account new)/g" ./parity-genesis.json + sed -i "s/yyyyy/$(parity --keys-path ./keys --password ./parityPassword account new)/g" ./parity-genesis.json + sed -i "s/zzzzz/$(parity --keys-path ./keys --password ./parityPassword account new)/g" ./parity-genesis.json + - save_cache: + paths: + - node_modules + key: node-modules-{{ checksum "yarn.lock" }} + - run: + name: "Install lsof" + command: | + sudo apt-get update + sudo apt-get install lsof + - run: + name: "Greenkeeper lockfile update" + command: $HOME/.config/yarn/global/node_modules/.bin/greenkeeper-lockfile-update + - run: + name: "Linting JavaScript" + command: yarn run eslint + - run: + name: "Linting Solidity" + command: yarn run solium + - run: + name: "Checking contract storage variables" + command: yarn run check:storagevars + - run: + name: "Running unit tests" + command: yarn run test:contracts + - run: + name: "Running upgrade tests" + command: yarn run test:contracts:upgrade + - run: + name: "Running gas cost tests" + command: yarn run test:contracts:gasCosts + - run: + name: "Running colony-contract-loader-network tests" + command: cd packages/colony-contract-loader-network && yarn run test + - run: + name: "Greenkeeper uploading lockfile" + command: $HOME/.config/yarn/global/node_modules/.bin/greenkeeper-lockfile-upload + # Save test results + - store_test_results: + path: test-results.xml + - store_artifacts: + path: test-results.xml + + test-coverage: + docker: + - image: circleci/node:9.1.0 + working_directory: ~/colonyNetwork + steps: + - checkout + - restore_cache: + keys: + - node-modules-{{ checksum "yarn.lock" }} + - node-modules- + - run: + name: "Set up global packages" + command: | + yarn global add greenkeeper-lockfile@1 + yarn --pure-lockfile + git submodule update --init + - run: + name: "Running unit tests with coverage" + command: yarn run test:contracts:coverage + + # Save coverage artifacts + - store_artifacts: + path: coverage + +workflows: + version: 2 + commit: + jobs: + - lint-and-unit-test + - test-coverage diff --git a/src/lib/colonyNetwork/.eslintignore b/src/lib/colonyNetwork/.eslintignore new file mode 100644 index 0000000..f68d0e4 --- /dev/null +++ b/src/lib/colonyNetwork/.eslintignore @@ -0,0 +1,8 @@ +#/node_modules/* and /bower_components/* ignored by default + +build/* +contracts/* +coverage/* +keys/* +lib/* +packages/reputation-miner/node_modules/* diff --git a/src/lib/colonyNetwork/.eslintrc b/src/lib/colonyNetwork/.eslintrc new file mode 100644 index 0000000..59e24c2 --- /dev/null +++ b/src/lib/colonyNetwork/.eslintrc @@ -0,0 +1,21 @@ +{ + "extends": "@colony/eslint-config-colony", + "env": { + "node": true, + "mocha": true + }, + "globals": { + "web3": true, + "assert": true, + "contract": true + }, + "rules": { + "import/no-extraneous-dependencies": [2, {"devDependencies": ["**/*.js"]}], + "max-len": [2, { "code": 150, "ignoreComments": true }], + "prettier/prettier": ["error", {"printWidth": 150}], + "flowtype/require-valid-file-annotation": "off" + }, + "parserOptions": { + "ecmaVersion": 2017 + } +} diff --git a/src/lib/colonyNetwork/.gitattributes b/src/lib/colonyNetwork/.gitattributes new file mode 100644 index 0000000..7cc88f0 --- /dev/null +++ b/src/lib/colonyNetwork/.gitattributes @@ -0,0 +1 @@ +*.sol linguist-language=Solidity \ No newline at end of file diff --git a/src/lib/colonyNetwork/.gitignore b/src/lib/colonyNetwork/.gitignore new file mode 100644 index 0000000..a781cad --- /dev/null +++ b/src/lib/colonyNetwork/.gitignore @@ -0,0 +1,15 @@ +node_modules +parity-genesis.json +contracts/Updated* +contracts/IUpdated* +keys/* +test-results.xml +0 +parityPassword +**/build/* +coverage +coverage.json +lib/dappsys +ganache-accounts.json +.vscode/ +yarn-error.log diff --git a/src/lib/colonyNetwork/.gitmodules b/src/lib/colonyNetwork/.gitmodules new file mode 100644 index 0000000..b888773 --- /dev/null +++ b/src/lib/colonyNetwork/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lib/dappsys"] + path = lib/dappsys + url = https://github.com/dapphub/dappsys-monolithic.git diff --git a/src/lib/colonyNetwork/.nvmrc b/src/lib/colonyNetwork/.nvmrc new file mode 100644 index 0000000..47da986 --- /dev/null +++ b/src/lib/colonyNetwork/.nvmrc @@ -0,0 +1 @@ +9.1.0 diff --git a/src/lib/colonyNetwork/.solcover.js b/src/lib/colonyNetwork/.solcover.js new file mode 100644 index 0000000..5e44031 --- /dev/null +++ b/src/lib/colonyNetwork/.solcover.js @@ -0,0 +1,12 @@ +module.exports = { + skipFiles: [ + 'Migrations.sol', + 'EtherRouter.sol', + 'gnosis', + 'Token.sol', + 'PatriciaTree' + ], + compileCommand: '../node_modules/.bin/truffle compile', + testCommand: '../node_modules/.bin/truffle test --network coverage', + testrpcOptions: `--port 8555 -i coverage --acctKeys="./coverageEnv/ganache-accounts.json" --noVMErrorsOnRPCResponse` +}; diff --git a/src/lib/colonyNetwork/.soliumignore b/src/lib/colonyNetwork/.soliumignore new file mode 100644 index 0000000..932d9d0 --- /dev/null +++ b/src/lib/colonyNetwork/.soliumignore @@ -0,0 +1,7 @@ +node_modules +helpers +migrations +test +contracts/Migrations.sol +contracts/gnosis/MultiSigWallet.sol +lib \ No newline at end of file diff --git a/src/lib/colonyNetwork/.soliumrc.json b/src/lib/colonyNetwork/.soliumrc.json new file mode 100644 index 0000000..329b3bb --- /dev/null +++ b/src/lib/colonyNetwork/.soliumrc.json @@ -0,0 +1,14 @@ +{ + "extends": "solium:all", + "plugins": ["security"], + "rules": { + "imports-on-top": 0, + "variable-declarations": "error", + "arg-overflow": ["warning", 5], + "indentation": ["error", 2], + "quotes": ["error", "double"], + "security/no-inline-assembly": 0, + "security/no-call-value": 0, + "security/no-block-members": 0 + } +} diff --git a/src/lib/colonyNetwork/.yarnrc b/src/lib/colonyNetwork/.yarnrc new file mode 100644 index 0000000..19daaca --- /dev/null +++ b/src/lib/colonyNetwork/.yarnrc @@ -0,0 +1 @@ +workspaces-experimental true diff --git a/src/lib/colonyNetwork/LICENSE b/src/lib/colonyNetwork/LICENSE new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/src/lib/colonyNetwork/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program 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. + + This program 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 this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/src/lib/colonyNetwork/contracts/Authority.sol b/src/lib/colonyNetwork/contracts/Authority.sol new file mode 100644 index 0000000..f6297ec --- /dev/null +++ b/src/lib/colonyNetwork/contracts/Authority.sol @@ -0,0 +1,49 @@ +/* + This file is part of The Colony Network. + + The Colony Network 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. + + The Colony Network 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 The Colony Network. If not, see . +*/ + +pragma solidity ^0.4.23; +pragma experimental "v0.5.0"; + +import "../lib/dappsys/roles.sol"; + + +contract Authority is DSRoles { + uint8 ownerRole = 0; + uint8 adminRole = 1; + + constructor(address colony) public { + bytes4 makeTaskSig = bytes4(keccak256("makeTask(bytes32,uint256)")); + setRoleCapability(ownerRole, colony, makeTaskSig, true); + setRoleCapability(adminRole, colony, makeTaskSig, true); + + bytes4 acceptTaskSig = bytes4(keccak256("finalizeTask(uint256)")); + setRoleCapability(ownerRole, colony, acceptTaskSig, true); + setRoleCapability(adminRole, colony, acceptTaskSig, true); + + bytes4 setTaskDueDateSig = bytes4(keccak256("setTaskDueDate(uint256,uint256)")); + setRoleCapability(ownerRole, colony, setTaskDueDateSig, true); + setRoleCapability(adminRole, colony, setTaskDueDateSig, true); + + bytes4 setTaskPayoutSig = bytes4(keccak256("setTaskPayout(uint256,uint256,address,uint256)")); + setRoleCapability(ownerRole, colony, setTaskPayoutSig, true); + setRoleCapability(adminRole, colony, setTaskPayoutSig, true); + + bytes4 moveFundsBetweenPotsSig = bytes4(keccak256("moveFundsBetweenPots(uint256,uint256,uint256,address)")); + setRoleCapability(ownerRole, colony, moveFundsBetweenPotsSig, true); + setRoleCapability(adminRole, colony, moveFundsBetweenPotsSig, true); + } +} diff --git a/src/lib/colonyNetwork/contracts/Colony.sol b/src/lib/colonyNetwork/contracts/Colony.sol new file mode 100755 index 0000000..916be67 --- /dev/null +++ b/src/lib/colonyNetwork/contracts/Colony.sol @@ -0,0 +1,166 @@ +/* + This file is part of The Colony Network. + + The Colony Network 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. + + The Colony Network 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 The Colony Network. If not, see . +*/ + +pragma solidity ^0.4.23; +pragma experimental "v0.5.0"; + +import "./ERC20Extended.sol"; +import "./IColonyNetwork.sol"; +import "./IColony.sol"; +import "./ColonyStorage.sol"; +import "./PatriciaTree/PatriciaTreeProofs.sol"; + + +contract Colony is ColonyStorage, PatriciaTreeProofs { + + // This function, exactly as defined, is used in build scripts. Take care when updating. + // Version number should be upped with every change in Colony or its dependency contracts or libraries. + function version() public pure returns (uint256) { return 1; } + + function setToken(address _token) public + auth + { + token = ERC20Extended(_token); + } + + function getToken() public view returns (address) { + return token; + } + + function initialiseColony(address _address) public { + require(colonyNetworkAddress == 0x0, "colony-initialise-bad-address"); + colonyNetworkAddress = _address; + potCount = 1; + + // Initialise the task update reviewers + setFunctionReviewers(0xda4db249, 0, 2); // setTaskBrief => manager, worker + setFunctionReviewers(0xcae960fe, 0, 2); // setTaskDueDate => manager, worker + setFunctionReviewers(0x6fb0794f, 0, 1); // setTaskEvaluatorPayout => manager, evaluator + setFunctionReviewers(0x2cf62b39, 0, 2); // setTaskWorkerPayout => manager, worker + + // Initialise the root domain + domainCount += 1; + IColonyNetwork colonyNetwork = IColonyNetwork(colonyNetworkAddress); + uint256 rootLocalSkill = colonyNetwork.getSkillCount(); + domains[1] = Domain({ + skillId: rootLocalSkill, + potId: 1 + }); + } + + function bootstrapColony(address[] _users, int[] _amounts) public + auth + isInBootstrapPhase + { + require(_users.length == _amounts.length, "colony-bootstrap-bad-inputs"); + + for (uint i = 0; i < _users.length; i++) { + require(_amounts[i] >= 0, "colony-bootstrap-bad-amount-input"); + + token.transfer(_users[i], uint(_amounts[i])); + IColonyNetwork(colonyNetworkAddress).appendReputationUpdateLog(_users[i], _amounts[i], domains[1].skillId); + } + } + + function mintTokens(uint _wad) public + auth + { + return token.mint(_wad); + } + + function mintTokensForColonyNetwork(uint _wad) public { + require(msg.sender == colonyNetworkAddress, "colony-access-denied-only-network-allowed"); // Only the colony Network can call this function + require(this == IColonyNetwork(colonyNetworkAddress).getMetaColony(), "colony-access-denied-only-meta-colony-allowed"); // Function only valid on the Meta Colony + token.mint(_wad); + token.transfer(colonyNetworkAddress, _wad); + } + + //TODO: Secure this function 'properly' + function addGlobalSkill(uint _parentSkillId) public + auth + returns (uint256) + { + IColonyNetwork colonyNetwork = IColonyNetwork(colonyNetworkAddress); + return colonyNetwork.addSkill(_parentSkillId, true); + } + + function addDomain(uint256 _parentSkillId) public + auth + localSkill(_parentSkillId) + { + // Note: remove that when we start allowing more domain hierarchy levels + // Instead check that the parent skill id belongs to this colony own domain + // Get the local skill id of the root domain + uint256 rootDomainSkillId = domains[1].skillId; + require(_parentSkillId == rootDomainSkillId, "colony-parent-skill-not-root"); + + // Setup new local skill + IColonyNetwork colonyNetwork = IColonyNetwork(colonyNetworkAddress); + uint256 newLocalSkill = colonyNetwork.addSkill(_parentSkillId, false); + + // Add domain to local mapping + domainCount += 1; + potCount += 1; + domains[domainCount] = Domain({ + skillId: newLocalSkill, + potId: potCount + }); + } + + function getDomain(uint256 _id) public view returns (uint256, uint256) { + Domain storage d = domains[_id]; + return (d.skillId, d.potId); + } + + function getDomainCount() public view returns (uint256) { + return domainCount; + } + function setFunctionReviewers(bytes4 _sig, uint8 _firstReviewer, uint8 _secondReviewer) + private + { + uint8[2] memory _reviewers = [_firstReviewer, _secondReviewer]; + reviewers[_sig] = _reviewers; + } + + modifier verifyKey(bytes key) { + uint256 colonyAddress; + uint256 skillid; + uint256 userAddress; + assembly { + colonyAddress := mload(add(key,32)) + skillid := mload(add(key,52)) // Colony address was 20 bytes long, so add 20 bytes + userAddress := mload(add(key,84)) // Skillid was 32 bytes long, so add 32 bytes + } + colonyAddress >>= 96; + userAddress >>= 96; + // Require that the user is proving their own reputation in this colony. + require(address(colonyAddress) == address(this)); + require(address(userAddress) == msg.sender); + _; + } + + function verifyReputationProof(bytes key, bytes value, uint branchMask, bytes32[] siblings) // solium-disable-line security/no-assign-params + verifyKey(key) + public returns (bool) + { + // Get roothash from colonynetwork + bytes32 rootHash = IColonyNetwork(colonyNetworkAddress).getReputationRootHash(); + bytes32 impliedHash = getImpliedRoot(key, value, branchMask, siblings); + require(rootHash==impliedHash, "colony-invalid-reputation-proof"); + return true; + } +} diff --git a/src/lib/colonyNetwork/contracts/ColonyFunding.sol b/src/lib/colonyNetwork/contracts/ColonyFunding.sol new file mode 100755 index 0000000..91cd008 --- /dev/null +++ b/src/lib/colonyNetwork/contracts/ColonyFunding.sol @@ -0,0 +1,311 @@ +/* + This file is part of The Colony Network. + + The Colony Network 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. + + The Colony Network 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 The Colony Network. If not, see . +*/ + +pragma solidity ^0.4.23; +pragma experimental "v0.5.0"; + +import "../lib/dappsys/math.sol"; +import "./ERC20Extended.sol"; +import "./IColonyNetwork.sol"; +import "./ColonyStorage.sol"; + + +contract ColonyFunding is ColonyStorage, DSMath { + event RewardPayoutCycleStarted(uint256 indexed id); + event RewardPayoutCycleEnded(uint256 indexed id); + event TaskWorkerPayoutChanged(uint256 indexed id, address token, uint256 amount); + + function getFeeInverse() public pure returns (uint256) { + // TODO: refer to ColonyNetwork + return 100; + } + + function getRewardInverse() public pure returns (uint256) { + // TODO: Make settable by colony + return 100; + } + + function setTaskManagerPayout(uint256 _id, address _token, uint256 _amount) public isManager(_id) { + setTaskPayout(_id, MANAGER, _token, _amount); + } + + function setTaskEvaluatorPayout(uint256 _id, address _token, uint256 _amount) public self { + setTaskPayout(_id, EVALUATOR, _token, _amount); + } + + function setTaskWorkerPayout(uint256 _id, address _token, uint256 _amount) public self { + setTaskPayout(_id, WORKER, _token, _amount); + + emit TaskWorkerPayoutChanged(_id, _token, _amount); + } + + // To get all payouts for a task iterate over roles.length + function getTaskPayout(uint256 _id, uint256 _role, address _token) public view returns (uint256) { + Task storage task = tasks[_id]; + bool unsatisfactory = task.roles[_role].rating == TaskRatings.Unsatisfactory; + return unsatisfactory ? 0 : task.payouts[_role][_token]; + } + + function getTotalTaskPayout(uint256 _id, address _token) public view returns(uint256) { + uint totalPayouts; + for (uint8 roleId = 0; roleId <= 2; roleId++) { + totalPayouts = add(totalPayouts, getTaskPayout(_id, roleId, _token)); + } + return totalPayouts; + } + + function claimPayout(uint256 _id, uint256 _role, address _token) public + taskFinalized(_id) + { + Task storage task = tasks[_id]; + require(task.roles[_role].user == msg.sender, "colony-claim-payout-access-denied"); + + if (task.roles[_role].rating == TaskRatings.Unsatisfactory) { + return; + } + + uint payout = task.payouts[_role][_token]; + task.payouts[_role][_token] = 0; + + pots[task.potId].balance[_token] = sub(pots[task.potId].balance[_token], payout); + nonRewardPotsTotal[_token] = sub(nonRewardPotsTotal[_token], payout); + + uint fee = payout / getFeeInverse(); + uint remainder = sub(payout, fee); + + if (_token == 0x0) { + // Payout ether + task.roles[_role].user.transfer(remainder); + // Fee goes directly to Meta Colony + IColonyNetwork colonyNetworkContract = IColonyNetwork(colonyNetworkAddress); + address metaColonyAddress = colonyNetworkContract.getMetaColony(); + metaColonyAddress.transfer(fee); + } else { + // Payout token + // TODO: If it's a whitelisted token, it goes straight to the metaColony + // If it's any other token, goes to the colonyNetwork contract first to be auctioned. + ERC20Extended payoutToken = ERC20Extended(_token); + payoutToken.transfer(task.roles[_role].user, remainder); + payoutToken.transfer(colonyNetworkAddress, fee); + } + } + + function getPotBalance(uint256 _potId, address _token) public view returns (uint256) { + return pots[_potId].balance[_token]; + } + + function moveFundsBetweenPots(uint256 _fromPot, uint256 _toPot, uint256 _amount, address _token) public + auth + { + // Prevent people moving funds from the pot for paying out token holders + require(_fromPot > 0, "colony-funding-cannot-move-funds-from-pot-0"); + + // TODO Only allow sending from created pots - perhaps not necessary explicitly, but if not, note as such here. + require(_toPot <= potCount, "colony-funding-nonexistent-pot"); // Only allow sending to created pots + + uint fromTaskId = pots[_fromPot].taskId; + uint toTaskId = pots[_toPot].taskId; + + uint fromPotPreviousAmount = pots[_fromPot].balance[_token]; + uint toPotPreviousAmount = pots[_toPot].balance[_token]; + + // If this pot is associated with a task, prevent money being taken from the pot + // if the remaining balance is less than the amount needed for payouts, + // unless the task was cancelled. + if (fromTaskId > 0) { + Task storage task = tasks[fromTaskId]; + uint totalPayout = getTotalTaskPayout(fromTaskId, _token); + uint surplus = (fromPotPreviousAmount > totalPayout) ? sub(fromPotPreviousAmount, totalPayout) : 0; + require(task.cancelled || surplus >= _amount, "colony-funding-task-bad-state"); + } + + pots[_fromPot].balance[_token] = sub(fromPotPreviousAmount, _amount); + pots[_toPot].balance[_token] = add(toPotPreviousAmount, _amount); + updateTaskPayoutsWeCannotMakeAfterPotChange(toTaskId, _token, toPotPreviousAmount); + updateTaskPayoutsWeCannotMakeAfterPotChange(fromTaskId, _token, fromPotPreviousAmount); + } + + function claimColonyFunds(address _token) public { + uint toClaim; + uint feeToPay; + uint remainder; + if (_token == 0x0) { + // It's ether + toClaim = sub(sub(address(this).balance, nonRewardPotsTotal[_token]), pots[0].balance[_token]); + } else { + // Assume it's an ERC 20 token. + ERC20Extended targetToken = ERC20Extended(_token); + toClaim = sub(sub(targetToken.balanceOf(this), nonRewardPotsTotal[_token]), pots[0].balance[_token]); + } + feeToPay = toClaim / getRewardInverse(); + if (token == _token) { // Well this line isn't easy to understand + // Basically, if we're using our own tokens, then we don't siphon off a chunk for rewards + feeToPay = 0; + } + remainder = sub(toClaim, feeToPay); + nonRewardPotsTotal[_token] = add(nonRewardPotsTotal[_token], remainder); + pots[1].balance[_token] = add(pots[1].balance[_token], remainder); + pots[0].balance[_token] = add(pots[0].balance[_token], feeToPay); + } + + function getNonRewardPotsTotal(address _token) public view returns (uint256) { + return nonRewardPotsTotal[_token]; + } + + function getGlobalRewardPayoutCount() public view returns (uint256) { + return globalRewardPayoutCount; + } + + function getUserRewardPayoutCount(address _user) public view returns (uint256) { + return userRewardPayoutCount[_user]; + } + + function startNextRewardPayout(address _token) public auth { + require(!activeRewardPayouts[_token], "colony-reward-payout-token-active"); + + uint256 totalTokens = sub(token.totalSupply(), token.balanceOf(address(this))); + require(totalTokens > 0, "colony-reward-payout-invalid-total-tokens"); + + activeRewardPayouts[_token] = true; + globalRewardPayoutCount += 1; + + //TODO: Lock everyones tokens + + rewardPayoutCycles[globalRewardPayoutCount] = RewardPayoutCycle( + IColonyNetwork(colonyNetworkAddress).getReputationRootHash(), + totalTokens, + pots[0].balance[_token], + _token, + block.timestamp + ); + + emit RewardPayoutCycleStarted(globalRewardPayoutCount); + } + + function claimRewardPayout(uint256 _payoutId, uint256[7] _squareRoots, uint256 _userReputation, uint256 _totalReputation) public { + RewardPayoutCycle memory payout = rewardPayoutCycles[_payoutId]; + require(block.timestamp - payout.blockTimestamp <= 60 days, "colony-reward-payout-not-active"); + require(_payoutId - userRewardPayoutCount[msg.sender] == 1, "colony-reward-payout-bad-id"); + + //TODO: Prove that userReputation and totalReputation in reputationState are correct + + uint256 userTokens = token.balanceOf(msg.sender); + + require(_totalReputation > 0, "colony-reward-payout-invalid-total-reputation"); + require(userTokens > 0, "colony-reward-payout-invalid-user-tokens"); + require(_userReputation > 0, "colony-reward-payout-invalid-user-reputation"); + + // squareRoots[0] - square root of _userReputation + // squareRoots[1] - square root of userTokens + // squareRoots[2] - square root of _totalReputation + // squareRoots[3] - square root of totalTokens + // squareRoots[4] - square root of numerator + // squareRoots[5] - square root of denominator + // squareRoots[6] - square root of payout.amount + + require(mul(_squareRoots[0], _squareRoots[0]) <= _userReputation, "colony-reward-payout-invalid-parametar-user-reputation"); + require(mul(_squareRoots[1], _squareRoots[1]) <= userTokens, "colony-reward-payout-invalid-parametar-user-token"); + require(mul(_squareRoots[2], _squareRoots[2]) <= _totalReputation, "colony-reward-payout-invalid-parametar-total-reputation"); + require(mul(_squareRoots[3], _squareRoots[3]) <= payout.totalTokens, "colony-reward-payout-invalid-parametar-total-tokens"); + require(mul(_squareRoots[6], _squareRoots[6]) <= payout.amount, "colony-reward-payout-invalid-parametar-amount"); + uint256 numerator = mul(_squareRoots[0], _squareRoots[1]); + uint256 denominator = mul(_squareRoots[2], _squareRoots[3]); + + require(mul(_squareRoots[4], _squareRoots[4]) <= numerator, "colony-reward-payout-invalid-parametar-numerator"); + require(mul(_squareRoots[5], _squareRoots[5]) <= denominator, "colony-reward-payout-invalid-parametar-denominator"); + + uint256 reward = (mul(_squareRoots[4], _squareRoots[6]) / (_squareRoots[5] + 1)) ** 2; + + pots[0].balance[payout.tokenAddress] = sub(pots[0].balance[payout.tokenAddress], reward); + + userRewardPayoutCount[msg.sender] += 1; + + // TODO: Unlock user tokens + + ERC20Extended(payout.tokenAddress).transfer(msg.sender, reward); + } + + function waiveRewardPayouts(uint256 _numPayouts) public { + require(add(userRewardPayoutCount[msg.sender], _numPayouts) <= globalRewardPayoutCount, "colony-reward-payout-invalid-num-payouts"); + + userRewardPayoutCount[msg.sender] += _numPayouts; + + //TODO unlock user tokens + } + + function finalizeRewardPayout(uint256 _payoutId) public { + require(_payoutId <= globalRewardPayoutCount, "colony-reward-payout-not-found"); + + RewardPayoutCycle memory payout = rewardPayoutCycles[_payoutId]; + + require(activeRewardPayouts[payout.tokenAddress], "colony-reward-payout-token-not-active"); + require(block.timestamp - payout.blockTimestamp > 60 days, "colony-reward-payout-active"); + + activeRewardPayouts[payout.tokenAddress] = false; + + emit RewardPayoutCycleEnded(_payoutId); + } + + function getRewardPayoutInfo(uint256 _payoutId) public view returns (bytes32, uint256, uint256, address, uint256) { + RewardPayoutCycle memory rewardPayoutInfo = rewardPayoutCycles[_payoutId]; + return (rewardPayoutInfo.reputationState, rewardPayoutInfo.totalTokens, rewardPayoutInfo.amount, rewardPayoutInfo.tokenAddress, rewardPayoutInfo.blockTimestamp); + } + + function updateTaskPayoutsWeCannotMakeAfterPotChange(uint256 _id, address _token, uint _prev) internal { + Task storage task = tasks[_id]; + uint totalTokenPayout = getTotalTaskPayout(_id, _token); + uint tokenPot = pots[task.potId].balance[_token]; + if (_prev >= totalTokenPayout) { // If the old amount in the pot was enough to pay for the budget + if (tokenPot < totalTokenPayout) { // And the new amount in the pot is not enough to pay for the budget... + task.payoutsWeCannotMake += 1; // Then this is a set of payouts we cannot make that we could before. + } + } else { // If this 'else' is running, then the old amount in the pot could not pay for the budget + if (tokenPot >= totalTokenPayout) { // And the new amount in the pot can pay for the budget + task.payoutsWeCannotMake -= 1; // Then this is a set of payouts we can make that we could not before. + } + } + } + + function updateTaskPayoutsWeCannotMakeAfterBudgetChange(uint256 _id, address _token, uint _prev) internal { + Task storage task = tasks[_id]; + uint totalTokenPayout = getTotalTaskPayout(_id, _token); + uint tokenPot = pots[task.potId].balance[_token]; + if (tokenPot >= _prev) { // If the amount in the pot was enough to pay for the old budget... + if (tokenPot < totalTokenPayout) { // And the amount is not enough to pay for the new budget... + task.payoutsWeCannotMake += 1; // Then this is a set of payouts we cannot make that we could before. + } + } else { // If this 'else' is running, then the amount in the pot was not enough to pay for the old budget + if (tokenPot >= totalTokenPayout) { // And the amount is enough to pay for the new budget... + task.payoutsWeCannotMake -= 1; // Then this is a set of payouts we can make that we could not before. + } + } + } + + function setTaskPayout(uint256 _id, uint256 _role, address _token, uint256 _amount) private + taskExists(_id) + taskNotFinalized(_id) + { + uint currentTotalAmount = getTotalTaskPayout(_id, _token); + tasks[_id].payouts[_role][_token] = _amount; + + // This call functions as a guard to make sure the new total payout doesn't overflow + // If there is an overflow, the call will revert + getTotalTaskPayout(_id, _token); + + updateTaskPayoutsWeCannotMakeAfterBudgetChange(_id, _token, currentTotalAmount); + } +} diff --git a/src/lib/colonyNetwork/contracts/ColonyNetwork.sol b/src/lib/colonyNetwork/contracts/ColonyNetwork.sol new file mode 100644 index 0000000..925e662 --- /dev/null +++ b/src/lib/colonyNetwork/contracts/ColonyNetwork.sol @@ -0,0 +1,243 @@ +/* + This file is part of The Colony Network. + + The Colony Network 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. + + The Colony Network 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 The Colony Network. If not, see . +*/ + +pragma solidity ^0.4.23; +pragma experimental "v0.5.0"; + +import "../lib/dappsys/auth.sol"; +import "./Authority.sol"; +import "./IColony.sol"; +import "./EtherRouter.sol"; +import "./Token.sol"; +import "./ColonyNetworkStorage.sol"; +import "./IReputationMiningCycle.sol"; + + +contract ColonyNetwork is ColonyNetworkStorage { + event ColonyAdded(uint256 indexed id, address indexed colonyAddress); + event SkillAdded(uint256 skillId, uint256 parentSkillId); + + // Meta Colony allowed to manage Global skills + // All colonies are able to manage their Local (domain associated) skills + modifier allowedToAddSkill(bool globalSkill) { + if (globalSkill) { + require(msg.sender == metaColony); + } else { + require(_isColony[msg.sender]); + } + _; + } + + modifier skillExists(uint skillId) { + require(skillCount >= skillId); + _; + } + + modifier nonZero(uint256 parentSkillId) { + require(parentSkillId > 0); + _; + } + + modifier calledByColony() { + require(_isColony[msg.sender]); + _; + } + + function getCurrentColonyVersion() public view returns (uint256) { + return currentColonyVersion; + } + + function getMetaColony() public view returns (address) { + return metaColony; + } + + function getColonyCount() public view returns (uint256) { + return colonyCount; + } + + function getSkillCount() public view returns (uint256) { + return skillCount; + } + + function getRootGlobalSkillId() public view returns (uint256) { + return rootGlobalSkillId; + } + + function getColonyVersionResolver(uint256 _version) public view returns (address) { + return colonyVersionResolver[_version]; + } + + function getSkill(uint256 _skillId) public view returns (uint256, uint256) { + return (skills[_skillId].nParents, skills[_skillId].nChildren); + } + + function isGlobalSkill(uint256 _skillId) public view returns (bool) { + return skills[_skillId].globalSkill; + } + + function getReputationRootHash() public view returns (bytes32) { + return reputationRootHash; + } + + function getReputationRootHashNNodes() public view returns (uint256) { + return reputationRootHashNNodes; + } + + function createMetaColony(address _tokenAddress) public + auth + { + require(metaColony == 0); + // Add the root global skill + skillCount += 1; + Skill memory rootGlobalSkill; + rootGlobalSkill.globalSkill = true; + skills[skillCount] = rootGlobalSkill; + rootGlobalSkillId = skillCount; + // TODO: add the special 'mining' skill, which is local to the meta Colony. + + metaColony = createColony(_tokenAddress); + } + + function createColony(address _tokenAddress) public returns (address) { + EtherRouter etherRouter = new EtherRouter(); + address resolverForLatestColonyVersion = colonyVersionResolver[currentColonyVersion]; + etherRouter.setResolver(resolverForLatestColonyVersion); + + IColony colony = IColony(etherRouter); + colony.setToken(_tokenAddress); + + Authority authority = new Authority(colony); + DSAuth dsauth = DSAuth(etherRouter); + dsauth.setAuthority(authority); + authority.setRootUser(msg.sender, true); + authority.setOwner(msg.sender); + + // Initialise the root (domain) local skill with defaults by just incrementing the skillCount + skillCount += 1; + colonyCount += 1; + colonies[colonyCount] = colony; + _isColony[colony] = true; + + colony.initialiseColony(this); + emit ColonyAdded(colonyCount, etherRouter); + + return etherRouter; + } + + function addColonyVersion(uint _version, address _resolver) public + auth + { + colonyVersionResolver[_version] = _resolver; + if (_version > currentColonyVersion) { + currentColonyVersion = _version; + } + } + + function getColony(uint256 _id) public view returns (address) { + return colonies[_id]; + } + + function upgradeColony(uint256 _id, uint _newVersion) public { + address etherRouter = colonies[_id]; + // Check the calling user is authorised + DSAuth auth = DSAuth(etherRouter); + DSAuthority authority = auth.authority(); + require(authority.canCall(msg.sender, etherRouter, 0x0e1f20b4)); + // Upgrades can only go up in version + IColony colony = IColony(etherRouter); + uint currentVersion = colony.version(); + require(_newVersion > currentVersion); + // Requested version has to be registered + address newResolver = colonyVersionResolver[_newVersion]; + require(newResolver != 0x0); + EtherRouter e = EtherRouter(etherRouter); + e.setResolver(newResolver); + } + + function addSkill(uint _parentSkillId, bool _globalSkill) public + skillExists(_parentSkillId) + allowedToAddSkill(_globalSkill) + nonZero(_parentSkillId) + returns (uint256) + { + skillCount += 1; + + Skill storage parentSkill = skills[_parentSkillId]; + + // Global and local skill trees are kept separate + require(parentSkill.globalSkill == _globalSkill); + + Skill memory s; + s.nParents = parentSkill.nParents + 1; + s.globalSkill = _globalSkill; + skills[skillCount] = s; + + uint parentSkillId = _parentSkillId; + bool notAtRoot = true; + uint powerOfTwo = 1; + uint treeWalkingCounter = 1; + + // Walk through the tree parent skills up to the root + while (notAtRoot) { + // Add the new skill to each parent children + // TODO: skip this for the root skill as the children of that will always be all skills + parentSkill.children.push(skillCount); + parentSkill.nChildren += 1; + + // When we are at an integer power of two steps away from the newly added skill node, + // add the current parent skill to the new skill's parents array + if (treeWalkingCounter == powerOfTwo) { + skills[skillCount].parents.push(parentSkillId); + powerOfTwo = powerOfTwo*2; + } + + // Check if we've reached the root of the tree yet (it has no parents) + // Otherwise get the next parent + if (parentSkill.nParents == 0) { + notAtRoot = false; + } else { + parentSkillId = parentSkill.parents[0]; + parentSkill = skills[parentSkill.parents[0]]; + } + + treeWalkingCounter += 1; + } + + emit SkillAdded(skillCount, _parentSkillId); + return skillCount; + } + + function getParentSkillId(uint _skillId, uint _parentSkillIndex) public view returns (uint256) { + Skill storage skill = skills[_skillId]; + return skill.parents[_parentSkillIndex]; + } + + function getChildSkillId(uint _skillId, uint _childSkillIndex) public view returns (uint256) { + Skill storage skill = skills[_skillId]; + return skill.children[_childSkillIndex]; + } + + function appendReputationUpdateLog(address _user, int _amount, uint _skillId) public + calledByColony + skillExists(_skillId) + { + uint nParents = skills[_skillId].nParents; + // TODO: Is it cheaper to check if _amount is <0, and if not, just set nChildren to 0, because children won't be updated for such an update? + uint nChildren = skills[_skillId].nChildren; + IReputationMiningCycle(inactiveReputationMiningCycle).appendReputationUpdateLog(_user, _amount, _skillId, msg.sender, nParents, nChildren); + } +} diff --git a/src/lib/colonyNetwork/contracts/ColonyNetworkAuction.sol b/src/lib/colonyNetwork/contracts/ColonyNetworkAuction.sol new file mode 100644 index 0000000..75b1d97 --- /dev/null +++ b/src/lib/colonyNetwork/contracts/ColonyNetworkAuction.sol @@ -0,0 +1,216 @@ +/* + This file is part of The Colony Network. + + The Colony Network 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. + + The Colony Network 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 The Colony Network. If not, see . +*/ + +pragma solidity ^0.4.23; +pragma experimental "v0.5.0"; + +import "../lib/dappsys/math.sol"; +import "./ColonyNetworkStorage.sol"; +import "./ERC20Extended.sol"; +import "./IColony.sol"; + + +contract ColonyNetworkAuction is ColonyNetworkStorage { + event AuctionCreated(address auction, address token, uint256 quantity); + + function startTokenAuction(address _token) public { + address clny = IColony(metaColony).getToken(); + DutchAuction auction = new DutchAuction(clny, _token); + uint availableTokens = ERC20Extended(_token).balanceOf(this); + ERC20Extended(_token).transfer(auction, availableTokens); + emit AuctionCreated(address(auction), _token, availableTokens); + } +} + + +contract DutchAuction is DSMath { + address public colonyNetwork; + ERC20Extended public clnyToken; + ERC20Extended public token; + + // Total number of auctioned tokens + uint public quantity; + bool public started; + uint public startTime; + uint public endTime; + uint public minPrice; + uint public constant TOKEN_MULTIPLIER = 10 ** 18; + + // Keep track of all CLNY wei received + uint public receivedTotal; + uint public bidCount; + uint public claimCount; + + // Final price in CLNY per 10**18 Tokens (min 1, max 1e18) + uint public finalPrice; + bool public finalized; + + mapping (address => uint256) public bids; + + modifier auctionNotStarted { + require(startTime == 0); + require(!started); + _; + } + + modifier auctionStartedAndOpen { + require(started); + require(startTime > 0); + require(endTime == 0); + _; + } + + modifier auctionClosed { + require(endTime > 0); + _; + } + + modifier auctionNotFinalized() { + require(!finalized); + _; + } + + modifier auctionFinalized { + require(finalized); + _; + } + + modifier allBidsClaimed { + require(claimCount == bidCount); + _; + } + + event AuctionBid(address indexed _sender, uint _amount, uint _missingFunds); + event AuctionClaim(address indexed _recipient, uint _sentAmount); + event AuctionFinalized(uint _finalPrice); + + constructor(address _clnyToken, address _token) public { + colonyNetwork = msg.sender; + require(_clnyToken != 0x0 && _token != 0x0); + assert(_token != _clnyToken); + clnyToken = ERC20Extended(_clnyToken); + token = ERC20Extended(_token); + } + + function start() public + auctionNotStarted + { + quantity = token.balanceOf(this); + assert(quantity > 0); + + // Set the minimum price as such that it doesn't cause the finalPrice to be 0 + minPrice = (quantity >= TOKEN_MULTIPLIER) ? 1 : TOKEN_MULTIPLIER / quantity; + + startTime = now; + started = true; + } + + function totalToEndAuction() public view + auctionStartedAndOpen + returns (uint) + { + return mul(quantity, price()) / TOKEN_MULTIPLIER; + } + + // Get the price in CLNY per 10**18 Tokens (min 1 max 1e36) + // Starting price is 10**36, after 1 day price is 10**35, after 2 days price is 10**34 and so on + function price() public view + auctionStartedAndOpen + returns (uint) + { + uint duration = sub(now, startTime); + uint daysOpen = duration / 86400; + uint r = duration % 86400; + uint p = mul(10**sub(36, daysOpen), sub(864000, mul(9,r))) / 864000; + p = p < minPrice ? minPrice : p; + return p; + } + + function bid(uint256 _amount) public + auctionStartedAndOpen + { + require(_amount > 0); + uint _totalToEndAuction = totalToEndAuction(); + uint remainingToEndAuction = sub(_totalToEndAuction, receivedTotal); + + // Adjust the amount for final bid in case that takes us over the offered quantity at current price + // Also conditionally set the auction endTime + uint amount; + if (remainingToEndAuction > _amount) { + amount = _amount; + } else { + amount = remainingToEndAuction; + endTime = now; + } + + if (bids[msg.sender] == 0) { + bidCount += 1; + } + + clnyToken.transferFrom(msg.sender, this, amount); + bids[msg.sender] = add(bids[msg.sender], amount); + receivedTotal = add(receivedTotal, amount); + + emit AuctionBid(msg.sender, amount, sub(remainingToEndAuction, amount)); + } + + // Finalize the auction and set the final Token price + function finalize() public + auctionClosed + auctionNotFinalized + { + // Give the network all CLNY sent to the auction in bids + clnyToken.transfer(colonyNetwork, receivedTotal); + finalPrice = add((mul(receivedTotal, TOKEN_MULTIPLIER) / quantity), 1); + finalized = true; + emit AuctionFinalized(finalPrice); + } + + function claim() public + auctionFinalized + returns (bool) + { + uint amount = bids[msg.sender]; + require(amount > 0); + + uint tokens = mul(amount, TOKEN_MULTIPLIER) / finalPrice; + claimCount += 1; + + // Set receiver bid to 0 before transferring the tokens + bids[msg.sender] = 0; + uint beforeClaimBalance = token.balanceOf(msg.sender); + require(token.transfer(msg.sender, tokens)); + assert(token.balanceOf(msg.sender) == add(beforeClaimBalance, tokens)); + assert(bids[msg.sender] == 0); + + emit AuctionClaim(msg.sender, tokens); + return true; + } + + function close() public + auctionFinalized + allBidsClaimed + { + // Transfer token remainder to the network + uint auctionTokenBalance = token.balanceOf(this); + token.transfer(colonyNetwork, auctionTokenBalance); + // Check this contract balances in the working tokens is 0 before we kill it + assert(clnyToken.balanceOf(this) == 0); + assert(token.balanceOf(this) == 0); + selfdestruct(colonyNetwork); + } +} \ No newline at end of file diff --git a/src/lib/colonyNetwork/contracts/ColonyNetworkStaking.sol b/src/lib/colonyNetwork/contracts/ColonyNetworkStaking.sol new file mode 100644 index 0000000..6143708 --- /dev/null +++ b/src/lib/colonyNetwork/contracts/ColonyNetworkStaking.sol @@ -0,0 +1,138 @@ +/* + This file is part of The Colony Network. + + The Colony Network 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. + + The Colony Network 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 The Colony Network. If not, see . +*/ + +pragma solidity ^0.4.23; +pragma experimental "v0.5.0"; + +import "../lib/dappsys/auth.sol"; +import "./Authority.sol"; +import "./IColony.sol"; +import "./EtherRouter.sol"; +import "./ERC20Extended.sol"; +import "./ColonyNetworkStorage.sol"; +import "./IColonyNetwork.sol"; +import "./ReputationMiningCycle.sol"; + + +contract ColonyNetworkStaking is ColonyNetworkStorage, DSMath { + // TODO: Can we handle a dispute regarding the very first hash that should be set? + + modifier onlyReputationMiningCycle () { + require(msg.sender == activeReputationMiningCycle); + _; + } + + function deposit(uint256 _amount) public { + // Get CLNY address + ERC20Extended clny = ERC20Extended(IColony(metaColony).getToken()); + uint256 networkBalance = clny.balanceOf(this); + // Move some over. + clny.transferFrom(msg.sender, this, _amount); + // Check it actually transferred + assert(clny.balanceOf(this)-networkBalance==_amount); + // Note who it belongs to. + stakedBalances[msg.sender] = add(stakedBalances[msg.sender], _amount); + } + + function withdraw(uint256 _amount) public { + uint256 balance = stakedBalances[msg.sender]; + require(balance >= _amount); + bytes32 submittedHash; + (submittedHash, , , , , , , , , , ) = ReputationMiningCycle(activeReputationMiningCycle).reputationHashSubmissions(msg.sender); + bool hasRequesterSubmitted = submittedHash == 0x0 ? false : true; + require(hasRequesterSubmitted==false); + stakedBalances[msg.sender] -= _amount; + ERC20Extended clny = ERC20Extended(IColony(metaColony).getToken()); + clny.transfer(msg.sender, _amount); + } + + function getStakedBalance(address _user) public view returns (uint) { + return stakedBalances[_user]; + } + + function setReputationRootHash(bytes32 newHash, uint256 newNNodes, address[] stakers) public + onlyReputationMiningCycle + { + reputationRootHash = newHash; + reputationRootHashNNodes = newNNodes; + // Reward stakers + activeReputationMiningCycle = 0x0; + startNextCycle(); + rewardStakers(stakers); + } + + function startNextCycle() public { + require(activeReputationMiningCycle == 0x0); + activeReputationMiningCycle = inactiveReputationMiningCycle; + if (activeReputationMiningCycle == 0x0) { + // This will only be true the very first time that this is run, to kick off the whole reputation mining process + activeReputationMiningCycle = new ReputationMiningCycle(); + } + ReputationMiningCycle(activeReputationMiningCycle).resetWindow(); + inactiveReputationMiningCycle = new ReputationMiningCycle(); + } + + function getReputationMiningCycle(bool _active) public view returns(address) { + if (_active) { + return activeReputationMiningCycle; + } else { + return inactiveReputationMiningCycle; + } + } + + function punishStakers(address[] stakers) public + onlyReputationMiningCycle + { + // TODO: Actually think about this function + // Passing an array so that we don't incur the EtherRouter overhead for each staker if we looped over + // it in ReputationMiningCycle.invalidateHash; + for (uint256 i = 0; i < stakers.length; i++) { + // This is pretty harsh! Are we happy with this? + // Alternative: lose more than they would have gained for backing the right hash. + stakedBalances[stakers[i]] = 0; + } + // TODO: Where do these staked tokens go? Maybe split between the person who did the 'invalidate' transaction + // and the colony network? + // TODO: Lose rep? + } + + function rewardStakers(address[] stakers) internal { + // Internal unlike punish, because it's only ever called from setReputationRootHash + + // TODO: Actually think about this function + // Passing an array so that we don't incur the EtherRouter overhead for each staker if we looped over + // it in ReputationMiningCycle.confirmNewHash; + uint256 reward = 10**18; //TODO: Actually work out how much reputation they earn, based on activity elsewhere in the colony. + if (reward >= uint256(int256(-1))/2) { + reward = uint256(int256(-1))/2; + } + // TODO: We need to be able to prove that the assert on the next line will never happen, otherwise we're locked out of reputation mining. + // Something like the above cap is an adequate short-term solution, but at the very least need to double check the limits + // (which I've fingered-in-the-air, but could easily have an OBOE hiding inside). + assert(reward < uint256(int256(-1))); // We do a cast later, so make sure we don't overflow. + + IColony(metaColony).mintTokensForColonyNetwork(stakers.length * reward); // This should be the total amount of new tokens we're awarding. + + ReputationMiningCycle(inactiveReputationMiningCycle).rewardStakersWithReputation(stakers, metaColony, reward); // This gives them reputation in the next update cycle. + + for (uint256 i = 0; i < stakers.length; i++) { + // Also give them some newly minted tokens. + // We reinvest here as it's much easier (gas-wise). + stakedBalances[stakers[i]] += reward; + } + } +} diff --git a/src/lib/colonyNetwork/contracts/ColonyNetworkStorage.sol b/src/lib/colonyNetwork/contracts/ColonyNetworkStorage.sol new file mode 100644 index 0000000..7759f98 --- /dev/null +++ b/src/lib/colonyNetwork/contracts/ColonyNetworkStorage.sol @@ -0,0 +1,73 @@ +/* + This file is part of The Colony Network. + + The Colony Network 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. + + The Colony Network 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 The Colony Network. If not, see . +*/ + +pragma solidity ^0.4.23; +pragma experimental "v0.5.0"; + +import "../lib/dappsys/auth.sol"; +import "../lib/dappsys/roles.sol"; +import "./Authority.sol"; +import "./IColony.sol"; +import "./EtherRouter.sol"; +import "./Token.sol"; + + +contract ColonyNetworkStorage is DSAuth { + // Address of the Resolver contract used by EtherRouter for lookups and routing + address resolver; + // Number of colonies in the network + uint256 colonyCount; + // uint256 version number of the latest deployed Colony contract, used in creating new colonies + uint256 currentColonyVersion; + // Address of the Meta Colony + address metaColony; + // Maps index to colony address + mapping (uint256 => address) colonies; + mapping (address => bool) _isColony; + // Maps colony contract versions to respective resolvers + mapping (uint256 => address) colonyVersionResolver; + + struct Skill { + // total number of parent skills + uint256 nParents; + // total number of child skills + uint256 nChildren; + // array of `skill_id`s of parent skills starting from the 1st to `n`th, where `n` is an integer power of two larger than or equal to 1 + uint256[] parents; + // array of `skill_id`s of all child skills + uint256[] children; + // `true` for a global skill reused across colonies or `false` for a skill mapped to a single colony's domain + bool globalSkill; + } + // Contains all global and local skills in the network, mapping skillId to Skill. Where skillId is 1-based unique identofier + mapping (uint256 => Skill) skills; + // Number of skills in the network, including both global and local skills + uint256 skillCount; + // skillId of the root global skills tree + uint256 rootGlobalSkillId; + + // Address of the currently active reputation mining cycle contract + address activeReputationMiningCycle; + // Address of the next active reputation mining cycle contract, which is where new reputation updates are put. + address inactiveReputationMiningCycle; + // The reputation root hash of the reputation state tree accepted at the end of the last completed update cycle + bytes32 reputationRootHash; + // The number of nodes in the reputation state tree that was accepted at the end of the last mining cycle + uint256 reputationRootHashNNodes; + // Mapping containing how much has been staked by each user + mapping (address => uint) stakedBalances; +} diff --git a/src/lib/colonyNetwork/contracts/ColonyStorage.sol b/src/lib/colonyNetwork/contracts/ColonyStorage.sol new file mode 100755 index 0000000..817d401 --- /dev/null +++ b/src/lib/colonyNetwork/contracts/ColonyStorage.sol @@ -0,0 +1,190 @@ +/* + This file is part of The Colony Network. + + The Colony Network 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. + + The Colony Network 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 The Colony Network. If not, see . +*/ + +pragma solidity ^0.4.23; +pragma experimental "v0.5.0"; + +import "../lib/dappsys/auth.sol"; +import "./ERC20Extended.sol"; +import "./IColonyNetwork.sol"; + + +contract ColonyStorage is DSAuth { + // When adding variables, do not make them public, otherwise all contracts that inherit from + // this one will have the getters. Make custom getters in the contract that seems most appropriate, + // and add it to IColony.sol + + address resolver; + address colonyNetworkAddress; + ERC20Extended token; + + // Mapping function signature to 2 task roles whose approval is needed to execute + mapping (bytes4 => uint8[2]) reviewers; + uint256 taskChangeNonce; // Made obsolete in #203 + + mapping (uint256 => Task) tasks; + + // Pots can be tied to tasks or domains, so giving them their own mapping. + // Pot 1 can be thought of as the pot belonging to the colony itself that hasn't been assigned + // to anything yet, but has had some siphoned off in to the reward pot. + // Pot 0 is the 'reward' pot containing funds that can be paid to holders of colony tokens in the future. + mapping (uint256 => Pot) pots; + + struct RewardPayoutCycle { + // Reputation root hash at the time of reward payout creation + bytes32 reputationState; + // Total tokens at the time of reward payout creation + uint256 totalTokens; + // Amount alocated for reward payout + uint256 amount; + // Token in which a reward is paid out with + address tokenAddress; + // Time of creation (in seconds) + uint256 blockTimestamp; + } + + // Keeps track of all reward payout cycles + mapping (uint256 => RewardPayoutCycle) rewardPayoutCycles; + // Active payouts for particular token address. Assures that one token is used for only one active payout + mapping (address => bool) activeRewardPayouts; + // Incremented every time a reward payout is created. Used for comparing with `userRewardPayoutCount` + // to ensure that rewards are claimed in the right order. + // Can be used for iterating over all reward payouts (excluding index 0) + uint256 globalRewardPayoutCount; + // Keeps track of how many payouts are claimed by the particular user. + // Can be incremented either by waiving or claiming the reward. + mapping (address => uint256) userRewardPayoutCount; + + // This keeps track of how much of the colony's funds that it owns have been moved into pots other than pot 0, + // which (by definition) have also had the reward amount siphoned off and put in to pot 0. + // This is decremented whenever a payout occurs and the colony loses control of the funds. + mapping (address => uint256) nonRewardPotsTotal; + + mapping (uint256 => RatingSecrets) public taskWorkRatings; + + mapping (uint256 => Domain) public domains; + + uint256 taskCount; + uint256 potCount; + uint256 domainCount; + + uint8 constant MANAGER = 0; + uint8 constant EVALUATOR = 1; + uint8 constant WORKER = 2; + + // Mapping task id to current "active" nonce for executing task changes + mapping (uint256 => uint256) taskChangeNonces; + + struct Task { + bytes32 specificationHash; + bytes32 deliverableHash; + bool finalized; + bool cancelled; + uint256 dueDate; + uint256 payoutsWeCannotMake; + uint256 potId; + uint256 deliverableTimestamp; + uint256 domainId; + uint256[] skills; + + // TODO switch this mapping to a uint8 when all role instances are uint8-s specifically ColonyFunding source + mapping (uint256 => Role) roles; + // Maps task role ids (0,1,2..) to a token amount to be paid on task completion + mapping (uint256 => mapping (address => uint256)) payouts; + } + + enum TaskRatings { None, Unsatisfactory, Satisfactory, Excellent } + + struct Role { + // Address of the user for the given role + address user; + // Whether the user failed to submit their rating + bool rateFail; + // Rating the user received + TaskRatings rating; + } + + struct RatingSecrets { + uint256 count; + uint256 timestamp; + mapping (uint8 => bytes32) secret; + } + + struct Pot { + mapping (address => uint256) balance; + uint256 taskId; + } + + struct Domain { + uint256 skillId; + uint256 potId; + } + + modifier isManager(uint256 _id) { + Task storage task = tasks[_id]; + require(task.roles[0].user == msg.sender); + _; + } + + modifier taskExists(uint256 _id) { + require(_id <= taskCount); + _; + } + + modifier taskNotFinalized(uint256 _id) { + require(!tasks[_id].finalized); + _; + } + + modifier taskFinalized(uint256 _id) { + require(tasks[_id].finalized); + _; + } + + modifier globalSkill(uint256 _skillId) { + IColonyNetwork colonyNetworkContract = IColonyNetwork(colonyNetworkAddress); + require(colonyNetworkContract.isGlobalSkill(_skillId)); + _; + } + + modifier localSkill(uint256 _skillId) { + IColonyNetwork colonyNetworkContract = IColonyNetwork(colonyNetworkAddress); + require(!colonyNetworkContract.isGlobalSkill(_skillId)); + _; + } + + modifier skillExists(uint256 _skillId) { + IColonyNetwork colonyNetworkContract = IColonyNetwork(colonyNetworkAddress); + require(_skillId <= colonyNetworkContract.getSkillCount()); + _; + } + + modifier domainExists(uint256 _domainId) { + require(_domainId <= domainCount); + _; + } + + modifier isInBootstrapPhase() { + require(taskCount == 0); + _; + } + + modifier self() { + require(address(this) == msg.sender); + _; + } +} diff --git a/src/lib/colonyNetwork/contracts/ColonyTask.sol b/src/lib/colonyNetwork/contracts/ColonyTask.sol new file mode 100755 index 0000000..b94d42e --- /dev/null +++ b/src/lib/colonyNetwork/contracts/ColonyTask.sol @@ -0,0 +1,411 @@ +/* + This file is part of The Colony Network. + + The Colony Network 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. + + The Colony Network 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 The Colony Network. If not, see . +*/ + +pragma solidity ^0.4.23; +pragma experimental "v0.5.0"; + +import "../lib/dappsys/math.sol"; +import "./IColonyNetwork.sol"; +import "./ColonyStorage.sol"; +import "./IColony.sol"; +import "./SafeMath.sol"; + + +contract ColonyTask is ColonyStorage, DSMath { + uint256 constant RATING_COMMIT_TIMEOUT = 432000; + uint256 constant RATING_REVEAL_TIMEOUT = 432000; + + event TaskAdded(uint256 indexed id); + event TaskBriefChanged(uint256 indexed id, bytes32 specificationHash); + event TaskDueDateChanged(uint256 indexed id, uint256 dueDate); + event TaskDomainChanged(uint256 indexed id, uint256 domainId); + event TaskSkillChanged(uint256 indexed id, uint256 skillId); + event TaskRoleUserChanged(uint256 indexed id, uint8 role, address user); + event TaskFinalized(uint256 indexed id); + event TaskCanceled(uint256 indexed id); + + modifier confirmTaskRoleIdentity(uint256 _id, uint8 _role) { + Role storage role = tasks[_id].roles[_role]; + require(msg.sender == role.user); + _; + } + + modifier userCanRateRole(uint256 _id, uint8 _role) { + // Manager rated by worker + // Worker rated by evaluator + if (_role == MANAGER) { + require(tasks[_id].roles[WORKER].user == msg.sender); + } else if (_role == WORKER) { + require(tasks[_id].roles[EVALUATOR].user == msg.sender); + } else { + revert(); + } + _; + } + + modifier ratingSecretDoesNotExist(uint256 _id, uint8 _role) { + require(taskWorkRatings[_id].secret[_role] == ""); + _; + } + + modifier workNotSubmitted(uint256 _id) { + require(tasks[_id].deliverableTimestamp == 0); + _; + } + + modifier beforeDueDate(uint256 _id) { + require(tasks[_id].dueDate >= now); + _; + } + + modifier taskWorkRatingCommitOpen(uint256 _id) { + RatingSecrets storage ratingSecrets = taskWorkRatings[_id]; + require(ratingSecrets.count < 2); + + // Check we are either past the due date or work has already been submitted + uint taskCompletionTime = tasks[_id].deliverableTimestamp != 0 ? tasks[_id].deliverableTimestamp : tasks[_id].dueDate; + require(taskCompletionTime > 0 && taskCompletionTime <= now); + + // Check we are within 5 days of the work submission time + require(sub(now, taskCompletionTime) <= RATING_COMMIT_TIMEOUT); + _; + } + + modifier taskWorkRatingRevealOpen(uint256 _id) { + RatingSecrets storage ratingSecrets = taskWorkRatings[_id]; + require(ratingSecrets.count <= 2); + + // If both ratings have been received, start the reveal period from the time of the last rating commit + // Otherwise start the reveal period after the commit period has expired + // In both cases, keep reveal period open for 5 days + if (ratingSecrets.count == 2) { + require(sub(now, ratingSecrets.timestamp) <= RATING_REVEAL_TIMEOUT); + } else if (ratingSecrets.count < 2) { + uint taskCompletionTime = tasks[_id].deliverableTimestamp != 0 ? tasks[_id].deliverableTimestamp : tasks[_id].dueDate; + require(sub(now, taskCompletionTime) > RATING_COMMIT_TIMEOUT); + require(sub(now, taskCompletionTime) <= add(RATING_COMMIT_TIMEOUT, RATING_REVEAL_TIMEOUT)); + } + _; + } + + modifier taskWorkRatingsClosed(uint256 _id) { + uint taskCompletionTime = tasks[_id].deliverableTimestamp != 0 ? tasks[_id].deliverableTimestamp : tasks[_id].dueDate; + require(sub(now, taskCompletionTime) > add(RATING_COMMIT_TIMEOUT, RATING_REVEAL_TIMEOUT)); // More than 10 days from work submission have passed + _; + } + + modifier taskWorkRatingsAssigned(uint256 _id) { + require(tasks[_id].roles[WORKER].rating != TaskRatings.None); + require(tasks[_id].roles[MANAGER].rating != TaskRatings.None); + _; + } + + function makeTask(bytes32 _specificationHash, uint256 _domainId) public + auth + domainExists(_domainId) + { + taskCount += 1; + potCount += 1; + + Task memory task; + task.specificationHash = _specificationHash; + task.potId = potCount; + task.domainId = _domainId; + task.skills = new uint256[](1); + tasks[taskCount] = task; + tasks[taskCount].roles[MANAGER] = Role({ + user: msg.sender, + rateFail: false, + rating: TaskRatings.None + }); + + pots[potCount].taskId = taskCount; + + emit TaskAdded(taskCount); + } + + function getTaskCount() public view returns (uint256) { + return taskCount; + } + + function getTaskChangeNonce(uint256 _id) public view returns (uint256) { + return taskChangeNonces[_id]; + } + + function executeTaskChange( + uint8[] _sigV, + bytes32[] _sigR, + bytes32[] _sigS, + uint8[] _mode, + uint256 _value, + bytes _data) public + { + require(_value == 0); + require(_sigR.length == _sigS.length && _sigR.length == _sigV.length); + + bytes4 sig; + uint256 taskId; + (sig, taskId) = deconstructCall(_data); + require(!tasks[taskId].finalized); + + uint8 nSignaturesRequired; + if (tasks[taskId].roles[reviewers[sig][0]].user == address(0) || tasks[taskId].roles[reviewers[sig][1]].user == address(0)) { + // When one of the roles is not set, allow the other one to execute a change with just their signature + nSignaturesRequired = 1; + } else if (tasks[taskId].roles[reviewers[sig][0]].user == tasks[taskId].roles[reviewers[sig][1]].user) { + // We support roles being assumed by the same user, in this case, allow them to execute a change with just their signature + nSignaturesRequired = 1; + } else { + nSignaturesRequired = 2; + } + + require(_sigR.length == nSignaturesRequired); + + bytes32 msgHash = keccak256(abi.encodePacked(address(this), address(this), _value, _data, taskChangeNonces[taskId])); + address[] memory reviewerAddresses = new address[](nSignaturesRequired); + for (uint i = 0; i < nSignaturesRequired; i++) { + // 0 'Normal' mode - geth, etc. + // >0 'Trezor' mode + // Correct incantation helpfully cribbed from https://github.com/trezor/trezor-mcu/issues/163#issuecomment-368435292 + bytes32 txHash; + if (_mode[i] == 0) { + txHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", msgHash)); + } else { + txHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n\x20", msgHash)); + } + + reviewerAddresses[i] = ecrecover(txHash, _sigV[i], _sigR[i], _sigS[i]); + } + + require(reviewerAddresses[0] == tasks[taskId].roles[reviewers[sig][0]].user || reviewerAddresses[0] == tasks[taskId].roles[reviewers[sig][1]].user); + + if (nSignaturesRequired == 2) { + require(reviewerAddresses[0] != reviewerAddresses[1]); + require(reviewerAddresses[1] == tasks[taskId].roles[reviewers[sig][0]].user || reviewerAddresses[1] == tasks[taskId].roles[reviewers[sig][1]].user); + } + + taskChangeNonces[taskId]++; + require(executeCall(address(this), _value, _data)); + } + + // The address.call() syntax is no longer recommended, see: + // https://github.com/ethereum/solidity/issues/2884 + function executeCall(address to, uint256 value, bytes data) internal returns (bool success) { + assembly { + success := call(gas, to, value, add(data, 0x20), mload(data), 0, 0) + } + } + + function submitTaskWorkRating(uint256 _id, uint8 _role, bytes32 _ratingSecret) public + userCanRateRole(_id, _role) + ratingSecretDoesNotExist(_id, _role) + taskWorkRatingCommitOpen(_id) + { + RatingSecrets storage ratingSecrets = taskWorkRatings[_id]; + ratingSecrets.count += 1; + ratingSecrets.timestamp = now; + ratingSecrets.secret[_role] = _ratingSecret; + } + + function revealTaskWorkRating(uint256 _id, uint8 _role, uint8 _rating, bytes32 _salt) public + taskWorkRatingRevealOpen(_id) + { + // MAYBE: we should hash these the other way around, i.e. generateSecret(_rating, _salt) + bytes32 ratingSecret = generateSecret(_salt, _rating); + require(ratingSecret == taskWorkRatings[_id].secret[_role]); + + TaskRatings rating = TaskRatings(_rating); + require(rating != TaskRatings.None, "Cannot rate None!"); + tasks[_id].roles[_role].rating = rating; + } + + // In the event of a user not committing or revealing within the 10 day rating window, + // their rating of their counterpart is assumed to be the highest possible + // and they will receive a reputation penalty + function assignWorkRating(uint256 _id) public + taskWorkRatingsClosed(_id) + { + Role storage managerRole = tasks[_id].roles[MANAGER]; + Role storage workerRole = tasks[_id].roles[WORKER]; + Role storage evaluatorRole = tasks[_id].roles[EVALUATOR]; + + if (workerRole.rating == TaskRatings.None) { + evaluatorRole.rateFail = true; + workerRole.rating = TaskRatings.Excellent; + } + + if (managerRole.rating == TaskRatings.None) { + workerRole.rateFail = true; + managerRole.rating = TaskRatings.Excellent; + } + } + + function generateSecret(bytes32 _salt, uint256 _value) public pure returns (bytes32) { + return keccak256(abi.encodePacked(_salt, _value)); + } + + function getTaskWorkRatings(uint256 _id) public view returns (uint256, uint256) { + return (taskWorkRatings[_id].count, taskWorkRatings[_id].timestamp); + } + + function getTaskWorkRatingSecret(uint256 _id, uint8 _role) public view returns (bytes32) { + return taskWorkRatings[_id].secret[_role]; + } + + // TODO: Restrict function visibility to whoever submits the approved Transaction from Client + // Note task assignment is agreed off-chain + function setTaskRoleUser(uint256 _id, uint8 _role, address _user) public + taskExists(_id) + taskNotFinalized(_id) + { + require(tasks[_id].roles[MANAGER].user == msg.sender); + tasks[_id].roles[_role] = Role({ + user: _user, + rateFail: false, + rating: TaskRatings.None + }); + + emit TaskRoleUserChanged(_id, _role, _user); + } + + function setTaskDomain(uint256 _id, uint256 _domainId) public + taskExists(_id) + taskNotFinalized(_id) + domainExists(_domainId) + { + require(tasks[_id].roles[MANAGER].user == msg.sender); + tasks[_id].domainId = _domainId; + + emit TaskDomainChanged(_id, _domainId); + } + + // TODO: Restrict function visibility to whoever submits the approved Transaction from Client + // Maybe just the administrator is adequate for the skill? + function setTaskSkill(uint256 _id, uint256 _skillId) public + taskExists(_id) + taskNotFinalized(_id) + skillExists(_skillId) + globalSkill(_skillId) + { + require(tasks[_id].roles[MANAGER].user == msg.sender); + + tasks[_id].skills[0] = _skillId; + + emit TaskSkillChanged(_id, _skillId); + } + + function setTaskBrief(uint256 _id, bytes32 _specificationHash) public + self() + taskExists(_id) + taskNotFinalized(_id) + { + tasks[_id].specificationHash = _specificationHash; + + emit TaskBriefChanged(_id, _specificationHash); + } + + function setTaskDueDate(uint256 _id, uint256 _dueDate) public + self() + taskExists(_id) + taskNotFinalized(_id) + { + tasks[_id].dueDate = _dueDate; + + emit TaskDueDateChanged(_id, _dueDate); + } + + function submitTaskDeliverable(uint256 _id, bytes32 _deliverableHash) public + taskExists(_id) + taskNotFinalized(_id) + beforeDueDate(_id) + workNotSubmitted(_id) + confirmTaskRoleIdentity(_id, WORKER) + { + tasks[_id].deliverableHash = _deliverableHash; + tasks[_id].deliverableTimestamp = now; + } + + function finalizeTask(uint256 _id) public + auth + taskWorkRatingsAssigned(_id) + taskNotFinalized(_id) + { + Task storage task = tasks[_id]; + IColonyNetwork colonyNetworkContract = IColonyNetwork(colonyNetworkAddress); + + task.finalized = true; + + for (uint8 roleId = 0; roleId <= 2; roleId++) { + Role storage role = task.roles[roleId]; + + if (roleId == EVALUATOR) { // They had one job! + role.rating = role.rateFail ? TaskRatings.Unsatisfactory : TaskRatings.Satisfactory; + } + + uint payout = task.payouts[roleId][token]; + int reputation = getReputation(int(payout), uint8(role.rating), role.rateFail); + + colonyNetworkContract.appendReputationUpdateLog(role.user, reputation, domains[task.domainId].skillId); + if (roleId == WORKER) { + colonyNetworkContract.appendReputationUpdateLog(role.user, reputation, task.skills[0]); + } + } + + emit TaskFinalized(_id); + } + + function cancelTask(uint256 _id) public + auth + taskExists(_id) + taskNotFinalized(_id) + { + tasks[_id].cancelled = true; + + emit TaskCanceled(_id); + } + + function getTask(uint256 _id) public view returns (bytes32, bytes32, bool, bool, uint256, uint256, uint256, uint256, uint256, uint256[]) { + Task storage t = tasks[_id]; + return (t.specificationHash, t.deliverableHash, t.finalized, t.cancelled, t.dueDate, t.payoutsWeCannotMake, t.potId, t.deliverableTimestamp, t.domainId, t.skills); + } + + function getTaskRole(uint256 _id, uint8 _role) public view returns (address, bool, uint8) { + Role storage role = tasks[_id].roles[_role]; + return (role.user, role.rateFail, uint8(role.rating)); + } + + function getReputation(int payout, uint8 rating, bool rateFail) internal pure returns(int reputation) { + require(rating > 0 && rating <= 3, "Invalid rating"); + + // -1, 1, 1.5 multipliers, -0.5 penalty + int8[3] memory ratingMultipliers = [-2, 2, 3]; + int8 ratingDivisor = 2; + + reputation = SafeMath.mulInt(payout, ratingMultipliers[rating - 1]); + reputation = SafeMath.subInt(reputation, rateFail ? payout : 0); // Deduct penalty for not rating + reputation /= ratingDivisor; // We may lose one atom of reputation here :sad: + } + + // Get the function signature and task id from the transaction bytes data + // Note: Relies on the encoded function's first parameter to be the uint256 taskId + function deconstructCall(bytes _data) internal pure returns (bytes4 sig, uint256 taskId) { + assembly { + sig := mload(add(_data, 0x20)) + taskId := mload(add(_data, add(0x20, 4))) // same as calldataload(72) + } + } +} diff --git a/src/lib/colonyNetwork/contracts/ERC20Extended.sol b/src/lib/colonyNetwork/contracts/ERC20Extended.sol new file mode 100644 index 0000000..6b7339e --- /dev/null +++ b/src/lib/colonyNetwork/contracts/ERC20Extended.sol @@ -0,0 +1,31 @@ +/* + This file is part of The Colony Network. + + The Colony Network 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. + + The Colony Network 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 The Colony Network. If not, see . +*/ + +pragma solidity ^0.4.23; +pragma experimental "v0.5.0"; + +import "../lib/dappsys/erc20.sol"; + + +contract ERC20Extended is ERC20 { + event Mint(address indexed guy, uint wad); + event Burn(address indexed guy, uint wad); + + function mint(uint wad) public; + + function burn(uint wad) public; +} diff --git a/src/lib/colonyNetwork/contracts/EtherRouter.sol b/src/lib/colonyNetwork/contracts/EtherRouter.sol new file mode 100644 index 0000000..f555b8c --- /dev/null +++ b/src/lib/colonyNetwork/contracts/EtherRouter.sol @@ -0,0 +1,66 @@ +/* + This file is part of The Colony Network. + + The Colony Network 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. + + The Colony Network 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 The Colony Network. If not, see . +*/ + +pragma solidity ^0.4.23; +pragma experimental "v0.5.0"; + +import "./Resolver.sol"; +import "../lib/dappsys/auth.sol"; + + +contract EtherRouter is DSAuth { + Resolver public resolver; + + function() payable external { + if (msg.sig == 0x0) { + return; + } + // Contracts that want to receive Ether with a plain "send" have to implement + // a fallback function with the payable modifier. Contracts now throw if no payable + // fallback function is defined and no function matches the signature. + // However, 'send' only provides 2300 gas, which is not enough for EtherRouter + // so we shortcut it here. + // + // Note that this means we can never have a fallback function that 'does' stuff. + // but those only really seem to be ICOs, to date. To be explicit, there is a hard + // decision to be made here. Either: + // 1. Contracts that use 'send' or 'transfer' cannot send money to Colonies/ColonyNetwork + // 2. We commit to never using a fallback function that does anything. + // + // If we wish to have such a fallback function for a Colony, it could be in a separate + // contract. + + // Get routing information for the called function + address destination = resolver.lookup(msg.sig); + + // Make the call + assembly { + calldatacopy(mload(0x40), 0, calldatasize) + let result := delegatecall(gas, destination, mload(0x40), calldatasize, mload(0x40), 0) + returndatacopy(mload(0x40), 0, returndatasize) + switch result + case 1 { return(mload(0x40), returndatasize) } + default { revert(mload(0x40), returndatasize) } + } + } + + function setResolver(address _resolver) public + auth + { + resolver = Resolver(_resolver); + } +} diff --git a/src/lib/colonyNetwork/contracts/IColony.sol b/src/lib/colonyNetwork/contracts/IColony.sol new file mode 100644 index 0000000..7157071 --- /dev/null +++ b/src/lib/colonyNetwork/contracts/IColony.sol @@ -0,0 +1,416 @@ +/* + This file is part of The Colony Network. + + The Colony Network 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. + + The Colony Network 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 The Colony Network. If not, see . +*/ + +pragma solidity ^0.4.23; +pragma experimental "v0.5.0"; + + +/// @title Colony interface +/// @notice All publicly available functions are available here and registered to work with EtherRouter Network contract +contract IColony { + // Events + /// @notice Event logged when a new task is added + /// @param id The newly added task id + event TaskAdded(uint256 indexed id); + + /// @notice Event logged when a task's specification hash changes + /// @param id Id of the task + /// @param specificationHash New specification hash of the task + event TaskBriefChanged(uint256 indexed id, bytes32 specificationHash); + + /// @notice Event logged when a task's due date changes + /// @param id Id of the task + /// @param dueDate New due date of the task + event TaskDueDateChanged(uint256 indexed id, uint256 dueDate); + + /// @notice Event logged when a task's domain changes + /// @param id Id of the task + /// @param domainId New domain id of the task + event TaskDomainChanged(uint256 indexed id, uint256 domainId); + + /// @notice Event logged when a task's skill changes + /// @param id Id of the task + /// @param skillId New skill id of the task + event TaskSkillChanged(uint256 indexed id, uint256 skillId); + + /// @notice Event logged when a task's role user changes + /// @param id Id of the task + /// @param role Role of the user + /// @param user User that fulfills the designated role + event TaskRoleUserChanged(uint256 indexed id, uint8 role, address user); + + /// @notice Event logged when a task's worker funding changes + /// @param id Id of the task + /// @param token Token of the payout funding + /// @param amount Amount of the payout funding + event TaskWorkerPayoutChanged(uint256 indexed id, address token, uint256 amount); + + /// @notice Event logged when a task has been finalized + /// @param id Id of the finalized task + event TaskFinalized(uint256 indexed id); + + /// @notice Event logged when a task has been canceled + /// @param id Id of the canceled task + event TaskCanceled(uint256 indexed id); + + /// @notice Event logged when a new reward payout cycle has started + /// @param id Payout id + event RewardPayoutCycleStarted(uint256 indexed id); + + // Implemented in DSAuth.sol + /// @notice Get the `Authority` for the colony + /// @return The `Authority` contract address + function authority() public view returns (address); + + /// @notice Get the colony `owner` address. Inherited from the DSAuth contract + /// @return Address of the colony owner + function owner() public view returns (address); + + // Implemented in Colony.sol + /// @notice Get the Colony contract version + /// Starts from 1 and is incremented with every deployed contract change + /// @return Version number + function version() public pure returns (uint256); + + /// @notice Set the colony token. Secured function to authorised members + /// @param _token Address of the token contract to use. + /// Note that if the `mint` functionality is to be controlled through the colony, + /// that control has to be transferred to the colony after this call + function setToken(address _token) public; + + /// @notice Get the colony token + /// @return Address of the token contract + function getToken() public view returns (address); + + /// @notice Called once when the colony is created to initialise certain storage slot values + /// @param _network Address of the colony network + function initialiseColony(address _network) public; + + /// @notice Allows the colony to bootstrap itself by having initial reputation and token `_amount` assigned to users `_users` + /// This reputation is assigned in the colony-wide domain. Secured function to authorised members + /// @dev Only allowed to be called when `taskCount` is 0 by authorized addresses + /// @param _users Array of address to bootstrap with reputation + /// @param _amount Amount of reputation/tokens for every address + function bootstrapColony(address[] _users, int[] _amount) public; + + /// @notice Mint `_wad` amount of colony tokens. Secured function to authorised members + /// @param _wad Amount to mint + function mintTokens(uint256 _wad) public; + + /// @notice Mints CLNY in the Meta Colony and transfers them to the colony network + /// Only allowed to be called on the Meta Colony by the colony network + /// @param _wad Amount to mint and transfer to the colony network + function mintTokensForColonyNetwork(uint256 _wad) public; + + /// @notice Add a new global skill, under skill `_parentSkillId` + /// Can only be called from the Meta Colony + /// @dev Calls `IColonyNetwork.addSkill` + /// @param _parentSkillId Id of the skill under which the new skill will be added + /// @return Id of the added skill + function addGlobalSkill(uint256 _parentSkillId) public returns (uint256); + + /// @notice Add a colony domain, and its respective local skill under skill with id `_parentSkillId` + /// New funding pot is created and associated with the domain here + /// @param _parentSkillId Id of the local skill under which the new skill will be added + function addDomain(uint256 _parentSkillId) public; + + /// @notice Get the domain's local skill and funding pot id + /// @param _id Id of the domain which details to get + /// @return The domain "local" skill id + /// @return The domain's funding pot id + function getDomain(uint256 _id) public view returns (uint256, uint256); + + /// @notice Get the number of domains in the colony + /// @return The domain count. Min 1 as the root domain is created at the same time as the colony + function getDomainCount() public view returns (uint256); + + /// @notice Helper function that can be used by a client to verify the correctness of a patricia proof they have been supplied with. + /// @param key The key of the element the proof is for. + /// @param value The value of the element that the proof is for. + /// @param branchMask The branchmask of the proof + /// @param siblings The siblings of the proof + /// @return True if the proof is valid, false otherwise. + /// @dev For more detail about branchMask and siblings, examine the PatriciaTree implementation + /// While public, likely only to be used by the Colony contracts, as it checks that the user is proving their own + /// reputation in the current colony. The `verifyProof` function can be used to verify any proof, though this function + /// is not currently exposed on the Colony's EtherRouter. + function verifyReputationProof(bytes key, bytes value, uint256 branchMask, bytes32[] siblings) public view returns (bool); + + // Implemented in ColonyTask.sol + /// @notice Make a new task in the colony. Secured function to authorised members + /// @param _specificationHash Database identifier where the task specification is stored + /// @param _domainId The domain where the task belongs + function makeTask(bytes32 _specificationHash, uint256 _domainId) public; + + /// @notice Get the number of tasks in the colony + /// @return The task count + function getTaskCount() public view returns (uint256); + + /// @notice Starts from 0 and is incremented on every co-reviewed task change via `executeTaskChange` call + /// @param _id Id of the task + /// @return The current task change nonce value + function getTaskChangeNonce(uint256 _id) public view returns (uint256); + + /// @notice Executes a task update transaction `_data` which is approved and signed by two of its roles (e.g. manager and worker) + /// using the detached signatures for these users. + /// @dev The Colony functions which require approval and the task roles to review these are set in `IColony.initialiseColony` at colony creation + /// Upon successful execution the `taskChangeNonces` entry for the task is incremented + /// @param _sigV recovery id + /// @param _sigR r output of the ECDSA signature of the transaction + /// @param _sigS s output of the ECDSA signature of the transaction + /// @param _mode How the signature was generated - 0 for Geth-style (usual), 1 for Trezor-style (only Trezor does this) + /// @param _value The transaction value, i.e. number of wei to be sent when the transaction is executed + /// Currently we only accept 0 value transactions but this is kept as a future option + /// @param _data The transaction data + function executeTaskChange(uint8[] _sigV, bytes32[] _sigR, bytes32[] _sigS, uint8[] _mode, uint256 _value, bytes _data) public; + + /// @notice Submit a hashed secret of the rating for work in task `_id` which was performed by user with task role id `_role` + /// Allowed within 5 days period starting which whichever is first from either the deliverable being submitted or the dueDate been reached + /// Allowed only for evaluator to rate worker and for worker to rate manager performance + /// Once submitted ratings can not be changed or overwritten + /// @param _id Id of the task + /// @param _role Id of the role, as defined in `ColonyStorage` `MANAGER`, `EVALUATOR` and `WORKER` constants + /// @param _ratingSecret `keccak256` hash of a salt and 0-50 rating score (in increments of 10, .e.g 0, 10, 20, 30, 40 or 50) + /// Can be generated via `IColony.generateSecret` helper function + function submitTaskWorkRating(uint256 _id, uint8 _role, bytes32 _ratingSecret) public; + + /// @notice Reveal the secret rating submitted in `IColony.submitTaskWorkRating` for task `_id` and task role with id `_role` + /// Allowed within 5 days period starting which whichever is first from either both rating secrets being submitted + /// (via `IColony.submitTaskWorkRating`) or the 5 day rating period expiring + /// @dev Compares the `keccak256(_salt, _rating)` output with the previously submitted rating secret and if they match, + /// sets the task role properties `rated` to `true` and `rating` to `_rating` + /// @param _id Id of the task + /// @param _role Id of the role, as defined in `ColonyStorage` `MANAGER`, `EVALUATOR` and `WORKER` constants + /// @param _rating 0-50 rating score (in increments of 10, .e.g 0, 10, 20, 30, 40 or 50) + /// @param _salt Salt value used to generate the rating secret + function revealTaskWorkRating(uint256 _id, uint8 _role, uint8 _rating, bytes32 _salt) public; + + /// @notice Assign missing ratings penalising users where needed for missing the rating window + /// @param _id Id of the task + function assignWorkRating(uint256 _id) public; + + /// @notice Helper function used to generage consistently the rating secret using salt value `_salt` and value to hide `_value` + /// @param _salt Salt value + /// @param _value Value to hide + /// @return `keccak256` hash of joint _salt and _value + function generateSecret(bytes32 _salt, uint256 _value) public pure returns (bytes32); + + /// @notice Get the `ColonyStorage.RatingSecrets` for task `_id` + /// @param _id Id of the task + /// @return Number of secrets + /// @return Timestamp of the last submitted rating secret + function getTaskWorkRatings(uint256 _id) public view returns (uint256, uint256); + + /// @notice Get the rating secret submitted for role `_role` in task `_id` + /// @param _id Id of the task + /// @param _role Id of the role, as defined in `ColonyStorage` `MANAGER`, `EVALUATOR` and `WORKER` constants + /// @return Rating secret `bytes32` value + function getTaskWorkRatingSecret(uint256 _id, uint8 _role) public view returns (bytes32); + + /// @notice Set the user for role `_role` in task `_id`. Only allowed before the task is `finalized`, as in + // you cannot change the task contributors after the work is complete. Allowed before a task is finalized. + /// @param _id Id of the task + /// @param _role Id of the role, as defined in `ColonyStorage` `MANAGER`, `EVALUATOR` and `WORKER` constants + /// @param _user Address of the user to assume role `_role` + function setTaskRoleUser(uint256 _id, uint8 _role, address _user) public; + + /// @notice Set the skill for task `_id` + /// @dev Currently we only allow one skill per task although we have provisioned for an array of skills in `Task` struct + /// Allowed before a task is finalized + /// @param _id Id of the task + /// @param _skillId Id of the skill which has to be a global skill + function setTaskSkill(uint256 _id, uint256 _skillId) public; + + /// @notice Set the domain for task `_id` + /// @param _id Id of the task + /// @param _domainId Id of the domain + function setTaskDomain(uint256 _id, uint256 _domainId) public; + + /// @notice Set the hash for the task brief, aka task work specification, which identifies the task brief content in ddb + /// Allowed before a task is finalized + /// @param _id Id of the task + /// @param _specificationHash Unique hash of the task brief in ddb + function setTaskBrief(uint256 _id, bytes32 _specificationHash) public; + + /// @notice Set the due date on task `_id`. Allowed before a task is finalized + /// @param _id Id of the task + /// @param _dueDate Due date as seconds since unix epoch + function setTaskDueDate(uint256 _id, uint256 _dueDate) public; + + /// @notice Submit the task deliverable, i.e. the output of the work performed for task `_id` + /// Submission is allowed only to the assigned worker before the task due date. Submissions cannot be overwritten + /// @dev Set the `task.deliverableHash` and `task.deliverableTimestamp` properties + /// @param _id Id of the task + /// @param _deliverableHash Unique hash of the task deliverable content in ddb + function submitTaskDeliverable(uint256 _id, bytes32 _deliverableHash) public; + + /// @notice Called after task work rating is complete which closes the task and logs the respective reputation log updates + /// Allowed to be called once per task. Secured function to authorised members + /// @dev Set the `task.finalized` property to true + /// @param _id Id of the task + function finalizeTask(uint256 _id) public; + + /// @notice Cancel a task at any point before it is finalized. Secured function to authorised members + /// Any funds assigned to its funding pot can be moved back to the domain via `IColony.moveFundsBetweenPots` + /// @dev Set the `task.cancelled` property to true + /// @param _id Id of the task + function cancelTask(uint256 _id) public; + + /// @notice Get a task with id `_id` + /// @param _id Id of the task + /// @return Task brief hash + /// @return Task deliverable hash + /// @return Finalised property + /// @return Cancelled property + /// @return Due date + /// @return Number of payouts that cannot be completed with the current task funding + /// @return Id of funding pot for task + /// @return Deliverable submission timestamp + /// @return Task domain id, default is root colony domain with id 1 + /// @return Array of global skill ids assigned to task + function getTask(uint256 _id) public view returns (bytes32, bytes32, bool, bool, uint256, uint256, uint256, uint256, uint256, uint256[]); + + /// @notice Get the `Role` properties back for role `_role` in task `_id` + /// @param _id Id of the task + /// @param _role Id of the role, as defined in `ColonyStorage` `MANAGER`, `EVALUATOR` and `WORKER` constants + /// @return Address of the user for the given role + /// @return Whether the user failed to rate their counterpart + /// @return Rating the user received + function getTaskRole(uint256 _id, uint8 _role) public view returns (address, bool, uint8); + + // Implemented in ColonyFunding.sol + /// @notice Return 1 / the fee to pay to the network. e.g. if the fee is 1% (or 0.01), return 100 + /// @return The inverse of the network fee + function getFeeInverse() public pure returns (uint256); + + /// @notice Return 1 / the reward to pay out from revenue. e.g. if the fee is 1% (or 0.01), return 100 + /// @return The inverse of the reward + function getRewardInverse() public pure returns (uint256); + + /// @notice Get payout amount in `_token` denomination for role `_role` in task `_id` + /// @param _id Id of the task + /// @param _role Id of the role, as defined in `ColonyStorage` `MANAGER`, `EVALUATOR` and `WORKER` constants + /// @param _token Address of the token, `0x0` value indicates Ether + /// @return Payout amount + function getTaskPayout(uint256 _id, uint256 _role, address _token) public view returns (uint256); + + /// @notice Get total payout amount in `_token` denomination for task `_id` + /// @param _id Id of the task + /// @param _token Address of the token, `0x0` value indicates Ether + /// @return Payout amount + function getTotalTaskPayout(uint256 _id, address _token) public view returns (uint256); + + /// @notice Set `_token` payout for manager in task `_id` to `_amount` + /// @param _id Id of the task + /// @param _token Address of the token, `0x0` value indicates Ether + /// @param _amount Payout amount + function setTaskManagerPayout(uint256 _id, address _token, uint256 _amount) public; + + /// @notice Set `_token` payout for evaluator in task `_id` to `_amount` + /// @param _id Id of the task + /// @param _token Address of the token, `0x0` value indicates Ether + /// @param _amount Payout amount + function setTaskEvaluatorPayout(uint256 _id, address _token, uint256 _amount) public; + + /// @notice Set `_token` payout for worker in task `_id` to `_amount` + /// @param _id Id of the task + /// @param _token Address of the token, `0x0` value indicates Ether + /// @param _amount Payout amount + function setTaskWorkerPayout(uint256 _id, address _token, uint256 _amount) public; + + /// @notice Claim the payout in `_token` denomination for work completed in task `_id` by contributor with role `_role` + /// Allowed only by the contributors themselves after task is finalized. Here the network receives its fee from each payout. + /// Ether fees go straight to the Meta Colony whereas Token fees go to the Network to be auctioned off. + /// @param _id Id of the task + /// @param _role Id of the role, as defined in `ColonyStorage` `MANAGER`, `EVALUATOR` and `WORKER` constants + /// @param _token Address of the token, `0x0` value indicates Ether + function claimPayout(uint256 _id, uint256 _role, address _token) public; + + /// @notice Start next reward payout for `_token`. All funds in the reward pot for `_token` will become unavailable. + /// All tokens will be locked, and can be unlocked by calling `waiveRewardPayout` or `claimRewardPayout`. + /// @param _token Addess of the token used for reward payout + function startNextRewardPayout(address _token) public returns (uint256); + + /// @notice Claim the reward payout at `_payoutId`. User needs to provide their reputation and colony-wide reputation + /// which will be proven via Merkle proof inside this function. + /// Can only be called if payout is active, i.e if 60 days have not passed from its creation. + /// Can only be called if next in queue + /// @param _payoutId Id of the reward payout + /// @param _squareRoots Square roots of values used in equation + /// _squareRoots[0] - square root of user reputation + /// _squareRoots[1] - square root of user tokens + /// _squareRoots[2] - square root of total reputation + /// _squareRoots[3] - square root of total tokens + /// _squareRoots[4] - square root of numerator (user reputation * user tokens) + /// _squareRoots[5] - square root of denominator (total reputation * total tokens) + /// _squareRoots[6] - square root of payout amount + /// @param _userReputation User reputation at the point of creation of reward payout cycle + /// @param _totalReputation Total reputation at the point of creation of reward payout cycle + function claimRewardPayout(uint256 _payoutId, uint256[7] _squareRoots, uint256 _userReputation, uint256 _totalReputation) public; + + /// @notice Waive reward payouts. This will unlock the sender's tokens and increment users reward payout counter, + /// allowing them to claim next reward payout + /// @param _numPayouts Number of payouts you want to waive + function waiveRewardPayouts(uint256 _numPayouts) public; + + /// @notice Get useful information about specific reward payout + /// @param _payoutId Id of the reward payout + /// @return Reputation root hash at the time of creation + /// @return Total colony tokens at the time of creation + /// @return Total amount of tokens taken aside for reward payout + /// @return Remaining (unclaimed) amount of tokens + /// @return Token address + /// @return Block number at the time of creation + function getRewardPayoutInfo(uint256 _payoutId) public view returns (bytes32, uint256, uint256, uint256, address, uint256); + + /// @notice Finalises the reward payout. Allows creation of next reward payouts for token that has been used in `_payoutId` + /// Can only be called when reward payout cycle is finished i.e when 60 days have passed from its creation + /// @param _payoutId Id of the reward payout + function finalizeRewardPayout(uint256 _payoutId) public; + + /// @notice Get number of reward payout cycles + /// @return Number of reward payout cycles + function getGlobalRewardPayoutCount() public returns (uint256); + + /// @notice Get number of claimed and waived reward payouts for `_user` + /// @return Number of claimed and waived reward payouts + function getUserRewardPayoutCount(address _user) public returns (uint256); + + /// @notice Get the `_token` balance of pot with id `_potId` + /// @param _potId Id of the funding pot + /// @param _token Address of the token, `0x0` value indicates Ether + /// @return Funding pot balance + function getPotBalance(uint256 _potId, address _token) public view returns (uint256); + + /// @notice Move a given amount: `_amount` of `_token` funds from funding pot with id `_fromPot` to one with id `_toPot`. + /// Secured function to authorised members + /// @param _fromPot Funding pot id providing the funds + /// @param _toPot Funding pot id receiving the funds + /// @param _amount Amount of funds + /// @param _token Address of the token, `0x0` value indicates Ether + function moveFundsBetweenPots(uint256 _fromPot, uint256 _toPot, uint256 _amount, address _token) public; + + /// @notice Move any funds received by the colony in `_token` denomination to the top-level domain pot, + /// siphoning off a small amount to the reward pot. If called against a colony's own token, no fee is taken + /// @param _token Address of the token, `0x0` value indicates Ether + function claimColonyFunds(address _token) public; + + /// @notice Get the total amount of tokens `_token` minus amount reserved to be paid to the reputation and token holders as rewards + /// @param _token Address of the token, `0x0` value indicates Ether + /// @return Total amount of tokens in pots other than the rewards pot (id 0) + function getNonRewardPotsTotal(address _token) public view returns (uint256); +} diff --git a/src/lib/colonyNetwork/contracts/IColonyNetwork.sol b/src/lib/colonyNetwork/contracts/IColonyNetwork.sol new file mode 100644 index 0000000..0772f24 --- /dev/null +++ b/src/lib/colonyNetwork/contracts/IColonyNetwork.sol @@ -0,0 +1,188 @@ +/* + This file is part of The Colony Network. + + The Colony Network 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. + + The Colony Network 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 The Colony Network. If not, see . +*/ + +pragma solidity ^0.4.23; +pragma experimental "v0.5.0"; + + +/// @title Colony Network interface +/// @notice All publicly available functions are available here and registered to work with EtherRouter Network contract +contract IColonyNetwork { + + /// @notice Event logged when a new colony is added + /// @dev Emitted from `IColonyNetwork.createColony` function + /// @param colonyId The colony id in the network + /// @param colonyAddress The colony address in the network + event ColonyAdded(uint256 indexed colonyId, address indexed colonyAddress); + + /// @notice Event logged when a new skill is added + /// @dev Emitted from `IColonyNetwork.addSkill` function + /// @param skillId The skill id + /// @param parentSkillId The id of the parent skill under which this new skill is added + event SkillAdded(uint256 skillId, uint256 parentSkillId); + + /// @notice Event logged when a new auction is created and started + /// @dev Emitted from `IColonyNetwork.startTokenAuction` function + /// @param auction Address of the created auction contract + /// @param token Address of the token for auction + /// @param quantity Quantity of `token` to auction + event AuctionCreated(address auction, address token, uint256 quantity); + + /// @notice Get the Meta Colony address + /// @return The Meta colony address, if no colony was found, returns 0x0 + function getMetaColony() public view returns (address); + + /// @notice Get the number of colonies in the network + /// @return The colony count + function getColonyCount() public view returns (uint256); + + /// @notice Adds a new skill to the global or local skills tree, under skill `_parentSkillId` + /// Only the Meta Colony is allowed to add a global skill, called via `IColony.addGlobalSkill` + /// Any colony is allowed to add a local skill and which is associated with a new domain via `IColony.addDomain` + /// @dev Errors if the parent skill does not exist or if this is called by an unauthorised sender + /// @param _parentSkillId Id of the skill under which the new skill will be added + /// @param _globalSkill true if the new skill is global, false if it is local + /// @return Id of the added skill + function addSkill(uint256 _parentSkillId, bool _globalSkill) public returns (uint256); + + /// @notice Get the `nParents` and `nChildren` of skill with id `_skillId` + /// @param _skillId Id of the skill + /// @return uint256 `skill.nParents` i.e. the number of parent skills of skill with id `_skillId` + /// @return uint256 `skill.nChildren` i.e. the number of child skills of skill with id `_skillId` + function getSkill(uint256 _skillId) public view returns (uint256, uint256); + + /// @notice Checks if skill with id `_skillId` is a global skill + /// @param _skillId Id of the skill + /// @return true if skill with id `_skillId` is a global skill, false otherwise + function isGlobalSkill(uint256 _skillId) public view returns (bool); + + /// @notice Adds a reputation update entry to log + /// @dev Errors if it is called by anyone but a colony or if skill with id `_skillId` does not exist or + /// @param _user The address of the user for the reputation update + /// @param _amount The amount of reputation change for the update, this can be a negative as well as a positive value + /// @param _skillId The skill for the reputation update + function appendReputationUpdateLog(address _user, int256 _amount, uint256 _skillId) public; + + /// @notice Get the number of skills in the network including both global and local skills + /// @return The skill count + function getSkillCount() public view returns (uint256); + + /// @notice Get the id of the root global skill + /// @dev This is set once when the Meta Colony is created + /// @return The root global skill id + function getRootGlobalSkillId() public view returns (uint256); + + /// @notice Create the Meta Colony, same as a normal colony plus the root skill + /// @param _tokenAddress Address of the CLNY token + function createMetaColony(address _tokenAddress) public; + + /// @notice Creates a new colony in the network + /// Note that the token ownership (if there is one) has to be transferred to the newly created colony + /// @param _tokenAddress Address of an ERC20 token to serve as the colony token + /// Additionally token can optionally support `mint` as defined in `ERC20Extended` + /// Support for `mint` in mandatory only for the Meta Colony Token + /// @return Address of the newly created colony + function createColony(address _tokenAddress) public returns (address); + + /// @notice Adds a new Colony contract version and the address of associated `_resolver` contract. Secured function to authorised members + /// @param _version The new Colony contract version + /// @param _resolver Address of the `Resolver` contract which will be used with the underlying `EtherRouter` contract + function addColonyVersion(uint256 _version, address _resolver) public; + + /// @notice Get a colony address by its Id in the network + /// @param _id Id of the colony to get + /// @return The colony address, if no colony was found, returns 0x0 + function getColony(uint256 _id) public view returns (address); + + /// @notice Returns the latest Colony contract version. This is the version used to create all new colonies + /// @return The current / latest Colony contract version + function getCurrentColonyVersion() public view returns (uint256); + + /// @notice Upgrades a colony with identifier: `_id` to a new Colony contract version `_newVersion` + /// @dev Downgrades are not allowed, i.e. `_newVersion` should be higher than the currect colony version + /// @param _id The colony identifier in the network + /// @param _newVersion The target version for the upgrade + function upgradeColony(uint256 _id, uint _newVersion) public; + + /// @notice Get the id of the parent skill at index `_parentSkillIndex` for skill with Id `_skillId` + /// @param _skillId Id of the skill + /// @param _parentSkillIndex Index of the `skill.parents` array to get + /// Note that not all parent skill ids are stored here. See `Skill.parents` member for definition on which parents are stored + /// @return Skill Id of the requested parent skill + function getParentSkillId(uint256 _skillId, uint256 _parentSkillIndex) public view returns (uint256); + + /// @notice Get the id of the child skill at index `_childSkillIndex` for skill with Id `_skillId` + /// @param _skillId Id of the skill + /// @param _childSkillIndex Index of the `skill.children` array to get + /// @return Skill Id of the requested child skill + function getChildSkillId(uint256 _skillId, uint256 _childSkillIndex) public view returns (uint256); + + /// @notice Get the address of either the active or inactive reputation mining cycle, based on `active`. The active reputation mining cycle + /// is the one currently under consideration by reputation miners. The inactive reputation cycle is the one with the log that is being appended to + /// @param _active Whether the user wants the active or inactive reputation mining cycle + /// @return address of active or inactive ReputationMiningCycle + function getReputationMiningCycle(bool _active) public view returns (address); + + /// @notice Get the `Resolver` address for Colony contract version `_version` + /// @param _version The Colony contract version + /// @return Address of the `Resolver` contract + function getColonyVersionResolver(uint256 _version) public view returns (address); + + /// @notice Allow a reputation miner to stake an `_amount` of CLNY tokens, which is required + /// before they can submit a new reputation root hash via `ReputationMiningCycle.submitNewHash` + /// @dev The Colony Network has to be authorised to transfer the `_amount` on behalf of the user prior to this call + /// @param _amount Number of CLNY tokens to stake + function deposit(uint256 _amount) public; + + /// @notice Allow a user who has staked CLNY tokens to withdraw them + /// @dev Errors if the user has submitted a new reputation root hash or backed one someone else submitted in the current mining cycle + /// @param amount CLNY tokens amount to withdraw + function withdraw(uint256 amount) public; + + /// @notice Get the amount of staked CLNY tokens for user `_user` + /// @param _user Address of the user whose balance we want to get + /// @return User stake balance + function getStakedBalance(address _user) public view returns (uint256); + + /// @notice Set a new Reputation root hash and starts a new mining cycle. Can only be called by the ReputationMiningCycle contract. + /// @param newHash The reputation root hash + /// @param newNNodes The updated nodes count value + /// @param stakers Array of users who submitted or backed the hash, being accepted here as the new reputation root hash + function setReputationRootHash(bytes32 newHash, uint256 newNNodes, address[] stakers) public; + + /// @notice Starts a new Reputation Mining cycle. Explicitly called only the first time, + /// subsequently called from within `setReputationRootHash` + function startNextCycle() public; + + /// @notice Function called to punish people who staked against a new reputation root hash that turned out to be incorrect + /// @dev While public, it can only be called successfully by the current ReputationMiningCycle. + /// @param stakers Array of the addresses of stakers to punish + function punishStakers(address[] stakers) public; + + /// @notice Get the root hash of the current reputation state tree + /// @return bytes32 The current Reputation Root Hash + function getReputationRootHash() public view returns (bytes32); + + /// @notice Get the number of nodes in the current reputation state tree. + /// @dev I cannot see a reason why a user's client would need to call this - only stored to help with some edge cases in reputation mining dispute resolution + /// @return uint256 The number of nodes in the state tree + function getReputationRootHashNNodes() public view returns (uint256); + + /// @notice Create and start a new `DutchAuction` for the entire amount of `_token` owned by the Colony Network + /// @param _token Address of the token held by the network to be auctioned + function startTokenAuction(address _token) public; +} diff --git a/src/lib/colonyNetwork/contracts/IReputationMiningCycle.sol b/src/lib/colonyNetwork/contracts/IReputationMiningCycle.sol new file mode 100644 index 0000000..b735439 --- /dev/null +++ b/src/lib/colonyNetwork/contracts/IReputationMiningCycle.sol @@ -0,0 +1,153 @@ +/* + This file is part of The Colony Network. + + The Colony Network 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. + + The Colony Network 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 The Colony Network. If not, see . +*/ + +pragma solidity ^0.4.23; +pragma experimental "v0.5.0"; + + +contract IReputationMiningCycle { + + /// @notice The getter generated by solidity for the disputeRounds mapping of array of dispute rounds. + /// @param round The dispute round to query + /// @param index The index in the dispute round to query + /// @return The elements of the Submission struct for the submission requested. See ReputationMiningCycle.sol for the full description + function disputeRounds(uint256 round, uint256 index) public view returns (bytes32 proposedNewRootHash, uint256 nNodes, uint256 lastResponseTimestamp, uint256 challengeStepCompleted, bytes32 jrh, bytes32 intermediateReputationHash, uint256 intermediateReputationNNodes, uint256 jrhNnodes, uint256 lowerBound, uint256 upperBound, uint256 providedPreviousReputationUID); + + /// @notice Get the hash for the corresponding entry. + /// @param submitter The address that submitted the hash + /// @param entryIndex The index of the entry that they used to submit the hash + /// @param newHash The hash that they submitted + function getEntryHash(address submitter, uint256 entryIndex, bytes32 newHash) public pure returns (bytes32); + + /// @notice Resets the timestamp that the submission window opens to `now` + /// @dev only allowed to be called by ColonyNetwork + function resetWindow() public; + + /// @notice Submit a new reputation root hash + /// @param newHash The proposed new reputation root hash + /// @param nNodes Number of nodes in tree with root `newHash` + /// @param entryIndex The entry number for the given `newHash` and `nNodes` + function submitRootHash(bytes32 newHash, uint256 nNodes, uint256 entryIndex) public; + + /// @notice Confirm a new reputation hash. The hash in question is either the only one that was submitted this cycle, + /// or the last one standing after all others have been proved wrong. + /// @param roundNumber The round number that the hash being confirmed is in as the only contendender. If only one hash was submitted, then this is zero. + function confirmNewHash(uint256 roundNumber) public; + + /// @notice Invalidate a hash that has timed out relative to its opponent its current challenge step. Note that this can be called to 'invalidate' + /// a nonexistent hash, if the round has an odd number of entrants and so the last hash is being given a bye to the next round. + /// @param round The round number the hash being invalidated is in + /// @param idx The index in the round that the hash being invalidated is in + function invalidateHash(uint256 round, uint256 idx) public; + + /// @notice Respond to a binary search step, to eventually discover where two submitted hashes differ in their Justification trees. + /// @param round The round number the hash we are responding on behalf of is in + /// @param idx The index in the round that the hash we are responding on behalf of is in + /// @param jhIntermediateValue The contents of the Justification Tree at the key given by `targetNode` (see function description). The value of `targetNode` is computed locally to establish what to submit to this function. + /// @param branchMask The branchMask of the Merkle proof that `jhIntermediateValue` is the value at key `targetNode` + /// @param siblings The siblings of the Merkle proof that `jhIntermediateValue` is the value at key `targetNode` + function respondToBinarySearchForChallenge(uint256 round, uint256 idx, bytes jhIntermediateValue, uint branchMask, bytes32[] siblings) public; + + /// @notice Respond to challenge, to establish which (if either) of the two submissions facing off are correct. + /// @param u A `uint256[9]` array. The elements of this array, in order are: + /// * 1. The current round of the hash being responded on behalf of + /// * 2. The current index in the round of the hash being responded on behalf of + /// * 3. The branchMask of the proof that the reputation is in the reputation state tree for the reputation with the disputed change + /// * 4. The number of nodes in the last reputation state that both submitted hashes agree on + /// * 5. The branchMask of the proof that the last reputation state the submitted hashes agreed on is in this submitted hash's justification tree + /// * 6. The number of nodes this hash considers to be present in the first reputation state the two hashes in this challenge disagree on + /// * 7. The branchMask of the proof that reputation root hash of the first reputation state the two hashes in this challenge disagree on is in this submitted hash's justification tree + /// * 8. The branchMask of the proof for the most recently added reputation state in this hash's state tree in the last reputation state the two hashes in this challenge agreed on + /// * 9. A dummy variable that should be set to 0. If nonzero, transaction will still work but be slightly more expensive. For an explanation of why this is present, look at the corresponding solidity code. + /// @param _reputationKey The key of the reputation being changed that the disagreement is over. + /// @param reputationSiblings The siblings of the Merkle proof that the reputation corresponding to `_reputationKey` is in the reputation state before and after the disagreement + /// @param agreeStateReputationValue The value of the reputation at key `_reputationKey` in the last reputation state the submitted hashes agreed on + /// @param agreeStateSiblings The siblings of the Merkle proof that the last reputation state the submitted hashes agreed on is in this submitted hash's justification tree + /// @param disagreeStateReputationValue The value of the reputation at key `_reputationKey` in the first reputation state the submitted hashes disagree on + /// @param disagreeStateSiblings The siblings of the Merkle proof that the first reputation state the submitted hashes disagreed on is in this submitted hash's justification tree + /// @param previousNewReputationKey The key of the newest reputation added to the reputation tree in the last reputation state the submitted hashes agree on + /// @param previousNewReputationValue The value of the newest reputation added to the reputation tree in the last reputation state the submitted hashes agree on + /// @param previousNewReputationSiblings The siblings of the Merkle proof of the newest reputation added to the reputation tree in the last reputation state the submitted hashes agree on + /// @dev If you know that the disagreement doesn't involve a new reputation being added, the arguments corresponding to the previous new reputation can be zeroed, as they will not be used. You must be sure + /// that this is the case, however, otherwise you risk being found incorrect. Zeroed arguments will result in a cheaper call to this function. + function respondToChallenge( + uint256[9] u, //An array of 9 UINT Params, ordered as given above. + bytes _reputationKey, + bytes32[] reputationSiblings, + bytes agreeStateReputationValue, + bytes32[] agreeStateSiblings, + bytes disagreeStateReputationValue, + bytes32[] disagreeStateSiblings, + bytes previousNewReputationKey, + bytes previousNewReputationValue, + bytes32[] previousNewReputationSiblings) public; + + /// @notice Submit the Justification Root Hash (JRH) for a submitted reputation hash. + /// @param round The round that the hash is currently in. + /// @param index The index in the round that the hash is currently in + /// @param jrh The JRH being submitted + /// @param branchMask1 The branchmask for the Merkle proof that the currently accepted reputation state (given by `ColonyNetwork.getReputationRootHash()` + `ColonyNetwork.getReputationRootHashNNodes()`, where `+` is concatenation) is at key 0x000..000 in the submitted JRH + /// @param siblings1 The siblings for the same Merkle proof + /// @param branchMask2 The branchmask for the Merkle proof that the proposed new reputation state is at the key corresponding to the number of transactions expected in this update in the submitted JRH. This key should be the number of decay transactions plus the number of transactions the log indicates are to happen. + /// @param siblings2 The siblings for the same Merkle proof + /// @dev The majority of calls to this function will have `round` equal to `0`. The exception to this is when a submitted hash is given a bye, in which case `round` will be nonzero. + /// @dev Note that it is possible for this function to be required to be called in every round - the hash getting the bye can wait until they will also be awarded the bye in the next round, if + /// one is going to exist. There is an incentive to do so from a gas-cost perspective, but they don't know for sure there's going to be a bye until the submission window has expired, so I think + /// this is okay. + function submitJustificationRootHash( + uint256 round, + uint256 index, + bytes32 jrh, + uint branchMask1, + bytes32[] siblings1, + uint branchMask2, + bytes32[] siblings2) public; + + /// @notice Add a new entry to the reputation update log + /// @param _user The address of the user having their reputation changed by this log entry + /// @param _amount The amount by which the user's reputation is going to change. Can be positive or negative + /// @param _skillId The skillId of the reputation being affected + /// @param _colonyAddress The address of the colony the reputation is being affected in + /// @param _nParents The number of parent skills the skill defined by the skillId has + /// @param _nChildren The number of child skills the skill defined by the skillId has + function appendReputationUpdateLog(address _user, int _amount, uint _skillId, address _colonyAddress, uint _nParents, uint _nChildren) public; + + /// @notice Get the length of the ReputationUpdateLog stored on this instance of the ReputationMiningCycle contract + /// @return nUpdates + function getReputationUpdateLogLength() public view returns (uint); + + /// @notice Get the `ReputationLogEntry` at index `_id` + /// @param _id The reputation log members array index of the entry to get + /// @return user The address of the user having their reputation changed by this log entry + /// @return amount The amount by which the user's reputation is going to change + /// @return skillId The skillId of the reputation being affected + /// @return colony The address of the colony the reputation is being affected in + /// @return nUpdates The number of updates this log entry implies (including updates to parents, children and colony-wide totals thereof) + /// @return nPreviousUpdates The number of updates all previous entries in the log imply (including reputation decays, updates to parents, children, and colony-wide totals thereof) + function getReputationUpdateLogEntry(uint256 _id) public view returns (address, int256, uint256, address, uint256, uint256); + + /// @notice Start the reputation log with the rewards for the stakers who backed the accepted new reputation root hash. + /// @param stakers The array of stakers addresses to receive the reward. + /// @param commonColonyAddress The address of the common colony, which the special mining skill is earned in + /// @param reward The amount of reputation to be rewarded to each staker + /// @dev Only callable by colonyNetwork + /// @dev Note that the same address might be present multiple times in `stakers` - this is acceptable, and indicates the + /// same address backed the same hash multiple times with different entries. + function rewardStakersWithReputation(address[] stakers, address commonColonyAddress, uint reward) public; + + function reputationMiningWindowOpenTimestamp() public view returns (uint); +} diff --git a/src/lib/colonyNetwork/contracts/Migrations.sol b/src/lib/colonyNetwork/contracts/Migrations.sol new file mode 100644 index 0000000..574ad42 --- /dev/null +++ b/src/lib/colonyNetwork/contracts/Migrations.sol @@ -0,0 +1,26 @@ +pragma solidity ^0.4.23; +pragma experimental "v0.5.0"; + + +contract Migrations { + address public owner; + + uint public last_completed_migration; + + modifier restricted() { + if (msg.sender == owner) { _; } + } + + constructor() public { + owner = msg.sender; + } + + function setCompleted(uint completed) public restricted { + last_completed_migration = completed; + } + + function upgrade(address new_address) public restricted { + Migrations upgraded = Migrations(new_address); + upgraded.setCompleted(last_completed_migration); + } +} diff --git a/src/lib/colonyNetwork/contracts/PatriciaTree/Bits.sol b/src/lib/colonyNetwork/contracts/PatriciaTree/Bits.sol new file mode 100644 index 0000000..acad80b --- /dev/null +++ b/src/lib/colonyNetwork/contracts/PatriciaTree/Bits.sol @@ -0,0 +1,44 @@ +pragma solidity ^0.4.16; +pragma experimental "v0.5.0"; +pragma experimental "ABIEncoderV2"; + + +library Bits { + /// @title Bits library + /// @notice Subset of the bits library found at https://github.com/ethereum/solidity-examples + /// only these parts are used by the PatriciaTree implementation, so removed the unused functions + /// for brevity + + uint constant internal ONE = uint(1); + + /// @notice Computes the index of the highest bit set in 'self'. + /// Returns the highest bit set as an `uint8` + /// @param self The `uint256` to find the highest bit set in + /// @dev Requires that `self != 0`. + function highestBitSet(uint self) internal pure returns (uint8 highest) { + require(self != 0); + uint val = self; + for (uint8 i = 128; i >= 1; i >>= 1) { + if (val & (ONE << i) - 1 << i != 0) { + highest += i; + val >>= i; + } + } + } + + /// @notice Computes the index of the lowest bit set in 'self'. + /// Returns the lowest bit set as an `uint8` + /// @param self The `uint256` to find the lowest bit set in + /// @dev Requires that `self != 0`. + function lowestBitSet(uint self) internal pure returns (uint8 lowest) { + require(self != 0); + uint val = self; + for (uint8 i = 128; i >= 1; i >>= 1) { + if (val & (ONE << i) - 1 == 0) { + lowest += i; + val >>= i; + } + } + } + +} diff --git a/src/lib/colonyNetwork/contracts/PatriciaTree/Data.sol b/src/lib/colonyNetwork/contracts/PatriciaTree/Data.sol new file mode 100644 index 0000000..3742b91 --- /dev/null +++ b/src/lib/colonyNetwork/contracts/PatriciaTree/Data.sol @@ -0,0 +1,145 @@ +pragma solidity ^0.4.16; +pragma experimental "v0.5.0"; +pragma experimental "ABIEncoderV2"; + +import {Bits} from "./Bits.sol"; + + +/// @title Patricia tree Data library +/// @notice Data structures and utilities used in the Patricia Tree +/// More info at: https://github.com/chriseth/patricia-trie +library Data { + + struct Label { + bytes32 data; + uint length; + } + + struct Edge { + bytes32 node; + Label label; + } + + struct Node { + Edge[2] children; + } + + struct Tree { + bytes32 root; + Edge rootEdge; + mapping(bytes32 => Node) nodes; + } + + // Returns a label containing the longest common prefix of `self` and `label`, + // and a label consisting of the remaining part of `label`. + function splitCommonPrefix(Label memory self, Label memory other) internal pure returns ( + Label memory prefix, + Label memory labelSuffix + ) + { + return splitAt(self, commonPrefix(self, other)); + } + + // Splits the label at the given position and returns prefix and suffix, + // i.e. 'prefix.length == pos' and 'prefix.data . suffix.data == l.data'. + function splitAt(Label memory self, uint pos) internal pure returns (Label memory prefix, Label memory suffix) { + assert(pos <= self.length && pos <= 256); + prefix.length = pos; + if (pos == 0) { + prefix.data = bytes32(0); + } else { + prefix.data = bytes32(uint(self.data) & ~uint(1) << 255 - pos); + } + suffix.length = self.length - pos; + suffix.data = self.data << pos; + } + + // Removes the first bit from a label and returns the bit and a + // label containing the rest of the label (shifted to the left). + function chopFirstBit(Label memory self) internal pure returns (uint firstBit, Label memory tail) { + require(self.length > 0); + return (uint(self.data >> 255), Label(self.data << 1, self.length - 1)); + } + + function edgeHash(Edge memory self) internal pure returns (bytes32) { + return keccak256(abi.encodePacked(self.node, self.label.length, self.label.data)); + } + + function insert(Tree storage self, bytes key, bytes value) internal { + Label memory k = Label(keccak256(key), 256); + bytes32 valueHash = keccak256(value); + Edge memory e; + if (self.root == 0) { + // Empty Trie + e.label = k; + e.node = valueHash; + } else { + e = insertAtEdge(self, self.rootEdge, k, valueHash); + } + self.root = edgeHash(e); + self.rootEdge = e; + } + + // Private functions + function insertAtEdge(Tree storage self, Edge e, Label key, bytes32 value) private returns (Edge) { + assert(key.length >= e.label.length); + Label memory prefix; + Label memory suffix; + (prefix, suffix) = splitCommonPrefix(key, e.label); + uint256 head; + Label memory tail; + bytes32 newNodeHash; + if (suffix.length == 0) { + // Full match with the key, update operation + newNodeHash = value; + } else if (prefix.length >= e.label.length) { + // Partial match, just follow the path + assert(suffix.length > 1); + Node memory n = self.nodes[e.node]; + (head, tail) = chopFirstBit(suffix); + n.children[head] = insertAtEdge(self, n.children[head], tail, value); + delete self.nodes[e.node]; + newNodeHash = insertNode(self, n); + } else { + // Mismatch, so let us create a new branch node. + (head, tail) = chopFirstBit(suffix); + Node memory branchNode; + branchNode.children[head] = Edge(value, tail); + branchNode.children[1 - head] = Edge(e.node, removePrefix(e.label, prefix.length + 1)); + newNodeHash = insertNode(self, branchNode); + } + return Edge(newNodeHash, prefix); + } + + function insertNode(Tree storage tree, Node memory n) private returns (bytes32 newHash) { + bytes32 h = nodeEncodingHash(n); + tree.nodes[h].children[0] = n.children[0]; + tree.nodes[h].children[1] = n.children[1]; + return h; + } + + // Returns the hash of the encoding of a node. + function nodeEncodingHash(Node memory self) private pure returns (bytes32) { + return keccak256(abi.encodePacked(edgeHash(self.children[0]), edgeHash(self.children[1]))); + } + + // Returns the result of removing a prefix of length `prefix` bits from the + // given label (shifting its data to the left). + function removePrefix(Label memory self, uint prefix) private pure returns (Label memory r) { + require(prefix <= self.length); + r.length = self.length - prefix; + r.data = self.data << prefix; + } + + function commonPrefix(Label memory self, Label memory other) private pure returns (uint prefix) { + uint length = self.length < other.length ? self.length : other.length; + if (length == 0) { + return 0; + } + uint diff = uint(self.data ^ other.data) & ~uint(0) << 256 - length; // TODO Mask should not be needed. + if (diff == 0) { + return length; + } + return 255 - Bits.highestBitSet(diff); + } +} diff --git a/src/lib/colonyNetwork/contracts/PatriciaTree/IPatriciaTree.sol b/src/lib/colonyNetwork/contracts/PatriciaTree/IPatriciaTree.sol new file mode 100644 index 0000000..b533144 --- /dev/null +++ b/src/lib/colonyNetwork/contracts/PatriciaTree/IPatriciaTree.sol @@ -0,0 +1,37 @@ +pragma solidity ^0.4.16; +pragma experimental "v0.5.0"; +pragma experimental "ABIEncoderV2"; + +import {Data} from "./Data.sol"; + + +/// @title Interface for Patricia trees +/// @notice More info at: https://github.com/chriseth/patricia-trie +contract IPatriciaTree { + + /// @notice Get the root hash + /// @dev This value is a keccak256 hash of the rootEdge: `keccak256(Edge.node, Edge.label.length, Edge.label.data)` + /// @return The `bytes32` hash value + function getRootHash() public view returns (bytes32); + + /// @notice Get the root edge + /// @return The root `Data.Edge` + function getRootEdge() public view returns (Data.Edge e); + + /// @notice Get the node with the given key + /// @param hash The `keccak256` hash of the actual key + /// @return `Data.Node` for key `hash` + function getNode(bytes32 hash) public view returns (Data.Node n); + + /// @notice Returns the Merkle-proof for the given `key` + /// @return branchMask Bitmask with high bits at the positions in the `key` where we have branch nodes (bit in key denotes direction) + /// @return _siblings Hashes of sibling edges + function getProof(bytes key) public view returns (uint branchMask, bytes32[] _siblings); + + /// @notice Calculates and returns a root hash for the `key`, `value`, `branchMask` and `siblings` + /// @return The calculated hash + function getImpliedRoot(bytes key, bytes value, uint branchMask, bytes32[] siblings) public view returns (bytes32); + + /// @notice Insert the `key`/`value`in the appropriate place in the tree + function insert(bytes key, bytes value) public; +} diff --git a/src/lib/colonyNetwork/contracts/PatriciaTree/PatriciaTree.sol b/src/lib/colonyNetwork/contracts/PatriciaTree/PatriciaTree.sol new file mode 100644 index 0000000..3ffc9cc --- /dev/null +++ b/src/lib/colonyNetwork/contracts/PatriciaTree/PatriciaTree.sol @@ -0,0 +1,71 @@ +pragma solidity ^0.4.16; +pragma experimental "v0.5.0"; +pragma experimental "ABIEncoderV2"; + +import {Data} from "./Data.sol"; +import {Bits} from "./Bits.sol"; +import "./IPatriciaTree.sol"; +import "./PatriciaTreeProofs.sol"; + + +/// @title Patricia tree implementation +/// @notice More info at: https://github.com/chriseth/patricia-trie +contract PatriciaTree is IPatriciaTree, PatriciaTreeProofs { + + using Data for Data.Tree; + using Data for Data.Edge; + using Data for Data.Label; + using Bits for uint; + + Data.Tree internal tree; + + function getRootHash() public view returns (bytes32) { + return tree.root; + } + + function getRootEdge() public view returns (Data.Edge e) { + e = tree.rootEdge; + } + + function getNode(bytes32 hash) public view returns (Data.Node n) { + n = tree.nodes[hash]; + } + + function getProof(bytes key) public view returns (uint branchMask, bytes32[] _siblings) { + require(tree.root != 0); + Data.Label memory k = Data.Label(keccak256(key), 256); + Data.Edge memory e = tree.rootEdge; + bytes32[256] memory siblings; + uint length; + uint numSiblings; + while (true) { + Data.Label memory prefix; + Data.Label memory suffix; + (prefix, suffix) = k.splitCommonPrefix(e.label); + assert(prefix.length == e.label.length); + if (suffix.length == 0) { + // Found it + break; + } + length += prefix.length; + branchMask |= uint(1) << 255 - length; + length += 1; + uint256 head; + Data.Label memory tail; + (head, tail) = suffix.chopFirstBit(); + siblings[numSiblings++] = tree.nodes[e.node].children[1 - head].edgeHash(); + e = tree.nodes[e.node].children[head]; + k = tail; + } + if (numSiblings > 0) { + _siblings = new bytes32[](numSiblings); + for (uint i = 0; i < numSiblings; i++) { + _siblings[i] = siblings[i]; + } + } + } + + function insert(bytes key, bytes value) public { + tree.insert(key, value); + } +} diff --git a/src/lib/colonyNetwork/contracts/PatriciaTree/PatriciaTreeProofs.sol b/src/lib/colonyNetwork/contracts/PatriciaTree/PatriciaTreeProofs.sol new file mode 100644 index 0000000..5c747be --- /dev/null +++ b/src/lib/colonyNetwork/contracts/PatriciaTree/PatriciaTreeProofs.sol @@ -0,0 +1,33 @@ +pragma solidity ^0.4.16; +pragma experimental "v0.5.0"; +pragma experimental "ABIEncoderV2"; + +import {Data} from "./Data.sol"; +import {Bits} from "./Bits.sol"; + +/// @title Functions related to checking Patricia Tree proofs +/// @notice More info at: https://github.com/chriseth/patricia-trie +contract PatriciaTreeProofs { + using Bits for uint; + using Data for Data.Edge; + using Data for Data.Label; + + function getImpliedRoot(bytes key, bytes value, uint branchMask, bytes32[] siblings) public view returns (bytes32) { // solium-disable-line security/no-assign-params + Data.Label memory k = Data.Label(keccak256(key), 256); + Data.Edge memory e; + e.node = keccak256(value); + for (uint i = 0; branchMask != 0; i++) { + uint bitSet = branchMask.lowestBitSet(); + branchMask &= ~(uint(1) << bitSet); + (k, e.label) = k.splitAt(255 - bitSet); + uint bit; + (bit, e.label) = e.label.chopFirstBit(); + bytes32[2] memory edgeHashes; + edgeHashes[bit] = e.edgeHash(); + edgeHashes[1 - bit] = siblings[siblings.length - i - 1]; + e.node = keccak256(abi.encodePacked(edgeHashes)); + } + e.label = k; + return e.edgeHash(); + } +} diff --git a/src/lib/colonyNetwork/contracts/ReputationMiningCycle.sol b/src/lib/colonyNetwork/contracts/ReputationMiningCycle.sol new file mode 100644 index 0000000..23b5481 --- /dev/null +++ b/src/lib/colonyNetwork/contracts/ReputationMiningCycle.sol @@ -0,0 +1,740 @@ +/* + This file is part of The Colony Network. + + The Colony Network 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. + + The Colony Network 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 The Colony Network. If not, see . +*/ + +pragma solidity ^0.4.23; +pragma experimental "v0.5.0"; + +import "../lib/dappsys/math.sol"; +import "./IColonyNetwork.sol"; +import "./PatriciaTree/PatriciaTreeProofs.sol"; + + +// TODO: Can we handle all possible disputes regarding the very first hash that should be set? +// Currently, at the very least, we can't handle a dispute if the very first entry is disputed. +// A possible workaround would be to 'kick off' reputation mining with a known dummy state... +contract ReputationMiningCycle is PatriciaTreeProofs, DSMath { + ReputationLogEntry[] reputationUpdateLog; + struct ReputationLogEntry { + address user; + int amount; + uint256 skillId; + address colony; + uint256 nUpdates; + uint256 nPreviousUpdates; + } + address colonyNetworkAddress; + // TODO: Do we need both these mappings? + mapping (bytes32 => mapping( uint256 => address[])) public submittedHashes; + mapping (address => Submission) public reputationHashSubmissions; + uint256 public reputationMiningWindowOpenTimestamp; + mapping (uint256 => Submission[]) public disputeRounds; + + // Tracks the number of submissions in each round that have completed their challenge, one way or the other. + // This might be that they passed the challenge, it might be that their opponent passed (and therefore by implication, + // they failed), or it might be that they timed out + mapping (uint256 => uint256) nHashesCompletedChallengeRound; + // A flaw with this is that if someone spams lots of nonsense transactions, then 'good' users still have to come along and + // explicitly complete the pairings. But if they get the tokens that were staked in order to make the submission, maybe + // that's okay...? + + // Number of unique hashes submitted + uint256 public nSubmittedHashes = 0; + uint256 public nInvalidatedHashes = 0; + + struct Submission { + bytes32 proposedNewRootHash; // The hash that the submitter is proposing as the next reputation hash + uint256 nNodes; // The number of nodes in the reputation tree being proposed as the next reputation hash + uint256 lastResponseTimestamp; // If nonzero, the last time that a valid response was received corresponding to this + // submission during the challenge process - either binary searching for the challenge, + // responding to the challenge itself or submitting the JRH + uint256 challengeStepCompleted; // How many valid responses have been received corresponding to this submission during + // the challenge process. + bytes32 jrh; // The Justification Root Hash corresponding to this submission. + bytes32 intermediateReputationHash; // The hash this submission hash has as a leaf node in the tree the JRH is the root of where + // this submission and its opponent differ for the first time. + uint256 intermediateReputationNNodes; // The number of nodes in the reputation tree in the reputation state where this submission and + // its opponent first differ. + uint256 jrhNnodes; // The number of nodes in the tree the JRH is the root of. + uint256 lowerBound; // During the binary search, the lowest index in the justification tree that might still be the + // first place where the two submissions differ. + uint256 upperBound; // During the binary search, the highest index in the justification tree that might still be the + // first place where the two submissions differ. + // When the binary search is complete, lowerBound and upperBound are equal + uint256 provedPreviousReputationUID; // If the disagreement between this submission and its opponent is related to the insertion of a + // new leaf, the submitters also submit proof of a reputation in a state that the two agree on. The + // UID that reputation has is stored here, and whichever submission proves the higher existing UID is + // deemed correct, assuming it also matches the UID for the new reputation being inserted. + } + + // Records for which hashes, for which addresses, for which entries have been accepted + // Otherwise, people could keep submitting the same entry. + mapping (bytes32 => mapping(address => mapping(uint256 => bool))) submittedEntries; + + /// @notice A modifier that checks that the supplied `roundNumber` is the final round + /// @param roundNumber The `roundNumber` to check if it is the final round + modifier finalDisputeRoundCompleted(uint roundNumber) { + require (nSubmittedHashes - nInvalidatedHashes == 1); + require (disputeRounds[roundNumber].length == 1); //i.e. this is the final round + // Note that even if we are passed the penultimate round, which had a length of two, and had one eliminated, + // and therefore 'delete' called in `invalidateHash`, the array still has a length of '2' - it's just that one + // element is zeroed. If this functionality of 'delete' is ever changed, this will have to change too. + _; + } + + /// @notice A modifier that checks if the challenge corresponding to the hash in the passed `round` and `id` is open + /// @param round The round number of the hash under consideration + /// @param idx The index in the round of the hash under consideration + modifier challengeOpen(uint256 round, uint256 idx) { + // TODO: More checks that this is an appropriate time to respondToChallenge + require(disputeRounds[round][idx].lowerBound == disputeRounds[round][idx].upperBound); + _; + } + + /// @notice A modifier that checks if the proposed entry is eligible. The more CLNY a user stakes, the more + /// potential entries they have in a reputation mining cycle. This is effectively restricting the nonce range + /// that is allowable from a given user when searching for a submission that will pass `withinTarget`. A user + /// is allowed to use multiple entries in a single cycle, but each entry can only be used once per cycle, and + /// if there are multiple entries they must all be for the same proposed Reputation State Root Hash with the + /// same number of nodes. + /// @param newHash The hash being submitted + /// @param nNodes The number of nodes in the reputation tree that `newHash` is the root hash of + /// @param entryIndex The number of the entry the submitter hash asked us to consider. + modifier entryQualifies(bytes32 newHash, uint256 nNodes, uint256 entryIndex) { + // TODO: Require minimum stake, that is (much) more than the cost required to defend the valid submission. + // Here, the minimum stake is 10**15. + require(entryIndex <= IColonyNetwork(colonyNetworkAddress).getStakedBalance(msg.sender) / 10**15); + require(entryIndex > 0); + if (reputationHashSubmissions[msg.sender].proposedNewRootHash != 0x0) { // If this user has submitted before during this round... + require(newHash == reputationHashSubmissions[msg.sender].proposedNewRootHash); // ...require that they are submitting the same hash ... + require(nNodes == reputationHashSubmissions[msg.sender].nNodes); // ...require that they are submitting the same number of nodes for that hash ... + require (submittedEntries[newHash][msg.sender][entryIndex] == false); // ... but not this exact entry + } + _; + } + + /// @notice A modifier that checks if the proposed entry is within the current allowable submission window + /// @dev A submission will only be accepted from a reputation miner if `keccak256(address, N, hash) < target` + /// At the beginning of the submission window, the target is set to 0 and slowly increases to 2^256 - 1 after an hour + modifier withinTarget(bytes32 newHash, uint256 entryIndex) { + require(reputationMiningWindowOpenTimestamp > 0); + // Check the ticket is a winning one. + // TODO Figure out how to uncomment the next line, but not break tests sporadically. + // require((now-reputationMiningWindowOpenTimestamp) <= 3600); + // x = floor(uint((2**256 - 1) / 3600) + if (now - reputationMiningWindowOpenTimestamp <= 3600) { + uint256 x = 32164469232587832062103051391302196625908329073789045566515995557753647122; + uint256 target = (now - reputationMiningWindowOpenTimestamp ) * x; + require(uint256(getEntryHash(msg.sender, entryIndex, newHash)) < target); + } + _; + } + + function getEntryHash(address submitter, uint256 entryIndex, bytes32 newHash) public pure returns (bytes32) { + return keccak256(abi.encodePacked(submitter, entryIndex, newHash)); + } + + /// @notice Constructor for this contract. + constructor() public { + colonyNetworkAddress = msg.sender; + } + + function resetWindow() public { + require(msg.sender == colonyNetworkAddress); + reputationMiningWindowOpenTimestamp = now; + } + + function submitRootHash(bytes32 newHash, uint256 nNodes, uint256 entryIndex) + entryQualifies(newHash, nNodes, entryIndex) + withinTarget(newHash, entryIndex) + public + { + // Limit the total number of miners allowed to submit a specific hash to 12 + require (submittedHashes[newHash][nNodes].length < 12); + + // If this is a new hash, increment nSubmittedHashes as such. + if (submittedHashes[newHash][nNodes].length == 0) { + nSubmittedHashes += 1; + // And add it to the first disputeRound + // NB if no other hash is submitted, no dispute resolution will be required. + disputeRounds[0].push(Submission({ + proposedNewRootHash: newHash, + jrh: 0x0, + nNodes: nNodes, + lastResponseTimestamp: 0, + challengeStepCompleted: 0, + lowerBound: 0, + upperBound: 0, + jrhNnodes: 0, + intermediateReputationHash: 0x0, + intermediateReputationNNodes: 0, + provedPreviousReputationUID: 0 + })); + // If we've got a pair of submissions to face off, may as well start now. + if (nSubmittedHashes % 2 == 0) { + disputeRounds[0][nSubmittedHashes-1].lastResponseTimestamp = now; + disputeRounds[0][nSubmittedHashes-2].lastResponseTimestamp = now; + /* disputeRounds[0][nSubmittedHashes-1].upperBound = disputeRounds[0][nSubmittedHashes-1].jrhNnodes; */ + /* disputeRounds[0][nSubmittedHashes-2].upperBound = disputeRounds[0][nSubmittedHashes-2].jrhNnodes; */ + } + } + + reputationHashSubmissions[msg.sender] = Submission({ + proposedNewRootHash: newHash, + jrh: 0x0, + nNodes: nNodes, + lastResponseTimestamp: 0, + challengeStepCompleted: 0, + lowerBound: 0, + upperBound: 0, + jrhNnodes: 0, + intermediateReputationHash: 0x0, + intermediateReputationNNodes: 0, + provedPreviousReputationUID: 0 + }); + // And add the miner to the array list of submissions here + submittedHashes[newHash][nNodes].push(msg.sender); + // Note that they submitted it. + submittedEntries[newHash][msg.sender][entryIndex] = true; + } + + function confirmNewHash(uint256 roundNumber) public + finalDisputeRoundCompleted(roundNumber) + { + // TODO: Require some amount of time to have passed (i.e. people have had a chance to submit other hashes) + Submission storage submission = disputeRounds[roundNumber][0]; + IColonyNetwork(colonyNetworkAddress).setReputationRootHash(submission.proposedNewRootHash, submission.nNodes, submittedHashes[submission.proposedNewRootHash][submission.nNodes]); + selfdestruct(colonyNetworkAddress); + } + + function invalidateHash(uint256 round, uint256 idx) public { + // What we do depends on our opponent, so work out which index it was at in disputeRounds[round] + uint256 opponentIdx = (idx % 2 == 1 ? idx-1 : idx + 1); + uint256 nInNextRound; + + // We require either + // 1. That we actually had an opponent - can't invalidate the last hash. + // 2. This cycle had an odd number of submissions, which was larger than 1, and we're giving the last entry a bye to the next round. + if (disputeRounds[round].length % 2 == 1 && disputeRounds[round].length == idx) { + // This is option two above - note that because arrays are zero-indexed, if idx==length, then + // this is the slot after the last entry, and so our opponentIdx will be the last entry + // We just move the opponent on, and nothing else happens. + + // Ensure that the previous round is complete, and this entry wouldn't possibly get an opponent later on. + require(nHashesCompletedChallengeRound[round-1] == disputeRounds[round-1].length); + + // Prevent us invalidating the final hash + require(disputeRounds[round].length > 1); + // Move opponent on to next round + disputeRounds[round+1].push(disputeRounds[round][opponentIdx]); + delete disputeRounds[round][opponentIdx]; + + // Note the fact that this round has had another challenge complete + nHashesCompletedChallengeRound[round] += 1; + // Check if the hash we just moved to the next round is the second of a pairing that should now face off. + nInNextRound = disputeRounds[round+1].length; + + if (nInNextRound % 2 == 0) { + startPairingInRound(round+1); + } + } else { + require(disputeRounds[round].length > opponentIdx); + require(disputeRounds[round][opponentIdx].proposedNewRootHash != ""); + + // Require that this is not better than its opponent. + require(disputeRounds[round][opponentIdx].challengeStepCompleted >= disputeRounds[round][idx].challengeStepCompleted); + require(disputeRounds[round][opponentIdx].provedPreviousReputationUID >= disputeRounds[round][idx].provedPreviousReputationUID); + + // Require that it has failed a challenge (i.e. failed to respond in time) + require(now - disputeRounds[round][idx].lastResponseTimestamp >= 600); //'In time' is ten minutes here. + + // Work out whether we are invalidating just the supplied idx or its opponent too. + bool eliminateOpponent = false; + if (disputeRounds[round][opponentIdx].challengeStepCompleted == disputeRounds[round][idx].challengeStepCompleted && + disputeRounds[round][opponentIdx].provedPreviousReputationUID == disputeRounds[round][idx].provedPreviousReputationUID) { + eliminateOpponent = true; + } + + if (!eliminateOpponent) { + // If here, then the opponent completed one more challenge round than the submission being invalidated or + // proved a later UID was in the tree, so we don't know if they're valid or not yet. Move them on to the next round. + disputeRounds[round+1].push(disputeRounds[round][opponentIdx]); + delete disputeRounds[round][opponentIdx]; + // TODO Delete the hash(es) being invalidated? + nInvalidatedHashes += 1; + // Check if the hash we just moved to the next round is the second of a pairing that should now face off. + nInNextRound = disputeRounds[round+1].length; + if (nInNextRound % 2 == 0) { + startPairingInRound(round+1); + } + } else { + // Our opponent completed the same number of challenge rounds, and both have now timed out. + nInvalidatedHashes += 2; + // Punish the people who proposed our opponent + IColonyNetwork(colonyNetworkAddress).punishStakers(submittedHashes[disputeRounds[round][opponentIdx].proposedNewRootHash][disputeRounds[round][opponentIdx].nNodes]); + } + + // Note that two hashes have completed this challenge round (either one accepted for now and one rejected, or two rejected) + nHashesCompletedChallengeRound[round] += 2; + + // Punish the people who proposed the hash that was rejected + IColonyNetwork(colonyNetworkAddress).punishStakers(submittedHashes[disputeRounds[round][idx].proposedNewRootHash][disputeRounds[round][idx].nNodes]); + } + //TODO: Can we do some deleting to make calling this as cheap as possible for people? + } + + function respondToBinarySearchForChallenge(uint256 round, uint256 idx, bytes jhIntermediateValue, uint branchMask, bytes32[] siblings) public { + // TODO: Check this challenge is active. + // This require is necessary, but not a sufficient check (need to check we have an opponent, at least). + require(disputeRounds[round][idx].lowerBound!=disputeRounds[round][idx].upperBound); + + uint256 targetNode = add(disputeRounds[round][idx].lowerBound, sub(disputeRounds[round][idx].upperBound, disputeRounds[round][idx].lowerBound) / 2); + bytes32 jrh = disputeRounds[round][idx].jrh; + + bytes memory targetNodeBytes = new bytes(32); + assembly { + mstore(add(targetNodeBytes, 0x20), targetNode) + } + + bytes32 impliedRoot = getImpliedRoot(targetNodeBytes, jhIntermediateValue, branchMask, siblings); + require(impliedRoot==jrh, "colony-invalid-binary-search-response"); + // If require hasn't thrown, proof is correct. + // Process the consequences + processBinaryChallengeSearchResponse(round, idx, jhIntermediateValue, targetNode); + } + + uint constant U_ROUND = 0; + uint constant U_IDX = 1; + uint constant U_REPUTATION_BRANCH_MASK = 2; + uint constant U_AGREE_STATE_NNODES = 3; + uint constant U_AGREE_STATE_BRANCH_MASK = 4; + uint constant U_DISAGREE_STATE_NNODES = 5; + uint constant U_DISAGREE_STATE_BRANCH_MASK = 6; + uint constant U_PREVIOUS_NEW_REPUTATION_BRANCH_MASK = 7; + uint constant U_REQUIRE_REPUTATION_CHECK = 8; + + function respondToChallenge( + uint256[9] u, //An array of 9 UINT Params, ordered as given above. + bytes _reputationKey, + bytes32[] reputationSiblings, + bytes agreeStateReputationValue, + bytes32[] agreeStateSiblings, + bytes disagreeStateReputationValue, + bytes32[] disagreeStateSiblings, + bytes previousNewReputationKey, + bytes previousNewReputationValue, + bytes32[] previousNewReputationSiblings + ) public + challengeOpen(u[U_ROUND], u[U_IDX]) + { + u[U_REQUIRE_REPUTATION_CHECK] = 0; + // TODO: More checks that this is an appropriate time to respondToChallenge (maybe in modifier); + /* bytes32 jrh = disputeRounds[round][idx].jrh; */ + // The contract knows + // 1. the jrh for this submission + // 2. The first index where this submission and its opponent differ. + // Need to prove + // 1. The reputation that is updated that we disagree on's value, before the first index + // where we differ, and in the first index where we differ. + // 2. That no other changes are made to the reputation state. The proof for those + // two reputations in (1) is therefore required to be the same. + // 3. That our 'after' value is correct. This is done by doing the calculation on-chain, perhaps + // after looking up the corresponding entry in the reputation update log (the alternative is + // that it's a decay calculation - not yet implemented.) + + // Check the supplied key is appropriate. + checkKey(u[U_ROUND], u[U_IDX], _reputationKey); + + // Prove the reputation's starting value is in some state, and that state is in the appropriate index in our JRH + proveBeforeReputationValue(u, _reputationKey, reputationSiblings, agreeStateReputationValue, agreeStateSiblings); + + // Prove the reputation's final value is in a particular state, and that state is in our JRH in the appropriate index (corresponding to the first disagreement between these miners) + // By using the same branchMask and siblings, we know that no other changes to the reputation state tree have been slipped in. + proveAfterReputationValue(u, _reputationKey, reputationSiblings, disagreeStateReputationValue, disagreeStateSiblings); + + // Perform the reputation calculation ourselves. + performReputationCalculation(u, agreeStateReputationValue, disagreeStateReputationValue, previousNewReputationValue); + + // If necessary, check the supplied previousNewRepuation is, in fact, in the same reputation state as the agreeState + if (u[U_REQUIRE_REPUTATION_CHECK]==1) { + checkPreviousReputationInState( + u, + _reputationKey, + reputationSiblings, + agreeStateReputationValue, + agreeStateSiblings, + previousNewReputationKey, + previousNewReputationValue, + previousNewReputationSiblings); + saveProvedReputation(u, previousNewReputationValue); + } + + // If everthing checked out, note that we've responded to the challenge. + disputeRounds[u[U_ROUND]][u[U_IDX]].challengeStepCompleted += 1; + disputeRounds[u[U_ROUND]][u[U_IDX]].lastResponseTimestamp = now; + + // Safety net? + /* if (disputeRounds[round][idx].challengeStepCompleted==disputeRounds[round][opponentIdx].challengeStepCompleted){ + // Freeze the reputation mining system. + } */ + + } + + function submitJustificationRootHash( + uint256 round, + uint256 index, + bytes32 jrh, + uint branchMask1, + bytes32[] siblings1, + uint branchMask2, + bytes32[] siblings2 + ) public + { + // Require we've not submitted already. + require(disputeRounds[round][index].jrh == 0x0); + + // Check the proofs for the JRH + checkJRHProof1(jrh, branchMask1, siblings1); + checkJRHProof2(round, index, jrh, branchMask2, siblings2); + + // Store their JRH + disputeRounds[round][index].jrh = jrh; + disputeRounds[round][index].lastResponseTimestamp = now; + disputeRounds[round][index].challengeStepCompleted += 1; + + // Set bounds for first binary search if it's going to be needed + disputeRounds[round][index].upperBound = disputeRounds[round][index].jrhNnodes; + } + + function appendReputationUpdateLog(address _user, int _amount, uint _skillId, address _colonyAddress, uint _nParents, uint _nChildren) public { + require(colonyNetworkAddress == msg.sender); + uint reputationUpdateLogLength = reputationUpdateLog.length; + uint nPreviousUpdates = 0; + if (reputationUpdateLogLength > 0) { + nPreviousUpdates = reputationUpdateLog[reputationUpdateLogLength-1].nPreviousUpdates + reputationUpdateLog[reputationUpdateLogLength-1].nUpdates; + } + uint nUpdates = (_nParents + 1) * 2; + if (_amount < 0) { + //TODO: Never true currently. _amount needs to be an int. + nUpdates += 2 * _nChildren; + } + reputationUpdateLog.push(ReputationLogEntry( + _user, + _amount, + _skillId, + _colonyAddress, + nUpdates, + nPreviousUpdates)); + } + + function getReputationUpdateLogLength() public view returns (uint) { + return reputationUpdateLog.length; + } + + function getReputationUpdateLogEntry(uint256 _id) public view returns (address, int256, uint256, address, uint256, uint256) { + ReputationLogEntry storage x = reputationUpdateLog[_id]; + return (x.user, x.amount, x.skillId, x.colony, x.nUpdates, x.nPreviousUpdates); + } + + function rewardStakersWithReputation(address[] stakers, address commonColonyAddress, uint reward) public { + require(reputationUpdateLog.length==0); + require(msg.sender == colonyNetworkAddress); + for (uint256 i = 0; i < stakers.length; i++) { + // We *know* we're the first entries in this reputation update log, so we don't need all the bookkeeping in + // the AppendReputationUpdateLog function + reputationUpdateLog.push(ReputationLogEntry( + stakers[i], + int256(reward), + 0, //TODO: Work out what skill this should be. This should be a special 'mining' skill. + commonColonyAddress, // They earn this reputation in the common colony. + 4, // Updates the user's skill, and the colony's skill, both globally and for the special 'mining' skill + i*4 //We're zero indexed, so this is the number of updates that came before in the reputation log. + )); + } + } + + ///////////////////////// + // Internal functions + ///////////////////////// + + function processBinaryChallengeSearchResponse(uint256 round, uint256 idx, bytes jhIntermediateValue, uint256 targetNode) internal { + disputeRounds[round][idx].lastResponseTimestamp = now; + disputeRounds[round][idx].challengeStepCompleted += 1; + // Save our intermediate hash + bytes32 intermediateReputationHash; + uint256 intermediateReputationNNodes; + assembly { + intermediateReputationHash := mload(add(jhIntermediateValue, 0x20)) + intermediateReputationNNodes := mload(add(jhIntermediateValue, 0x40)) + } + disputeRounds[round][idx].intermediateReputationHash = intermediateReputationHash; + disputeRounds[round][idx].intermediateReputationNNodes = intermediateReputationNNodes; + + uint256 opponentIdx = (idx % 2 == 1 ? idx-1 : idx + 1); + if (disputeRounds[round][opponentIdx].challengeStepCompleted == disputeRounds[round][idx].challengeStepCompleted ) { + // Our opponent answered this challenge already. + // Compare our intermediateReputationHash to theirs to establish how to move the bounds. + processBinaryChallengeSearchStep(round, idx, targetNode); + } + } + + function processBinaryChallengeSearchStep(uint256 round, uint256 idx, uint256 targetNode) internal { + uint256 opponentIdx = (idx % 2 == 1 ? idx-1 : idx + 1); + if ( + disputeRounds[round][opponentIdx].intermediateReputationHash == disputeRounds[round][idx].intermediateReputationHash && + disputeRounds[round][opponentIdx].intermediateReputationNNodes == disputeRounds[round][idx].intermediateReputationNNodes + ) + { + disputeRounds[round][idx].lowerBound = targetNode + 1; + disputeRounds[round][opponentIdx].lowerBound = targetNode + 1; + } else { + // NB no '-1' to mirror the '+1' above in the other bound, because + // we're looking for the first index where these two submissions differ + // in their calculations - they disagreed for this index, so this might + // be the first index they disagree about + disputeRounds[round][idx].upperBound = targetNode; + disputeRounds[round][opponentIdx].upperBound = targetNode; + } + // We need to keep the intermediate hashes so that we can figure out what type of dispute we are resolving later + // If the number of nodes in the reputation state are different, then we are disagreeing on whether this log entry + // corresponds to an existing reputation entry or not. + // If the hashes are different, then it's a calculation error. + + // Our opponent responded to this step of the challenge before we did, so we should + // reset their 'last response' time to now, as they aren't able to respond + // to the next challenge before they know what it is! + disputeRounds[round][opponentIdx].lastResponseTimestamp = now; + } + + function checkKey( uint256 round, uint256 idx, bytes memory _reputationKey) internal { + // If the state transition we're checking is less than the number of nodes in the currently accepted state, it's a decay transition (TODO: not implemented) + // Otherwise, look up the corresponding entry in the reputation log. + uint256 updateNumber = disputeRounds[round][idx].lowerBound - 1; + bytes memory reputationKey = new bytes(20+32+20); + reputationKey = _reputationKey; + address colonyAddress; + address userAddress; + uint256 skillId; + assembly { + colonyAddress := mload(add(reputationKey,20)) // 20, not 32, because we're copying in to a slot that will be interpreted as an address. + // which will truncate the leftmost 12 bytes + skillId := mload(add(reputationKey, 52)) + userAddress := mload(add(reputationKey,72)) // 72, not 84, for the same reason as above. Is this being too clever? I don't think there are + // any unintended side effects here, but I'm not quite confortable enough with EVM's stack to be sure. + // Not sure what the alternative would be anyway. + } + bool decayCalculation = false; + if (decayCalculation) { + } else { + require(reputationUpdateLog[updateNumber].user == userAddress); + require(reputationUpdateLog[updateNumber].colony == colonyAddress); + require(reputationUpdateLog[updateNumber].skillId == skillId); + } + } + + function proveBeforeReputationValue(uint256[9] u, bytes _reputationKey, bytes32[] reputationSiblings, bytes agreeStateReputationValue, bytes32[] agreeStateSiblings) internal { + bytes32 jrh = disputeRounds[u[U_ROUND]][u[U_IDX]].jrh; + uint256 lastAgreeIdx = disputeRounds[u[U_ROUND]][u[U_IDX]].lowerBound - 1; // We binary searched to the first disagreement, so the last agreement is the one before. + uint256 reputationValue; + assembly { + reputationValue := mload(add(agreeStateReputationValue, 32)) + } + + bytes32 reputationRootHash = getImpliedRoot(_reputationKey, agreeStateReputationValue, u[U_REPUTATION_BRANCH_MASK], reputationSiblings); + bytes memory jhLeafValue = new bytes(64); + bytes memory lastAgreeIdxBytes = new bytes(32); + assembly { + mstore(add(jhLeafValue, 0x20), reputationRootHash) + let x := mload(add(u, mul(32,3))) // 3 = U_AGREE_STATE_NNODES. Constants not supported by inline solidity + mstore(add(jhLeafValue, 0x40), x) + mstore(add(lastAgreeIdxBytes, 0x20), lastAgreeIdx) + } + // Prove that state is in our JRH, in the index corresponding to the last state that the two submissions + // agree on. + bytes32 impliedRoot = getImpliedRoot(lastAgreeIdxBytes, jhLeafValue, u[U_AGREE_STATE_BRANCH_MASK], agreeStateSiblings); + + if (reputationValue == 0 && impliedRoot != jrh) { + // This implies they are claiming that this is a new hash. + return; + } + require(impliedRoot == jrh); + // They've actually verified whatever they claimed. We increment their challengeStepCompleted by one to indicate this. + // In the event that our opponent lied about this reputation not existing yet in the tree, they will both complete + // a call to respondToChallenge, but we will have a higher challengeStepCompleted value, and so they will be the ones + // eliminated. + disputeRounds[u[U_ROUND]][u[U_IDX]].challengeStepCompleted += 1; + // I think this trick can be used exactly once, and only because this is the last function to be called in the challege, + // and I'm choosing to use it here. I *think* this is okay, because the only situation + // where we don't prove anything with merkle proofs in this whole dance is here. + } + + function proveAfterReputationValue(uint256[9] u, bytes _reputationKey, bytes32[] reputationSiblings, bytes disagreeStateReputationValue, bytes32[] disagreeStateSiblings) internal { + bytes32 jrh = disputeRounds[u[U_ROUND]][u[U_IDX]].jrh; + uint256 firstDisagreeIdx = disputeRounds[u[U_ROUND]][u[U_IDX]].lowerBound; + bytes32 reputationRootHash = getImpliedRoot(_reputationKey, disagreeStateReputationValue, u[U_REPUTATION_BRANCH_MASK], reputationSiblings); + // Prove that state is in our JRH, in the index corresponding to the last state that the two submissions + // agree on. + bytes memory jhLeafValue = new bytes(64); + bytes memory firstDisagreeIdxBytes = new bytes(32); + + assembly { + mstore(add(jhLeafValue, 0x20), reputationRootHash) + let x := mload(add(u, mul(32,5))) // 5 = U_DISAGREE_STATE_NNODES. Constants not supported by inline solidity. + mstore(add(jhLeafValue, 0x40), x) + mstore(add(firstDisagreeIdxBytes, 0x20), firstDisagreeIdx) + } + + bytes32 impliedRoot = getImpliedRoot(firstDisagreeIdxBytes, jhLeafValue, u[U_DISAGREE_STATE_BRANCH_MASK], disagreeStateSiblings); + require(jrh==impliedRoot, "colony-invalid-after-reputation-proof"); + } + + function performReputationCalculation(uint256[9] u, bytes agreeStateReputationValueBytes, bytes disagreeStateReputationValueBytes, bytes previousNewReputationValueBytes) internal { + // TODO: Possibility of decay calculation + uint reputationTransitionIdx = disputeRounds[u[U_ROUND]][u[U_IDX]].lowerBound - 1; + int256 amount; + uint256 agreeStateReputationValue; + uint256 disagreeStateReputationValue; + uint256 agreeStateReputationUID; + uint256 disagreeStateReputationUID; + + assembly { + agreeStateReputationValue := mload(add(agreeStateReputationValueBytes, 32)) + disagreeStateReputationValue := mload(add(disagreeStateReputationValueBytes, 32)) + agreeStateReputationUID := mload(add(agreeStateReputationValueBytes, 64)) + disagreeStateReputationUID := mload(add(disagreeStateReputationValueBytes, 64)) + } + + if (agreeStateReputationUID != 0) { + // i.e. if this was an existing reputation, then require that the ID hasn't changed. + // TODO: Situation where it is not an existing reputation + require(agreeStateReputationUID==disagreeStateReputationUID); + } else { + uint256 previousNewReputationUID; + assembly { + previousNewReputationUID := mload(add(previousNewReputationValueBytes, 64)) + } + require(previousNewReputationUID+1 == disagreeStateReputationUID); + // Flag that we need to check that the reputation they supplied is in the 'agree' state. + // This feels like it might be being a bit clever, using this array to pass a 'return' value out of + // this function, without adding a new variable to the stack in the parent function... + u[U_REQUIRE_REPUTATION_CHECK] = 1; + } + + // We don't care about underflows for the purposes of comparison, but for the calculation we deem 'correct'. + // i.e. a reputation can't be negative. + if (reputationUpdateLog[reputationTransitionIdx].amount < 0 && uint(reputationUpdateLog[reputationTransitionIdx].amount * -1) > agreeStateReputationValue ) { + require(disagreeStateReputationValue == 0); + } else if (uint(reputationUpdateLog[reputationTransitionIdx].amount) + agreeStateReputationValue < agreeStateReputationValue) { + // We also don't allow reputation to overflow + require(disagreeStateReputationValue == 2**256 - 1); + } else { + // TODO: Is this safe? I think so, because even if there's over/underflows, they should + // still be the same number. + require(int(agreeStateReputationValue)+reputationUpdateLog[reputationTransitionIdx].amount == int(disagreeStateReputationValue)); + } + } + + function checkPreviousReputationInState( + uint256[9] u, + bytes _reputationKey, + bytes32[] reputationSiblings, + bytes agreeStateReputationValue, + bytes32[] agreeStateSiblings, + bytes previousNewReputationKey, + bytes previousNewReputationValue, + bytes32[] previousNewReputationSiblings) + internal + { + uint256 lastAgreeIdx = disputeRounds[u[U_ROUND]][u[U_IDX]].lowerBound - 1; // We binary searched to the first disagreement, so the last agreement is the one before + + bytes32 reputationRootHash = getImpliedRoot(previousNewReputationKey, previousNewReputationValue, u[U_PREVIOUS_NEW_REPUTATION_BRANCH_MASK], previousNewReputationSiblings); + bytes memory jhLeafValue = new bytes(64); + bytes memory lastAgreeIdxBytes = new bytes(32); + assembly { + mstore(add(jhLeafValue, 0x20), reputationRootHash) + let x := mload(add(u, mul(32,3))) // 3 = U_AGREE_STATE_NNODES. Constants not supported by inline assembly + mstore(add(jhLeafValue, 0x40), x) + mstore(add(lastAgreeIdxBytes, 0x20), lastAgreeIdx) + } + // Prove that state is in our JRH, in the index corresponding to the last state that the two submissions agree on + bytes32 impliedRoot = getImpliedRoot(lastAgreeIdxBytes, jhLeafValue, u[U_AGREE_STATE_BRANCH_MASK], agreeStateSiblings); + require(impliedRoot == disputeRounds[u[U_ROUND]][u[U_IDX]].jrh); + } + + function saveProvedReputation(uint256[9] u, bytes previousNewReputationValue) internal { + uint256 previousReputationUID; + assembly { + previousReputationUID := mload(add(previousNewReputationValue,0x40)) + } + // Save the index for tiebreak scenarios later. + disputeRounds[u[U_ROUND]][u[U_IDX]].provedPreviousReputationUID = previousReputationUID; + } + + function checkJRHProof1(bytes32 jrh, uint branchMask1, bytes32[] siblings1) internal { + // Proof 1 needs to prove that they started with the current reputation root hash + bytes32 reputationRootHash = IColonyNetwork(colonyNetworkAddress).getReputationRootHash(); + uint256 reputationRootHashNNodes = IColonyNetwork(colonyNetworkAddress).getReputationRootHashNNodes(); + bytes memory jhLeafValue = new bytes(64); + bytes memory zero = new bytes(32); + assembly { + mstore(add(jhLeafValue, 0x20), reputationRootHash) + mstore(add(jhLeafValue, 0x40), reputationRootHashNNodes) + } + bytes32 impliedRoot = getImpliedRoot(zero, jhLeafValue, branchMask1, siblings1); + require(jrh==impliedRoot, "colony-invalid-jrh-proof-1"); + } + + function checkJRHProof2(uint round, uint index, bytes32 jrh, uint branchMask2, bytes32[] siblings2) internal { + // Proof 2 needs to prove that they finished with the reputation root hash they submitted, and the + // key is the number of updates in the reputation update log (implemented) + // plus the number of nodes in the last accepted update, each of which will have decayed once (not implemented) + // TODO: Account for decay calculations + uint256 nUpdates = reputationUpdateLog.length; + bytes memory nUpdatesBytes = new bytes(32); + disputeRounds[round][index].jrhNnodes = nUpdates + 1; + bytes32 submittedHash = disputeRounds[round][index].proposedNewRootHash; + uint256 submittedHashNNodes = disputeRounds[round][index].nNodes; + bytes memory jhLeafValue = new bytes(64); + assembly { + mstore(add(jhLeafValue, 0x20), submittedHash) + mstore(add(jhLeafValue, 0x40), submittedHashNNodes) + mstore(add(nUpdatesBytes, 0x20), nUpdates) + } + bytes32 impliedRoot = getImpliedRoot(nUpdatesBytes, jhLeafValue, branchMask2, siblings2); + require(jrh==impliedRoot, "colony-invalid-jrh-proof-2"); + + } + + function startMemberOfPair(uint256 roundNumber, uint256 index) internal { + disputeRounds[roundNumber][index].lastResponseTimestamp = now; + disputeRounds[roundNumber][index].upperBound = disputeRounds[roundNumber][index].jrhNnodes; + disputeRounds[roundNumber][index].lowerBound = 0; + disputeRounds[roundNumber][index].provedPreviousReputationUID = 0; + if (disputeRounds[roundNumber][index].jrh != 0x0) { + // If this submission has a JRH, we give ourselves credit for it in the next round - it's possible + // that a submission got a bye without submitting a JRH, which will not have this starting '1'. + disputeRounds[roundNumber][index].challengeStepCompleted = 1; + } else { + disputeRounds[roundNumber][index].challengeStepCompleted = 0; + } + } + + function startPairingInRound(uint256 roundNumber) internal { + uint256 nInRound = disputeRounds[roundNumber].length; + startMemberOfPair(roundNumber, nInRound-1); + startMemberOfPair(roundNumber, nInRound-2); + } +} diff --git a/src/lib/colonyNetwork/contracts/Resolver.sol b/src/lib/colonyNetwork/contracts/Resolver.sol new file mode 100644 index 0000000..3d40268 --- /dev/null +++ b/src/lib/colonyNetwork/contracts/Resolver.sol @@ -0,0 +1,40 @@ +/* + This file is part of The Colony Network. + + The Colony Network 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. + + The Colony Network 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 The Colony Network. If not, see . +*/ + +pragma solidity ^0.4.23; +pragma experimental "v0.5.0"; + +import "../lib/dappsys/auth.sol"; + + +contract Resolver is DSAuth { + mapping (bytes4 => address) public pointers; + + function register(string signature, address destination) public + auth + { + pointers[stringToSig(signature)] = destination; + } + + function lookup(bytes4 sig) public view returns(address) { + return pointers[sig]; + } + + function stringToSig(string signature) public pure returns(bytes4) { + return bytes4(keccak256(abi.encodePacked(signature))); + } +} diff --git a/src/lib/colonyNetwork/contracts/SafeMath.sol b/src/lib/colonyNetwork/contracts/SafeMath.sol new file mode 100644 index 0000000..25adddf --- /dev/null +++ b/src/lib/colonyNetwork/contracts/SafeMath.sol @@ -0,0 +1,49 @@ +/* + This file is part of The Colony Network. + + The Colony Network 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. + + The Colony Network 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 The Colony Network. If not, see . +*/ + +pragma solidity ^0.4.23; +pragma experimental "v0.5.0"; + + +library SafeMath { + function safeToAddInt(int a, int b) public pure returns (bool) { + return (b >= 0 && a + b >= a) || (b < 0 && a + b < a); + } + + function safeToSubInt(int a, int b) public pure returns (bool) { + return (b >= 0 && a - b <= a) || (b < 0 && a - b > a); + } + + function safeToMulInt(int a, int b) public pure returns (bool) { + return (b == 0) || (a * b / b == a); + } + + function addInt(int a, int b) public pure returns (int) { + require(safeToAddInt(a, b)); + return a + b; + } + + function subInt(int a, int b) public pure returns (int) { + require(safeToSubInt(a, b)); + return a - b; + } + + function mulInt(int a, int b) public pure returns (int) { + require(safeToMulInt(a, b)); + return a * b; + } +} \ No newline at end of file diff --git a/src/lib/colonyNetwork/contracts/Token.sol b/src/lib/colonyNetwork/contracts/Token.sol new file mode 100644 index 0000000..2f22ed4 --- /dev/null +++ b/src/lib/colonyNetwork/contracts/Token.sol @@ -0,0 +1,53 @@ +/* + This file is part of The Colony Network. + + The Colony Network 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. + + The Colony Network 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 The Colony Network. If not, see . +*/ + +pragma solidity ^0.4.23; +pragma experimental "v0.5.0"; + + +import "../lib/dappsys/auth.sol"; +import "../lib/dappsys/base.sol"; +import "./ERC20Extended.sol"; + + +contract Token is DSTokenBase(0), DSAuth, ERC20Extended { + bytes32 public symbol; + uint256 public decimals; + bytes32 public name; + + constructor(bytes32 _name, bytes32 _symbol, uint256 _decimals) public { + name = _name; + symbol = _symbol; + decimals = _decimals; + } + + function mint(uint wad) public + auth + { + _balances[msg.sender] = add(_balances[msg.sender], wad); + _supply = add(_supply, wad); + + emit Mint(msg.sender, wad); + } + + function burn(uint wad) public { + _balances[msg.sender] = sub(_balances[msg.sender], wad); + _supply = sub(_supply, wad); + + emit Burn(msg.sender, wad); + } +} \ No newline at end of file diff --git a/src/lib/colonyNetwork/contracts/gnosis/MultiSigWallet.sol b/src/lib/colonyNetwork/contracts/gnosis/MultiSigWallet.sol new file mode 100644 index 0000000..96fc10f --- /dev/null +++ b/src/lib/colonyNetwork/contracts/gnosis/MultiSigWallet.sol @@ -0,0 +1,370 @@ +pragma solidity ^0.4.15; + + +/// @title Multisignature wallet - Allows multiple parties to agree on transactions before execution. +/// @author Stefan George - +contract MultiSigWallet { + + /* + * Events + */ + event Confirmation(address indexed sender, uint indexed transactionId); + event Revocation(address indexed sender, uint indexed transactionId); + event Submission(uint indexed transactionId); + event Execution(uint indexed transactionId); + event ExecutionFailure(uint indexed transactionId); + event Deposit(address indexed sender, uint value); + event OwnerAddition(address indexed owner); + event OwnerRemoval(address indexed owner); + event RequirementChange(uint required); + + /* + * Constants + */ + uint constant public MAX_OWNER_COUNT = 50; + + /* + * Storage + */ + mapping (uint => Transaction) public transactions; + mapping (uint => mapping (address => bool)) public confirmations; + mapping (address => bool) public isOwner; + address[] public owners; + uint public required; + uint public transactionCount; + + struct Transaction { + address destination; + uint value; + bytes data; + bool executed; + } + + /* + * Modifiers + */ + modifier onlyWallet() { + require(msg.sender == address(this)); + _; + } + + modifier ownerDoesNotExist(address owner) { + require(!isOwner[owner]); + _; + } + + modifier ownerExists(address owner) { + require(isOwner[owner]); + _; + } + + modifier transactionExists(uint transactionId) { + require(transactions[transactionId].destination != 0); + _; + } + + modifier confirmed(uint transactionId, address owner) { + require(confirmations[transactionId][owner]); + _; + } + + modifier notConfirmed(uint transactionId, address owner) { + require(!confirmations[transactionId][owner]); + _; + } + + modifier notExecuted(uint transactionId) { + require(!transactions[transactionId].executed); + _; + } + + modifier notNull(address _address) { + require(_address != 0); + _; + } + + modifier validRequirement(uint ownerCount, uint _required) { + require(ownerCount <= MAX_OWNER_COUNT + && _required <= ownerCount + && _required != 0 + && ownerCount != 0); + _; + } + + /// @dev Fallback function allows to deposit ether. + function() + payable + { + if (msg.value > 0) + Deposit(msg.sender, msg.value); + } + + /* + * Public functions + */ + /// @dev Contract constructor sets initial owners and required number of confirmations. + /// @param _owners List of initial owners. + /// @param _required Number of required confirmations. + function MultiSigWallet(address[] _owners, uint _required) + public + validRequirement(_owners.length, _required) + { + for (uint i=0; i<_owners.length; i++) { + require(!isOwner[_owners[i]] && _owners[i] != 0); + isOwner[_owners[i]] = true; + } + owners = _owners; + required = _required; + } + + /// @dev Allows to add a new owner. Transaction has to be sent by wallet. + /// @param owner Address of new owner. + function addOwner(address owner) + public + onlyWallet + ownerDoesNotExist(owner) + notNull(owner) + validRequirement(owners.length + 1, required) + { + isOwner[owner] = true; + owners.push(owner); + OwnerAddition(owner); + } + + /// @dev Allows to remove an owner. Transaction has to be sent by wallet. + /// @param owner Address of owner. + function removeOwner(address owner) + public + onlyWallet + ownerExists(owner) + { + isOwner[owner] = false; + for (uint i=0; i owners.length) + changeRequirement(owners.length); + OwnerRemoval(owner); + } + + /// @dev Allows to replace an owner with a new owner. Transaction has to be sent by wallet. + /// @param owner Address of owner to be replaced. + /// @param newOwner Address of new owner. + function replaceOwner(address owner, address newOwner) + public + onlyWallet + ownerExists(owner) + ownerDoesNotExist(newOwner) + { + for (uint i=0; i + +## Steps to Reproduce (for bugs) + + +## Expected Behavior + + + +## Current Behaviour + + + +## Possible Solution + + + +## Context + + + +## Environment + +* Operating System: +* Ethereum client: +* solc version: \ No newline at end of file diff --git a/src/lib/colonyNetwork/docs/PULL_REQUEST_TEMPLATE.md b/src/lib/colonyNetwork/docs/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..8f36838 --- /dev/null +++ b/src/lib/colonyNetwork/docs/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,6 @@ + +Closes #[GH issue] +Implements [X] part for #[GH issue] + + + diff --git a/src/lib/colonyNetwork/docs/README.md b/src/lib/colonyNetwork/docs/README.md new file mode 100644 index 0000000..b524cb3 --- /dev/null +++ b/src/lib/colonyNetwork/docs/README.md @@ -0,0 +1,43 @@ + + +# The Colony Network +[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/JoinColony/colonyNetwork) +[![CircleCI](https://circleci.com/gh/JoinColony/colonyNetwork/tree/develop.svg?style=shield&circle-token=3091a867864d55d39aa8f4f552ecb2257376cb0f)](https://circleci.com/gh/JoinColony/colonyNetwork/tree/develop) +[![Greenkeeper badge](https://badges.greenkeeper.io/JoinColony/colonyNetwork.svg?token=12a1f49a1f7f9afa0b0af1370e6a4646c989cba0d90ec0d5b3872cb95c08facc&ts=1505828301742)](https://greenkeeper.io/) + +Contracts for running the Colony Network as defined in the [Colony White Paper](https://colony.io/whitepaper.pdf) + +## Install +``` +git clone https://github.com/JoinColony/colonyNetwork.git +cd colonyNetwork +yarn +git submodule update --init +``` + +## Contracts +The contract upgradability is using the EtherRouter pattern, see [Upgrades to the Colony Network](https://joincolony.github.io/colonynetwork/docs-upgrades-to-the-colony-network/) in the documentation for implementation details. + +The `math`, `erc20`, `auth`, `roles` and a significant part of the `token` contract have been reused from the [Dappsys library](https://github.com/dapphub/dappsys-monolithic). + +## Testing +To run all tests: +``` +yarn run test:contracts +``` +To run tests with code coverage using [solidity-coverage](https://github.com/sc-forks/solidity-coverage): +``` +yarn run test:contracts:coverage +``` +To lint contracts using [Solium](https://github.com/duaraghav8/Solium) +``` +yarn run solium +``` + +To lint JS using `eslint` (this is also a pre-commit hook) +``` +yarn run eslint +``` + +## Contributing +For details about how to contribute you can check the [contributing page](CONTRIBUTING.md) diff --git a/src/lib/colonyNetwork/docs/_Docs_Colony.md b/src/lib/colonyNetwork/docs/_Docs_Colony.md new file mode 100644 index 0000000..2f9bdbe --- /dev/null +++ b/src/lib/colonyNetwork/docs/_Docs_Colony.md @@ -0,0 +1,65 @@ +--- +title: Colony +section: Docs +order: 0 +--- + +Colony is a protocol for a new type of open, meritocratic organization that operates via software rather than paperwork and management hierarchy. + +A colony is a set of smart contracts on the Ethereum blockchain that contains all of the normal functions of a traditional firm, as well as some new functions that are only possible using a decentralized platform. Using the functions built into Colony, an organization can do: + +* Decision making +* Ownership +* Reputation +* Dispute resolution +* Work management and delegation +* Financial management + +The basic ideas of how Colony fits together are presented below. + +==TOC== + +## `Tasks` +The smallest conceptual unit within a Colony is a **task**. A task is a discrete unit of work which requires no further subdivision or delegation, and which can be evaluated as complete or incomplete based on some set of criteria. + +There is intentionally no further prescription for how a task is meant to be used within a colony. Depending on context and criteria, a task could be called a "bounty", a "salary", a "reimbursement", or an "incentive". + +At a minimum, a newly created task must be assigned a `domainId` and reference a specification for the task's completion, i.e. a description of the work to be done and how that work will be evaluated. + +[More about Tasks](/colonynetwork/docs-tasks/) + + +## `Reputation and Tokens` +In an organization of any type, reputation is an essential heuristic for people to keep track of each other's perceived merit in an environment of limited information. Reputation within Colony is meant to stay as close as possible to the concept of reputation as it is commonly understood. Reputation is a representation of _merit_, which in Colony implies an immutable record of contributions to a shared goal. + +In the Colony Protocol, **reputation** is a number that quantifies a particular individual’s influence, calculated from the sum of work that has been completed within the colony. + +Every Colony has its own **native token** which complements reputation. Tokens, when earned as a task payout, create reputation for the recipient. + +Tasks are expected to be funded with native tokens (thus awarding reputation), and/or payment tokens (which do not confer reputation). When a task is funded, the task awaits work completion and approval before paying out to a worker. + +Unlike a token, reputation cannot be transacted between accounts, and can only be gained or lost through the completion of tasks, the resolution of disputes, or participating in the reputation mining process. Reputation decays over time due to encourage frequent and regular engagement-- it has a half-life of ~3.5 months. + +Within a colony, both tokens and reputation are required in order to create tasks and domains, to raise objections or disputes, and to vote on the collective actions/decisions of the colony. + +It's up to each colony to decide how they use their token. Creators of a colony get to determine an initial `TokenSupplyCeiling` and `TokenIssuanceRate`. Depending on how these parameters are set and what the colony does, tokens could be valuable and bought/sold for a hefty price, or they could be ubiquitous and more of a symbolic gesture -- like an upvote. + +[More about Reputation and Tokens](/colonynetwork/docs-reputation/) + +## Domains and Skills +Domains and Skills are concepts that define a colony's organizational structure in a decentralized context, and allow for the division of labor without a strict management hierarchy. + +Domains are a structure for compartmentalizing the work and shared resources of a colony into smaller, more specialized sub-groups which are analogous to the departments of a traditional company. + +Skills are a similar structure that categorize the _type_ of work done, independent of the domain or colony in which the work took place. + +[More about Domains and Skills](/colonynetwork/docs-domains-and-skills/) + +## Pots +All funding within a colony resides in pots. Pots can be thought of as 'earmarked' funds for a specific purpose, and depending on context, might be called a bounty, a budget, working capital, or rewards. A colony will have many pots, but at a minimum will have one pot for rewards ( `pots[0]` ) and one for working capital ( `pots[1]` ). + +When domains (and tasks within those domains) are created, they each are assigned a newly created pot, which can then be funded with the `moveFundsBetweenPots` function. This action will eventually be mediated by a user's reputation score, but for now is merely permissioned based on the roles defined in `Authority.sol` (meaning only colony owners and admins may create new pots and move funds between pots). + +Every colony has a special pot, `pots[0]`, which accrues funds by taking a small percentage of colony revenue. Members of the colony may claim rewards from this pot based on the number of colony tokens they have. + +[More about Pots](/colonynetwork/docs-pots-and-funding/) diff --git a/src/lib/colonyNetwork/docs/_Docs_Disputes.md b/src/lib/colonyNetwork/docs/_Docs_Disputes.md new file mode 100644 index 0000000..de08b6c --- /dev/null +++ b/src/lib/colonyNetwork/docs/_Docs_Disputes.md @@ -0,0 +1,38 @@ +--- +title: Objections and Disputes +section: Docs +order: 7 +--- +The solution to collective decision making is usually voting, but Colony is designed for day to day operation of an organisation. Voting on every decision is wholly impractical. + +Colony is designed to be permissive. The [reputation system](/colonynetwork/docs-reputation/) mediates the extent to which members may influence a colony, but beyond that constraint, members are free to take executive action with most colony matters without any aproval from a management authority. + +In the event of disagreement, the Dispute system allows colony members to signal disapproval and potentially force a vote on decisions and actions that would otherwise have proceeded unimpeded. + +## Objections +When a member of a colony feels that something is amiss, they can _raise an objection_. By doing so, they are fundamentally proposing that a variable, or more than one variable, in the contract should be changed to another value. For this reason we call supporters of the objection the "change" side and opponents the "keep" side. + +The user raising the objection must put up a stake of colony tokens to back it up. In essence, they are challenging the rest of the colony to disagree with them. + +In raising an objection, the objector must provide the change to be made, as well as specify the Reputation that should vote on the issue. + +Objections pass *automatically* after three days if they are not opposed by other colony members, who must stake tokens on the "keep" side in order to _escalate_ the objection to become a _dispute_. + +## Disputes +>In Colony you cannot escalate a decision to higher management, you can only escalate to bigger groups of your peers. + +A dispute is settled by vote to "Change" or "Keep", within the domain and/or skill that was specified when the objection was raised. + +During the vote, any member with reputation in the named domain or skill may stake the "Change" or the "Keep" side with the colony's native token. + +At the conclusion of the poll, losing stakers receive some of their staked tokens back and they lose the complementary percentage of the reputation that was required to stake. The exact amount of tokens they receive back (and therefore reputation they lose) is based on: +* The fraction of the reputation in the colony that voted. +* How close the vote ultimately was. + +At the end of a vote, if the vote was very close, then the losing side receives nearly 90% of their stake back. If the vote is lopsided enough that the winning side’s vote weight reaches a landslide threshold of the total vote weight, then they receive 0% of their staked tokens back. + +The motivation here is efficiency — it aims to discourage spurious objections and disputes. A close vote is a sign that the decision was not a simple one and forcing a vote may have been wise. Therefore, the instigators of the dispute should not be harshly punished. On the other hand, if a vote ended in a landslide, it is a sign that the losing side was going up against a general consensus. + +We encourage communication within the colony. Members should be aware of the opinions of their peers whenever possible before disputes are invoked. + +Complete details of the dispute mechanism can be found in the [Colony Whitepaper](https://colony.io/whitepaper.pdf) in section 9.2 diff --git a/src/lib/colonyNetwork/docs/_Docs_DomainsSkills.md b/src/lib/colonyNetwork/docs/_Docs_DomainsSkills.md new file mode 100644 index 0000000..3bc653a --- /dev/null +++ b/src/lib/colonyNetwork/docs/_Docs_DomainsSkills.md @@ -0,0 +1,47 @@ +--- +title: Domains and Skills +section: Docs +order: 5 +--- + +Domains and Skills are concepts that define a colony's organizational structure in a decentralized context, and allow for the division of labor without a strict management hierarchy. + +Domains are a structure for compartmentalizing the work and shared resources of a colony into smaller, more specialized sub-groups which are analogous to the departments of a traditional company. + +Skills are a similar structure that categorize the _type_ of work done, independent of the domain or colony in which the work took place. + +==TOC== + +## Domains +Like a file system that contains files and sub-folders, any domain can contain tasks, sub-domains, or both. + +![Example Domains](https://raw.githubusercontent.com/JoinColony/colonyNetwork/develop/docs/img/domains_r1.svg?sanitize=true) + +With the exception of the top-level colony domain, which contains all tasks and sub-domains, every domain in a colony belongs to a larger parent domain. + +Every domain has an associated [pot](/colonynetwork/docs-pots-and-funding/) which can receive funding (in most circumstances from the parent domain's pot). + + +Tasks are tagged with a `DomainId` that specifies which domain they belong to. When a member of a colony earns native tokens as a result of a completed task (Managers, Workers, and Evaluators all earn reputation from task completion), they earn reputation in that domain as well as all parent domains, including the colony-wide domain. They do not earn any reputation in child domains. + +A well-organized domain hierarchy is one way to isolate and compartmentalize work within a colony: Reputation mediates the flow of funding from parent domains to their children (see [pots](/colonynetwork/docs-pots-and-funding/) for more about funding), which may in turn direct funding toward smaller and more specialized or specific child domains or tasks. + +## Skills +Skills do not exist within a particular colony, but instead are a single structure available to all colonies on the network. The global skill hierarchy is maintained by [The Meta Colony](/colonynetwork/docs-the-meta-colony-and-clny/). + +Tasks are tagged with a `SkillId` that specifies a skill from the global skill hierarchy. When a member of a colony earns native tokens for completing a task, they earn reputation in the skill, as well as all parent skills. They do not earn any reputation in child skills. + +Even though the global set of Skills is shared by all colonies, reputation earned in a particular skill only affects an individual's influence over the colony in which the reputation was earned. + +Skill tags are meant to provide a more fine-grained categorization of work than domains, allowing for tasks within the same domain to be further differentiated. + +## Disputes +Domains and Skills determine the scope of voting in the event of a dispute or collective decision. + +In Colony you cannot escalate a decision to higher management, you can only escalate to bigger groups of your peers. Domains and Skills mediate this behavior. + +When an objection is raised, the objector must specify at least one domain or skill which should vote on the issue in the event of a dispute. All members within the specified domain/skill will then carry out a reputation-weighted vote to settle the dispute. If the results of the vote are disagreeable to a sufficient amount of collective reputation, the dispute may be escalated to a parent domain and/or skill with a subsequent round of objection/dispute. + +Because of the recursively-awarded reputation in parent domains/skills, an individual will always have the same absolute voting power as a dispute is escalated, but of course will have diminishing proportional voting power as the dispute involves more and more participants. + +See [Objections and Disputes](/colonynetwork/docs-objections-and-disputes/) for more information about the dispute resolution process. diff --git a/src/lib/colonyNetwork/docs/_Docs_GetStarted.md b/src/lib/colonyNetwork/docs/_Docs_GetStarted.md new file mode 100644 index 0000000..b86a0c0 --- /dev/null +++ b/src/lib/colonyNetwork/docs/_Docs_GetStarted.md @@ -0,0 +1,88 @@ +--- +title: Get Started +section: Docs +order: 2 +--- + +The Colony Network contracts are moving toward being live on `testnet`, but in the mean time you will need to run your own version for testing and development. + +## Set Up and Deploy the colonyNetwork contracts + +### Install +See the colonyNetwork [README.md](https://github.com/JoinColony/colonyNetwork#install) for detailed instructions. + +You'll need the latest versions of all the colonyNetwork contracts ready to deploy: + +``` +~$ git clone https://github.com/JoinColony/colonyNetwork.git + +~$ cd colonyNetwork/ + +~$ yarn + +~$ git submodule update --init +``` + +This should install all the bare-bones tools and scripts you can use to start testing! + +To deploy all contracts and run all tests: +``` +~$ yarn run test:contracts + +``` + +Alternatively, you can start a local test node and deploy the contracts yourself (using the locally installed `truffle`): +``` +~$ yarn run start:blockchain:client + +~$ ./node_modules/.bin/truffle migrate --reset --compile-all +``` + +For more detailed instructions, and additional steps required to set up an environment for use with colonyJS, refer to the [colonyJS get started doc](/colonyjs/docs-get-started/). + +## Set Up Reputation Mining for Local Testing + +The Reputation Mining client is usable for testing, but has a limited functionality. It currently has no support for the challenge-response process to accommodate multiple submitted Reputation Root Hashes. Still, it is possible to run a single miner instance for usable reputation scores on a testnet. + +### Start the Mining Client + +Start the mining client with: + +``` +node packages/reputation-miner/bin/index.js --file ./reputations.json --colonyNetworkAddress 0x76d508fa65654654ffdb334a3023353587112e09 --minerAddress 0xb77d57f4959eafa0339424b83fcfaf9c15407461 +``` + +The `minerAddress` in the execution above is the first account in `ganache-accounts.json`. + +The `colonyNetwork` address in the execution above is not the address outputted at contract deployment, but is the address of the Colony Network `EtherRouter`. See [Upgrades to the Colony Network](/colonynetwork/docs-upgrades-to-the-colony-network/) for more information about the EtherRouter design pattern. + + +### Force Reputation Updates +The client is set to provide a reputation update once per hour. For testing, you'll likely want to 'fast-forward' your network through a few submissions to see usable reputation. + +Move the network forward by an hour with: +``` +$ curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"evm_increaseTime","params":[3600],"id": 1}' localhost:8545 +``` +And mine a new block: +``` +$ curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"evm_mine","params":[]}' localhost:8545 +``` + +Note that because reputation is awarded for the *previous* submission window, you will need to use the 'fast-forward' commands above to speed through at least 3 reputation updates before noticing a change in the miner's reputation. + +### Get Reputation from the Reputation Oracle +The mining client will answer queries for Reputation scores locally over HTTP: +``` +http://127.0.0.1:3000/{colonyAddress}/{skillId}/{userAddress} +``` + +For example, you can get the reputation score of the miner using the address of the Meta Colony (`0xdb8fe93a3a9c97f04f5c862f52a84f992bd331df`), the skill tag of `0`, and the address of the miner (0xb77d57f4959eafa0339424b83fcfaf9c15407461): +``` +http://127.0.0.1:3000/0xdb8fe93a3a9c97f04f5c862f52a84f992bd331df/0/0xb77d57f4959eafa0339424b83fcfaf9c15407461 +``` + +The oracle should return something like this: +``` +{"branchMask":"0x00","siblings":[],"key":"0xdb8fe93a3a9c97f04f5c862f52a84f992bd331df0000000000000000000000000000000000000000000000000000000000000000b77d57f4959eafa0339424b83fcfaf9c15407461","value":"0x0000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000001","reputationAmount":"1000000000000000000"} +``` diff --git a/src/lib/colonyNetwork/docs/_Docs_Glossary.md b/src/lib/colonyNetwork/docs/_Docs_Glossary.md new file mode 100644 index 0000000..acb4b5f --- /dev/null +++ b/src/lib/colonyNetwork/docs/_Docs_Glossary.md @@ -0,0 +1,62 @@ +--- +title: Glossary of Terms +section: Docs +order: 11 +--- + +==TOC== + +### CLNY +The Native Token of the Meta Colony. CLNY is staked in the reputation mining process. + +### Dispute +An objection to an objection triggers a dispute, which must be resolved through a reputation-weighted vote within the domain that the objection was initially raised. + +### Domain +A category for organizing tasks, skills, and pots within a Colony. Domains can be thought of as 'departments' or 'divisions' within the larger organizational whole. + +### Funding Pots +All funding within a colony resides in pots. Pots can be thought of as 'earmarked' funds for a specific purpose, and depending on context, might be called a bounty, a budget, working capital, or rewards. A colony will have many pots, but at a minimum will have one pot for rewards ( `pots[0]` ) and one for working capital ( `pots[1]` ). + +### Meta Colony +The Meta Colony is “the Colony colony” — its remit is to develop, support, and grow the Colony Network. Every colony on the public network needs the Meta Colony, and everyone may be a member. + +### Native Token +A token chosen by a colony which confers reputation when paid out as a task bounty. The Native token together with reputation is used for vote-weighting and calculating rewards payouts. + +### Objection +A statement by a member of a colony that proposes some variable in the contracts of the colony should be changed to another state. To raise an objection, a colony member is required to put up a stake of native tokens. If another member opposes an objection, they may stake tokens to elevate the objection to become a dispute. Otherwise, the objection will pass automatically after a defined period of time. + +### Reputation +A number associated with an account which attempts to quantify the merit of a user’s recent contributions to a colony. Reputation is used to weight a user’s influence in decisions related to the expertise they have demonstrated, and to determine amounts owed to a colony’s members when rewards are disbursed. + +Unlike tokens, reputation cannot be transferred between addresses; it must be earned by direct action within the colony. Reputation that is earned will eventually be lost through inactivity (decay), error, or malfeasance. + +### Reputation Mining +The calculations involved in maintaining the entire state of reputation amongst all accounts on the Colony Network are far too complex to be performed on-chain. Instead, reputation is calculated off-chain and periodically put on-chain by CLNY holders in a process resembling a proof-of-stake blockchain protocol -- engaging in the process of updating the global state of reputation for the Colony Network is called "Reputation Mining". + +### Rewards +When a colony earns Ether or other currencies as revenue, the revenue distribution system allocates some of them to be claimed as rewards. In particular, the special triggering transaction takes any such revenue that has accumulated since the last such transaction, and makes 99% available to the colony as working capital, while the remaining 1% is used to pay out rewards to users that hold both colony tokens and reputation in the colony. + +### Role +A task has 3 roles associated with it: +* A Manager - someone responsible for defining and coordinating the delivery of the task. +* An Evaluator - someone responsible for assessing whether the work has been completed satisfactorily. +* A Worker - someone responsible for executing the task. + +### Skills +Skills are a global hierarchy of tags that can be assigned to any task. Tagging a task with a skill allows for a more granular account of the work a user completes to earn their reputation. + +The Meta Colony curates the hierarchy of global skill tags. + +### Task +A discrete unit of work which requires no further subdivision or delegation, and which can be evaluated as complete or incomplete based on some set of criteria. + +### Token Issuance Rate +The rate at which new native tokens are minted and made available to fund tasks. A higher rate could result in an inflated supply and perhaps diminishing value per-token. + +### Token Supply Ceiling +An upper bound on the total supply of a token. + +### Work Specification +A description of the work to be done for a task. In the `colonyNetwork` contracts, the work specification is pointed to by a hash, and stored off-chain. diff --git a/src/lib/colonyNetwork/docs/_Docs_MetaColony.md b/src/lib/colonyNetwork/docs/_Docs_MetaColony.md new file mode 100644 index 0000000..388c7d1 --- /dev/null +++ b/src/lib/colonyNetwork/docs/_Docs_MetaColony.md @@ -0,0 +1,25 @@ +--- +title: The Meta Colony and CLNY +section: Docs +order: 8 +--- + +The Meta Colony is “the Colony colony” — its remit is to develop, support, and grow the Colony Network. + +Every colony on the public network needs the Meta Colony, and everyone may become a member. + +The Meta Colony has special permissions, including the ability to add, remove, or modify the skill tags used by all colonies on the Colony Network. + +## CLNY +CLNY is the Token of “The Meta Colony”. + +Just like in a "normal" colony, accounts holding both CLNY and Reputation in the Meta Colony may claim a share of the revenue of the Meta Colony proportional to combined Reputation and CLNY holdings. + +CNLY is required as a stake to participate in [Reputation Mining](/colonynetwork/docs-reputation-mining/). Miners earn a reward in CLNY, as well as reputation within the Meta Colony tagged with a special 'mining' skill. + +## Revenue and Rewards +The Meta Colony, as custodian of the Colony Network, collects a small fee every time a user claims a payout from a task. If the task payout is in a token other than whitelisted ones such as Ether or Dai, the token is sent to an auction contract, and the proceeds are sent to the Meta Colony. + +This idea of a fee is a little unusual for such a decentralized system. One of the appeals of Ethereum is that other than gas costs, platforms do not generally seek rent and are free to use. However, the Network Fee is vital in ensuring the game theoretic security of the Colony Network’s reputation mining and governance processes by providing underlying value to the CLNY held by Meta Colony members. + +Importantly, this fee is not payable to any centrally controlled entity, but rather to the Meta Colony. Anybody may contribute to the Meta Colony and claim a share of these fees proportional to their contribution. We believe that the benefit of being part of a secure, well supported network will ultimately be appealing enough that a small fee to pay for its existence will be acceptable. diff --git a/src/lib/colonyNetwork/docs/_Docs_NetworkOverview.md b/src/lib/colonyNetwork/docs/_Docs_NetworkOverview.md new file mode 100644 index 0000000..546a39a --- /dev/null +++ b/src/lib/colonyNetwork/docs/_Docs_NetworkOverview.md @@ -0,0 +1,35 @@ +--- +title: The Colony Network +section: Docs +order: 1 +--- + +The Colony Network, at a high level, is a collection of smart contracts on the Ethereum blockchain. + +The contracts that comprise the Colony Network provide a standard framework for the creation of decentralized organizations as described in the [Colony Whitepaper](https://colony.io/whitepaper.pdf). + +In addition to the core business logic of all colonies, the Colony Network contains several contracts that mediate low-level transactions and permissions on the blockchain, such as [upgradability](/colonynetwork/docs-upgrades-to-the-colony-network/), as well as contracts which manage functionality of the network as a whole, including interactions with the reputation system and the creation of new colonies. + +The Colony Network is maintained and improved by [The Meta Colony](/colonynetwork/docs-the-meta-colony-and-clny/). + +Developers interested in contributing to the Colony Network are encouraged to look at the code on [GitHub](https://github.com/JoinColony/colonyNetwork), and to come say hi on [Gitter](https://gitter.im/JoinColony/colonyNetwork). Please have a look at our [contribution guidelines](https://github.com/JoinColony/colonyNetwork/blob/develop/docs/CONTRIBUTING.md) as well. + +## Interface Contracts +The full collection of Colony Network contracts can be inspected on [GitHub](https://github.com/JoinColony/colonyNetwork). Once deployed, however, the publically available functions for interacting with the Colony Network are aggregated into two Interface contracts: + +* `IColony.sol` contains the functions that pertain to a particular colony, including the creation of tasks, funding, and work ratings. + +* `IColonyNetwork.sol` contains the functions that pertain to the network as a whole, such as the global hierarchy of skill tags and interactions with the reputation mining client. + +* `IReputationMiningCycle.sol` contains the functions that pertain to the reputation mining system, such as submission of a reputation root hash, staking, and initiating the challenge process. + +## First Version +The first deployed version of the Colony Network will have a more modest functionality than what is described in these pages and in the whitepaper. This is intended to allow further development for finished contracts to be informed by real user experiences and testing while new features are being developed for future iterations of the network. + +The major differences between the planned first release and the system described in the whitepaper are: + +* Domains within a colony will be restricted to a single level. +* Voting, Objections, and Dispute resolution will not be included. +* Task creation does not require reputation, and tasks ratings still use a 5 point system (the 3 point system will be implemented when colonyNetwork#161 is merged) + +Subsequent versions of the Colony Network will add functionality (working toward a complete implementation of the whitepaper), and all deprecated versions will remain fully supported by the network after an upgrade. See [upgrades](/colonynetwork/docs-upgrades-to-the-colony-network/) for more information. diff --git a/src/lib/colonyNetwork/docs/_Docs_Pots.md b/src/lib/colonyNetwork/docs/_Docs_Pots.md new file mode 100644 index 0000000..c0dfaac --- /dev/null +++ b/src/lib/colonyNetwork/docs/_Docs_Pots.md @@ -0,0 +1,46 @@ +--- +title: Pots and Funding +section: Docs +order: 6 +--- +All funding within a colony resides in pots. To each pot, a colony can associate any number of unassigned tokens it holds. Pots can be thought of as 'earmarked' funds for a specific purpose, and depending on context, might be called a bounty, a budget, working capital, or rewards. + +Assigning funding to pots is purely a bookkeeping mechanism for a colony. From the perspective of the blockchain, ether and tokens are held by the colony contract until they are paid out when a task is completed. + +==TOC== + +## Types of Pots +A colony will have many pots, but at a minimum will have one pot for rewards ( `pots[0]` ) and one for working capital ( `pots[1]` ), both of which are associated with the colony-wide domain. + +### Rewards +Every colony has a special pot, `pots[0]`, which accrues funds by taking a small percentage of colony revenue. Members of the colony may claim rewards from this pot based on the number of colony tokens they have. + +When funds are sent to a colony as revenue, they must be put into the working capital pot before they can be further distributed to relevant sub-domains. In doing so, 1% of the revenue is siphoned off and put into the _rewards_ pot. + +When triggered, the rewards pot disburses to all members of the colony that have *both* tokens and reputation. Rewards are limited to the (normalized) geometric average of token holdings and reputation score (read more about the rewards formula in section 10.2 of the colony whitepaper). + +The rewards mechanism maximizes payout for individuals who both contribute meaningful work to the colony (evidenced by their reputation), and who maintain 'skin in the game' (evidenced by their unsold token holdings). + +### Domain Funding +When new domains are created, they each are assigned a newly created pot, which can then be funded from the parent domain (see 'Funding Proposals' below). Pots associated with domains may only pay out to other pots. + +### Task Funding +Each task created within a domain also has its own pot, which is funded from the domain to which the task belongs. Pots associated with tasks may only pay out to the individuals associated with the task (the Manager, Evaluator, and Worker of the task). + +## Funding Proposals +Funding proposals are the mechanism that mediates the flow of funds between pots. Funding proposals are created by any user with sufficient reputation to stake in the relevant domain. + +Funding proposals can be one of two types: Basic Funding Proposals (BFPs), or Priority Funding Proposals (PFPs). + +_Basic Funding Proposals_ are immediately active upon creation, but are restricted to funding pots which are direct descendants of the source. In other words, the `From` pot must be a parent of the `To` pot. BFPs also have an upper limit on the rate funds can be moved. + +_Priority Funding Proposals_ must be explicitly voted on before it starts directing funds, but may move funds from any pot to any other pot within a colony, at any rate, so long as there is consensus in the relevant domain. + +### The Funding Queue +In normal circumstances, funding should flow naturally from the pots of general, top-level domains toward more specific and focused sub-domains and tasks through the use of Basic Funding Proposals (BFPs). + +Any user with sufficient reputation may create a BFP. Once created, the BFP is `active`, and is placed in a _Funding Queue_ associated with the `From` pot. + +All funding proposals in the same _Funding Queue_ are ranked according to the reputation that is 'backing' the proposal, which may come from multiple users. The greater the reputation backing the proposal, the closer to the top the proposal sits. + +To mitigate possible manipulation and attack, only the top proposal in the queue is funded at any given time. This allows for other members to halt malicious funding proposals with an objection before too many funds can be taken. diff --git a/src/lib/colonyNetwork/docs/_Docs_Reputation.md b/src/lib/colonyNetwork/docs/_Docs_Reputation.md new file mode 100644 index 0000000..eee8d06 --- /dev/null +++ b/src/lib/colonyNetwork/docs/_Docs_Reputation.md @@ -0,0 +1,53 @@ +--- +title: Reputation +section: Docs +order: 4 +--- + +In an organization of any type, reputation is an essential heuristic for people to keep track of each other's perceived merit in an environment of limited information. Reputation within Colony is meant stay close to the concept of reputation as it is commonly understood. Reputation is a representation of _merit_, which in Colony implies an immutable record of contributions to a shared goal. + +In the Colony Protocol, **reputation** is a number that quantifies a particular individual’s influence, calculated from the sum of work that has been completed within the colony. + +Every Colony has its own **native token** which complements reputation. Tokens, when earned as a task payout, create reputation for the recipient. + +The Reputation System in Colony is a tool for governance in a decentralized context: It allows for members of an organization to have different amounts of influence over the organization, without the use of a management hierarchy or frequent voting. + +Reputation confers influence in a colony by mediating a member's ability to adjust various aspects of the organization. Whether it is the ability to move funds to fund tasks, to create new domains and skills, or to settle disputes, reputation determines influence by degrees. + +==TOC== + +## Gaining and Losing Reputation +Unlike a token, reputation cannot be transacted between accounts. Reputation can only be gained or lost through interactions with other members of a colony. + +### Completing Tasks +The most straightforward way of gaining reputation is by completing tasks within the colony. Tasks funded with native tokens generate reputation for their recipient upon payout. + +The amount of reputation gained or lost through a task is determined by the task's rating: + * *1 point*. User was unable to complete the task. Reputation penalty equal to the token payout. + * *2 points*. User completed the task acceptably. Reputation gain equal to the token payout. + * *3 points*. User completed the task to a higher standard than requested. Reputation gain equal to 1.5 × the token payout. + +When a payout is received for the completion of a task, reputation is awarded within the task's domain, as well as all its parent domains. If the task is tagged with a skill, reputation is awarded in the skill, as well as all its parent skills. + +See [Tasks](/colonynetwork/docs-tasks/) for more information about the task workflow and ratings. + +### Staking Reputation +Almost every interaction with a colony requires that the user stake some amount of reputation. How much reputation is required to stake depends on how important the interaction is. Actions like the creation and funding of tasks require a nominal amount of reputation, while things like creating a new domain require comparatively more. + +Staked reputation has the potential to be both lost and gained in the event of an objection or a dispute. + +If an objection to any action is raised by another member, the reputation stake is given to the objector (objections pass automatically if they are not challenged). + +If an objection is escalated to a dispute, a reputation-weighted vote is called within the objection's domain, in which both sides must stake reputation. The amount of reputation gained/lost by each side is determined by the vote's outcome ('landslide' outcomes punish the losing side harshly, while more contentious decisions have only small penalties for the losing side). + +See [Objections and Disputes](./docs-disputes/) for more information about reputation-weighted voting and the dispute resolution process. + +### Reputation Bootstrapping +After a colony is created, reputation can only be gained and lost through normal interactions within a colony. But at the colony's beginning, we are presented with a bootstrapping problem: When a colony is new, no-one has yet completed any work in it and so nobody will have earned any reputation. + +During a colony's creation, the creator of the colony is granted the ability to designate an initial set of addresses to receive native tokens and an equivalent amount of reputation. Users receiving reputation are presumably the colony creator and their colleagues, and this starting reputation should be seen as a representation of the existing trust within the team. + +## Reputation Decay +One of the unique characteristics of reputation is that it decays over time. This is meant to incentivise frequent and consistent contributions to a colony, and to ensure that reputation represents _recent_ contributions. + +Every 600000 blocks, a user’s reputation in every domain or skill decays by a factor of 2. This implies a 'reputation half-life' of about 3.5 months. diff --git a/src/lib/colonyNetwork/docs/_Docs_ReputationMining.md b/src/lib/colonyNetwork/docs/_Docs_ReputationMining.md new file mode 100644 index 0000000..c55d7ee --- /dev/null +++ b/src/lib/colonyNetwork/docs/_Docs_ReputationMining.md @@ -0,0 +1,63 @@ +--- +title: Reputation Mining +section: Docs +order: 9 +--- + +This is an overview of the process by which Reputation scores in Colony are maintained. + +For a complete description of the Reputation Mining process, see the [whitepaper](https://colony.io/whitepaper.pdf) + +# Rationale for off-chain Reputation +Events in Colony that affect reputation are numerous and expected to be frequent. The calculations for global reputation updates would be unreasonable to perform on-chain. However, Reputation doesn't *need* to be on-chain, because reputation is entirely deterministic and calculated from on-chain events. + +So, rather than calculating reputation scores on-chain, users submit to the colony contract a transaction which contains their score, together with a proof that the score is consistent with the global state of reputation. + +## Reputation Mining Overview +The process of maintaining consensus over the global state of reputation is called *Reputation Mining*. + +Reputation Mining resembles a proof-of-stake blockchain consensus protocol. Miners must put up a stake of the network token, CLNY, to participate in the reputation mining process, whereby the global state of reputation is calculated off-chain and submitted to the blockchain as a `reputationRootHash`. In the case of honest submissions, the miner is rewarded reputation in the Meta Colony tagged with a special 'mining' skill. In the event of malicious activity, miners with false submission is punished by losing her stake. + + +### Reputation Updates +One feature of reputation that distinguish it from a token or cryptographic asset is that reputation cannot be transferred between accounts through a voluntary transaction. Rather, it is a number associated with an address, calculated from a well-defined set of on-chain events. + +Reputation within a specific colony can only be earned and lost by completing tasks within the colony, through the [objections and disputes mechanism](/colonynetwork/docs-objections-and-disputes/), and in the case of the Meta Colony, through participation in the reputation mining process. + +### Reputation Root Hashes +Using a [Patricia Tree](https://github.com/ethereum/wiki/wiki/Patricia-Tree), all updates to the global state of reputation are maintained on-chain with a single "Reputation Root Hash". + +The Reputation Root Hash is effectively a fingerprint for the network state (of reputation). It is calculated off-chain, but it represents the collection of all reputation-updating events that have occured on the network, and even a single discrepancy in the complete history of reputational updates will result in a different Root Hash. + + +## The Reputation Mining Cycle +Reputation mining is a cyclic process in which multiple actors compete to verify the global reputation state. + +The process works on an “innocent until proven guilty” principle: Although it’s infeasible for a valid hash to be proven true on-chain, it’s relatively straightforward for an invalid hash to be proven false. In the event that two submitted hashes differ, the false one can be fleshed out through an automated challenge process *on-chain* that will eventually zero in on the exact on-chain events that differ between any two submitted hashes. + +The reputation system depends on having at *at least one* honest submission per cycle (as opposed to at least 51% of submissions as is the case in proof-of-work mining). + +### Submissions +Each cycle begins with a submission window, in which all miners compete to submit a correct Root Hash to the network. The Root Hash must be calculated from the events stored in a Reputation Update Log, which contains a fixed list of updates to global reputation logged during the previous mining cycle. + +A miner is eligible to submit a new Root Hash only if they stake an amount of CLNY. The amount of CLNY staked determines the number of times a miner can submit a Root Hash to the network during each submission window. Thus the greater the stake, the greater the likelihood that a miner will receive rewards from a successful submission. + +### Challenges +The complete challenge-response protocol is described in section 7.5.1 of the [Colony whitepaper](https://colony.io/whitepaper.pdf). + +For the sake of legibility, the general process has been simplified below to describe a situation in which only two miners are participating in the challenge process, with one of them being a malicious actor: + +If two different root hashes are submitted, it is assumed that one submission is honest. Therefore, one submission is false, and the miner that submitted an invalid hash must be punished. + +In whichever submission is false, there must be one or more reputation update(s) inconsistent with the global state of reputation up until the current submission window. + +Miners can submit a justification to the network that shows how a reputation update results in a Root Hash consistent with the last agreed upon Root Hash (of the previous cycle), and they can do so for each reputation update in the current cycle. + +Both miners must provide such a justification to the network for each historical update until the discrepancy is found, at which point the correct hash can be calculated *on-chain*. + +Whichever miner is found to have performed the calculation incorrectly is punished by losing some of their CLNY stake. + +### Acceptance +When a new Root Hash is accepted by the network, its corresponding Reputation Update Log is deleted from on-chain memory. + +All reputation events that occurred during the current cycle are 'frozen' as the new Reputation Update Log to be used by miners in the next cycle. diff --git a/src/lib/colonyNetwork/docs/_Docs_Tasks.md b/src/lib/colonyNetwork/docs/_Docs_Tasks.md new file mode 100644 index 0000000..ff09f2c --- /dev/null +++ b/src/lib/colonyNetwork/docs/_Docs_Tasks.md @@ -0,0 +1,67 @@ +--- +title: Tasks +section: Docs +order: 3 +--- +The smallest conceptual unit within a Colony is a **task**. A task is a discrete unit of work which requires no further subdivision or delegation, and which can be evaluated as complete or incomplete based on some set of criteria. + +There is intentionally no further prescription for how a task is meant to be used within a colony. Depending on context and criteria, a task could be called a "bounty", a "salary", a "reimbursement", or an "incentive". + + +==TOC== + +### Task structure + +This is a general description of the Task as it functions in the current Colony Network implementation, with some aspects suppressed for legibility. For a more exact description, please refer to the [colonyJS API](../../colonyjs/api-colonyclient/) or [IColony.sol](https://github.com/JoinColony/colonyNetwork/blob/develop/contracts/IColony.sol). + +| component | description | +|------------|---------| +|Brief or Specification|A reference for a description of the work to be done.| +|Deliverable |A reference for the work done to complete the task.| +|Due Date |A due date for the submission of task deliverables.| +|Payouts |A payout for the task upon successful completion, for each of the MANAGER, EVALUATOR, and WORKER roles.| +|Domain|The task's associated domain.| +|Skill tags |Any skills associated with the task.| + +### Roles +Every task has three roles associated with it which determine permissions for editing the task, submitting work, and ratings for performance. In the `colonyNetwork` contracts, the roles are represented as 8-bit numbers to keep permission logic simple. + +| Role [`role Id`]| Description | +|------|------| +|Manager [`0`]| A task's Manager role is by default the creator of the task, and usually expected to be the person to accept the task as complete when the work is done. +|Evaluator [`1`]| A task's Evaluator role is a person who will independently establish the quality of the work done by the Worker. +|Worker [`2`]| A task's Worker role is the person who will fulfill the requirements of the task as specified in the task brief. + +## The Task Life-cycle + +### Create +A newly created task must be assigned to a domain and must reference a specification for the task's completion, i.e. a description of the work to be done and how that work will be evaluated. + +### Modify +Once created, the task may be modified to include additional data. This could be setting the task's due date, payouts for completion, or skill tag(s). + +Important changes to a task must be approved by multiple people. Task changes requiring two signatures are: +* Changing the task Brief (Manager and Worker) +* Changing or setting the task Due Date (Manager and Worker) +* Changing or setting the Worker's payout (Manager and Worker) +* Changing or setting the Evaluator's payout (Manager and Evaluator) + +At any time before a task is finalized, the task can be canceled, which allows any funding to be returned to the colony and halts any further modification of the task. + +### Rate +After the work has been submitted (or the due date has passed), the work rating period begins. + +Task payouts are determined by work rating, which is currently implemented as "5-star" system, but which will change to a "3-star" system in the future. + +* The Evaluator reviews the work done and submits a rating for the Worker. +* The Worker considers the task assignment and submits a rating for the Manager. + +Because work ratings are on-chain, they follow a _*Commit* and *Reveal*_ pattern in which ratings are obscured to prevent them from influencing each other. + +* During the *Commit* period, hidden ratings are submitted to the blockchain. The commit period lasts at most 5 days, but completes earlier if all parties commit. +* During the *Reveal* period, users submit a transaction to reveal their rating. The reveal period also lasts at most 5 days, but completes earlier if all parties reveal. + +During the rating period, if either party fails to commit or reveal their rating, their counterpart is given the highest possible rating, and their own rating is penalized. + +### Finalize +After the rating period has finished, the task may be finalized, which prevents any further task modifications and allows each role to claim their payout. diff --git a/src/lib/colonyNetwork/docs/_Docs_Upgrades.md b/src/lib/colonyNetwork/docs/_Docs_Upgrades.md new file mode 100644 index 0000000..27f68ce --- /dev/null +++ b/src/lib/colonyNetwork/docs/_Docs_Upgrades.md @@ -0,0 +1,27 @@ +--- +title: Upgrades to the Colony Network +section: Docs +order: 10 +--- + +Improvements to the Colony Network are expected to be continuously developed and periodically deployed. + +Providing an upgrade path is important to allow people to use Colony without preventing themselves using new features as they are added to the Network. At the same time, all depreciated versions of Colony should remain functional indefinitely after deployment, so that the organizations created are not predicated upon the actions/efforts of a third party. + +The contracts comprising the Colony Network are upgradeable using the design pattern called EtherRouter. + +## EtherRouter +This pattern uses two contracts in addition to the contract(s) providing their intended functionality: + +* The `EtherRouter` contract which passes transactions (via `delegatecall`) to the contract that implements the called function. +* A `Resolver` contract where the addresses of the contracts that implement the desired function are defined. + +Whenever a transaction is received by the `EtherRouter` contract, it looks up the contract that implements that function (if any) in the `Resolver`, and then `delegatecall`s that contract. + +![EtherRouter](https://raw.githubusercontent.com/JoinColony/colonyNetwork/develop/docs/img/EtherRouter.svg?sanitize=true) + +In order to upgrade, new contracts are deployed with new functionality, and then contracts that the `Resolver` contract points to must be changed to point to these new contracts. + +In order to avoid a situation where the contract partially implements both old and new functionality, a new instance of `Resolver` will be deployed for each upgrade, and then a single transaction can point `EtherRouter` at the new Resolver. + +This pattern applies for both upgrades to individual colonies as well as to the Network-level contracts. diff --git a/src/lib/colonyNetwork/docs/doc.config.json b/src/lib/colonyNetwork/docs/doc.config.json new file mode 100644 index 0000000..49b550c --- /dev/null +++ b/src/lib/colonyNetwork/docs/doc.config.json @@ -0,0 +1,6 @@ +{ + "logo": "img/colonyNetwork_combomark.svg", + "logoSmall": "img/colonyNetwork_wordmark.svg", + "sectionOrder": ["Docs", "API"], + "description": "The contracts that comprise the Colony Network provide a standard framework for the creation of decentralized organizations as described in the Colony Whitepaper." +} diff --git a/src/lib/colonyNetwork/docs/img/Colony_Header.png b/src/lib/colonyNetwork/docs/img/Colony_Header.png new file mode 100644 index 0000000000000000000000000000000000000000..d0c0ee646fb47a8cc1b42ca6dc696c557b43be7d GIT binary patch literal 79796 zcmb@tWmubA^F16WR-6(nP>K`W9g2G?1W1u0!J&9@cXvvQmLkR7-K`Xd;ts_nxVQY% zb9$cNhxhB73(0loPO|sx*)wa_njN9`S{?@zgb4rua1<3})BymLN&o;U9s?P1g=-e~ zDdOK#2L&A`004{d&o2@nErS$s5#3o)MHYPn=@|xCki~Qz32}+cSytOw+TPaI%+47g z{oc&T+02y6&C1!5N?uV#O)CJG1OT7{D9T7`x-T3qD@N1Jr!rnWUT3yhq;pi6{>}T!~d?iB?;~6i+Lk5vX;|kZ|=BAIMKaGDKi2E$7Bv|O_v*wTlDjeR# zX7n_)<}gztC|$`nny5N0^DSbssFw8fd7hf!x__U$cX-VzZAyP;J;6(>F_cCer&u1`2X{n|Nq|@{>%8&|GtQk19OJ2b-<3+ zi0bMY#%|;{`u&mAA~UMUnbDHbF%Q=Xkg=7|7<6U28k!jlh&7J zk|7B6kdgeKeH=?Y@U*gvw_l*r|7WP<&@7#Pwi0QA$Z3RJ*< zty)VRJd~&(A}EEgz#z)Kl3TpSjNhf30-&N8ulZ+D{!BC?@Q`8$)hljX-GQ?Y%%uS= zg+KxLx};CmU|+EQ`~HkWur~FW4>@XXcv2!xZrCF$V7E9BM*74=!kM&6@4xXg@?ySu z3mGSk^m>LG$BN?$!RPE+m;K)?GUmYFJi1h#5UQmm&LHk!Kv-Q56>fxmxGwj9H#LH_ zXTLca3fLek-7Dp+LF6RS$2id(ol*YJPK>OW#O>t-mKR>a7<8DFDnJ`h67KLgC?O;# z*JhpekH7unX`-0?IQdN#EGS5KV)T#`%iOGM3}o#md9m&3C4bk{u`+7SOW~Q&PjJeP z-gGISrxOKszgEveX=MAkfIlwY!;W zZz8xftDBlypz*3-54hH&zrq|NnC<(*$i0_d(EN&0wkyvh4__9j8xbgfJ`m6p6&ML) zt9{x2#q(cZLKw7)V~V2V7KdM6Tf5UK*~)0{bKE;nX~pJ(i^1ElYf@|nPt*dfZwu`7 zo^h8r-VaYJ>|sX!J71(J;9JOPp?>EHkJDkT?VnBD#me>iEWXgjp6(B68yv3)rJ-qc^bdSF z*)J9dz4rl!45H}BwPiNDBaP|j8^A|Fo|pW-r^=bHPY-z--HqI^EX{v!aol`+VCiRx!)zPyleAr+lo!ADrYLm5)4vLu`;YjR8jHHs#Qew* z!*Nw*@^9|15bw75az068;Dg#VT!tqga5MG@-`-Yfy%KIa%?DxQ-7gP$Ej15{dox_-pL-&5xr#lQP+G`*Wnr? zZ<2wD$An2t|0G;0l7>cz&0WT-vJ4Zsl9*xFU_XxFZ_qGyOG6X?C6v))?-xf*+`I+9 z6JEI|t0=p5+IiUMelpuDGY+zNZQ?O#*z{fep~`drS=(>sKCWp19SmFKuxR zD;Z|&sHz39{*7ms=;u12Euc+gt8j;HVLXD*LM3-T9qqBzur%d^P@pn! z$t~xcGSjWCr=|?E850m4z!zs-qxZj29jqDt#`K7V`y>;Sv>4uA@ci!MAUhco8*mN% zZt#}P`|ho1Ca+d`@ukaU|AC-aXgIzgn$O$FLyUXpzAgm!Ip1`a`D)ZVPTxeqaOd{Gf zB_jVojMIY1AmI-6ctAv+c;zIBPDmB;;+_|y=-*TlKCj~Bea4jOiD@y4Pw@R2{C9AL z{xu2v%{nZO#iZ=?qQTv^?eb@4aqL`xPx8`WRaIN|sqHLo#j-qJK-uDC%ZFTZNe z{7seNIwVsse1hq^u*L`os+oKra1nlD@3+W!+TPAX@F^L8;CD%d+RyzXxLV>`$c~lE zNAWux1FuVr?vyv$N(5+)&9N*8oJgTuxNey!T100{0yxomM#Z(Cx&rTG1Bv!QG8k-u zux;>Mr%F3(@dYxeGvR1 znDN8*84m?T=P7NOC!`n9j*936aO3QK6CbrhT5d6Hggpl~Ma7|(L?!i%Hqu{Q!FyU?f@H*Rwc>D3=q5SV1!wvDfMQ>jM zz$GoVvF3<3oLK-TGVrrW*~9^p$yeLq_FP!Z_kaMZlsXbiuWyw{0=bv$x^e$O2u3M= z6X8B(4sL>JzQhza_Waa@9qrYuIzEs^p>-0ym25>v=tm-E%-?4$&F@k3HaU%H)KUBa z^~Ap@KM{Kf{`@>bo{olX8B&eH^ZIl5{R`)*9z1G@x98O39^Nl6!!;4r%`-A&42i7M zvaP1NWK(l^0?EopHIS9kjFO^5hpOJaQLse{U?vb~8CtQBDU}V}*fsqhLNjKNMFR97 zA&rAvqyY_swzfC|cExo#yp;V^*aW1cL93pG_U$X?6rM*!OS*`3yuQz;y9%Ru6S_!+XoD|5XaodQsAVf4hyu)L#7LJ7=zbXM8mGbg35@LM$qGbxGzP~fC^)r678qqGYTv2e_zIf45b>T9Q2w8ZdZ5~C)^M#R$rLlIHU4QR7Q(TWHsOHkkvrGk54?!VYf3WMuI zwG4#|;asRR!c1jv=jMJSvp@4Hjhjm;|1fZ#yce?Lc+6@>)+!I|TCl5ImTTFf2VD@z zhSTW%N_)KRpfcx2>jI3fUqpV#LZG;hL_hcvQDoFG86E|fF5&xC_c**y$hI-cnpSr!xlQcJ%gE&Aq2{uxsl>cNQtv?|7Erc`8R+Nf| zw2)bI`q+F*`7g4SZ@RL*wipcsWO^+ZS;1bB>`ww^6|E00mYnuOb{u})eYVyBsfvX- zS?m>v_Z;!zOIqs*#*t*A6I5f1KLT>O(m*pCACnX4fVwAdHeZ+BE~-vVa{n@X#A6`z zCm3)`G=*kAN3K%U%|5+}!fSl@u=3zlcs^8ns`YDSzHYI_w zgDAaRA=xrrKJt=r)xp=}AVtxGuQ&C~b8?c_Ms)uHa>3U_dUkHrT%D9FH5Qfd{-UbY zyNc)|_iwfhgvdxTmUuY?T##$~JPFLm!e#k}x^z1ZtAv&pXaI=JiU!oF!_7i*1Y4_H zi1~ed_wBj+DJnQ-v7xFdLR3BxW#qzs{-i57d4E?%A zL4`N5Hi1(Dz+b^MiEKHD#59_1<@y|Tv6$+~%rI}@er2w*>vFzC%FL7zojfRzA zu0{_mmzex)WQsn3+NZ*IKT%05i6K9JjpwIY`F8r)-z=b{3$e3xq3IubUnX*cA|K*j zc6n|y(%ab#^Wbnh>AcTW24*aN0l^`5vR!0e0redB#i33B7dV$w-*@dxJSI`?g5 zsQCq|TCsO3D2C~Mm21B}2=LD<%Tf^Gc?We7At$27_(qC?R8+2{ z2(CCg-pf&E> z)7-UN2b& zCL|c0>-TYb@r$uM{_y-zE?cPDw&I}x0wY6l%C3k|clgBA|5ozuH%hhSBU(^BsGa~o z+8PBZ~x+6S|JNHzvVmE*z>@}Pn@==@*gWVdoL-y0%ay2_Hjq?A#w_oY8}OhgaMN>qW2z zEJ1bka#ol$tQ-Uw9-~_2H0kewK^W=e2$WJ=HJDBtDV0RO4{{9dq>4OQ89TXXI2mq$ z01Nl+%scm)uf1xUBRi4(xwPA2MhF4{GsZ^QEp6oFHp8FKgS{}UhQw^P8|wqU!Q8Jo zd%jJ!!V7}qZ)LjX8ByvrzfghfHhhbzY`>pVAN*3HtMCCOt$MRy!%EC(#2ZrYmmma752}J07@GK>-2k z2%IS3N1`%?Lsv_T?H*TAenMjSo`N(9`bEl~tAr@IHrJn5lYcS@=8P(Uyiu<4pb>L(OR&5oM7Lo*oiDN>F<0hIs0bzDg zRco}x7s`vy{mMF6AI$1e(OisI$-V$YO7m{m7(Pdh3 z%e*BT#sZ>-wPi)&kE zdL4reZwTaUE6DwemO-As^%|->Jfg%*jBet0%w`-~QlyylRy&g$s<`@$BSTQ+XnGU! zyF_|6EHd%uF4G+?MU$j}O1OWSK}Ub&pPwJjL`(1=Xmofma8=yh`kGHh1pK_Vux z5?%jJ{kmCZc7@cM3v`Mo;r-6tEUlgfA^o0#XP=(n^b;abzTXXtL{;5#gKbA7*%Wqy z?9^JSz1tJU_V!TG0TvE1n+a7+2@*DQ4fm`0$?G4!)Tt;@QG$NBfbY*b zZd1lGA<9&mpl{AQJ*=s64!jhez757q3X(JjYYhQqzsJGmIfO#ZMp9%CDwL> ztbg}1W$&EhWDpT3d2y<-A>jz7VrJIy(z^Nm$IWobainNTNGEAA^BJX~cSN47_bENk z=3c=IT}rxL0Kjggvju)5u-XlCm{U!@ZglyudLQxS_36?%DfUmZvt6*D3DY#(MvVDC zP~98ArakWkM8H}iYHTL#qN6I0?z0ox<|}eUx!c?Eo7(pmK}E)yVxXv&iu7!SiP0{H z{?9!6c3)|+du+rHQsV=w-Aea1gTi{#khV}rbN?g_fn(O~g;htroS}a9VhJy4{L?kD zGbY~~S|EKzMz_7+3kLVOyyJ(Dc)rIK-h+xtN3K)S8cZ_MpZ>LL% zYV$u_GnS+a4Mt12<;t7yQDH9a3GmzlG5?a+#5tg_Qkzv(2;>mm zkBB}tHpZe57g@(wL&_(a{e-0%QfbDb<|ZfmLwMHgy22@IuWQK6&HEQX6=hYpS7#4( z)TVfb^TZXIZLc`mUy*PuKlW(=ZAJz$gWXgxepI6Ipt+c95-qX6jl=v45xgP-WxL9a zkrRUt6=MQLc-C1nn}e&rs=kE!`(2SermKR-xF{02e(;9Vtjv8ySid%~3WFC>Dff8& z!0~uZ2i7B~Cy9POzo2L1I_T;q}NW`nX_ zS>-;36u>1YO7jCN*U7xaJEN|S2jlZgmu8>0P$Hcu!ET36r37^~5DKp?`fGn6#tHV7 zCNx9E(JSTv1W_o^LZGiDQ#1tEnfzs0|C!~Nc4gJ|k%k{Z-<_|YS`CjnBKSrOJLm+{B)9rtAq-{tZlOykZ$ym zIIKUE_xR7aAA7X^&et`_a5(;yjD9& zBTbmlkFW?3i?v1X`S|4Wl(Dt-r|ReKGwz1xo(m8pC@LI|(k=0axTf+~FSNFa)%;}S z^TcH&nH^CUO(?th&_kk=4fC}OwG_{GUrN|QE5UO-QpynLjb`)_am>3iqtjsU0z$}G zqY&*GUb2@Pe#CqK$)gDi!D6&G!4kI;+`DTBP?ZOCHJ*K#IRkZQO~KM=Rm|BYY#Pj6 zV(pjTXjK>sZ{^7v=x#e$?>+=20{le>7MgYSp|TOYTlV@JLt`|N=F3N^TNpTj{^IvZ zLy2F!UZZZO$Vr+<_pj*oP7p#L7AT1gp>Ku!5JXu$8-ij5&cz!9a zOm&z88+7Rl$To<}IT<~Ax2PN||8U8-)EdINSuC~832fb=a&Gve?d9E8ggYHD=|6A2ZcIqaN4R z`x=7UdO@?F7KuFS*itf1svR}1PU^~JyrYGlMog>;oU;5`6Rkh3t?Ve%f5`QP$4Q@d z%xAe1q(nG*Cy@j53NN=hKF^}O4FMEmD$$O|bzuSC_G}<&WAQivFDUb*rzEU z9-@Eu%G}ly;*Vp-&XjN&kx_d$T#<4?RbasmLlpzXM*7nRP8H(7)kMu&6k)Kw~VLciGElPjQ<64U=;Hr<`y~GOV^81Pn7Sv*J{9 z^j_Q3WdUJplAgIA9-zsjyw)KYsKN}C*JI<^PmAiF<#YBoh(q>S;{ecDhVTYBEmsMf zzyi_xyFaggN6~j1F`-0lF*F{UKV@+?^5ieLBb`fWB(D4q%vx2HGq0a6evkb zMkl}bLN-WsH4NMZ7GguL=au(-NS?d+`#y5!tc^xR({P8%nHUPi(w;@{{rHe0m_yYm zP!c=5#QP1aoMi^-((~fmYo7CwU`sa$NRucd$f=Te#+z1e+TrNtGAy)zGyX}yb1e}k z;8Lt96h~H{S)>)L?LxwO^zL7hd!zR>vnD$Ij~w%waU30XJuU)9o78{W*nR!| zU08i`Y+e7lCMsOnT9>qVFR7*o4_Q}x_jkjaa2nKhCq)&B)vdGtdI5SoRz7hhTqQk? z-5#_*M>tSb<*xw{3X<2@M_TxcxYGkKN@BPV32MtdK85<}6c2M)HFEaQI`^_KNyXbe zZf1l)?^}X|ctTmB#k!wXQ-nUQJiX!>#_7awhMf2lC1jBQo`^mOlEe!t$&;<`{~(oE zXrgZBLS%2}2?%nckl}x|Wq=ng& z9ow=VHgFTCF2cI9IzK8rG>xc$ib1vM(xFaGYxT_Eu&qs-e;Fu*{G-{%`Fv%Lqkw_EDX!+L0IuoBd)ar-P}IWvBixUh6Vp58vI5f!yR#PYDB zns9Yfm;B2ioR`}A>HP|gF7!|=Y@LEqkRYW+7^?3y)#>G*x_xc+gojk^{N4@`R^%sM z^=vH0q#Y$FK;AH?C2i9Lav zqysy?%(7Tm?-CvPPe&op1Pgb(JPH32d=#}v3%I4Hp-YcS3}=S4-u%k@B0ikE-eKJj z7HQipDa+U4B?z4tqvw}z$Uej^8LLC))uamhvBs}*PmfSlxHqB3IXDzjM*t5}45;)wFQp=SLo?BV5leZSsAkz@d z(EK<0X}<&6iO(Ki$4+eb4=`iCPpG-B{FIZFlp`pWMx_!S-W@-bC?NkbT|G^WV$4W- z+qZni>s3L9*^1YN7c-_%tOuvRx+z;UhT0q0E&}pbwkmHvPdD*nQjW@v9OYO~b)tml>eQ6{+ddM`$T6H%?vdtI z7N4Jp>Q?r7YF8{;vZA0p^>g^b9uOF+2NVU}+9EiIgRX@|M(|GGVUcWJp7#n6#bTtK!KrA)i_( ziTxN)-_P1_j~53X9od3VK#JVfu79h5Q<;28*Vw4U#a{skRnFnbL0TO`rk*h4%>&1F zz4GWHPhT-jy26E*=3g(3rWRTUzcm{!)0XA`T6{L2wD~QJx~@CE)NH4jHUV8M`C$c2 z3eU0019szof>0W>9`c9JWQoai6|?yEU!4>O#)Pr7aOeM*0OC1&WCzU#v&GWhO%wWu z=U~*pA8lHU8Ms;ta(>3(*yH3eg`g8-rFIQ_jDCo)2WczsWj&vExQ?U!$~4V)mLWzP z+q_!&9P4@>W}aVK?Q&;##g^>0x>)v(8eT}ea66FM657WSJW)D80=E?dQBKN@xXN3< zCDO!H^yVeE{+IUKP*m2yX|#Os)JJM0m5bBLdPg4F9Jv|Ztv0ytAfD=gXPCn`8Jrdx z6)3>p%Jt(Qq0T8bWW@<`V%qI8(yx{{E{z-h42;n2Xe_qt+c1xAxsItzEZd@l7p0A} z8G0eJ`!(R^+|ct#gTQ-0%;S$j|Rft!7I0 z(^$%zH$qvoSlnhp{hYTqs5s*$o(yuAGk>A`uB#X%FK4av%w5%E)cW9MZBqVuM2J3c z*c;k~@&i8hgC#sXCmwifH43BHZR+|QqwR_?%eGe(cz;99K%(S0VmcJ|KGZ*LpzsI($0FJSi#Z`S+ zpB9lsB@bRyN6F=`F>qgWmF{rq2jRZ)?S7@8e)&fL2{B9t^ZQ`vQWF3}8g{22Er z_t(9icExnD`nP5;9}4Pp@|Kw2J|D&H=O>msVwl97dKiuG)G;_3b%Bfzi?X(tjDAFi zK6r;8JuiFqw^_>A%_D0WtNBgSLHWZ1(X4)xZW9^>Q=QGo(65y|L17YEmYIBAYZ~O0 z7jfd>s~aZQ^T0y2$}X`bkuTci{MUIgTfto(AiH4xyW zH>)s3>kE{@K;F+Qwu;~JzIP=I{gF;hY^Q~)944V*UjcDovJ8=hixsi((c#VS#tdXm^s8#z#>>eNhl+25gdO#o9M+4Kv@;w?D_k050V0 z9a36k$(DG%tZwIyfXjxUCEd3gKy}MMQpB7Pt~4gCdYo;6I(&lH`xSeB8S#~8p*1t6 zA7T=+NmrT<9nrJ6xT&ui!9wG^VrvaYF zy655iGyTcC+MIB3VuJ*AuQXA6)7H{uapN0e!{n`_yHSJjg2Y{^S_f)Ot?tSfD5pU! z4xHx|j2{eNSHr*dC>wb{n5Zpk)RqgWT&1JIBSRnp1?A+11g@JbKR>&(H_Vcv1Qc73 zVzGZ`z$|+1z3N(wq6QVsbkN~sx=<%VIbUtJj#g3^A8}7xop!rOmn>P#wQPR1%j`<; z6{lBYA$$hD>D1m;n;uWoA9NW}D$1t@APOV%=fr-Rb2?~e@eB79*-s}bF+b*?%q1R?m>8eWfD>DGQtj$Rw&%Fax&hGZA)auZFQ zdQW>?Id)ma1f1Zj%X86+ZPPE%27codJeSsjW_+z}a0r9@tUZP(nf?FUGz=NdEucIFpbQ)haz1q8|WP7U+(JVtX;*<98IO4g}p{hNwwX2 z;uz9RCQ{*ES|u`30Xo>jUu`@Y+;dm` zyo>~S<-|%Y&^C`pa)uu!OwZO$&wl;h=;IXrZB@xSFBEH1y`5EEq7IY?>assiMs$G5 zQ&*vXUQ^v!h)HtN$t8re5OEIemasI|MGgj|`%vNzrriQfRZc2561kYo#Ya+sIVS{S z<^WB;lp;3sXI)VJJK_9@kY?}@wrmaYeDl8EwE1?E*es81SK0G2^Mjp#$jsh|6Nvuf zKzgp~0oqzv2fWR2+K(ILN1^rjb@szOLvSM_e)}}J0p{j)&BPdEuAlGucG!nOx6mGe z&>#bcFC7Cca6c|ebQzB8`^9Xo>)(v&xtgf<7if3xjFjer1F~I4GG6JNRRh}E?-AUK zAZA3W1C1&#)8%e?dW$EsSWs$mau)EjLBLbB+4K3&bLO-14`|9OxnOOA(l$Rj8y)3l!b%q}|HJOHte`N1>sgTaGU(xM}-^$R;=IsRX7om_%0!Fi}jcc+xoGcgFabx`axN+l>Q%oapaQjzKpUzA)tJ(3r)FH289V45q$nTuId0 z;PPZwe=ho*eyq=`G;r+f;q%0HU9~BU6vb8E1(sX<+uP;RufvgNazDgCl@JNG{lzx+ z_r}!`{3^`;k_6W;-)q@HgBJURK8dj$^j6e@T%F?iN>{sUa&DdGEciJ>%CK}PeFXmC z^NQotJZ~p*iVVy=4~)vF>(@yBv1PGWq--i(Oc9yr^Ca&|gl97WnqNPS!xNbpG!gx>Ij*{cD;4$5rF^d{ch*@f5mb3`F*%kIHUWkV zMBylvOH*9lkBKYg$RI^8bJY4z%EiSz14|eB4#!|`uR2Q zO`QB@iA&95!`S2djJDFChO&=d;NY9>{i`G#Kflu-ELI(5#J}S{RD4mLg0o{A?q5DD z>li*4H`M<%Z~1WLa1)f5cf=JmmG9x^!~?ynb9NYRkmkp+K#=chQ){FCM%bwUB@KiQ z??5rZD)i+5Tl@T>HXr;mXH9XNk&u78Q{)aGLeb-8nhL*$raxVb z)`S9jL}A-9>HN9)D~QUwUhd_tbOkYY?&%a+Ly7`&aY7;I zbNj^gBnI5hlJ$pj%m6+f@%oK5iM8Hyo%?a8J!}=xH-$-s->b{)bniyv7%HQS+ncOU z|C!!768ig4eEuuOG zA95Q(9DqffNolt>kV;dn_xLcQ!i|*UBBW;l;fcXH;gNwg!*K&Pw#m(SyJ&8sYEamS#dh zlJY|I{#w)hlg=HDmn|P2lT;$E1u6G+H6HP%_WV-l-ZO^a$3=(Oe+~L#k$cUME>0e& z`t~0FS>*on`uL&tPji*?(f(~Im~V-==x70Ysz;&+&DXuE!f#9nwinXtG3s#~^$a4D z{qf!UlOFFybOojh^x~Kcye6oUOO=E0md*b18`h;AhRHC~ZUfbr{+C1E6$QxBEyB$6 zecgpo7P1r1>qQ&28%w}9BMLK=5w%y9xv;nWns{K7f7XHOF^q*##9aAsouk|@E%^@= zt?BKqF>+oARh1w7vT}E)PVsAI*(yF25ndjJhkWfDTa9DwUznJWa@&Eh@Amy^x-wUy z8-{fBk}_0VRKC73USA&5M+hF(>bsYkiQ_>QMk|cO`Ams2_5&n%O+2^rWTz^QYgb>T90REJxx`Fn-wCa)T6ZXWue+f8ruOM<$%02m&A@PD`Re?f9_H}Dp2YJ_ zK3$#nP^UDCTwZrK>@2!t+zu6|QF`Lz@W3OzE(6uPmWV(RI}U>E*<8VVtI^vZ$+120 zQp!$nn>;@Hi0}CZA~MuRo0tAzsi{urw}w&TV{xCO=)l@^Fh(aro=EFiE}VBwaG~Ev zLnu(O5Ro?s4In(XcK_GAsY5XwWWc+%9=Sgax^Lu)ocJFU>zm#{MO5*8IVm3*hJ5{u zwo1j?x4McEY#f-*Iu5Q|9ToCa77>sNGz@{jJ}2^`>p9sjS6&Q)#9&Xcx-i5t*3Q5o z&on;WTCK!{WZ3W9p+kP~5ecEE1^Hi{mn|Tj+Ctb@4eKgn5KSD#lEIuym!`Pp@lq6& zD{>?CVc)Fx~r2`M* zv)X)L!#t+y=z=B=rC2GmBT+vY3XSCxy7T+hFW&a7!vrYHR0Cuc$z<4qVa3Q8*=>G9 zQ)I{FIX%UgzC10+iD-XHGuOh@^j{y*7v1z49_?v@1rnJP$6`EOdU` zvz2GOEZ>quxFViZqUh^@$naXZv_b|M$PKGWo=|KOm+E^)b@OuOQ7klkc?4+8!uxqz z-_WpHK!<30mt7xvHt~R1_)B#@(7nyRSJA@b^-^qz3yzji8tphwpVU|(g&q!asn6Q0 z+j)*n&Ky`sG4c^@%b$HCdMlMzsy=7v6X&mK-hdda3291RrvV%0j!)@jVfpGZ#pn8U z>$XiV&q{Ek)wrFY_o1D;$c3oN$LnuSqudp|ncuX(4MRg(Plm&3_b)Z^DQ-*<7=9d< zHI>9j_=Th$j6YIDS^~_ANPFe2bJmI$S^EJH1e0gQZdUnvjiUuc)e0b+foZX+#syz5 zqnc38LlNBb#?uA~Ub@3`Y@@6n8UdfunSxXFOD}ZDe>bPtyn%lGp(-H%#dN--&E1oU zbKpF%BrPg&GyKXa=|Heosw^S@2k#Q@%oNhbE+@^@x(p&^8Mwm z&cdToM7WS3RJD7udW6lEb=WEMRVywy_T;8t%G?h0v&mkxJN~XMx7547Z*E{Y#(&K@I(evckD4x`Fbvi>z{ai@D6Y@b|2(d+w?k2Cui5FF1^+yDg% zaNr_K`x`dANk2*pw>;231qnGR5LcVU5{FQNDIOUjfG?^Du4>Pg6z<)uq6X)E60Qq%*}|gYJOtlhN^fBBZcw}n|*X2 zzEvqZk*IDj%b1V=^`9}4K=sAXX7_;g_L);pyP7owSaZN#aqHnp`iH>^|8?`+`nRCs zV~b+_B8Ru`p7`GN78)k?l?0(a#-CiDym?V)qC;uAEouQ!^rqRqS|-P0q(E`|u49W) z%A7>66xNJJ`W43JY2}4cRt9&W-pLfn$AI>|C0DZC`A$h?Zl0gN?g}?FfF&Yfml?5! z5gTEY6~*kz4yyF@k2_?=c>o{eSbHaP-s66V7|S;(vLoCpZ&ysSv8TxMX#Lg#o^wY~ zeM=z@Cf{^}siXIVU5~|yN5wGT#n2`ELnU)D`eo!BPLDjk`BdXZp+B+TVX(_F_{N92 z*QRyna|=7sL>^~5EVse4$H*b$cjT%kNvU;XCDyxd+S=3L_u?QYuS2#m$SeTH zmPp!9Grn57HgW7nQQr|V^TXH4Keed5saP$EG^Q(k9ErRKAWy)C4JDo2B%O)?BUA?F z=c)`DW`FXE!ie6Yxus5XZVZp zEUUHpYHOf0)4z>X=eYro#^Z3+%SX|X5;D+mtNF0s!a*CsH**N0t=x)pOenHhSoL6D z@K-JmNpg&s9g7!Q3fG7aemobW)1YF2dD*mSx9n3Iek2a|VsN1F+KRBgPXdfhCyFlM z`Upvsy$#utrCQ3`_my&k3@`*y7Ahk)gXpO(*P9}F6492J+}Hw*js|M*(Wm9fY`ZL? zjhoj%?{QTdibM`a|zam=ULBOcC<%dy-&5L7a0#=(L~s$m7CCz;c1E zLT%0u@z_oA@a`I2bG%5C8gB~*o#zzi4auPb^1kC*1AeiFkh^M_brEaRs+I`hp`+Kl zg$4taqGkKQ;P=EDrVQ&E^u!biJ>ZHL>D2Zo{l`wxYiM6k*YWR-lgy#SlC&o=yig+r zmzY1t#14&E@5Fk!C=Z^o^N^sba+kB%k++SWC6-uIs){1%YE%@M!vR0!y7B|mF^+!a zQt`-{*t2aY_?(M#^$2P5mC9P;-EA*5!OCFLmJxxBnFz97P&;kct;}aJWh{Mr>}=z) z>^q`mvDcvJ6b$M4aL|B#IY`jcOZXMJ=U+*wL#KyDN8O2sz?d_ zIXdekr$796Rb9*CR%2LnZ}g<&mbNwM0(!p*(2kM~3ZWJWJ0&eCp$hT+a__S{;KYhS z(8m=*fS3e>ujuKF8jwJYciUPeJMVOE%smmof3H&@&RB$ZyB_|eEU&*$>7-Qp?|@?* z*d+3UH1nT>p2r>DNto-7aoTav5C@-SMuc}D-z*tkIThj8Ll7ui5e-fdvU>>|4!Vna zPma|VRtFr2`^L6tUW(5h)MYkU{*x+;F8ijdDuYa=XY*-4qCdt{jFpvYJnl3-;93uu zVb)%J`b~RRtis+suaeWd7prcON;e27b-oL}iN{=D_vT+GE0>vmgL<^&`5}@q=wJ21 zvGV|emlsdBPv`x8O{|*9f-EJ0ZZ|JZkVZkqNMWWLQJ#o{s;Yn?=S9SSnq2p^SuXCG zJv2pL(4Zi(vBLz{PEpd+zj1$M;$S~Cj@_ur0n$H}CD;T@>!tB-Go|X-QgHiM{?$jn{o4_!f-{#xR0W)eB z?l1I*u%hKoq74EK@OYiF9py`20YfVE8X^#QtJsDSUwA-vP$_#>Ls9CTz^W1x2zMNQ zO4oBI%s|MB?IGx`H%81Xs~9LagP{0_lTC16;A2IM^L}%(`_k@}2o+(^IYO^_WC{$! zM{TIFrh};ctFZTWp;GTi6qkKkYWe9Lt3TL3`6L%MGL_LLpT>OdUapf0nQg5KD3+rz z;_O@j?chUzG_}R7E#D0qUFsd&Ae9@{F!kNMBswqnMlKNNZa1%02+=6iPsqyQ^lX#s z^J~dqg#3~3{e7zFMVt`!-ii@#XpPg&B(PjACvn^e(*%dG4Y8fnQqj0i$ZOm>7DkMs4Q9}1lLQV#lD1&J3 zDJkJvC6Nv83Cx7YNW>;ZDBfJXC;1It4Ps14mKGDd9cynuqDz1~!{AA;tN6 z#qoapk95tNHgAD5z2Ru|?_yquZIVuQ|Lo0g3JfyJmM9^|ls45aU@NH(te67JC zg|9}6TaZ4`8Z}W28i@*jf(C#HF&(ZqKnxmbS@?VwF zh({ROUcbMy8U)Da{skq{2`jOgu{$e7Dyj@U5@2+R{Aj z14@)~qbowf6d)&^&kupxKSc?MHhJDBJhbK^6U=LrhmZ0VxY0N(K2_!Qy55J9Ru}lq zsZvrhS8^3Y!|ccIQI?b0Ezk1q*g4I53&TSSaMf5ue4=o6xY)|nxx&_{IQrP_sE0Xs zxGg7Ec2KI*NjAfBfVwPUXUPVG+ViO{^o8gu$)~!wEaNQ1P1@G9%Il3wHt};K8wt8j zpPW8%k(Mh&IZ@gUF8RMp-V~hFEOd1~nPe2sWk&H)9$` z7IZlM+B5;;);gbVjY-LN>j6@L z;hpafhK%#MVn8h2$F+rpih`onEmoq=io8KLjxs%HUMjPkoLmod`lPdoBU9~rLcXMd z&Q=|NAb@a_RB7;27YEXH#|}6O5mOqed_hnXxmu+BMd~Mdw-#^J1K<$y6UAZ0 z@59oKd^F<@?4+_0f|6;Hh^|^a5-C#9zdI>`o#nEL6}}_DcY>}{|NQ|Yu3!9EhJ)m~ zitGHXl1~o#j(IaFA_}NN8M4*EO6~VM3eVV;Df_nGSQ}`|B*ID+NBRv+*m#usAibZ< z>uuig4^~mrcl&p08%!wXT>ENAjN43hJpp45k5Y5U9X5R`-hWdO6=tMp0$^7HpGVAiN#$BGMUmNR}n&Cj0scEf~oe_dI%%D4*>#i^Q?)?O&b0V5R z0>;#L(NE6R(5q#wYD6)ArP5V@<*wl6|CxjpwOeA2A5hJvpJd4&Y;MX_QT}c*pYyP; zW_5_=LR8p0e22tg6D>b~?%Hy7Or6sy(E<8U|Gw%OB$xdwEU(dk1o|OPS0yQr9n1M+ zIm5}-cPglvZo@C_lx*M`vJ%4L?T$}Dh~2@xud0>A?$TlQ;Z2gkM4U}b9?7|JRO3AA zHo20x#mp00+T73CR6L2nQ%O_NKB{lnI&7o#!^kR4Ir`PDM!83wjs$<+;~RHq7-gDR zrRIH&IBin~wPK+<5kE7MsP`ei3Z{~LC6l;z@1U=wVW2nY3Lyt+4DlgD=-dI2b&& za-XD`6p&Vfk`O-pClFkgJ?q__l`X{BpLiaL{!^a&2kmoqYlPJoiyP@xbgTfTZ?!8Z zXz7~d4STBHlZOqa+{!7QAMRP;Dc z;{7ibu)|DBNr|kIoGt{u6m`w?j9?@r^TyUaF(0C6l;yZJbmFoRm-pmR?bLK zH8OHSLb4{ikZVIDw~7tyr>_#A_K8q%>hUy5ZBVYaJ+n97@|Mh{?@V0EbX)&w2*=jg z9UhbmKc1hT2q^-Nx|5t%*9o^RkkcJH+B51p4<)e~)9N(G*>+2}y3jToz8vklJnq6I z{OC^$54ul#xH+i2dZx4~P;65D4ZEJ@%jjV}dLQWDm$DDDsdZE98FpVOBj}u4L3jE3 zz25cA(=Gc+$9ubQiRL`&>W^`7EtecQ@H-s`o$JB_uMNz|`5aUTOm!B^1^#LB-dIKcm`%uuTZ%_NTvfimg%%A>pET_waUF=A&uLvWCUH)RyLt;E0y z`jW=&UZ0lE=R4?t>x7h#295`SH-O%kY}%hOsy8--RJS?-!!J(q?-*5>sItS9~@Qh)q_Xnwi+)$|Bt4n-KAn!3BvB_Aw+ zqduiIHgVle*M0jSO`oQuRR{vFNuNFVTaL*%)=(FRq|{R~Af=+LpLG;1Gi7H~Z7*l) zr43%!?y+}qrH|8}xUsMVYPXMm=Jom>+Z<+#qCUYX-%O`e73uv>F6Wx$)I{b6ILn%V zJb;aY5_8Dj!enRtS17Tw`?5;=cW)L<%8q-8{LM1I?TLGH!;OWl>C;bf*0wCANcC81 zqz?H-49*7JFj%^}KT7B$j2A=*d8Jg6!5$*mm!3n-5?bVP4c$TK%bu37Ex}CGEI97owL@+=ke^8LN;1fOUdV#X=cL7Ou2r|R<^3d{7fGD>-6ZC~VgNttE zeWlqY<0a!~XDlNx#N0MX1#kyGsrfyj@$8OyMT-ksq{h=$4j!_j7I*JyBQ%J!Rikg= z=TC@&#MxkEj*;U(e@B;=3SXflGfvvE`sN7vET!2LB_!YgZDno*b$OymJN?Kxyph^9 z2F+FcQO8pzez`+Hg)eblzJgF>Y{xu%Vrj6&l%wbbdw6W4k*%Md2wAFcv8mEvWq;L5 zZp9UWUZDmf(o%Ol**T=U+VnUnIqG^O5m+xCq%5Qz0YV}WZo!XBl;?^Pb> z7@2b5MJtXof#f(m&o~BXbp9*I4xtH6y&>y5=eB4QNyj^>KDS+B2qQC78U!4w;&Md? z6}~P89yvAOPcmZywg5z=mXve!?_C^R8P7-j^r6sfU5jwR8MjcDgW65bRYCGfb7yp^ zsfnfa4D4qXoV%}WqVQbZ+my571F>NnrW;;A6R9<|#Jiwtc3*Mrjj9pG&DF@|TFjq_ zLw7k}YaZKf2AZ4=M|MS5P>R9AW1-B`#t^LLA%az803;TydspWyP&9);hGLwQ%7y?& zG#LD~V`Cl^xxU9`jKZ|I392@lzDGCy{hIkMpZOW0*=XOJ9L_)b!e{02i{U!k+!Gx* z(Zz)|k67D-mnUiB_7{HTaz)}f)KF%!H-_x)B7ak{Y!KKN@2Rm3)icaHkiIWCW}9HjUoSCFme0+PbZoyIQ72_f)wupMZnFyheg1l!2}VdVwy20&E4=w;U|tV%GI^?&D_X9m?4-!E2(5v>)}+nK&FsP-y%;QD>QW`}O{K<#hT)d=G=|a9gDB?Y8|L>gU zd`v+is3tn|~DQ#7xUGHmt z58^=x6&2HMrTNPFfoKEs^^vZvn*iM(1<>G6O_d~e{0srotN^*Bo--$SD|TTBg@!H> z2^aJ6S1YF*7%qqIGaFe5{hTn1q&#diT_@kBp-n7i=L>J)2!TW;7V8PSfUUMc16*Y% zH*w9Jk^&q~NY6MJW#yIOyo8I_<%iaP$5>l;cZOwHK7F~cNW})1--xM=W3q%t#p_Uj zn*^Cxe7t|9CBDF073e*~4(8fzTb9>)y^nLr2H$z(C&aEFAzrs9q^zvRs53i@-+IaX z>CUvlfw>BaU~2_*JqS2_;+A*}LL77c!J_@y>xye*IK~f+-HjY=bHYQJ<*aF^ zl6T1sj@S@Ztbe(sTnyQa!r6ow?_luO)Vz1teyGUsbVSfLvBGdPoFo5M_Q!FDl)J?!7bsS-siL;VJCJW?NeM3DRbMi5_ zlLz0gkn^TyhDw>rE@e{-Yf{rAH%Sc}dv&S*B6(f=TgGvU72EMdQn@fYg{ca^vg}!( zY?A-nsnrn?@i9@{+xX;B$|-`8X@EoCDcE@Eh8k=Hf=befDSthf)=qHxE$?!9T}3T> z+Nt}6PVVbW*S4!h*zN|3&xP3+Z@77tEY=}KaBFGy>$?UpxM+tr>!SW`N4~xuqd5hHMWcK7&nn)R1$E`o<{h z(dzS*$4_dii^;9m|mXT~W9Wjo=VCCF~n)voh=ZB&hxa(WbcZGF5l&$9i zeY&x{GZ+7YRb~=GilVoo!v5!IZWmxU>el_OT}TNP|IHJGy5FK;|G#yRz6ajV4C-MX z3h?Ij?IB1wEL($&HF4jO=%u;G@xI21D%&Lor5FR1?6-8xo@FA5k7Lm;?|?+7Q4xR_W}>$JLwUl99JFTFR-J zK#T_+Cz}X9C8aks%A_86*_J^TYEx7wD&}J+*#rMXia0T(!Zxx|mh z;YA}^#NIq?sgi${+nqDB@J$Pzb#!>a>UrQL;X_;|TGLCR($E(+cluqKdoZO5n2FN6 z+GSD^N!SOn9d=wcuQsl3V<2Uq4_9NM;P-mOr|eN4l7GVh1h22gOtd><-XfJRJO2LJ z>x^v2{psA5-w}Jcc7IGQrp@6A81d8fmm@cLyuu^*{VJMtrB^gPf_mh6&9%DP(8(!U ztMV3V$2SCAg(I@s!H zi_JGBQ~USxM(o{LraW8gXY{AR)?wx|XI5w@|McHtz#v@>kKBbQULrep7qc$=JBIdo z3E=gEVvSR?M1#Kdc_ElxG#72RvzKZaIiyeT3Otq0_OOAmaL`K)9gW+)CS$1EsgYIm z$_WxHVzkNXOw`v^&Z$+8YQr(5hly>QxgZ~Z+9FfixHxNRokHT~^xS$c9FS?1(;o6^ zk0HjxLo1lIqcwlub$j(;!QFH%cwcrq))*a$i^){@&6QMbNc`@Y0iGV24_zk^{<_GT zEQ&1rqN^2w+zGn6`C?Fc_ zt|m4KS6bGw7_=V{P$v z5BW{VVcvUcm{JCH(ttGF@3`6~Maw?jV{|Thy1hZsIF5TT3|gD89gM4-$2^jHM56#` zbQm=e1{9aS+OfQP`r0D{(4?IlvMP*DOUR?t4e`;fQV19zL_d&c)4$FjRzji=ci3S1 zb|4l>mto8xwlIGAoPwRN&hkx0%i&&*pjCOPFQ-%x2uHyM->Z!EQBP1q*K!Y^oNn+l z+JEKpuW=KLd1WR3g+@(_QmVlIJ+WG@faUHHzrJ_QV8V!w$0MJmQKJ1uaTZr1jv<)h zzGdbJ#T>2Bhh`fYy%~%?aanOBJ%sxy83GM|66;JTZo%FvYOPHn%`>iPz0z7=v-|CZ zcDS{PB-Wi=ihNhbe9C##&U!uU3Sk{i2n;DA!RoK3=H|syaL$Jo$o1_Ls;u#@#{jY<|D4_C(-;=Rs$-*~aM^x5UiQAf!1Y zI`s&PJGA3O?>4>Nk4_C?mk)|&TP5&jU}m|}fB87;M5N+NR_Qui@kc^2_)Nlo{CtY8 zO*xBF?h+1$keNwSdxoa?CcyTgTGqAZu6zgvtG@W;j|yyja`v@wnCXB;pD7ZavD z3-jY0eIvrP)g$HIVSZI>69MX=aTlT#O7WW&zX0ByG;f;<7@c0?((H(nbhdOY~P zTF2d}L>diNz+EG%*8;^{^L0f*nWs)y!y>kD<|59`#v@l#FWB~0h-j|mh+&`I3?f&< z6ZYyp<~!AtK?t4W3njmOI$J$mW707Q$&?2NwlSqe0>heCTDzXo2EH{mXBkQ_?R;-R zI=e3beEIJzxgT<%*T+9kI9mNzi2znZDC)65&@*F&m`bYAeL2JpM*&`dd;+ zcp&=ggEy{^>AEa7dB(y3%BU;2qC&1mIu(X(E+tOTjQ~HA6rneKQU(^241iAKK-kW> zItAB90Z>V9ZXEQmfpC&ikyi#c6jc27IOqO!lWHF^Z}tPSU`x)WpGZV?4umG=rIm

x7o=lRroZE30wZlGP{F1pm51x8OO}R`6G}>66v(2wG_hW#dmF^ku$n6v`h%YO3-1HoY_m_;V0VtpR(oIV8XmdT zM(**1Z>n`B&APUW53$M&A!H)|h0P-^^gHFW+Yw`tLg{HaL;-ncvCMB`AV!UaJ`pYH zM8I@0Ey{{N1td7MNRXgzG4L+9EMq}~rz*`EmYS)cPf<`U+KVTIGQ!%|J!9lo1)0iH z7$8_$?~RkLpR6vO7VPx}M$#b?(97QnIP8gJmZQxlxaBk}^zIP1S|C!3QY6%j3TVWz z8h}!mHCR3hn(FuQ1jw`jWAx>CwN0PSnD^&C9q`Cs#K2WK%*ewd-EP=5DTB$NmXm%+ zCxPA0ddd@2!CN8%NRZPHmZc>Rv(RI64s|11UAtC z;ofZ|a@#gnEDGe%K6FkE(M-y0bpmWo4*Uq?%0-EZMF|*MrIh+=zaohYJZALLe=xK~ zOqbrLpSq$XLgbEh)Xd9`s8ocnxrE=9EChgviSTTui#4BMIvCD35t-=wehB`H2O3~1 zm5=|ve+^+kRh42?`YDos6cSG2alI`##XcYt3nD?-=Z>Bq*LTMh2JG+raOA(?CWOyn zEWsn@YpoF0MN-0wFnRb}*($j>7a%)aU4SKvU~Y;xieL>pjv-u+qX$_vR&wsjA$dfh zCR9P^t#}m5=maLEJ?j}vd6w1^pmO2KxW{?qG`IgCMor3=G4H=H?BUYHQCz#T&U=`_ zIydn~qKCNr4Z$U$S>9~68W#|3Vt9fap>cppF|(+<`O9z6JF!O>uP`%#Y~!6Jw$}-U ztYfCVGgm^s#v9#FLHua7vRYun+z8O(K4XW@t=nx`s7!X}}td;2tjKuy=GU>|@ zEKeML%5=AIco(B)a`%K#1a!!|+;?Zz5#(b3+#>yOB7mb(DnF#n0OZm$_(KK34upWf zP*@iV3puXi0*+i?FBQ=qL@F~yEhnx1MnkO#V=zYKQZTLDM&MP3m?5|)P}b%+vj)tv zI%M!f8Lihd0267%KA~nF^U9yp$htTOG9Zn{@1CH4h9S)I`GCCSFlYE|;t4B>T7+%q z&Ftw4+tj2@+pK+ekW5}}iQSmH&@A75IUc--CovuWA$y)-wobSRv(RqfN#qvLN7 z*xGLoqm-IUfCHWGAJ46=0~X9M%yn>8Y>M}c(8S%EjQ)JIk1tEP7HH{pBKb!( zo8T$MD5*S&k9ioohc)WdqIvZNM+2GUbAHpqGs!#L^HPt_;;$1I70&O<;dpd9iY#Y+{o zLTHQpwn8<6fT1vRT8v1KfFr^T`^Jlof3eSD8;$oF#)d%cq|{6p!2d?cKJ=JS3dRV` zeSm0tNLj8}#m=kR4*49`BwSRZLG(uJuSVc7NVa!=rujhs@ygu1#8Y)lq!vvzTL{37 zx+zfqVBOmhV8QKBT%{B2R1N#D7qEcV`#|`G7E4=w&hUE_yu-kBk3c>Plk98QRn6~ig0gX>j2E%UQinq?J;kaP_ zkgnIoG!-@o2$F5J-M?eQx6QEfljyo$ghW*}pPlMmFOw*i>wqOpHO8UPOCJrvt%39H z%{L?%N7_X&a;u1WIBcY@8d=SH4>~Vk5Qh3*rvS+2kDM$YA6NM>AA_ zA%!Q4l{dboc*QG0ctR(hWa(8;620(}r$*I4nFbE4n?kKH=5Ff&^P|QE@e1FMhw>yt zGVZt*<%ul+smcZ65{Er*IKASGM9RM}RU3Bu6Z?A|?h(uzdT31O4AJtr7}H;x?R1e?z!MbUwTk{px0j`l4um{EX%*_o|_(l?>gp8H?E|O9RcQn z?07_DV!*?%9=SuHK$E_@eb*lbPtCZPwv&*SE?l6^yc*7CRYb%mT2qyS&`a znP9UdOR^}JW*%$_bai#dCm`WBLv}swxw^hm0kkWhGHwT<->Xs>1zY*db*PA5L1*LPEyjdkst&6!=;={7ZB>3{B{c&=axuM z9FqOLp-Ik76x0Q36o#{N{e_(OC#dhMlhTD5RgEkkME|D+(BGn@g8a?B5$p09D_8QL znTt$86yauYKVJ=AKfqRv#hI|E(&pEMHpMgt`YYt3^_(N~*5C@Ry1LRR1KFL;r|=Wxah!iFFT@2vvh4nB_jLS6f2J_NI!>|=t(cynPTvYkvQcf zX2ETraVzjFRf(_mjqbhr+RwR^aIMt|;lgQZkL(T+e26rG?~=nI9X592v4j1E4baGk z@XDX0xpqujy_BsHS=+>~clpa@Mj4kY3yX;>N-K(`(#|{)hx||1MDqh~N*EqgaFYa! z)4|A53=|3Q#2HYuo{{Q+AIC6@l;}BQt%H2Vx3YhT7s|rwrE!@fB5k%paz)~ zmy{j<**+T&s%Ue@l2-7feLYv-pY58YNy4UWZ(Yyb-ACsxg(|OE!v4x!BqFbzL&1U_u0OG;!b^|rM@5Dyj-7Rd@YIu%uR>^la8Tg%qlYO8DSIEi2xXoU(Xa1XVNxa->dzccyibTZeENvqOB|_(;bzC}HqV+W+ z?|zgoO1hwSkGJ}juGYUeyb!fi=h-f3j|f;a3tBKsb5CEj$mp0zsff+0`=5KJXAYK( zw|%tE56Cj@M>Fj(^#(EhMX1#cU6N9~=Tz9Z)+y*HMA8?Z+|8g7v zpGwP8m(rbxHGl`7N+P3xLy|?dLLiNXX854^x@W*6CgLw5QdUqzovxYMpMwJk(eapJ zSbg0cllVwz_#f|h9on(EUfM@^dfd~#tYmB{d!#dFzhq_Emr^Dr`am9n*qm9$#=4!v ztDNp#y2CkfV^L&O-w{h|WBwanqa0wo$y7P2YJ(r9FcJI6SLfr%Y{1F0SP1joyxWF< zS9vH8b7Q+UT7HXdXmIDwDs+AQ?A=TaExgK!f-pmgrkyACzgT`85njB5LON>XOTQ4w-k2s;lYJuNAKNIzS3>iHI z8|@@o?lm*z?X2H-9Pku}m~C=EfX(cioVlISIX9Y&;rf+leiPPJ&m|6hN+$y_vjqM^ zXddYo!YW{Jd`47PzrItkS?_7G;a(9BOf%RW3TNhQy}<)}{lE% z@z_-Bpi@d^3JE*tp?%p*iPf50-r$(B^9}!t!|H@nDn_e#)?}6Nm9jM@g3i*qdkrUk z>O^Yy?B!WA)yJgfZCcTjMk{i&apBd&Uw=h3ovzmM9@P~81T!XjSCtAe6_BIqm^UM#0Q^l^C0bLw~=+c#*GrWi4|Kjdx zoUQXYGy8`oW=n!iS9s#$KoxM_8_@}wj_iL-Y6qyDK})7Vlwo0l^tTSZsx>1b<99bg z_N>9j(-FCl0f$UekeZruU3Zq>w;z73o8QdK z=dm^FPMEPC*>#pPo3hn@sqN*RKdeZ~5T*~boO65ZKwe&c;VKvmSSQNNC~XvLt4bC_ z63&J1FxXEHg@Dd1kTu2YBK{4DQ1hoPjY?MQ6OecZEjq}(x35X%JK`qpBtCK)K6r+; z_LZZs&j9J8tN)|K?ygHb(Ygc|pHv7+WCot_IDBv?QZEA6lvMdFS?ir?-$UQJlkG`t z*LCMHK!Ng?C7D0vo#095W!y3=!BgJQb(ngdTvN^u$FGPtkzQ|+l2tYtq6c?h6>le* z@h25ZL%}rUAsq>iNMO7hJa~vZnRVjg3g)%y&n=h5d+Y@KB=kEF#|Oco{iT2*(F}xW zipQw?BXU1IV_+jz8Iap0Y_C_ypB5NjL7UAZ2ags2kdBf~d;Ymwu(GOVmV$_+l&Vep z8wRN*Y$a`kgzeZ94R$n({8}0?mwD^6a|Fz?H2XA>o_nU%C!(q;WjUtQ9T)1}L5_pN zBllcUb|`f8z7-uIpDorUhr@KeI_j-j#Bt1nL&bn}FHr|N7l>5@cXxlr)LRl?G=O)N zTs){P+J&I@^+V8{NKzjYcnt-{p>75wsh5h;%k<*7p$5{#n#qg|yDk+>(U8yXA~*2q zd3vxP6vO;)I^H_d3=~`~|DbfJWvHY3#P%u%U+iPPeD=+JqA$lxa6T40Wo_^PT^p>S zlw6J~vwfAc-fg>V|0qznL%JVPh`hA_VcDDW7v5{i_1zJdpDoD%j-p6XON`qG(B%B| zLhtiJ>3bu-d0J^MIz3TuA{wEud3sifDmrTeZbw=AX6Ok-1C+tO;9YSIEd2MB?@vg& zRgP7|CMLRAnwt6SMMyY~7x)5?3<7UhJumnSNRsi$x7c*wqL+R;>yL^c6BAc+B(F$j z@u_v&Db>%dwa!>50weBo1Jxq)3tZaFMh3}8blQ*CTjD~c2bHS3^je83S1K4hFaOnf zXGMyn6OAW#csFPCR%Wm@*o`scNhRX3yd8{cd`ORfBU8X41i#)h7VZ#R9I^zno}-XB z(Hd+GP2ADfSsf`DjG4^O(N-J>B1B z(%;y@lAMLQDea}zP5Z(GwvRXYV>Zhrf0-A0@f(UN>usE;51pFUp(fcvf7L3mBH^!c zc6ZA0+eg9YA84=xqdxv$aY-^0XZ=!AJoX%Y?ycKB5^cNq-_u7nPyNL#*zXCB?~)ZF zMyKaW#=&Q9hyvGt?MuiLLm>%v$30x+aQzM1-lGQ&IPdaCn7p4Y1BW%O_cO}eO8Qne zg^M#Y;2P^QGB}Dim>%fClWqFp*2&mXz~8R+P&{dQ`3+bxfyv&0Y!U{e734pf9i7tDIoj?k%Up zz&(#3N8~dsCGDVL8O2wzxFMw&<{ve8U`xIuo=&|Uv<5|)O8hxsqFI5usFrflnVrVJ zL2_kjz7`xrE|U2a(h{Obzw0Bf^xQv{&+NMRc2DOYFMZU%CEwoLlzhai{8w>BR)*R- zFS%A8uFRfk3Ukw(qS5lqoEh-ibO8^;mfVZ#XKtv$08 zgSSi@&L0!V0&X#t>aG(JCg5QK$yi{-&12nk;AXitK9UqjuqB+`|Hy*nfAoiyp^A5{lwUN2nH0P+ zdh}hbhdI71?-Mkd25)r9N02eBt{oe#9!)@qK-kf(MR%D$HDw{VKI+iAbaVVuyaENg zd1Ko#yr!4TB;t6a|3_0i5p|iZWo;9GKgQag*F`Yy9I?+iIx~;h%6I__>p0yCDw< z-sg3H*#iF{iQi;dzLa@xE$ZG!Q42wE&RUMX*YEo*JU&v3s9NWkWhf&Cq|8-u`o+e? zz|ESBCLFrl6gF2ks;>ti(2R7ff|i#~2E~^NzW56#itGkK<2 zmIwz8tzt{ezQzdRhDDM_4g!~J=QNR2RG>TI)xt`)!`VVJ;)QI^_xq_DwN9{ZbTpq; z+TnLmfIh!HT@K3A`+kka4>c0|9E#zRjP8-gp@6-@7}eGDIkpX8BFc|9rdZ<&=~!>c zOpNNddbR?p=ouIgDI@hY`{!6)dAS`4Cr64xgL(*9T0{N`Cw+_jiNy`JwD#fQKDHhI zd|7|43tNWR_gweeYK0V=xYaJ3z@7mbo7+FG^!+`=>AMb{?s?inTCOvIc6ho@JkI+V zv41H=>pm8k&dM+`Wlwl>eqe9Lu-9vh5^2%)>9hQ%m7czH<7mF5Eou#D*vi=9)S^Og z?JA5SGnC*80^UuzgMI0|wHp)we{}1ED={j}rL?s6v-E!q?FpN!M@4rjI?%6oGUVSo zU;u6jJ>%4?uC}M^8z;Vz;6Q6|eNI!VH9G1t3|%LphHNCm-QAaBr0C%U0x@=fDs{Ta zO>ZBFhJzJuk=RE^3Fd&mIdRTv)@`7AEkEhd(0^MVo0mD7PY$HA02_6QxCoo93`=u- zOE_64AadFL_4Rq#Fg$jHomKlgv@@&lWF{94f*|4K$t^#1vXhL~nF@p!A) zt{9bQLD??AK@BbP)!h%Qw%$wM(*#ikRN|uqCFJ^M#tA+E&)PH^;@n{p&y*7r+DVWy zgwcj_FA5BQr5;EG4=O(Fo6{l!0t%DeB z*fxPT{stvWzm_5X6K#pABlyrwrnV4AZQgh({q@&+K%e%8kvJNO?LhN?3byaQSquB< ztY`kH>U*i{y(_`_^13>`7={kAHobc=8ce29tctAb`FcEk{)=|e<~m2yqm1UdwE}Fc zg_UAn_!EKD{0GY%GQ9aoMwzA49@)B7Td))xqb%d|mQ3;Y!>%-(j>}IeN#`7ui>4pw z?w+X2ctNX^F)f^D_kMYC%04FY3e$JH#0yl7JSR^N3XKGYJ*TeafKxToCPkKXG68Ot z>$pL%uL7`9OU!=b1{!|qZs}5zoYzU!=a5Mit03>CTqIu~+?8L15%MM4QZT)oE$WvH zcG@kXBz39T6?Bye7mFGCzH(ft0VlO+S2(T6c;v4_9f|%3$g9MeT)MQ_CLSC48x<_= zwa7kP^=SHC6D-^+Jp2l&uX#71?Cdpsn*vKMqT_w&MM(Ywys+}xrM$1nWW?77VzU$w zA>g39=zDA9EE;g_xtr7Y@-ln%l(YTp%a#bnGgg>yr8kpTWn5Fg+884Vxb8HQtzBC` zw^AlUC@oqcgYP4qESMvdox`6{{nQ_0j0nYliRyN|=8<0XsRQ5O@TXN$j=t;6&g1`NwYjdpXm@>%QRo zP~OM0!rztnxAqKK2?^+5x7WYfe6At#_!Od}jU6M22>kk6UDIgQjL6t5H_sL8*yUp8 zRTTDSgyBvp1J4spt}utL-GG*hncWOkaGz8|V=mohPIwU!2aKdzGMj4xiD)N4pXg{N zP``r*2h|$TUisKKJb+*RhWd+ZNHch-eoRqn4sOxL_W7@4z7~A(CDTws=g@#S(RTM4 zt4JTnD*v$OkC=wXf`@}mH06H2ppmX6IX~`X%{OxOFKCZNI#@Mi!pSPl%+sU9=k!+W z$cm{TCr!SG7fsG6&h!j8P#j`_Po8etd`wXUU(Wr{iA~><2#Ct;k4})0R{8ReH;~74 z$pgN|e~p&W=;`eKkpHVr?4IaVli*v~!?#{d;OQejOEnQ`XM>IZ%d|y>p3jr-ONR=z z{=z>w^Ywj~*3x<`Nv*4UYfrYu^Wa)+7sCPE5?p0ZPCv zp=BkQ{`Ji*&R^xp%o!Raud5cJw}9JKS3rP+juV}Piz6Q173FrRw*t>lRlvmCE`!-J z)u^XX#k9Z=5h+i1pruv^z%wnqUSyzfMvM?nwdz-;7p<3I_^;Fg%C&=7*?S=NNQQnp=(^b8l7g%wL<@#%pxxhAMU_=!CH6KXq0Rk{Cek^ z0_Qkd&onq*f7SI?OcRT;{dN{m#aFh0@{)<>s+)5vdz#_G$NyKBH|xB}D50joLHbZJ z0pqUIbvv9+TbA`tKOWaFTBiLT*ht<^9y3l&O&8GG4tT!dK?9%=MU|*pb9iFGo}}X- zd7$KpOQKmZJ0U@DJhK>X!tp)GY!j4}bmod47C|0|nREEN^I&C#YfD5*y4N7%G#f`Z z)kaISx4V*6Qr`mV^~<7_vB0yH_gv=pAhWB#g9((^0(V-B&7cIz4J(22Gb-q6Qr{oP zO8zt>AAdf-bVm(uckFY@FuW00CyobB(2nci20`tpvSm;2ru|EVJ~ z_wuncu#a17YQ_-1Dx>s2R=6R-F0UexP6r>vrOxqB5(pMOdu*Uj4#I37Dc6ir;9>=AY#IIg}fZEayx%Vk|N31 zp=p1ODq7CRAbh&)vQWfH|Col@KiTdedXNrjcqH!%{61auoObEs(iWYFh}L=1wAy2) zR3mZ0X^wi=V!hKLHBV-mp+20EvUci1C4!rDH9ymkkTITgODIAP0Kj;|zfvsTFAVBz z4Qd|qbTM{JiQZ$!EqYWh9d~-YLt$gH2#7C#^EAgNNGm6>zxEjN3HxuavM|N4BHT;t zsFu){G&`@4C;g`Q{_HFYjFIu27^ze=2(r;o{)P zzm!oe7i}!vCY+r3&8;H@t&x2Of$@tiWDrL83wH^p^g)dp`n)#dJc=^3E-8w zATSt4B$V=}0I6sz^ovOI+oQ0gR`0#iIt8pYp)*ZK7OgckezS&{^RA%}WS46%dPQn=<>ik`2)4#whQ?%4~}b{b7W;nG8WaTn<E!4A8I8+^VqX&MigiU-C7wL$I)pjHjbWdm)O!Q&@bew_1&w^r zr?7q_w6l>Se8X2qS>@1-zxw<4p7+Q+A22#_OtefIH1q*0WM-JTCko*vQ3B zb2!A8&*?7+mTEdH*${B5bwt-XXKw5`_Z*EJY|S4QH2*D*4Fk zxr%G5s(kpU^?k8bnfE3|fr2THMkz)d6g?yh5)$fs5?v_cPbe%8$PXa$fQqO7Qw-7* z7A_IR07y$^-0|MG&Og4qIoeU%Ch@R2Uzt*OoF@w=B|A@VeaqYI^{%;p6G>NOg8*XB z{)Jk4BPm8Xg~EW){s?>U7tzFh5J&!iT40w7WWl&xYdq*DpoS$AiR2zHC?x|)@(QAd zfY?aIzL}awF+@jkt`93W+O;uqo5y)^BWNNtP9({8H?o+drbEcA4@laBE@ugl-O*|yuiJ&J`2T|Ms*zZ_unhr;m z%tw>MRB1)S&}@qkWENFZdG=awOH0Kbt1OLCXv}d~8)yxKq!%9?VA({fOv{rOZmNmx z5)1L*iz-?{Ahie>FC6n^#yyP0`HsQb+D!~L=IPWgbq62;;iRA;I6}jUb{Is*qqBVB z5Kap(lP#XU(pIMctWdJm)~}QWR%t5@!;Xi&D8y4jxL&u;KZS~F(aw%5o0f_X7cyY4 zy2{oo%8VWEyfPzOX#ddF4+;|LZw58=T*^Rb82^@ZQIR26LL_Y?(xkT3i<}ozYq7<% zN$FKw9Fy0mjqV^REQRw{p#P)_s;?DRtGXPZBdyk6bW0*K!>RY2}q&9!RL-*rHD;*E&#BWr~ z;i$~Boav^Ua3)J_Ly|;?NI@XSeLpP$DZ&hTXc^6tiQ^Vtl~qKY&{upV)J&I&6oXO% zT7DUoO^g0i1p+V|b3f#coT}0aEwIxj<`a2jjequPxgX+#{z=hEJGv{iK|VNvu93Q5 zPf|~wAQR~qVGMxk{(wY=W_zG78E2))3bk|)t5(x9_+PXkJXmfTj;TDCnyN%7q=@%g z9cPqUg6$dJF%|e*J#Gr^?1?#To^0DTwJxO8*7c0YEb(8zFlk0S9w(KGpgSE%$&`g~ z8m8>=85!BufUrE5UNw86&a)b(^|NKjGO(i>Z>>9L@1sZq_W%6(q}dE(Bn6>fV=gyb z03WTIi8af_(q^`nCNUk^(J6(HTK!{}lL`tU#M1)hTDz@DrAjy<+=cTO+F5KCz+C1h zHEfR~8#`#XCcH7nP`D1y3ZD?F8(Qt_%8Yh!p+z~duAhu}uSpPS1VLI9u zn*1ER+apm{)NJ7#=YTNB|I-2xP?|G`@3|0E4P1h7 z|ExSe`@%Y?ORM2<+t|$O08!_eyk&UOZx3lHB@c~oa6GUbK#F8mG!Y7Z>`mC|&xoWg zHR}MzvnTUtzjc_DkV{<*`sd&z6W5v(^Heju7<4T&f0t8`*{q|5Gaz$(h*g|U{H7D0 zY4v;Cs!4akCF{!;Z^HrF1-m2V9sUr$Sr?qO!d0e zJ9;ujjc`j9=AURQRsZmefYKbIOe?aFM_=nC4pU^}E45o}>hnTb+~3E(ZJwJSCYf1W zA?w-gbWyC1d%2HWuRB}bS1K3cYU={A86_bX^;fs`1vBjF)Eu0O1*EnFkuX#k#sQ>5 zAPwfcwAyh@n*0LDp|A*587$k3acMb#^E+@UEq_r|y5R5%*NHy_j$8_7E_5cp*f2)O4tqk0Dh1EfNKRVKyxpQGdoB^n=;MA%w!NQ zh1NcK)?X=HspWHYWWO%mB6GW@soLjLY}Dds#DatVv=$BrLUv9erJYU&7+M)|7wYr| zCo1*YJ(0vD>4n9D5?GZoo0_Id03mbm+8UWG0m_5V)S>696Dvxlu32>z)L^ArjsI^& zIe{tm_dRZ3gTH-=UzdK1kfC~CaQF@cnYC@d&*K>Q_zg!LuG(M=Q77XGcujo!;=Hij z=O<40z4jrm@?uGG#-xBWgH(<}%}mZ@2pC4D8-MG`xMsvkhJk>=H{G&`085niDNrm) znU)nfLta#kwg^!$z+~Je&NY_2G<9s!Xv0^HN5-1)OH3nAwdOD7!dh$!Ne9MhglOd8 zka7p4kk=}vjWmpK!w_{%gQD`!UT_Yn-^Hu;CcMvssDL1~C50t7{SuanW5^_K zOb&rd!E!`yaZlyL{Tpk6sNq)&F81sV_-g>+ARGXv!VNp_q_3z^az6LwKSqb;#F>^xO+HVmXR^Gn zD~}y5MM*)I;&+I@xj_$tNkULoBQIp$D6H&+llz2@F>bCkPn%I5@-5h{UNU|G-&RKg znG1c@k~da~V#U?-iCL!X*JFobf_N4~@>lvK_Uim>la5@`h118A5iD2{;hoWFS4!BH z@S;QUat>TCj5Yn?H9^RLE_{9ZW(nW`A&N7`~yo${9IN_K2V+H*mV%du%GlpicuUPwP0N~B5I!=6$;Dt z)ElCpAQ$yZ#8T~d;ehfwC`zhz)V5Y>xgu37c&Jahrc}~P$`p&chw)tGnH;>C&4<9{2<0ST^W_Cjz5QMy$}WoUH{dzX(0_!wdOx8 z&Rvxf_bsk{XsWR_vWJb4pj*3WIbC4nr7D@vu(GgNtW;EFwdrwsyI-^nZ4HZ^z`&} z#1WkoAc&NTgiY5>v{x}=|B{EF5EcH3Ag5GEN)!&GOg@KX0*z*+9Z6K?974E=HTW*s zEQu_pu11Mbm~_6#!RmwC$!x)fdHrz0=dCYZgffAd8VYY@OK-Jy$BCj4F`e9^c~MmP z@4$j3y-3*wj&D1lm6#K@NKwqP=m2R|p+w*t`JzAk)Qr(!WBChom6M(+EgOZU)Wpti zYyLfJL@ef-ANypzr2w)uesKXSN@%=coW#Z6SC8#L6eV4(SXRcvgS#!!FACMWqfw^P zf+(b}&%ZIS!%)Of$#dvA;|rD80+kX?CR(_-TxF>{|6!{$FMQ?ei2A8i5@PhrXmaB*W#)(J~fySwcpwXc1?v{ng$<-%Pnqb#~R;T zc)j5dBg3?d5-nLb+ngh|;#0Js&<)MWRVs@Y)iz`-XTfcn$&_54FbB5Rk)s@AtgBAE zSt+69Dr2%^6(07QF1)8a2^y?5#hRFAWuTPFg(4F{n=$sju>>t zNt|N4L0Py7Mqx%wv&12aphD7!*m}25Eks!^iEyXg1>A)f2AUt@GV{|8uob|?ZVe9+ z5=Ayrba!Rxi8c&pYW~ee+=@5_&Uti3%!w={u;aV!K5{IrX*L${b5uhT?N8PyQqHok z(|b>Zdwb~tN)b1%U92HiKTJ&}jD2emAUYIvU^VBLZ7|R(;1gxg!W;?L*0E*gY(@45 z2;(Ko!;`RFpka8EZBL3pTk74~;mlblAjAIexxZP(l>pAHw`$M7Y|!{m z@4zP152MT-IjW`c^8)p7XDi&Q1ZM?W@FYH~ctk=Jn>LzvfXQ@6WQ#^lA~EQhA|X3!)7JJUGNI^K z5qMDo#sW^#ZsA+Wf96`Z+g^2l>QoDszu^L_Oz_FPxDK&zq%|=yP`&hJX1cEqND;}# z={1!2+G%B1OrYE#VLCxImFr&++M78Sxr0Lw1^tc8%`xqmu}yJBxoHccAHixgjJLkx z{ZM)iY$0$cS;UvZp6r_WeJ4SPP1M1qC3SXf%tHbbNMdco03(M9&tW9srls8eLFqBR zs-S@hIr0CCH-@y>AIVwlr%ArxxxzP%l`WBo6vOu*vmEP8*fT6LiFZ~wVtQVf zg^8dsx)L@pvc=w5E~hzvj28p}GXpZ3lHwJZwYt+P_pCn?F)f>Ct-0S-rCxdyvY|{K zOCP>U_2Wj?1>}D+f@CbvRALW^Vnxu}yyZBh;71r6E9Y%mF$~39W28}a61K00TVVXe zVH}pMH2&8m+I1sZ;S#N&hv;sL?mODXwEb~FX5a5YM>pJ_ zOPB|~=^542$g>);fo4{?8p|1Or(KyyW)v*Ei2+9~%ic3SDZF76_ET}rtS;-fK#Ouh zlt@D|#9+d3{&lmj``IU0VsF&6mh5Qg*jD&R@*jV4^3nX z_J!sRVcMPgW3E+rpg=3L=-@q-vh;NOHlE{6M~HWSy6T^BjA{45^<0= z-rgG;K~)A`tcA#3TWlx1RAt6z0N_7H_Cync1KeWKPkSVb)1ph&Rto4B6AoQ7xvF>c zYR;5{H|Cw>G%|I5$tEZZ-cgpL@%D=6dMeWm@OtDgp_n9$zo!@I$2UPhZFl@$n3q$jRGAz4IMw2{KjY2ST zHms@tGBuB0{3YubbC{2PlD2Q{q|@$Gc17f2WfH(SlZlPbViayR_Ede=`6g0VFfui8 zpvQHY<}TmMuRHNOPrU_@;tik_6v_UOeA6s%YijUhD}%R7qVQ7ZGb4+8d9ND9G;^@7Kfw*0!ZqkZ9}%H&%+ zm0Vw|Yp|oUlyq>+&4kKKk)W)Du+%$=ofhBSsjX5tph;L41^C{)jt% zD0C)%9FL3hwzfg0H&E1b0f%w#`1sBhhAJq?E!P?xci7XAF1mI1^cckp-mkjMjKLEB zbkyp((aH5N~QEk9isMwKj zzpoDX<;Dn>U3@>$UH>?>BZvxWpgeeiOwMggk=$BpX}4sTtKq=hEVTT#BK?&PZkK1? zO>WR1b}VZ0yd#^X?yA00g(P9Q?S)yvNNy+>`^K7R`H^S$UE)5^u&jNK8#%@Ypjtg5FP@yX}C zwfAi(@BLO&bs>?*Kx-uyjY87zI=W2n=U&O(9a1;LqRG2@kKse$ppgjbrY`L(Ww+ar zLV*$wcyeJIc#w!(8aiscuZIkJk1|0MC;NUc7u+-aS5^1-_tiDr92@{I5&Uw=Uot4bPi9c1C8qwc-#=l%vR8Rw+k220*QU&%%}NI8EJ zA3ImkW=lsTQfha(v%9*QPB>yphh!o;^Tyy3gWg>;F#}W0iFqq$b~JD;1+XiuEd7b> zKA+g?QEcU*Vu6@O&a5(HtYN{kE&9=2)k?C%04-~YtpBXXFn@pid zgfWSMJ}mp z@u5YyHm*;KPR5Cn z3bo1nR8_(COq`M6r`Ka)|8oL|F6?8xhnukgE$$~Ht)uhbo$o9U72!RpRBY*OsRt%-Q`X+94jHuy@FiTj3k$4 z)a$z+#^%@b&Akacf{cEM_B+NfdgdxD(`>11TmaZl^zQzrUR&44jE-xnkGxguE zDMu#Ks?r{sV*2Mx3m*c->O(^LOV;>2-Ma21zkX{-jK|~h1-N%l1Rq{oN=n+VzE2!B z2tUu=3BR4j&+s097|###K(F5dkIp+ zc3PjJS=x$<-ok~ufMeQWQkKjdsG(OIZ;AR1?sd>QKNqjkcoH`m#b5Vh;%ii z4y~Y2V+vTqf>1<36OJq7^)%U7xX+#uY$V^qA!`k0iX?|(aqa}#rtgm12$_N$OzV9O&0wE--3{jbbgZCJtM7KdW^vBQ0oMna>%Q3#qT-7g=JH0&O2(+& z^e+fu`e{B*k@-Nw?|SHXnhzx0dy~R4mHVcj{UVGQ1aoNUKzdYmQMl1+F7WZ%2wYLI zevc;rbC03dQ8Zx#0Dyl(IR1j>gy)rN47Ht?XU=x?suP(3GG`a5UcuPag zE(SW}t#$1Mae$?YlgS!KyXId~Lvvy!H8b;(gtcr}A}+-7;!rDhB;CkwP;8sLcQ`?a zV(HW}k-CcRuF@+e+kP(e@FCww3Lm*MDhD{`*0CF9coW3gLe1o~Qb`0cq+u$Q7=N9R zm(=(-2Hr+Jq|^rigv#hC>Zo6@gIaXdn#VSReG!Ps}$>L^LT2)sy{# zzLA5)i4-Pd1Thl~A~XIK75_OynbvTR{Po2R_+r!z(Iq~`9F8BbBDzH{L800G-AI;e;}?7oZJqyFG+)}K4%pp20qvA8x9{! z8a>YUiv9~J3>t*~uL*LgjN2Kos4CO&-3^mLiJoy+{^PR;Rp9T!Z;PJCzMN?jsc*5m zD{m79xvwj|`rSa%X6gDjPo#$X*oQLCIlmm{EP<-H-GBfU@=1YSeET(v5H6&Dd@bLRVELOWUH&bTvX4 zrTr_zV@uYsQmgjFMXMo1FruWux_1>Q=qGp#j#{Lly_%Eke<4wl1l9tz6pd+FMlp-gT6D zCBqxw%tkcwbRF-&1Dp|tz|Y(wq#HfEK`t!qe{D7>7*9#Ouev>eQ#d~@5ey-OC`xaD zla2$u)l!jsQ~A5cW!rd6TlLny`gZ6o~ zzZktg#a6w8IEy-#knRj*Wu?kXI3Pm&N| zGGtF=Dg-kd>OIn3AN`{n^cYuJM5|&aldt9+);1CYg?-1mit8$2CaO#jYn=2}MfpU> zQ)u1EM%rZea`wCTCFe?aZsu^?eM7+_=PvIMN&ceQtdZ#B&fq`HUJJ_G2hv;a!gpb} zw`VtgkZ*0*&CS#o36E6HP?5Fi{fOl;$C0O>L_`Eqid94Nq(%NR6p^*!ME76!U>y*rw5ef2otFLrV8x*wZ zDWsI>rkTdOl>6hXH@FMb07=r`WlEZYS%FzW?qO>yRMA0b)lKSzIhMe|!e!}`V`ujWN@0aMU6 z%lD|EUl-2I?@m`vim(oCD|D58@7)eBo_=*AlpGq?>#>{OZo2f|919EAt48_lM}FAY z*m$4Um$@^4vXGK`S+mHy-jANSvnZGme7M!5#`nH-q+A%-SzGTKJ!`ec3L48q92DG_d69IJ9Rlu^?YYKe>vwNls&=E5R|c4 zhlYb`cZLZ3h)rgX(3IqBP+6f(AXO`&jf{q?(fKR^4IzeK?*kKLm?SF5{vt#uB^y?g zWM+STharP6l%2|)((Goc)&1VEE=k4we_8K)CI6-BF2Oq3@|Hf!5$1JQwfL=3PHu?!bG~`@E|^7+0{i(q8Z|EG%Hmj zShO%GJBoAM5gdo-#~j}nXRjqo-s@jb!Xm7J8W>-bp&@z!5cK6A_}2px79#KSG6Ubc zDL>S2SM##isjZ9c0YeqReTba(2=~ISTCg=2MYHsfPP^z z54bH!)BiWkPhxvlzrPBg>t|&05bjn}HqSvM;mY5?ckE#OphX4pkb)75EH>20*$_{j z&Ff}qsc_Vw;6Fq1tvw~loVk52LZyoT6R@5sr9@^-ekWjm^(#|y47!5;l) zZZoH5J3K)qg~)(PlI*4UiXP?HID+rh)lG&yn;yN}&&?rmnZXHp(Jf0`n;Gi_URPFr z8a0L^N2f3JSxM27KJ6JXaAKJ74HOJ&W*CgNHd45S_451tai7R7y=2UamHxsRP+=Gw zI)mAQKxJ3 zYePu_#3SkH8VaLR-5Cu+*GNcn{yaLR^T7;;r({QEhP~a3D1-^6Pvpj*db@F(XIMS) zU97EClne^*v2GVt$vmd+k$BhLPuiTZ*NTk)o9+Ic4m61vzEVFmOfYY@Te3F%N7?{D z&GU9HXSW1#@ZV9E{~}ICztB4WRhJu}SrLBv+t_&=flrmp=6+HTHD7{?j;7}bti*!> zVt+H?|Mvb++wlafu&o)CnM5+nSsO`?Z{W+D0Ui~9g$y>g^`>r*KzlB?GyODO=ck9B zhiab4PMhVb_w9!s0It2)NJ(sZ9?ux70J{v+dVQAXq)1x%SxUrb-PmHbqh-YFlompc zor;0|d`uMr@a_Z!`5~n$U6*i_P$rDM*n;uF9 zw3fDg&q$W#7Aq-<1r^B+?zeYXp{4RzS2M_IOo!JPUK=+Rr_zei*Y8l>f(kY^Net?v z^(GSZOKvQ&hDNCQO37l#|@Ieiu zB1;{W+KLuo04f|;Jx2Y333bCOt1Mm5NlWc0EtfiDD$;xqYx4y;pLrYP_6KTo7OUC! z$@IWXc`NZ45?F zp{Ww3WUm2&-?8o1yxn7&2%3B1>~v~$sX|3FnxrW^KAtNuWAkX2YZ5>!5BI_7BIR2j zr%d>a*q-kKS~_w?Bj@Gb;&^qOc*;7z;R2Uz+9@Vtks27kl&Clt^ogLlyNZ;!HSg~5|~ zCSi(p_N_a98)d@2i~X=9>khGXmU9EOz8Bg0c4o=JC_=8a-KFt(?9`$Ip`w6@2aCjy z=b?G!9q(3G>+)E*_b!4$=4?&5?Q4Gvkd~UUa$S*&SZ5#4R1INYK z6G$_wQappa4pY)tdLCcHiM?!BPHcfIV`oH&OAr~xQYh~QIRAV=g4Rl1x|lM;eZMW^ zX3}ZlFz38%KYj<8`ZH^7N!(Ar%n}P4K@GrXz16Rp2VBQg+AHn`aG6SByneqOHZnAs zEAi~{i+C|@oxIV>C{CSyw{5u;IT>aNHxt^$JB5^un4p{KP@5Cxf|P6s8pSAcR4JA1 ziLNSt-M2W<&5KKM1FcIu2rWW>> zue2(Oyod$mzSZT&2ZK+z^AT36+=U_}4qc%SN8jN7q_?-8SXIJPMPmKl?T(5k33D=$ zTN#NLtB;U~R#t8F{haSg&hu<|A~@HALKTIqqW+rqukLyGQLLas?ZFTWHFeE=T7W(4 z;$-eSK0)}V<6yiZ-)XWqxfQNt8U_mcOtxnrh;K&tV^U4S*J3Jj={j#`d;30^ME50J zSYX=$n*BI$$Aqe5u4qKpZRsJN|I%g5RCdLUlaHG^QRTD9?n}>=_kZvUP+_tG#Mm`S z)|C6}F6@fX^&j?9t4no?aZ0{^R=*|iL9m_0t&^zyLW_HXXRgPF9e1r>XQ>oQ7Khb1 zmWB_gI7xBNt!Sdwc4Mgb{q6~vH3=Jv#u@Ujx_ZIU<8Zk@hsn_>tvrL4u%m}17Fu4c zhOff-F7#CP9|2Q#o%HGUwxH%6c&PZ#$|?3Y1uUkk2<+RAMuabOf87I#+h;e>+hlpq zLil9}5|&U?PnN+*^p{zJQ5~q^0Qj^@EEu^Fw*4WTBm$u(Lf=f`9IgLdB}!BTB7pxC z1D1^u6Y3PRp`CU^^^A|Iiulizdm)I`RHDE&3jIsw3)yn*NW`AgLz6g%5xGyE@UygH z20dFwAkmX6MXBeUL>eb&HSfzg_zXla8L@1~ztC!x$;sJVmg7D=5Xw-~b<=t3O6@1& zax{7K<~J|e2GAzQlNnh4ZiGTUe*_;kdky;=8fSzYR_pdEe#oxeDb54plp4^OX+ulP zF z@B{xtpgXed`{3JXJ{8^ZeBa}2a_|c%>s+R@<1c}Zg>sSP$j3O44*YJC6s*rNFb^U0 ziiEu3)Mk$nRcj}?y?|I>0sm#Eq(A?^zTn>LScjpmC!o^vK8Rg$_xWD0DFC!pjD`L+ z<_X?syG+;C6s3fPmda!_&2l;uPMep2E@?wJoQ<%evM1!|6665^r=>P9trd}9i8(G( z#3l+o0mWWHkH_ap-0Bh1o{bn}zt2=iJ$1~Rmj+R$LY_h{L8dVD&q%YCSTL#vDAm5B zopKyaA?aiue*0xbhwZuSts;BgnP;3XctXv1@*=*`n^tFFHDe?MkkaWh#y`)!c(w5;O-^vfn6 zC45fh%6cERyK4R1%zessxO!nMft zobJ4ue!EGVi88nZS{CbB4%0%%*j7GkDMJv;I~!L5{eYft zqT(X$1K_ziGMA@1IZe%=Aef9PnIky(sOeidazr9{g`pcPL4-)upi)JQX16B8K;7mj z4`%9f%e1Q=4B4YMbGSyDMBGWudUOcMSjIhW@_Dz)-&oC@qHOE#a0uL@B5TXcg7FH$ z=s?*FX{sGe7p5c|@KW5`A5%)r!DaYZH=p7|?6Mt>W2-?$g$}IWVPkwV^Uk3i2mt_^ z!+WVW8(s`yV9CUI(d1eYH?Xq~Rejd)X<`HTFjlO1Id9w{`FQ+mAp~CAc2E<3%8(-Q z-A~GUoeZ!JNi%rg=)CG70w3{TKHjnTU2i-;6RV1ssZ{rKY6kdyLl8SJpxI) zZsTG*z=0--Lak&)7{M$R9&w=T~Z!sQN}I78Rpvl&Yvx#YgDq=r9BPn_v_KNgWqp>JRj(0?{3W z8+@J`fN!rZ-mX5OY`)wsd><0{@jT4k!)r1Oxg^nKfMY8%76QboP^ExYN83#9HzVfk zGBuzAmQ-Th6)*g&T;;l`_s3yw#(TU+#HKj0&Q3bc8DWe~W@QXKyG;i6#DfO9PBS?p zfN=`fL}<{YIhC9ul>{GCi`l+1G|-LW3Qt`o4t}Lm9V(wQeqw8PEZC&m6qxKXZudF1 zv(j?y8^K&S*K!y;oL!D{GO1TH|AcnhQT`i?6ORn<;=)Ku9nk0NOq2MGPH5C!xu807 zF>I`xCX-}IM@Y8{8U$F0;{D)Xn8GvjvS=r~fjMtKrq-VG1lK!rA{N;Yp77EBRh}HA z8*tgfRA$Ui4+pu&B8CPiv0hQQ9yOpE%?L)ckG!>5t9|2fwA<=vo)LO+#dVMX>P-K? z3Bn4Q9PRO;fNA|ZAmwNGyjg^thZ{1!4urjo{t^j5;tH3UH*EvmG?Yy03>p2Ld8$OIh|E7hPcH^TC!#pqbG% zLhMa{^yabiwlSrZCggy-qd+~lef!lo^s2HVql!M|T@tv20X(s)SJa#1I3RPJOR(bh zIxF_@@pk3EasNDDq5wcioyqpw{9xqv{iv%S8nZdZQKDa>(Xrc^rTU}La<2sxHOZ6E z!nXZ&38R8YapgzeQ(?&6Z7;JyfXd|Lua|&F?(4|!*V>hT@%}f$1_yDBG)d$++sc!6 z^r6puj0S-}A^CLV8xMx(ie(C$VHz#QL<lw9}WvcfgzC0`rg^QTsK_dzQhvg zGG&9-tyXqKWeo;4ygl!q2TV^l4FCP{8{vQVotyLYdhrU4lxTRIcBp+135rN;iD*0V z`x4$-R_0Z@v99>doFz1?$k;gFMXr+O3MXYZ0rQb(xyX$9M<#U1(DDr>P zV(+%=8Hy?ZWsqizPjuj{Qg38%6QTuEU*8N>&3X+Y+>pJ)I-`G*%7JTE;ta*}UK&IhHqnr^`umegM}BUxta{mTD#?scj* zJ563US6V4P6*fp@zh8b!WrFTe3C7@$Y3_x}hQ=aT4oU-&yn^kaqX z>3O^z4WbA~fT0Ij_erpSRHI9ZcbQdDvvb6{61|NLiHKLq`t=F?6zvZQFe1&`FeV}F z7nK0ETLBOy9WAWMnsa>v01uP{t6!DW812uTZW+;#@aWCYSug`1jzi?K2K>IQsN7^O z-Ndd8-n-}a#HX_<+;V)x;>o2!^@UtQ|0UO?)vD5!sF8yp#EDMpbK)x?brWLG3NAEs zgehQmL2alUw!m8VQbrVOYB8QHS9oOxEf=)A+4M576B0nj5Jb}@eRYPmW~-CO{Vb2c zi5G((TA|8nj~EhQ=YRx`fC!|L+k?%ji6K^4vyDe#>$vRSQ)oSE3EaA) zL8L#Q4%3XyEA;%HxZ?$GPS|R6XtEvWfu1})L_Lw1{~_vd0W@G-6UW=b$V1iu0NEoz zUed9#p}XSy{$%0V8bg>@UKzi<=)26i?>NLhC$82`mel3L|6>-wvp?%K&+mDG>w7bn zd;3R?#(x1UiWg#@#s&jNy=5uIff9q;bROeJ%E2%4AmsU`@H4jXTb2tz1|;bFcDI6f z|BmOIFGc*6gcYCldeOS``ZVLP^*Rp71@6IlJLrvVA5VF(UTBW`&1{z?A2X1vQzlU^>nSxKm6RNV^^sbMrCVja8p0vr^Fnu}J$3Rpq)7XrLcZd#a$C zPOY$`5ktU|$!)mo?flju?U~3h=d!;3c+vWI6UEe5kjN*3&D7E%dkonA(oKQR7q3=+ z+`l1@HVNM2VQjV4q%+!(rh;8FjJbK(2RBHPjb|CqVUkgWA#b@l-Qn9Z++mr~$Kk~m zh~?Aj?aoMB8?Ukg422r$s$`IYYQ5hewqRGw=gKJC8pPlznmG74erV2$vsZzic8(K@ zJaOOwgqh)Xm%pRR8v0KLIs9eLYfP=L=ZmVnZGwvE0P zSZd|Kar}P1k9#B_^$U~tSI=l{rgQJ&OT#9oN@p8|BhHzZ;DfHe9e?y9Z_$S7$4}Mw z8#{!I_zM!5n5F=LeC8glq@&~Ua?wj~@}^p`2q-@ufY!aogvRZviT~r<70Kq={%NXb zU8xY@g@$v{Y^2dJBtGdAQ2JJ8Mr3v3W=unzGa* zYi9)UX<@rFLS;xB-bz<#2b-cda|$ARVFrbvNSRPD84O3`jG0YX{-wp|!_3)B_8koT zmDs4oXh5x_!;?|?2^rJPty})<)M1@D67U-e)aoA1cIHQ}QQF)MT1!i!YX3C=DHa$x zZ43HD4IL{KAmGHPMSaM|?Fvl1`5A4J3>F{i3-HEMnMY_f0f}>1n7v*@`B;7rGKkBT z$dw+G2l=L5fkbg7VJyEINi011AfIa5$ey#f37`^9*K9|+JY5bppPFm+ene7SbaXsp zD6Wo?SpaP~y?SHM*47-?c|hNXK)~<5DS@Ns4)pXdA6v{OGE-R$I=rDoA-)tAAs#sD zIV8PC9e3|}Mh}usChyv^U<5g$*KIz*K2I7r;sWUNVoP>!_H`3*EO^ z;jQO1)EbIfuH8$(4rnl#8K5efq&1=QsRuOm>`|+!Ir4fU}rM;S-&$ZTB7E6 z5#9>}XY&@|gqUt;GKWs7iYwSaU`kHK4@|Cyld)N?TR1T4PF@g|*AD&_w0dOSd#NMJ z0Axo=1*$y(rs%;o)<$7hVrpIiAFbVu-9(%j3M`kfqsN`Qj7U($3x>=&>ZooBMyr7N zqoT>hGjkL&Rn$E;4hU4|PE;)Jrc%4U`#A*Y5X(8)|E{PI1WwCEWmY;cHp(|`x1#4^ zvKFn5c^HDB*maz{)6&FowaYaFKAL{pEiZ~&%aO{IFr{i=ze?xf(%;mD8gG@ z<@wuops195vrw<=eSy*m69VxcuW1KK1_4&Y)ozk<_tF=A1+%!ns7U%vGaX1m%XC9?!_?78e zt*S-$o~HrLf;a3KQ>BuMg#fsu+3Ha0d(Ka)zJH~J`6)HjC?pXPl{{`(iM+&7bsoiGDdE7V3LQO{lNwT?bucmNbmpCY_6GI$+y;csvhAM- zclK8qUk?J{?GEnOZJq%+^ooYhi+|i0lXtHjM$Bi zmCj*x^WSTkyca;VAKs)KX;&`*2m=EZ$-|;*{K$uzjm-qm;svMmcCoI0-P;Q%aRQoy z{}Einry3~2uYF=DZw~Tr^B<4#EICfY8n7F2)ekz|vLW17_;(R~!5M<_dTBDG8O5fe zaP@bT%UEo5{h~7mKDh`I6||-qs3~M5OB~LE+wKp%N^_*%LNCNR)Hg5%R!vxTF_q*Q z&~`_YWaMhGk3Wxa6((LN4ZyRr1FGNZ>hfACpyf+!B4r{?A#Hfd#;6a4TD-ZQARSWuTxCQG zM~Vku+0wbO>z+B4ON4+LN5pSG`m3PxjK=5VZEb7YWf;#wt^C%Mt^KO!#SP@E*I=sb zwmp({}(nC_2r_~pFE*liD;Uq=!LMcL@w*IbTnO*^NQXB zk^Ab1_w8?wZBNiRL+@T{sEb|Mx<{|~l+%bW^K{O|h22**qf+?{_YtCA;$kWK?u{gk zeU5QfTIvsIcJJKD!;)hsa*g?uV_o4X!YC5H*)a{riwU8O zi0JSS#}CyRDRIW&#u9a zz3;d*Psi+eyp_&a>0eF!^;SG4?>bzqRC!oSvv-c1PaDTPM{as1Tw0KR`>ph zpfc(#BQ4Ln`3}e6rTiW&6W;R0an|z~47>ZZ_m2v3@CW@}-=}!LBld6>gC53r6cVqK zci)GttA>g99m8-zz)0{4S?Fgk(TMZIDDlr-loWpZRbNKMUSo4$3RsSul2MlOSsVqU zKuOO681o7Q!&K0l0uEVa^(ZVb5`kCsrO2~jD05_}pTz7fsK@2iA}$Dou-B`e{6=Iy zu>1my6YRo)xw0fKSmFQjNRD5Z^!0_<#yXF_ z^&*}V>lAaHuf=iDnm!CE6ciYsi(K0qn5rH_6zoGxMD#1BFxI~d9!kg$w^*DHMnQ}% z5@|}uhfz<=T#i29@`~a&S& z5gv*0aIRh~lr=S;OV6P;>{FPX40A;25}o{E1MK2#5;$$!gFr5{II`v1n3{{LysRH7 z9$zv#Uv)C8u<&31w@2XzNaY?lpl>??4-^)Zq~gj3;fEpO_NDoymu-%zo~vj^dU#}V zzJWGS8|!^}`EGs?X#{OhMBzdC2^@V~0OB)28elYvr(qgyj^VXqJvKSIda$)alAyPx z=jvgmu4ZoLKJxVVDqh4!uHW_3X{Pfb7u+xB2hK8Ze;H@>zRv~>5lbtco8x`YG5#BQ zxbL{8tH6C{vOyNnJN)Qx^n2O_57~5CaO0G`68xPe@97TmN0d(nSt$>gX34m!AY zm1-1QSid~L;4{4#Y*DGyQ6v#kYGn91(bU$wRw)3LRwEz8^DLeHhQ7*$`04G97OMcR z>jW{|58vyh&WHm2i$tK^6~}cV^bpkWs&>hBQ6k;A>504OY6KGjnp=dg4};Qg-h-Ot z?rvYEEh7*Jv{Uqr8iGf$S!^RU!(=Qi=7+uOR@`C8WP`fP@W!K(xA%*-2U1iaCj5|- z3Cl=@`{Hbl*V!q+t|~MJsnq@);(gfhH)v%+KF)cl)acq*OZv$9Z{%Uh!EZxIm5wjA zOM;K{)N`J7cBK|GT2%~YL)b+oI6G^Ct3n*OuQ&lc?xFu->Oj zhFp%nsSfAL(bh4>Bwv>a4}$BRFt{87k0}t98I1?2t90T?`+`x77R-ys#gv;ce#eMT zX7Q_oXcf=!-VyQcBkcmaHAU#63Z1SLSME|jyJVKezP!jV@M)AHi@&C1zBnMAv&gSN z#}!&`4&Hv9f@JzRd!TQ@Ggg{`y_<98^Du;C5M^Fj;j`mENWcu}Mrk^|oaz`s>o&D{ zf4Kr{Kr8y*zUE>(#`L3#v3l`tInOUCDl(SV2%x_qq`a zk5XoIQf45R#y1Zp!46>%wG(4e8S^i=T%BgxJW_fk)a(m+)O)%v&yODd}1c?n`)I!Y$Dgaqv z=HrI->;1#eXS{UmAc(Ly(!LXY-^!{^)9Y0PcRlr`9|T+s1XFNE+(ikw*yiqp77o6C zrB<;7+-)_0wY?zRtCRnZG*SRRF0{|c14%T0eXBN{QRZ?RcoW>EJ`BqSyx>#Ov@Lt* z{rdM@|Mwm4JM913H8=)c4I=$1aYKnza)5^{%l9LknzsF-5h4%K`x09u2a#;Y>fstd z$m-iI`&}mHnWV{2jclS2?@hL%Ef!m`kc)+>0I}#4g`vcB#)9RduW7-4OfZ%f?Z%T9 zYH%<~cE4mzbb&I!8d-y$4UUo>!)VWkF+IGWOyHS^&uzu2%+GSiK`8HcM66 zRf}qWR5IcOW|#;DSG}QRNff1s!we5t4~|ViwlNflize?D22=Ira`V{PJ)6t)k#&m4 zCS#r5c`KrF+m^Eu?J8e{ES5}+%9j#!^BGA467!j1V0k_G@e^^4 zA~Z#p3JC5-tnqms^XqXKslvi4deeZh0?2W*(-z4H9x+Kcoj4c-Y_7V#F()kiP8@Ml zE<^u~2trWE^&gDi!%UdxS65enTo)BQ6HI#2)vN^f)qYAJQ{ubeoj9mw58wyv{_?%N z@He&0a!lzsblbhZ!YI5gSqOU{0JBC69qs4Y8N%QU9e|CPJ10R#oa}nLcd*zQ#a8au zR)B};?k=p=IO#~=hKk~2$}YgXA&+amFq z(nxoAH$zEC$k0f4hjd9xcXvvMARR+WcT3}dbax}&eCK(u>-#-0an5~qti9ISm}0?v zc3dDhB=SU-8W%k0Vwy4hOgiQXf)tMi^Sva~1EJlkiI-U>_F1<}5r~3yq0(=i;+sNT zRNFr%Ux0^icwB=8h1tg1Dr`XQeFQnI)U1aNAk&}bowXg=H(ADlb&j>lAEZs#NRp{@ zhBkR%IT;2fPSLu%DL_MzC?mtBo*o7H1Tf_3)ig~r!K$JA=d!3gMj6OOz5{wDH@H@fSRdvfGIEgs=}+wfMwB(KgjLZ9BTKl!oSkj1@HUj%#iDoojT zE8JIf{oc5|;_+XCv6#o1QRS2{dt$PPvJjtKXdcDPy#Af-ajNwv6%HAm$M3%41OIN* zsu^?=rA-(93aH6rz}^b~1{_1u7!Y?k}p94&(1m$IhtVqoh*Vi>Xo#h8_>gMrDQIKW%3G9AX&;nQcp3v-}ao zr1{gRsyDJ*?#YuT|}R0<^^I`jnfd5#*w0T);$dUf=DuTE7{X zCDU$GG`SttJ6AK8P>y3y2OR@qOF%SBe)stbAl_o4qcC2H5PaiYgbf*)mo@lU=#hf1g_YMQbq2^Dv^uMsQ0#ihX+(?W)Y!X$n zf_+MGKG211(;NEQboM7fn+N>&x-R?OLC1gVTlh zLO=i!Vh)Qi3}NAlE&jsQFX^mS`Gb!rf?~wu5?1 zBx3g&ZZtwCt#?3ESFig4{x}{*Mk71Um%mHnea4r5*}Yywyx9#d0_{_f424%2_R$)` zKesj^k1cmqTCa@=O8*0ZGGjf6@ccO6ZC@n*FI8RX^!aX={9Fg1hPr_}zElUd*vnDCItRaquDxQ^rA! z1Hq<*t|tA`Efkg*Cqg?anx?v7>^^rdbICTNh&FM{46xfBW58O+13+B)N~iGxdVPu=)Qk_esvNqP|- zGZU~wZ}^YPx{3K_tgbF1hvUX``Ov3pm7Cinc}5J}?VUoYn1-5dx+E>0aB5bTXem?O z>Us=EW_C8bP=}vdW>e|nJ>hbXc{sG@2Rl#WmY>gf=QbnF-q|03HMxG3QiG|LRY!JF z(EN^uQvm;tabz$=14pyiHy%SMQF^q|AC4jbHazH6^!f%oKNDRhE`JZxgz?21SuWTY zHD3TtbUe;GC!ZX6)q7JiFZvwSmk=S%cX)l$0KPb z7q{O8cx1Tx0&(BNmbaJw1)EITR~f}1Tyd2&8f!W)6l92yVv58v<^}H;l!pGY+XQej zaaF8gWC=-N6KyCp8hIDyw>lHicoCA%1m{a;p!k2+(1YXEY7V6~5r|Du1)kK&-=gyd zn^_B=hFuZbP;w+iD3GZe+s|JoTV&G4XtfR99{_2AyJcQ7AI(edUH6+v_uGr3$6d&{ zuQe_4X&$c+QvqamwO{JodSH;; zB{Dusx?N2e>vTT00(a3VU+=5|eeG7YH?cnuA0e!;wweQ@AW~LSl}(L9MoH0|0twg| zJl$xBg-CNC)`RaOWmQd06_hoZ+! zP$5Pfb)i-ZAgCTG^@{g=N2w&)w+Bx6-UR*B@CY&szWs{E9q!b=Dq9bCL50ekb8>_l zjZ)$OGFYS1y#Sjg1JUxjKqJ@&j0|#3{;@X-dWRei&{{Rk#$uDWg((HI_2udQ*qcr= zFfURThqY&w;pWAO_hdCKQ<6#`xW`Q|WQO(B7XzJ8-UDeG2Tb72@xKKYPYPc02eQ4X z{+@RferQI4f(@!{g?eGf)bZ5tE`ryoJ+b>*{oKyuGY7{~bG;X!R~JeY1TsH7lx3HM z><``vbi{QAeNISm62YX%f1E1fIX{L@;q3_}aw#uYp2*mDI8sf-+c)E-! za$U>JZ0x%gH4N|xqn&^LzU^Sy&wGlF;WQG2%;k?RY92Ay5wHBp&J-LD}TZ8{>}1E$I+Y*GZDI27Pu+px&fCyn)% z%dMw~_Hui$tkTg)5GpA$yk{LX7is@lc4k&kZe1!UbEI(KMMNR)h^gncZM~T@~G^Gyp>_cM;wZlXrppmX5#Iogq|nUNgtnbtDwPzviKo3)HmObubjz@@n|5C zPL}S(a4v@1H3#rA$HV2508-(I*`&Sj3tF_)tgYug_Vukvw}pEc(L2>ptJm%p5z!^8!@!0L$FtGqxug2LnINz!uyf@^CVa^h9cJi( z8P8+bJk!Utl|}1EKS4k7+@akClxmacj#OP&Z zknrsautHd*4oMu_ecPloT9>`qV{i5?si`^t^I42HvuTJ<4$^jX`Sv{3PAcd*nbXSY zvpDuKfTnu7F=6LQ8VSh>sB^9XithsOpTJ}O%X%g`!T);c_dzfSnDnk+JWQ>xjPzRN zJ#0Z5m`wJ7=HU4l@-z!XZO+AX6XP#m)ydXNI|lFQvF)>61i9pBW)T`yB$VX_1U1MH z+tiS`*~^w?0fSVm;6Qe};7yN;e(ca3#2*eLD58{Yh|r!3WNj8E0)0=I8yYp-aXfef z=Ff_>V+2|9Z5W0!%F2d_4AswQU`gykWM_kPd~DbXJ;rEeK#^C(;RTM(J+-O%K?x!% zVb+sJfX-KIZQJ692`}Diu(W*OuC0hRh);I-#u*)Gp_oI!-2k}ge%oA6qyx0}gH*_h zxhBmZ>^(p{y>%B5ssQr&K)|tZ`0r4NV0`#zf&|mS@!&XeT9}tBfGz?w(X3x(LQZx% zbz%x;rTK=9SX06=V(SsK2|dQ=NP)X!3@vCSjVkkzn$a|evkRCD0IjZp<_{#|;E@z- zi`~&npLXwrnZoaS6HwI!a3^O6JdEWVy&PTn-&E#%Oi~@Ry&h>BFZ`HVn9~l}F+6V@ z$q$WPLK3}L)BoC9-W$T%esZbQT*R1TL(+_gidv!WVEapP^Q02%f9B zhO=3oU9Z7I@ew3l$s|y7OgK0v%)*%euB14`Rl0f;E^a!43;IXQXNxNFSEJtH&y7vW z7MEgbbXjYemOjU8<|9)ELuQFAjs|PJUbV7Dq0lZ5I$jKL@LOGLonX>9dh3gIn(#go znDzROXU8lyfIx5}^cf7i=+X5e2UeEMtw$rh1p`-$(^4Fa3^ubf$fVc85TTLX=~(om zSqwIfuuDPJ5mf4p*`jR)Cj{ADbF>iY!I5K>LWmn#yqR^ybfX-fDURub|Dh86w?n^n z6Bx_Mo~2(p?HHIM!KL}VxXPR5Ru}iUWg1+WT0RFJphJj(n&X#k9u_RuQP*Oqe_-%d1mu7$*;R5g&C-Qb% z_wz)KtDs-oPb<+W0%lc*bDW1z+xa1#m!oz@7r{J4FnxK^rfySkaEk5c7hRz?@m(oyJHtKX&q1po3sJ+dGnTw&m_y9BzmaDctz`Hp zPPS!2D|!F$g3&_ILbftk=T!AtVj_LV#e4!&4J!X_B)S>?Cmo=#4E24(N3(gWvEkq%gx{AY@xNg7a)2?ZzqUtd2~Nb zw6t-m$qzdNGUq8y&)$EO&l~i#wEc1U)^O0V;$5*IU~!`_E5I=tWC4}Dun)AE%5#~t--&OVrk*w zp_VA^GMbsMEJLy7I|Mw3g}V#t$Zt+CV72fUv~p3tjYJY$YB2Sbe<@lixgP$Y$Ap%< z1wU6&rIlj%r_Y(1e%{u_TK2C&d3oy8FXrvhSimE?zg8htzFMTf{F~v|0pZ+8-tU(W zLhMySH!m?m(rF=q(7usW6s<}!sYW>boce4Hd@^6Ey~$qSDZ7CWHet*%Cla_sCUd8I ze4@e)g+V4d7*>_p$oQ!;QYun-Av|k)^JnYVajgvx5LvM!B<#koHOa}D6ou0H`cv3#+TTk-00tY);iQe$h7)Bg~7fZk3W1AhMF zzo@9>=sqkVUArG@&hb970emTP1zok2l^vHn8H(A`Wj;78wRqpSc0bN>c30&WwK z@?)>n<25$`%ynPV(7lUTNB28}%HcUAT_QQVIKn+*NVwL~0?C5`W{9oYM z*!Wul+22Vqo_3bo*sC+??E@@_Apn!HU9Xy|e{J$TK0+&5a_F;3`^G@aghsh_=((IF z5yP&l`gzFwDV!bAv^zHZ$*e#$R=9mu)p-{j2)_*tZ27xFZ=Z!+pfF4ryTu?pm3=m2 zksNBd2ilU?v}LhxFMxt)&j=3L>rRAq#OWSktiK=SiKL~GS z_~uu}YiQOhoOqe^C#vV>WwHK5HYuyH&KE45H4PdpEP$PmMH z2J{zrOobeTc;W8)eRSfDyN=yIRie3TUJ#7?7`FHV@e5RetR7;Q;8!$ zb({WDFMyMf+k?zz)UmVX6TmC? zFR$dHKE3mvu>0P|XVQXb$f4QqX~or;i(TCh7_9@f?=3(@zj*myu9pkU!go8Wh>uYi7z?DVvC(RLFIn|@5<9J&15PN-l zR?Lw72Ebr8bt=XtN$@aF6`{w!XBV3|)LyrbI||vx%A}kwlq#?|loIq=3y(V%qcC{f zz%>)3rBJW6orKMec70PY;rGwRPK${9-7h6nn?_}{1?Fkxe!Hn{I#bQhoiJs&%H3*V z+f?}ybuCcXWI6-Lh?;ZslRe{AL-}XPHdt$xOaf+D$sKR*sHCa+i1eN9`jSlP0vT@@|fy=v_U8imSBE~*?tUoFM)#ARl8v#nx^G;84)=Gw~8#E%AdP08h=un^Ww10lqvPbQ+YCo zt+I{h*b%mBBh;KVeh3f||)v#gkq5PfZk?-P)q z-}WZ5fw=+wr=Fa5I8>itct1J%lMBCG6Z+rxYa6-G?Lq}$^X~`Z0AaJo!=%T$ z$9g^>Ruijt>=%_q-Ogau{MPh4!c(*;HBG8byf`OAx^;{r43gr2jlGqDRCzPo4v-pJ zRj``q+a@b!c!6#g!e%@;4znqYp*Ue;kEOW}s?rcd+k7&p+4J$F7Bpc5{ zn38A>-o(}*N5i0r{#H-Hg_gl!IRRFF-xPN^=TQR%8_G)KjTV?@GJr%9La0#?hq}WrA^dCi zi(G@2*~QPMSSy=t0iTn}i$~u0d(v%x!4w!-XV>t?P4fFMU<3KGr~7&A>1*fBx3T&m zkrtYVSAkb`yfs4U%9Ns^D%b{i@-o}u!^fnowkqOGb<3{nKbWl$4}cf1G}Z|uz;mP4 zOOXkG^8EM|cWz=ObL1WTBRF=oxy9Ta`9hne3H|^;q@I`eY04?QGmwDgODSfAd8&M0 zJvWO$FZIN3nL$$duBE)=)D_8)o>CA_GkKNHb10V`4v?}esf*v!rg|VdCea@Rl z?yusnUa0O(IPShk?5n2d#}5OLWwXZ7!+gNYXkL5u>)2iQrZ?uW+{njbhX{I#gp{}I zmxt&}8mMOghZSFwK*|2&hzx`P?7M|K-{|UWwFk6no!Z8JhU$UGDR!#-5|_WFLjdpsb0@_(VMDQCNdjj73a2 z2pqVD%5;%r%JG|+N{ZhcT|TK=@4Xwf;7G@YUs(>hT}R-F!_6 zSxtaU=s zYla+e5&ItVcRNkXUEYKElq-g{8Sk_;?IW-i`YR1YQVYBp$Qyk92?!0 z043q%>nm}!Xu3_-ym0{3ecn%gv31W?=MsUI_VtQ?Np1!kynfa$T4 zGvF2YdKd7vWq9s=e)U!pBQ4#>@XLW_=w@z7MY|dxke#`3J!S3tL2qX6t3i&5mm%Me zOn5?u#sO@UG~g;*>_1jnb^Gvt+%ZUd*L>CP#%Z31el>L%<9pxPa?uY)!EQkH2^6l)PSRi=#`79DXy5>J^3GU})`#sdIzR8yaU#7_o27?p}DpFB?RHFQeXE*%m zt7I+I3Lztrx8=*6=@U^ES56!IbETsSRGONRV` zp1monQ4Z7AgubUId{bB^+%%t?jmXUh7N(y>ZQ`v4t5o8esw1l9beA7??YYraS)#x} zkwxc>rqZax*_F<0BFfTryo%SUl0xAkA~flxYI1leVB|lIZX~QG8kO8X!+?o8yL@pT zzyUd3UhjGu=P_O(VffK;?)P@tdH!-=?bumnhO`OD5?Z(8+kxH2HSBtgp0)w4z*&EU z=C=b)pwM21VQQhD7&3+Z+AaBb0^`58d+}yY)NaiF>mn7YBA(pdjsE`Z8(@Jg6(r(Y!{+ZZmr z3MznAsl5e7T4TX|brMHjE=6o2>3|T0Mzh)~P6NL}K94b9x$HmcTXFI<-=!}k)dEZQ ztb&G{hK0c9mW>Ie$$oQllUa$D#}%(mJ*8_ZI@&j=%E5>n+*5C|+!2z6Tn>OU=2_s; z(?%zG4yIKJW^GR>L+!vg%=N8XrKGtY)zNH2Fik$K;WG7aIoUa9^oBJNS&h=L2Vv@; zVLm0nU1&cYG(a-ZYLq(ERPd?fjbTx;&@vUQhmLm}Z7v#~4F3^*f_bKV|NU3i0p;79 z2;i4odSSJGKNR45J!1u+&}Kk$JpV9oe^V211Cs_k z0VKOC%*39AXR6GDLYJCzFT<{BqeB5)g5ig}bFo?BbPl{|M{lS;rLWT*-@L)RM#4G; zZ0>(~2=Ec^YVNuzv`lfqxzDFsnAPylcwkh0ZboclGQKWM_r1#YXxgMcYI}`y^!=}w zSj+y~55Nh4KOT8CB>Ujv6R6sf*Np{Vio}TjUYaO;WIwDVI+h^5IGDCx%S_xntH|af zJ{C@r4Gv7Z0j8Rs^>U#OR+cnmcsCkNVo{3r6TITjOt{%))T!a2I44{6L>7f|lWGPL zW0v4cuX^?Z-XGsGhZdXI71WCs`+gH9ara+&ZZpi&q|CIDSf`rkIJ=lR{P-`w1gPHM-bejxAd3V4N zpq6qv{=4*D+o-|(x7u=(6pzRT7%Hn+?2n`A`Wt00Pm3sKr?Q-jwl0 z5T>u^_RuBpZal!a@V)P?-=4D%tcUYA=JV@k>3HGu4sHJf3GJrMP1~&7pOi0dqgN1U z%ir?McE#IPoCB_k$q3Te>J{(0ffj~`^QzI-Vi;OH8(wu-8#@wz{PNmv8`z`%S zUezRvX3^|pYhj{;dL0$-_bvF9Fhk%hPvl9ZDbmt*IODdT!K=I4=vr0}n`=pA-FZ}G6#zQ2`4>I_0!+br|dqKekz?CLy=O*W}5 z*J$y3%$$9rApjf&xIiX9ToFbdCJHvNvF1;mOCtA!GFJ9C6HE=#>Un3DfA6{+sspoh zz?f6)Z4uBew^&Xb0iV;`TRn5-lJHS>8bV2&Dzjwhz=591AGlwe>%S04~xxu z_>UE(0&ZB^7Ls+h1AbdN5GvQ|L{ zNOlY#wPg(Fw=+T#b4lz-iY2XA@)Zs5NAWQvG7ujv>q~y!)XDx<9nX?a;jJ>;1A+0l z-x)5SHVq#1I*+$0h1ZqxpwK`=A+*Q~cg5%8nu8fD_eR~wvcFA7#;cCab-|iE#=RVf zbG9zVT>(>9z~%vdZf;>=VU2PP-}TBlTX8JwEK6OjIvo~*7=VS&V~IAN`%(FjW%)Xs z(4ZB#(5YDQv9b4E+SOX>(x%I;-~y05{`vJ34KkE@=WvNhA#gg&bOLv{Z4gep+%! zpkIE9dH#>E@x*acCf)jy-g-&ej|k%i5ZN)h{srx5+;-F>QUA9z3z2R(Q1!nBnOnh7 ztp8Xfs*aZOUyWf?uG5vXHgU*rYDdTM1sDC&h;(?|8BQuHIE*^XfdF8UX5`OpZxd)oq+K^$N*CNHE$Je{PtpQf$r~#7%{YzUHEQf$h-d zk9-GcY5dRM`f$YO%eyI^f$KVI0nsp7&S~Ic@V1oJb4#aF`HzVgvuC?hRa{OsOa@Oj zY$mAYO`nHU8ZKZ7Eee8Z6l86o#S4o@*hB(eMYPWSODq) z8)G{jXTTqe81YH;3E=RRWlhg^CK8lrfKV)GbfG5uHu>_=mZ2cj@cLy(62u>HGjtqZ zO8!*)$Wmh!(^#a)CUQ3{Po#86rtW2Ab)LSSK$A`XbkN6ddbzV?G{~tg)m6-gfOXF` zs#;U0PMP0B-6f9NxTC4y84QTCOICA8WU$@*@;#wY>8>@SRQa;jlfN4R(;AcerddTy zvN*SJN?)`9GU*bRw)$^k&0VHFCh$pp1+b?A>&M>gRc0%hi(uI(?~`27_rf%}lHRVV zyy3j5G+oZUmDNvkxCP7QRDAb?pVeQ~X!ztadr(Z4&9eYk(5F9fKTf3@L36L@v`RST zWLs!Igoq3TkHY@R_SCKOxu?xL^FPkuNq?FuoUUOxoC( zrR0z9PZ>!-;L+>flQ-2hRU#M8m6lk<`e|wIuSw8Bd?HQ|V1PTG;S{9Q#s$<}LDwCr z{vQ17smVWOhu&ARpdfHxv#|o)UNmBoey~(#X(T#sWe%O*4<1L-H8-#{kJsM+faUxU=i|HXXo+>J zKFH;rMm-J+Dno#1D)O6l6lkXrm!6mpP5u9OY%neuN&Yl z!PKJgJA=}Rtf5fF5tA7ugE?LhdE<$Q1lWb8`InDKS{{R1a&$T|xiNfBUWO9D4>GBu zH=Y3I99LvwUSVQHNfOo#>>CqUPo~0Vx>1P@nJyS?z6?^l^yARJPZ|bT1QXdI{g~fN zH1E>$d%_~9hu@<-q{>~UR=@j*mlTeD%~23mKKcpI8Sk@Hul0>j8sRvyX*inV_DzYq z%mk^uk(JA*f(C`3mH39rT66hWiYs2h)TUW_$8?5bP+tE7By=1znz}!e`1P1d z;ZaU#3xWla@u;TiuGOgo-lCWZvW7nmj1I_&9ZF*duLPnqh^xmC585JW4%_Mz37^1y z)TiB-zVT)R@XJd^R9UuD2SO+avQbQ1AW5QQhslq&lrIk_+c z-+ik%7SQVqhbyTYWoj71*mEo1KJ)4?97+|HQz*+LxVEkywOfw-cLC4~lp`_mQPR^` zCmfov-$HUf>YScsdc~XiPrA=5YuKg|zuD^=QvQU~-o3Kh-s!dWb*CoSQcSzyhK?BJ zpy8roX%?q&Vn%}nN!60~uP#&yNmHkyCZn2;HKzBOs?>YaEa4(emNm+O2G`+y_YYpw zPR~Bm7aa5RnMy@uB1Gb$_>=g;jBO(4P^R#GI0NmAJ)x8W0n7R71lz}aFaW}9$~Nn& z{$Ns>J0){j(PrKaG959^@NV%S^O4in|Cy+X4ota=`4$Mw`{r1(Eul43#bH9_^26x%ctH1tWxs5msjCH|4JGDQK$zr-W9NR8E0tbh;`jb#)7kLU znn-`p`S4s!YheK{W*k0P`h1IGJIgr0UcALfz8~Q)>qGMX-&)SghcUH!4~BlD2|auS zK~g!ee~(0eRDn7N|3usA4XkQ@$d9kfB65t^h)MF?e+~ZLstu~{wb@z_xyXMY37D3o z!op)h;f+(_gjqEb$kH+d_1_6bx2TjUgWi3dPgjyfOM90HNhxtAa=~)KsxR=6v)yY_YWnKFoK3N0QoB0>GD})(uKkXvD`jSEaC4Hh~NXj3W#>C9+ zjDA@Zm}Lei7TBDokeGTr(e&uTa`{h`s8)IWSS-=Cvf!~_Yfim(mH0mC(3HaVu>S%Z zJ+It~3fl=Et_h^jz?hAq<_T!pr)ml;3I{8^{X_$bAQoD`h;Om=$|^>fQvtq@FfSW= z$YtwcR8z6}{5HruZMyNpgKI1p8d@Shzq*Vkqs~GEPZkb*`yAMy*VLlZ=Njf3rK_Ni zLNX&>%)ybLt`_ITWlB;Ba} zm>?mbDu4pM z^2;IaVUj8CgbD^?&<=_8Tpk{>Gaz+!mV zGTCagOaT%A25>6fRtEDF(j{x)GKR&ySR$?YVUC%TpTD*0XM&>zLZW+e( z$A&*PR|CcjOrPYY0}JyCZENZ$eDw*$6BaF$-l30RAF_)cKGL;zY&{F1kk(mKVr{*I zJ+EhHo`b_OW!3E87N=+i6PK1prpXRf9JTl)=n}?fYK)+b#+PA+S>Kj*uA5QY`0T^U) ze${`F$cGKsVl_Y5l2VgNpoS#AFFGuW{Hv7rUokcio@9xjuO!I>{$G;*)~CfhHcs6D zn<_hQ8%Qp z&TCI4c-a9|lN;QkjNNzo&kk)p9lkM=0MLbrC34Fd&MfH_HhlzVXlXyf?7I}=8Za?@ zLe3P7#X=l6F|0(rZr-Q?HN3Tb+lW)ANIy7H!el z9IL*tr#_S>5*c8oANtrYZ#}SAIWUC&OeYyWd9d+r)m#KyDp68~xT80*FE!DpV)w;j zS&o1vp0D(VAId4|J~dYI<|-9o8=7REkL_0dt%|`RO1gaN3dr8CiSwwS!iU{I+RJwE zX{{jAh4c9D9#w`qePoZ_cuGbtk!oc|nJ?O*DvPnQCQHu>lwZ!(#p(kguk{J{?@C!q^it=)I(|pfS-4M)@JpQv0n_4W20)Z1rd~mq0Neop z&UOPM5njokRAB$za8zi;G%tzaNf1_vef5!Sp{mtIxm5_TMX0`G7{ZA4x>sDEZ_tgax6g&$p$YBh@~=|nm`jM z^1rhX$8fTwp(8Fl;Dz5K_Ke&>n9W>Qhdh5k%X0HI`QlrmrO)}W1QsP7LIV;Z?Vkm` zc|o++J^A$ri}%YE`2-~j0E#Wogpz6LaUaFJob&$sI~&#YS(@taabGTlb*tqyX#dH5Qd+-P z1h8%Kh?Tj;JFs5UH~-HCVEXb~Wv+Y*Mf7|waJv?Z*D5~J?3?Y0fSTrSUQ(~>qd%Mg z)VlOf2|EcQ&Kk`WykAF22Tp|W$)n1Y|EQqO&$sM`0-7)&y^%Q0$UZcy@?wAXd>7kp z=z%!nbJc23$74P+?JxT~4|Pfck0;~ZmlDtpRccoFY@<^|$nZ{0;*lB?Y}SXYtqq&* za*!lmZ}sWJmys(kyYVLWyPjX6$!%`4ip$w?wVG1)OR?S6Tc9EX3^+KQrqoNX1EFui zj68+NkceJ!`?Wp*(+5qj55w^s368V10fr8eL^tf$egr6_k9lt5&4iJ*Bl@Q*f|tU? z@bxNK74liq;Xp&C6jvEP%f~%oD5hnpgmW(%fz677)>$0}2RvHSypq_h?S)|mgfeBu zUKMm?Qe=#30NDRa?&1T03-g#Cu=zr7{0XHtqL4nlpJ^68$CD6afIg2WQcL)3K0V+6 zygV#jEdQeL!~@4hEm?2o#vhIaD~ppTyV{l#-^OQ&6&E0<21Z^pi$q%mO!?e4#Ch$$ zx%Pgo4rk0~SeFUt2DqGqTSVG-xj&ddiq|(^x-E8QYrm3za46{&XVVQ{%d@XIdz@iH z(IqHG^ziQq{&8$p%ES{vP1jICm5zH_ZiNA>>soAq+FzEhh+OXgRHMF-IrHLCX7-hT zLdBu`zd^w?iH`HdXF&wv)UA2fFOp0}$HDY6Tpfq-8+D~c; zB-51C^^1-S#%A(KVOZb(tN7{06ZGG}4_?L^_I)$n4Y_MbWlB>4B}uuqlh6xbQ23;d zS&06l3Zp^042UaxQ|44G@u`_4!BPM6>bMus}Zra0Klx&U|(q=@>i7Ti+=_B2|B6%B)R zG!v&%3asQ#{yW6AnA?Qn_X^zj*<0gc7a`xjb$}<<0LdeFBiy)7dpM;}Xjo6(Ffv_6g zr#X*+t!FdBMRfhI&=7zk=~kcsr22eb&B$L4^=wAnL6n}6A&F_6DX#lHO&=jUfTcoK zcoO#Q%Z!gC-dG;RzqjS~W+J)zYtfUp^PEUr>`Yxvzs#;F2P+RNODoO>k0jO^M4RkX z$;?o3+(ZQVR4UoP=Px2UHBF}d;lQ>I3bgxP`1kAYQT+?3L{v7iK0_o;TUR#6&n8ct z_L~}bL`3|`&)UqT2Lzob_ajCs&MF{w9)|VpuVTF3-fgU`w94idLt;~c>)Hgd!2_RU z8THYhV{WvEBLXH6UYmdKbm!*p_u$MV?T~do7JNV#eM5LSnzvWI$oi`9>MD&N6LWZk z)K*_*HF?IXwYL3>vWLj`A;#sL_3?&md>215<3Ys!n%>WH~nDb_QQeZSZZnBAX; zM=(xq9UG_28$sv&1E>5ELtvCglnxQ5Q)?Sz+mgQHB3z_wy?0_IQ<#b5j=9qEvCYG2lxqClu{c3wzlLJXY3bN?Kd*LTH?=#(j zqR(UH5cSv!?*%b+Z!6~Vt=Zt!0tHoLaW{9q)eigy1+f=7-=h@IGu#rkqH=dHW+6{{&^!K`Jm6qdh-t{J7pu!yuUJu+n{`8anzGy z7|TGsbBmAtR0p*RWZrxd3nlWs8B^2rcoUWO-Ea526B*~Uhj_RcUk*IOo>grmyrFAp z{oCbSd-1mWH^@1X-(3N?)})JJe&t+9)$yI)fKlD2o7%;l+8QSo`9(D(3;1U{bP6$Q zdg-L-RkSsxstuH@>+_2Z=qXPAmK@$r#fb(>TUmgnA^p!eFe+((c=hI&c=giM@Pf@& zKQGL0muDB1pR<;+vf84Js_pG7$d_gBq|f22rG0_V;h;kV3puYH+-XtLJ*dueVd3O5 z(Qp&l*U=m!V+JyAe&Wdecjj|JVf-{2&RZ7Uyxwcv5jL~JVdM1ThK6`SvHk|5l;6h) z3{-Jg`p1kD&waJmJ#q7Wq8Pu5pwPgF(M+9x?ZKV#_mv#bBcf%tSuS(r^WZMS5Fog< z0ZFs5Wt@td%E>X}k^_G6PD;_>M_oy5KD!8(;9irZABB)#HosUBth5U%!UNl8@c5>R zNus!LewJiN)23J)V6F*5o0b}n^xeZW=vyLFiI5M?Tk-K}1bT{bDw@A+_2A_4+6%lA z>F5r|WqWRV5q~{lCWSS6!=`%5hK{-NqOU!p3g6%vbZwrCJtg~|S}-pw?w)=`=O_iPbns&RhKju2yii`zLa!k6H#;_) z(^W+LlqlG(m6=>SO?2`jp}|Pu^cg1!M{n$^(q7Slv|_xlrs@xIh&7XPs?oVY^Sm%R z{FyJ-?213Gxmt?NrVweO(icWFu#q<}3!AYXR6w3__Q)Rw3U#RGW+@>h|N?w(% z&_X386OvOep!r*UUTEib$TRLO{^U|YB{Qy8H-m({(y@%rHt#FVZ1h6|Q|ZPUorvOU zK{c9T362|a{0^}yCN?(5pKq=5(md8?7;AD;kGLzA+^svoNxM*`1584qM2jyD-H{q0 z=gmE*v`xiDpFcA*u-O|hR|v%gQ&UY@d_BWHo-m0ex>DgkPa*Qa!GWXBMdsXZjZO;D z7swju7#MYybi+%ZkF=363wc=)5FdX%v+qui$a=SUr+Dk3@zfpTpukW@+VMP2K={IC z>W*eN!zw|GWifE3yuR% zNh>}^G+15C$au!;_mtbtA9@x#WLFLTUsqop7De~JO-ScbE{LS03(_UhAxO&tOT&VI zNOw1^w5UjTxzZid-5@EQg0yt=4v)|C`(D>O7k|wTbIyGFzCUNq*c6)7e&rzK4Bzj`BIgYijn26qe5@{Ain%AIbUEDy zIM);9qAhMYi`4i+NEv5$^-{fvKoq3o-8TX#_bs>BIR~V-0hGZ$I41bQOR`!A)6%miZL=e5W`hrp5c2-fEh-CA=ud_`VmQDZLYDM`uuBg zjV1AZ<3iKpsHO41GOavydv1;e6*iMf3XF?D>HECD{_`4d$bbjyPa(wxvcGwa8pxl7 zjJREhJlP5gjBg~9J4bp23?2|)QXr2PiA(6uGnIaoB4yq;{XB_JfTQRL~q`?R?uPO z$L*G1Of+aT!v2ezp`5Shs;rOH4QVB9t6${0HkSw9%k%R)+1jW>1+s_gVmK9lj!J~O z&N$M~Ph4O59}M!im)Lx(*++2e zefs$OGgCN;a>RfXzU^F#J5LbfcCGM2=y@gona{I&?6o%`1`O*mprxLm1Th2^ADQdSYHsvc0%f9|mmM+pHhotj0q`GKwlMxj!lk_84KE zHp&;&{g6u773lGIWd7eT&v)`P-wcPp&$boW-|kdyTI>c_Nw>f6(=V0Q|ul?0aajdo(MfJ`V+NIMP2Ircf5TGRY8%4rCQ=LvC)V2MSEX2c6Gyo@yVA@_X+OM{)N+ z01$ZCtNM0lWSlE-)H1(9i^5Wm?bSz;@2ao*d)Eutk1RXe#Bi$(Uu(j1sKLCClJ{j| zH{#5(B_G=5lbxK#{aJ{VtLIAJ;lmAt{UbpU^o!k)i{{44Ys0DDTi(p@Yo+De{yKX3 zI0WI=p)R>t#x`AGmc$#{ti5z>xo0bFev!5~CwgbUl-Ked_O!X~atBGRyO!S@N!7l$ zz9Sl$cQOOv8MW3Kg+6b-;Oxt{|1&i*-_`dNkR`tTp54;1QNU048#>Hx5iiss;oyW3(bdy#4hMUv-c!YSnYx$HHM z4WSY)YV7_Y!rmuO70AUsjD}K1M~U%{Q0(_`uGiC**_Ln4)^}ho7#eNvke~ouO&QG^ zW$GaMy*X66NmFTvv&QF`mUkwL^^G=F5v7>G*NjUc7K#Or$R%VJJhY1!TRQR1yNq~( zP_yYq(Tzk&U$}C@uJrKmjGQl;^h$Akb0N3+b#)&Oo??nJM zVSnbTUMh5@?eN=B?v`W*$J_AE<{;9fz#MSn4`oJyP~10)NWqvE0i3{ z2IY4$7lwj>x+dqg;`1ji>H;SbYC7fG9rM zjopeJol2~D!162X8mcOa(uK>_?XYyUIa`Cj&QUuwk*A#6}z>iTo%|7 zl}ndLmR+J(P7&)R-0ZGU1Ryj&e`R+knkd>=!`BzvJp_saW?-&fYAF4mVaSPwB|mkxc0r%ep#88K4speYv^k%k>>FMzzx zHG=Xp&qzgI(t$F+DS-EmaEJJnU-)ys@>hawwv-mWG#0l81C988k0bmLrNPthk|+6E zhL#T(+kd8qH6T7~mz{HT^g3HCxw>)R@uyshP&7pgweE_yt=Z(@aNVHp)<5ncSW>P_SokGUv$*SKsy-=^(wX<>p%EO~+tB&lm91ZLORwE8#bpJEKxR(02iDj%v8kR*4s5uU9C4=oRTYyfedONm zP%UkTU8D|1l`=6egcDM(Q<)6BvF%3Vdm~ok@ zp1IVd(9kj^vbjrRN3qc(knGH0Rf->UB$H7Tp|PI&ZBJ)j*L;$0T}Dj5S&4(2fPJr1 z1cLA~iC?ag2HC??OKs{t;W3aBR8?DrsIx)KRgCxLDM}u%)TPjPEQRMjA%=@K zl9h0BE0Ex=TI18zdcs&WJ8nc1xe{@x1fjccEr*~Jy z{23T~o(e*hDJ`XAQp>NlJ4A_njvty8u8s;XEstz9K0~kbMNdqPFZgL^dq4DV zxCwxl`y`=PfN{H*_zSTN4Z4%bM2aNld{P65m2Ue=2ICDj09_3W~()NK~&vXOb8;f1M_7=uo0 zgltm&knT%7Cq?2`%i4ZeG)Vjg1;FtEMx#@3lg-NFDjN-$0!-8xvhxt(S+amW0z(A4 z);xa1W;KSio6sE?q=ZLX$XdgC1fae5`q*6dCR-IZH1uE$)~fO=aZo-|)gJT{puT1a z3SX7xyHYRR=Se3il!Wr&4)uBbH1j27sP!aI_qLtYOBD_}+OXdh`SmN0Mg4(C^+owh z@>TAk^!B#4>LQ5et5*q12XhrfSD%PMUtXnIVFU8WOXOtue3Mi6yU-ZLpE8l0Pc9T4 z9=T)R;*yPm+)5y--3LkC>j!IR^^@<-X==>t`m>eJZwo)pjS7oh0~ZU}4RuHW3p)n( zhdWR=<^Tq3*kAsdFF*$DnR=EmUh6?xLs3?q^|b#b=m@WTy)unmOS`N-tEpA+PHiZ? zo7BQ#j~YpmOhpd7_}UyYYOnhA)fp9D>YB&myBAf4{ieD)<{K<&NY5BzP1G;_hJB7S z&_1d7-uR%o63{LKuHd|Q?*9zKUjz(&9D$)q%FiyfkO_O-%ongFi0cj|dIjX&7`2IwxZ6cj0rj0kdxQ)*u0C zMIk>hhehepB$%FZum+C5tV< z`x3u9(S2>_9^rN0yfa}kFLQxtP7q&WWc66E;qINc^K;OAG*3w9t(Zdz0F}FiTvqlp_{h)^{M+^eyuZ(OO*IUO|6Hu?rrz_jT)m|u!^B4^Wb1EQAyt}^rxDl z3^&zQ2%hJaKwO_?MiF_oz3?7nc}w2?w5EaT>7qEZ*>e>E3XG;}@>NHl4Vy++g8DC0!IX>d3dXvdxF`xcuwKLf~xX-jzzk<^#?LGdM21|8y2l1 zf(I-CHI)hPxil-V1d=@il0;QJBqSso!jpr<4e4j9*u>|v!WJq3_?#_teP83*3r#3_ zk@h0Hzv!2&SgbvMRT+T9i^+L5eci~p=V--pn6f_1IO!zB+e5jTY+`ZY8y^TC zG;4+lFwNDbE%;dIipZYYAHBwNzrb@p;fE|VHN17^@;7QTBS#XWgD#eke+*0XN6UlR zi;cSFr*cl>*2~NBStDCB0{cNCd>m3?d0lPPP3In>9_yQ-d`tue6M`1)|hNFg6`Eq=jWw%YxsKKoAUgdY;ORA z$mIy|dhqVd;qSnfRX_O9+779Zla_1h?JI>Z@y@=!)xY#Ehp?2t`ID)Hqp2EwIrBp* zf79mdf32MpF;k7i@rb^mx!@h1d7VGDEw1$KsaIn!02F@o1I}CPftRmJ-_Io;RtEz1 zSqhtM_cFtbi1^`&AGW0jgMlzY$y21&>4v9pTU-xN#WITjbXa}A_Rw!~mXS^(k;-&mOW@IJsz50W z1b3+u;&OtCM?8CZ^qcUl^RUuM>JeRx&SO>!WPj#(fr#7CuSVqZ61ptSgV~N6+D>3% zchd|Dz3||rHg!o!V&*64>s$M&?&h%B9~PQn^Nn_>Bn1V9qD?_YQj@z?R}@DKmCi8vlW&d z*lx>vi@|`kfj0>-TSw>r~}1* zQy4%^G4(mNe-*@(r5~a{sR|M42nK^zD>qEAHv`iQTX z#xbQ64P*t6PFeQuIBOjsXy;ZRVqcA`3nnof>i0S369mj+w4IQWWlt*O(p-gy&=+uD zEg%ZQt2<8~0qq-G4pR^Eh3w%nA3IN|rIcb1M2<1#MbxW@4$E!F$0zhT+kA3RDEvu3 zAv2|IWZ(_jDArxPj}~pr>scf=vTw({&-NK5ygr}Xa+@Fc{Pvd!CwV@mm-xZ|l)d=D zSGC76ATf!P>8vGST2RnOfht#!hkyZH{n6@-FtIHnq$)JSf2~ev8BI5RHQtD*sc)KL=oCmDcpq*2xMNkysFB-*Y@ShI;%Y25Nitq&*hyp3k3 zaEh4CrH)YA6M(uoRG;KPgQAkKTol>K32=HpLRT(--&$N{G&XA3v(hsu2mV8xu1(Fu~>Tk$$mDXc8+?h zn$Kgzw1|P2(coofP`@%X$v3Scf~r0Tm(i5Bi~{JZINhih%1ah<5WDP^(yVwwj%mKF z^3kwZ=ORnj&GJ;FGeR>A@)hU<2Na?2xl@RMKE)FThNNBA%@>!K6y^@jcrvnTpT~+r z4ZP|KyZVI}7w^yEy5J6=QsbO#G30;bIbs;HLxeg2( zLcP2=l8vhLbZ*SUOvAafHPcoPuVhP!1Nh6uoTg>TE!BojC#;?V4;083Rc*ufM%ThT zkNImP2xx6H1&>#=xeHm8EAc#?L{%n#>bh*#f7541w=^+uTi&V z!gZiJPqRVHq=kh!y)uy@>@vn25A25qqMr2U%M+7!!A~TMB%!@K&)zZrGfxp1fNz*a z?3SM@POtWB-`t3VLFBQ=jBXe-b}fvvl(I8qVS{^lttYJ0F2s_*W6isTkSo-O`cfnH z3O0D~C*o_eIYjnbvK_+78(ThaeGaY5O81KkFuPE2;at>x_N>6Bu+FK`-ANi65+mAq z0cEC9ROsAX4BK9>1;zCP=G<2HUIg7>F(GFJHFrdI8TgbdGP%KoQ2@!fV4Vi%;zH^G zXpR{zC%CCArVOmSJ!fCW`qwNYgDE7&oHx?2`&L-vdGh?Cb$e6&8=RK^` zs%g|cZlsB>5FN_x9CcPQT?&y3{*`<@nf7^BcQt7T`}eQ(IXSiWs{lZoU1eQi&+{A$ z2gHW=(a}BKcJ8I!cdHo+ql-BGx^j=kZQaKj;GiZS#9MKg``K5qn+X=_RM%jmtM-|J z%;V;HFMPeBr?$ds8c>b+^6!Nu-@{{yd)NCfe-3Y2j=LpVkp1gZxvXHcdZ8#itfp@q za?TFA>+AGHRnJ_h7!Q>~(f`oM<=A$tch{jgMMz_0U_btj#Wjy3ToE;Ri2@~CNvSqW zX6EPMu|Cv)Q-mX>_!d9%b9D$&!6Ww)S^9?1g(xD|?GlmA^unfmhAoOr=~+6a9PGh2 zd(x=77Wl~UfYf_xWV7R?57`dkQ`};#IxrCgcczMvU?`DT4T??UBP#SgtaLG(;BjCW z8Vqyepy0Tc;zN0Co7L>wv7Eessy7rAg2=ZI`I)LPg90MuRvN2|(!9_jYO3scsNOsA z@*PoRN3(pj;*<6GGv;_&Y1s56n_joXC(uP@`qG;jJ(COrogSzpL8Gh1Mi1Tgi>nip z3>(C8Ppfn$lTM2EPk>jKi&Qq2UL;Y-Me|aqG|*udFbwB;VbIn^yaKV|vfV!y z^_0USLXcG1T?JjHYVV!K)-#4hb2EXZCLOFUsT2>ZSk3rEel>akELP5>XPkzVI^t1} zvHyke3l~KhC2^n#RsLp9FH8SUM%-)IFBWWi|o8$wvUc3N1$Xq zq~GOd8NjvIFQ2Xy)-|nD&pgDcdUt01GE?$sH<{?`)zC%(GgmL8nD?1(avv z%)wDgQ<=6uiu82Jcmyq?nR$r)MH&J@ zv%v=zaYk)X0>bo}%|0Ebd09TrK+}dEOa*Q>)&drC+bpwx{jg&N6cd;X?5)D3oNbf5 zh3O%{A?!q^K9Ys(0Co+pcPy&Q`YkfI5C z@{-A!kT>-wo$cLi<>PsP{~IvEn8QGLSFF?XyiaS-O!K$PxE_ovzfINwxK^4KpnLPd zRAbwWCn~Ubrh7;No&%B1Oriek1|l5@az<|yAb~)VM=!ozWiPcW8J|{!On5>HO?D+u zf7I%&G1K!FAiD){7oO)Z@D$`RS*w$rn34fgO(X{2Uzsx_ur{W=ow1kG)PiN$A>Dg#*rTOrlf$c<%#4##E*hG!N zgT#=cJjr5PV~&)dd5c)R5;v-;@HrhPDLj(!7F|mG`(;uym2AOSi5xo?81VcqOIQ}` zX_8 zDG;Z-6qiW$hOV}z>90iCGyoF4js+A;*Kd5EnOlm<{ePYWHW3y3Jd}Z}QON5yJBPwE zbs}0N!Znh08yDpvJJyb__X`BN+oV!n?{g>Sc#?bzhz#vYXk38PVkFCT!=u!lSSET( zBk1noA!u|*wiQL0>-1%|F>TGI99~g(PTHx#G$%#zFs{^x4PXg_8X$F}ht7_}3vIi{ zs0|UsCS-GOUKZhpX+T9_F(E_KRkag#HQP0Gr-HwqBEm8k|&~A?^UTaY4RD(R%MSe79;Ci({^fFrH*A$WGEtc+~trS6VV@q zog@&F!N8i*%ky4ccDyb-A~4z1WKn=kqrGfI8m>rRy^(sxs>UXd(g?1eWio-rem z516u-d{?v<(V$&tgFp>=MiuUSZK zsFW4@Nrn`LSkITr)VxRZYE~MDb*#Ay-k8S^g4yucQUsznpXL8~0DA*;S(D_R8U0vR zt9VyG5xemTai2RZwFkd{R}8KKL{&yINeuC`<1Q#ajE#Bw z^Jk@n$Jq-VB{mFzZ;1D4Y|DwCb2Xl#lQNd$r$4ud6t0av#sB=*GqFf9o_E-aUMsHa9Q9L$n1znkgDZM2N3H8qsN~mZOc-EJX`M0PEQoJcN z7PR?s@KUCAAd9*Mu~tWb+D@NwfLatr#0$d9SLc!dkosIE1V0v7n;8EdAaV=<9_NQf zLCh&BzjAg4_*hoPpxEYHR|c{}_iJ+H_bd-)b2ixNQvRZ@$9bItG&lo5(i7{B7jgJl zGnFEOarKjV6Xl=UUhGh5gB+rPfPWwJH|eEbO`%Hc#SYq&MLOs%Ggq*FYp{kDeXykS z2LqK>GYf?Xb-&n)39Ho(D>D6LOwGjG%=DmLpkUx~@*5pr6?|1uh@?W((0~gZlT$}= zQLEfR7=X^sNd4qz^1)QiT+xHRfiU5RH=_bYc{!Y4vJ$G9Ag`(@+B0*WDD%$0*8S|0 z<#licETQ@*8F(i2+pPUmnyTOFcf1@aiJrC6gQr*Jm5pTEEZ=+(aM4L`*G!#!K5r{) zdG{qGnL?QWl|F;r?X9l+r$ePTnRC7K7+JWC_94?zVO3wD(&7g38(TpFRh%5(oHRZQ z^$>V9$hH=b)vGJ_I8qWuRyi(yeQ3=MehGVPpbB3$Ha<*gjsC~XHZ4!gxh(ubGxvX% zc0;|#baYyT-DC1XsC^+j8(gzuxVl0$Q-c9rN)dUdyT2`htGegDqXPc@Qi0ySZZ5sB z+7IpJa>x2s<75H2 z6oHS`jQRR27a8Pde-Iv5N+5a1j9wGtf*jKkN}%B~ibnj^HC_9A?7|F4tm8RXR7fW( z`H;G-;(g-b*U?KlpJqPFHj5

n$-g_sZ@ zuXY6j>*cx0F`sR9E;(=z(z7Kr$|sSOPz>}>=m8DNKn8epp6`Oyr^cc|z^Yv!6uCZ@ zQKR6UFa7ZEaGSt{bL8Ievq_EU=0uo+frt7ll_wo-oTfajTW=#lK>>;BA4P#e83>~$ zLJxqPeTG?w4jKFL5M*#?0DZl6*YbfG0DUc#_t>wY@I?aW5gYx3a}eS6{_xmtLUMQr87ZbhNzDh)1JyK0q~y0)Q-i8+ne*-_&`G zcs&os5Daeo?I*kBxJD_3wGV2$F;e*N=a;grVoP85tb{k`b-+vL*Se53291A*@icR! z^Dma(&J2f0FQ0Nxv7l|lZXD2LN-MGAy#eO>*SE-i7*DlgjNSe=5i(#whAs%FLz%{i_q;1W=Sla$!O-`hnE4P3!;tG9WJr zt@I(|!y?AW4;U%G#{X|}u4Fr29T6F6hSt;zk8B zFrW^g%|O`B`Z5L$wyd)eR6(;?IP zY2;LWBm-&uzmsb+l5n-prSa-O(EeMkU$GV(&=_FB)#7{pG3I}eRT)rbSWaad2SDI} z75}XWNQp6g06|Hr)7@M4zvoCW8c+&lCH<}b?|%EN*biceQ39L*c}o2I1fFx*bX*2> zxO8szk%53a+*diyBtML?4}8c5mZ)1Wvi?1Jd@kQgxFAjLA(l#R_J5;v3u6HrQUW>! zuKhprN%iNOb~!+0`=99EzYpZjI(dl$3oZBO{@*x`SpX~XzpE4wfjA3{ayk*fimQJu zF*TMCjHWyMKT$?vzY7g8|G)7+c2h;80@N1wY6Ca$FTionblo5KD*Na7|4)p<*Y2>2 XuhhLiz3U7@0S*OO6`5iwdiagram_1_r1returnER20 functionColony MemberEther RouterResolverColony Contractlookup (msg.ig)tokenAddress, return data sizedelegate callERC20 function return \ No newline at end of file diff --git a/src/lib/colonyNetwork/docs/img/colonyNetwork_combomark.svg b/src/lib/colonyNetwork/docs/img/colonyNetwork_combomark.svg new file mode 100644 index 0000000..1f82857 --- /dev/null +++ b/src/lib/colonyNetwork/docs/img/colonyNetwork_combomark.svg @@ -0,0 +1 @@ +colonyNetwork_combomark \ No newline at end of file diff --git a/src/lib/colonyNetwork/docs/img/colonyNetwork_wordmark.svg b/src/lib/colonyNetwork/docs/img/colonyNetwork_wordmark.svg new file mode 100644 index 0000000..32897cd --- /dev/null +++ b/src/lib/colonyNetwork/docs/img/colonyNetwork_wordmark.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/lib/colonyNetwork/docs/img/domains_r1.svg b/src/lib/colonyNetwork/docs/img/domains_r1.svg new file mode 100644 index 0000000..ee86d8a --- /dev/null +++ b/src/lib/colonyNetwork/docs/img/domains_r1.svg @@ -0,0 +1 @@ +domainsDevelopmentFrontendBackendDesignColony DomainNode.jsRuby \ No newline at end of file diff --git a/src/lib/colonyNetwork/gasCosts/gasCosts.js b/src/lib/colonyNetwork/gasCosts/gasCosts.js new file mode 100644 index 0000000..813d5d2 --- /dev/null +++ b/src/lib/colonyNetwork/gasCosts/gasCosts.js @@ -0,0 +1,330 @@ +/* globals artifacts */ +/* eslint-disable no-console */ + +import path from "path"; +import { toBN } from "web3-utils"; +import BN from "bn.js"; +import { TruffleLoader } from "@colony/colony-js-contract-loader-fs"; + +import { + MANAGER, + EVALUATOR, + WORKER, + MANAGER_ROLE, + EVALUATOR_ROLE, + WORKER_ROLE, + MANAGER_RATING, + WORKER_RATING, + RATING_1_SALT, + RATING_2_SALT, + RATING_1_SECRET, + RATING_2_SECRET, + SPECIFICATION_HASH, + DELIVERABLE_HASH, + SECONDS_PER_DAY +} from "../helpers/constants"; +import { getTokenArgs, currentBlockTime, createSignatures, forwardTime, bnSqrt } from "../helpers/test-helper"; +import { setupColonyVersionResolver } from "../helpers/upgradable-contracts"; +import { giveUserCLNYTokensAndStake, fundColonyWithTokens } from "../helpers/test-data-generator"; + +import ReputationMiner from "../packages/reputation-miner/ReputationMiner"; +import MaliciousReputationMinerExtraRep from "../packages/reputation-miner/test/MaliciousReputationMinerExtraRep"; + +const Colony = artifacts.require("Colony"); +const Token = artifacts.require("Token"); +const IColony = artifacts.require("IColony"); +const IColonyNetwork = artifacts.require("IColonyNetwork"); +const ColonyTask = artifacts.require("ColonyTask"); +const ColonyFunding = artifacts.require("ColonyFunding"); +const Resolver = artifacts.require("Resolver"); +const EtherRouter = artifacts.require("EtherRouter"); +const Authority = artifacts.require("Authority"); +const ReputationMiningCycle = artifacts.require("ReputationMiningCycle"); + +const oneHourLater = async () => forwardTime(3600, this); +const REAL_PROVIDER_PORT = process.env.SOLIDITY_COVERAGE ? 8555 : 8545; + +const contractLoader = new TruffleLoader({ + contractDir: path.resolve(__dirname, "..", "build", "contracts") +}); + +contract("All", accounts => { + const gasPrice = 20e9; + + let colony; + let token; + let tokenAddress; + let otherToken; + let colonyTask; + let colonyFunding; + let metaColony; + let authority; + let colonyNetwork; + + before(async () => { + colony = await Colony.new(); + const resolver = await Resolver.new(); + const etherRouter = await EtherRouter.deployed(); + colonyNetwork = await IColonyNetwork.at(etherRouter.address); + colonyTask = await ColonyTask.new(); + colonyFunding = await ColonyFunding.new(); + + await setupColonyVersionResolver(colony, colonyTask, colonyFunding, resolver, colonyNetwork); + const tokenArgs = getTokenArgs(); + token = await Token.new(...tokenArgs); + const { logs } = await colonyNetwork.createColony(token.address); + const { colonyAddress } = logs[0].args; + await token.setOwner(colonyAddress); + colony = await IColony.at(colonyAddress); + tokenAddress = await colony.getToken.call(); + const authorityAddress = await colony.authority.call(); + authority = await Authority.at(authorityAddress); + await IColony.defaults({ gasPrice }); + + const metaColonyAddress = await colonyNetwork.getMetaColony.call(); + metaColony = await IColony.at(metaColonyAddress); + + const otherTokenArgs = getTokenArgs(); + otherToken = await Token.new(...otherTokenArgs); + }); + + // We currently only print out gas costs and no assertions are made about what these should be. + describe("Gas costs", () => { + it("when working with the Colony Network", async () => { + const tokenArgs = getTokenArgs(); + const colonyToken = await Token.new(...tokenArgs); + await colonyNetwork.createColony(colonyToken.address); + }); + + it("when working with the Meta Colony", async () => { + await metaColony.addGlobalSkill(1); + await metaColony.addGlobalSkill(5); + await metaColony.addGlobalSkill(6); + await metaColony.addGlobalSkill(7); + }); + + it("when working with a Colony", async () => { + await colony.mintTokens(200); + await colony.claimColonyFunds(tokenAddress); + await authority.setUserRole(EVALUATOR, 1, true); + }); + + it("when working with a Task", async () => { + await colony.makeTask(SPECIFICATION_HASH, 1); + await colony.setTaskDomain(1, 1); + await colony.setTaskSkill(1, 7); + await colony.setTaskRoleUser(1, EVALUATOR_ROLE, EVALUATOR); + await colony.setTaskRoleUser(1, WORKER_ROLE, WORKER); + + let txData; + let sigs; + + // setTaskBrief + txData = await colony.contract.setTaskBrief.getData(1, SPECIFICATION_HASH); + sigs = await createSignatures(colony, 1, [MANAGER, WORKER], 0, txData); + await colony.executeTaskChange(sigs.sigV, sigs.sigR, sigs.sigS, [0, 0], 0, txData); + + // setTaskDueDate + let dueDate = await currentBlockTime(); + dueDate += SECONDS_PER_DAY * 5; + txData = await colony.contract.setTaskDueDate.getData(1, dueDate); + sigs = await createSignatures(colony, 1, [MANAGER, WORKER], 0, txData); + await colony.executeTaskChange(sigs.sigV, sigs.sigR, sigs.sigS, [0, 0], 0, txData); + + // moveFundsBetweenPots + await colony.moveFundsBetweenPots(1, 2, 150, tokenAddress); + + // setTaskManagerPayout + await colony.setTaskManagerPayout(1, tokenAddress, 50); + + // setTaskEvaluatorPayout + txData = await colony.contract.setTaskEvaluatorPayout.getData(1, tokenAddress, 40); + sigs = await createSignatures(colony, 1, [MANAGER, EVALUATOR], 0, txData); + await colony.executeTaskChange(sigs.sigV, sigs.sigR, sigs.sigS, [0, 0], 0, txData); + + // setTaskWorkerPayout + txData = await colony.contract.setTaskWorkerPayout.getData(1, tokenAddress, 100); + sigs = await createSignatures(colony, 1, [MANAGER, WORKER], 0, txData); + await colony.executeTaskChange(sigs.sigV, sigs.sigR, sigs.sigS, [0, 0], 0, txData); + + // submitTaskDeliverable + await colony.submitTaskDeliverable(1, DELIVERABLE_HASH, { from: WORKER, gasPrice }); + + // submitTaskWorkRating + await colony.submitTaskWorkRating(1, WORKER_ROLE, RATING_2_SECRET, { from: EVALUATOR, gasPrice }); + await colony.submitTaskWorkRating(1, MANAGER_ROLE, RATING_1_SECRET, { from: WORKER }); + + // revealTaskWorkRating + await colony.revealTaskWorkRating(1, WORKER_ROLE, WORKER_RATING, RATING_2_SALT, { from: EVALUATOR, gasPrice }); + await colony.revealTaskWorkRating(1, MANAGER_ROLE, MANAGER_RATING, RATING_1_SALT, { from: WORKER }); + + // finalizeTask + await colony.finalizeTask(1); + }); + + it("when working with staking", async () => { + // TODO: Should stakers be part of the constants? + const STAKER1 = accounts[0]; + const STAKER2 = accounts[1]; + const STAKER3 = accounts[2]; + + // Setup the stakers balance + const bigStr = "1000000000000000000"; + const lessBigStr = "10000000000000000"; + const big = new BN(bigStr); + + await giveUserCLNYTokensAndStake(colonyNetwork, STAKER1, big); + await giveUserCLNYTokensAndStake(colonyNetwork, STAKER2, big); + await giveUserCLNYTokensAndStake(colonyNetwork, STAKER3, big); + + let repCycleAddr = await colonyNetwork.getReputationMiningCycle.call(true); + + await oneHourLater(); + let repCycle = ReputationMiningCycle.at(repCycleAddr); + await repCycle.submitRootHash("0x0", 0, 1); + await repCycle.confirmNewHash(0); + await oneHourLater(); + + repCycleAddr = await colonyNetwork.getReputationMiningCycle.call(true); + repCycle = ReputationMiningCycle.at(repCycleAddr); + + const goodClient = new ReputationMiner({ loader: contractLoader, minerAddress: STAKER1, realProviderPort: REAL_PROVIDER_PORT }); + const badClient = new MaliciousReputationMinerExtraRep( + { loader: contractLoader, minerAddress: STAKER2, realProviderPort: REAL_PROVIDER_PORT }, + 1, + 0xfffffffff + ); + const badClient2 = new MaliciousReputationMinerExtraRep( + { loader: contractLoader, minerAddress: STAKER3, realProviderPort: REAL_PROVIDER_PORT }, + 2, + 0xfffffffff + ); + await goodClient.initialise(colonyNetwork.address); + await badClient.initialise(colonyNetwork.address); + await badClient2.initialise(colonyNetwork.address); + // Submit hashes + await goodClient.addLogContentsToReputationTree(); + await badClient.addLogContentsToReputationTree(); + await badClient2.addLogContentsToReputationTree(); + + await goodClient.submitRootHash(); + await badClient.submitRootHash(); + await badClient2.submitRootHash(); + + // Session of respond / invalidate between our 3 submissions + await goodClient.submitJustificationRootHash(); + await badClient.submitJustificationRootHash(); + await badClient2.submitJustificationRootHash(); + + await repCycle.invalidateHash(0, 3); // Bye for R1 + + await goodClient.respondToBinarySearchForChallenge(); + await badClient.respondToBinarySearchForChallenge(); + + await goodClient.respondToBinarySearchForChallenge(); + await badClient.respondToBinarySearchForChallenge(); + + await goodClient.respondToBinarySearchForChallenge(); + await badClient.respondToBinarySearchForChallenge(); + + await goodClient.respondToBinarySearchForChallenge(); + await badClient.respondToBinarySearchForChallenge(); + + // We now know where they disagree + await goodClient.respondToChallenge(); + // badClient will fail this if we try + // await badClient.respondToChallenge(); + await oneHourLater(); + await repCycle.invalidateHash(0, 1); + + await goodClient.respondToBinarySearchForChallenge(); + await badClient2.respondToBinarySearchForChallenge(); + + await goodClient.respondToBinarySearchForChallenge(); + await badClient2.respondToBinarySearchForChallenge(); + + await goodClient.respondToBinarySearchForChallenge(); + await badClient2.respondToBinarySearchForChallenge(); + + await goodClient.respondToBinarySearchForChallenge(); + await badClient2.respondToBinarySearchForChallenge(); + + await goodClient.respondToChallenge(); + await oneHourLater(); + await repCycle.invalidateHash(1, 0); + + await repCycle.confirmNewHash(2); + + // withdraw + await colonyNetwork.withdraw(lessBigStr, { from: STAKER1 }); + }); + + it("when working with reward payouts", async () => { + const totalReputation = toBN(350 * 1e18); + const workerReputation = toBN(200 * 1e18); + const managerReputation = toBN(100 * 1e18); + const initialFunding = toBN(360 * 1e18); + + const tokenArgs = getTokenArgs(); + const newToken = await Token.new(...tokenArgs); + const { logs } = await colonyNetwork.createColony(newToken.address); + const { colonyAddress } = logs[0].args; + const newColony = IColony.at(colonyAddress); + await newToken.setOwner(colonyAddress); + + await fundColonyWithTokens(newColony, otherToken, initialFunding.toString()); + await fundColonyWithTokens(newColony, newToken, initialFunding.toString()); + + await newColony.bootstrapColony([WORKER, MANAGER], [workerReputation.toString(), managerReputation.toString()]); + + const tx = await newColony.startNextRewardPayout(otherToken.address); + const payoutId = tx.logs[0].args.id; + + await newColony.waiveRewardPayouts(1, { + from: MANAGER + }); + + const workerReputationSqrt = bnSqrt(workerReputation); + const totalReputationSqrt = bnSqrt(workerReputation.add(managerReputation)); + const numeratorSqrt = bnSqrt(workerReputationSqrt.mul(workerReputationSqrt)); + const denominatorSqrt = bnSqrt(totalReputationSqrt.mul(totalReputationSqrt)); + + const info = await newColony.getRewardPayoutInfo.call(payoutId); + + const amountSqrt = bnSqrt(info[2]); + + const squareRoots = [ + workerReputationSqrt.toString(), + workerReputationSqrt.toString(), + totalReputationSqrt.toString(), + totalReputationSqrt.toString(), + numeratorSqrt.toString(), + denominatorSqrt.toString(), + amountSqrt.toString() + ]; + + await newColony.claimRewardPayout(payoutId, squareRoots, workerReputation.toString(), totalReputation.toString(), { + from: WORKER + }); + + await forwardTime(5184001); + await newColony.finalizeRewardPayout(payoutId); + + await fundColonyWithTokens(newColony, otherToken, initialFunding.toString()); + + const tx2 = await newColony.startNextRewardPayout(otherToken.address); + const payoutId2 = tx2.logs[0].args.id; + + await newColony.waiveRewardPayouts(1, { + from: MANAGER + }); + + await newColony.claimRewardPayout(payoutId2, squareRoots, workerReputation.toString(), totalReputation.toString(), { + from: WORKER + }); + + await forwardTime(5184001); + await newColony.finalizeRewardPayout(payoutId2); + }); + }); +}); diff --git a/src/lib/colonyNetwork/genesis.json b/src/lib/colonyNetwork/genesis.json new file mode 100644 index 0000000..6aebb3a --- /dev/null +++ b/src/lib/colonyNetwork/genesis.json @@ -0,0 +1,35 @@ +{ + "config": { + "chainId": 27921, + "homesteadBlock": 1, + "eip150Block": 2, + "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "eip155Block": 3, + "eip158Block": 3, + "clique": { + "period": 1, + "epoch": 30000 + } + }, + "nonce": "0x0", + "timestamp": "0x59ad1a99", + "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000xxxInsertSignerAddressHereNo0xPrefixxxxx0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "gasLimit": "0x47b760", + "difficulty": "0x1", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase": "0x0000000000000000000000000000000000000000", + "alloc": { + "xxxxx" : { + "balance": "1000000000000000000000" + }, + "yyyyy" : { + "balance": "1000000000000000000000" + }, + "zzzzz" : { + "balance": "1000000000000000000000" + } + }, + "number": "0x0", + "gasUsed": "0x0", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000" +} diff --git a/src/lib/colonyNetwork/helpers/constants.js b/src/lib/colonyNetwork/helpers/constants.js new file mode 100644 index 0000000..51aa446 --- /dev/null +++ b/src/lib/colonyNetwork/helpers/constants.js @@ -0,0 +1,53 @@ +import web3Utils from "web3-utils"; +import { getRandomString } from "../helpers/test-helper"; + +let MANAGER; +let EVALUATOR; +let WORKER; +let OTHER; +const MANAGER_ROLE = 0; +const EVALUATOR_ROLE = 1; +const WORKER_ROLE = 2; +// The base58 decoded, bytes32 converted hex value of a test task ipfsHash "QmNSUYVKDSvPUnRLKmuxk9diJ6yS96r1TrAXzjTiBcCLAL" +const SPECIFICATION_HASH = "0x017dfd85d4f6cb4dcd715a88101f7b1f06cd1e009b2327a0809d01eb9c91f231"; +// The above bytes32 hash where the last raw byte was changed from 1 -> 2 +const SPECIFICATION_HASH_UPDATED = "0x017dfd85d4f6cb4dcd715a88101f7b1f06cd1e009b2327a0809d01eb9c91f232"; +// The base58 decoded, bytes32 converted hex value of a test task ipfsHash "qmv8ndh7ageh9b24zngaextmuhj7aiuw3scc8hkczvjkww" +const DELIVERABLE_HASH = "0xfb027a4d64f29d83e27769cb05d945e67ef7396fa1bd73ef53f065311fd3313e"; +const INITIAL_FUNDING = 360 * 1e18; +const MANAGER_PAYOUT = web3Utils.toBN(100 * 1e18); +const EVALUATOR_PAYOUT = web3Utils.toBN(50 * 1e18); +const WORKER_PAYOUT = web3Utils.toBN(200 * 1e18); +const MANAGER_RATING = 2; +const WORKER_RATING = 3; +const RATING_MULTIPLIER = { 1: -1, 2: 1, 3: 1.5 }; +const SECONDS_PER_DAY = 86400; +const RATING_1_SALT = web3Utils.soliditySha3(getRandomString(10)); +const RATING_2_SALT = web3Utils.soliditySha3(getRandomString(10)); +const RATING_1_SECRET = web3Utils.soliditySha3(RATING_1_SALT, MANAGER_RATING); +const RATING_2_SECRET = web3Utils.soliditySha3(RATING_2_SALT, WORKER_RATING); + +module.exports = { + MANAGER: MANAGER || web3.eth.accounts[0], + EVALUATOR: EVALUATOR || web3.eth.accounts[1], + WORKER: WORKER || web3.eth.accounts[2], + OTHER: OTHER || web3.eth.accounts[3], + MANAGER_ROLE, + EVALUATOR_ROLE, + WORKER_ROLE, + SPECIFICATION_HASH, + SPECIFICATION_HASH_UPDATED, + DELIVERABLE_HASH, + SECONDS_PER_DAY, + INITIAL_FUNDING, + MANAGER_PAYOUT, + EVALUATOR_PAYOUT, + WORKER_PAYOUT, + MANAGER_RATING, + WORKER_RATING, + RATING_MULTIPLIER, + RATING_1_SALT, + RATING_2_SALT, + RATING_1_SECRET, + RATING_2_SECRET +}; diff --git a/src/lib/colonyNetwork/helpers/test-data-generator.js b/src/lib/colonyNetwork/helpers/test-data-generator.js new file mode 100644 index 0000000..144098b --- /dev/null +++ b/src/lib/colonyNetwork/helpers/test-data-generator.js @@ -0,0 +1,197 @@ +/* globals artifacts */ +import web3Utils from "web3-utils"; +import { BN } from "bn.js"; + +import { + MANAGER, + EVALUATOR, + WORKER, + MANAGER_PAYOUT, + EVALUATOR_PAYOUT, + WORKER_PAYOUT, + MANAGER_RATING, + WORKER_RATING, + RATING_1_SALT, + RATING_2_SALT, + MANAGER_ROLE, + EVALUATOR_ROLE, + WORKER_ROLE, + SPECIFICATION_HASH +} from "../helpers/constants"; +import { currentBlockTime, createSignatures } from "../helpers/test-helper"; + +const IColony = artifacts.require("IColony"); +const Token = artifacts.require("Token"); + +export async function setupAssignedTask({ colonyNetwork, colony, dueDate, domain = 1, skill = 0, evaluator = EVALUATOR, worker = WORKER }) { + const specificationHash = SPECIFICATION_HASH; + const tx = await colony.makeTask(specificationHash, domain); + // Reading the ID out of the event triggered by our transaction will allow us to make multiple tasks in parallel in the future. + const taskId = tx.logs[0].args.id.toNumber(); + // If the skill is not specified, default to the root global skill + if (skill === 0) { + const rootGlobalSkill = await colonyNetwork.getRootGlobalSkillId.call(); + if (rootGlobalSkill.toNumber() === 0) throw new Error("Meta Colony is not setup and therefore the root global skill does not exist"); + await colony.setTaskSkill(taskId, rootGlobalSkill); + } else { + await colony.setTaskSkill(taskId, skill); + } + await colony.setTaskRoleUser(taskId, EVALUATOR_ROLE, evaluator); + await colony.setTaskRoleUser(taskId, WORKER_ROLE, worker); + + let dueDateTimestamp = dueDate; + if (!dueDateTimestamp) { + dueDateTimestamp = await currentBlockTime(); + } + const txData = await colony.contract.setTaskDueDate.getData(taskId, dueDateTimestamp); + const signers = MANAGER === worker ? [MANAGER] : [MANAGER, worker]; + const sigs = await createSignatures(colony, taskId, signers, 0, txData); + const signatureTypes = Array.from({ length: signers.length }, () => 0); + await colony.executeTaskChange(sigs.sigV, sigs.sigR, sigs.sigS, signatureTypes, 0, txData); + return taskId; +} + +export async function setupFundedTask({ + colonyNetwork, + colony, + token, + dueDate, + domain, + skill, + evaluator = EVALUATOR, + worker = WORKER, + managerPayout = MANAGER_PAYOUT, + evaluatorPayout = EVALUATOR_PAYOUT, + workerPayout = WORKER_PAYOUT +}) { + let tokenAddress; + let txData; + let sigs; + + if (token === undefined) { + tokenAddress = await colony.getToken.call(); + } else { + tokenAddress = token === 0x0 ? 0x0 : token.address; + } + const taskId = await setupAssignedTask({ colonyNetwork, colony, dueDate, domain, skill, evaluator, worker }); + const task = await colony.getTask.call(taskId); + const potId = task[6].toNumber(); + const managerPayoutBN = new BN(managerPayout); + const evaluatorPayoutBN = new BN(evaluatorPayout); + const workerPayoutBN = new BN(workerPayout); + const totalPayouts = managerPayoutBN.add(workerPayoutBN).add(evaluatorPayoutBN); + await colony.moveFundsBetweenPots(1, potId, totalPayouts.toString(), tokenAddress); + + await colony.setTaskManagerPayout(taskId, tokenAddress, managerPayout.toString()); + + txData = await colony.contract.setTaskEvaluatorPayout.getData(taskId, tokenAddress, evaluatorPayout.toString()); + let signers = MANAGER === evaluator ? [MANAGER] : [MANAGER, evaluator]; + sigs = await createSignatures(colony, taskId, signers, 0, txData); + let signatureTypes = Array.from({ length: signers.length }, () => 0); + await colony.executeTaskChange(sigs.sigV, sigs.sigR, sigs.sigS, signatureTypes, 0, txData); + + txData = await colony.contract.setTaskWorkerPayout.getData(taskId, tokenAddress, workerPayout.toString()); + signers = MANAGER === worker ? [MANAGER] : [MANAGER, worker]; + sigs = await createSignatures(colony, taskId, signers, 0, txData); + signatureTypes = Array.from({ length: signers.length }, () => 0); + await colony.executeTaskChange(sigs.sigV, sigs.sigR, sigs.sigS, signatureTypes, 0, txData); + return taskId; +} + +export async function setupRatedTask({ + colonyNetwork, + colony, + token, + dueDate, + domain, + skill, + evaluator = EVALUATOR, + worker = WORKER, + managerPayout = MANAGER_PAYOUT, + evaluatorPayout = EVALUATOR_PAYOUT, + workerPayout = WORKER_PAYOUT, + managerRating = MANAGER_RATING, + managerRatingSalt = RATING_1_SALT, + workerRating = WORKER_RATING, + workerRatingSalt = RATING_2_SALT +}) { + const taskId = await setupFundedTask({ + colonyNetwork, + colony, + token, + dueDate, + domain, + skill, + evaluator, + worker, + managerPayout, + evaluatorPayout, + workerPayout + }); + const WORKER_RATING_SECRET = web3Utils.soliditySha3(workerRatingSalt, workerRating); + const MANAGER_RATING_SECRET = web3Utils.soliditySha3(managerRatingSalt, managerRating); + await colony.submitTaskWorkRating(taskId, WORKER_ROLE, WORKER_RATING_SECRET, { from: evaluator }); + await colony.submitTaskWorkRating(taskId, MANAGER_ROLE, MANAGER_RATING_SECRET, { from: worker }); + await colony.revealTaskWorkRating(taskId, WORKER_ROLE, workerRating, workerRatingSalt, { from: evaluator }); + await colony.revealTaskWorkRating(taskId, MANAGER_ROLE, managerRating, managerRatingSalt, { from: worker }); + return taskId; +} + +export async function giveUserCLNYTokens(colonyNetwork, address, _amount) { + const metaColonyAddress = await colonyNetwork.getMetaColony(); + const metaColony = IColony.at(metaColonyAddress); + const clnyAddress = await metaColony.getToken.call(); + const clny = Token.at(clnyAddress); + const amount = new BN(_amount); + const mainStartingBalance = await clny.balanceOf.call(MANAGER); + const targetStartingBalance = await clny.balanceOf.call(address); + await metaColony.mintTokens(amount * 3); + await metaColony.claimColonyFunds(clny.address); + const taskId = await setupRatedTask({ + colonyNetwork, + colony: metaColony, + managerPayout: amount.mul(new BN("2")), + evaluatorPayout: new BN("0"), + workerPayout: new BN("0") + }); + await metaColony.finalizeTask(taskId); + await metaColony.claimPayout(taskId, 0, clny.address); + + let mainBalance = await clny.balanceOf.call(MANAGER); + await clny.transfer( + 0x0, + mainBalance + .sub(amount) + .sub(mainStartingBalance) + .toString() + ); + await clny.transfer(address, amount.toString()); + mainBalance = await clny.balanceOf.call(MANAGER); + if (address !== MANAGER) { + await clny.transfer(0x0, mainBalance.sub(mainStartingBalance).toString()); + } + const userBalance = await clny.balanceOf.call(address); + assert.equal(targetStartingBalance.add(amount).toString(), userBalance.toString()); +} + +export async function giveUserCLNYTokensAndStake(colonyNetwork, address, _amount) { + const metaColonyAddress = await colonyNetwork.getMetaColony.call(); + const metaColony = IColony.at(metaColonyAddress); + const clnyAddress = await metaColony.getToken.call(); + const clny = Token.at(clnyAddress); + + await giveUserCLNYTokens(colonyNetwork, address, _amount); + await clny.approve(colonyNetwork.address, _amount.toString(), { from: address }); + await colonyNetwork.deposit(_amount.toString(), { from: address }); +} + +export async function fundColonyWithTokens(colony, token, tokenAmount) { + const colonyToken = await colony.getToken.call(); + if (colonyToken === token.address) { + await colony.mintTokens(tokenAmount); + } else { + await token.mint(tokenAmount); + await token.transfer(colony.address, tokenAmount); + } + await colony.claimColonyFunds(token.address); +} diff --git a/src/lib/colonyNetwork/helpers/test-helper.js b/src/lib/colonyNetwork/helpers/test-helper.js new file mode 100644 index 0000000..fd1f109 --- /dev/null +++ b/src/lib/colonyNetwork/helpers/test-helper.js @@ -0,0 +1,247 @@ +/* eslint-disable no-console */ +import shortid from "shortid"; +import { assert } from "chai"; +import web3Utils from "web3-utils"; +import ethUtils from "ethereumjs-util"; +import fs from "fs"; + +export function web3GetNetwork() { + return new Promise((resolve, reject) => { + web3.version.getNetwork((err, res) => { + if (err !== null) return reject(err); + return resolve(res); + }); + }); +} + +export function web3GetClient() { + return new Promise((resolve, reject) => { + web3.version.getNode((err, res) => { + if (err !== null) return reject(err); + return resolve(res); + }); + }); +} + +export function web3GetBalance(account) { + return new Promise((resolve, reject) => { + web3.eth.getBalance(account, (err, res) => { + if (err !== null) return reject(err); + return resolve(res); + }); + }); +} + +export function web3GetTransaction(txid) { + return new Promise((resolve, reject) => { + web3.eth.getTransaction(txid, (err, res) => { + if (err !== null) return reject(err); + return resolve(res); + }); + }); +} + +export function web3GetTransactionReceipt(txid) { + return new Promise((resolve, reject) => { + web3.eth.getTransactionReceipt(txid, (err, res) => { + if (err !== null) return reject(err); + return resolve(res); + }); + }); +} + +export function web3GetFirstTransactionHashFromLastBlock() { + return new Promise((resolve, reject) => { + web3.eth.getBlock("latest", true, (err, res) => { + if (err !== null) return reject(err); + return resolve(res.transactions[0].hash); + }); + }); +} + +export function web3GetCode(a) { + return new Promise((resolve, reject) => { + web3.eth.getCode(a, (err, res) => { + if (err !== null) return reject(err); + return resolve(res); + }); + }); +} + +// eslint-disable-next-line no-unused-vars +export async function checkErrorRevert(promise, errMsg) { + // There is a discrepancy between how ganache-cli handles errors + // (throwing an exception all the way up to these tests) and how geth/parity handle them + // (still making a valid transaction and returning a txid). For the explanation of why + // See https://github.com/ethereumjs/testrpc/issues/39 + // + // Obviously, we want our tests to pass on all, so this is a bit of a problem. + // We have to have this special function that we use to catch the error. + let tx; + let receipt; + try { + tx = await promise; + receipt = await web3GetTransactionReceipt(tx); + } catch (err) { + // TODO: Check errMsg == err.Error or wherever truffle decides ot put this + ({ tx, receipt } = err); + } + + // Check the receipt `status` to ensure transaction failed. + assert.equal(receipt.status, 0x00); +} + +export function checkErrorNonPayableFunction(tx) { + assert.equal(tx, "Error: Cannot send value to non-payable function"); +} + +export function getRandomString(_length) { + const length = _length || 7; + let randString = ""; + while (randString.length < length) { + randString += shortid + .generate() + .replace(/_/g, "") + .toLowerCase(); + } + return randString.slice(0, length); +} + +export function getTokenArgs() { + return [getRandomString(5), getRandomString(3), 18]; +} + +export async function currentBlockTime() { + const p = new Promise((resolve, reject) => { + web3.eth.getBlock("latest", (err, res) => { + if (err) { + return reject(err); + } + return resolve(res.timestamp); + }); + }); + return p; +} + +export async function getBlockTime(blockNumber) { + const p = new Promise((resolve, reject) => { + web3.eth.getBlock(blockNumber, (err, res) => { + if (err) { + return reject(err); + } + return resolve(res.timestamp); + }); + }); + return p; +} + +export async function expectEvent(tx, eventName) { + const { logs } = await tx; + const event = logs.find(e => e.event === eventName); + return assert.exists(event); +} + +export async function forwardTime(seconds, test) { + const client = await web3GetClient(); + const p = new Promise((resolve, reject) => { + if (client.indexOf("TestRPC") === -1) { + resolve(test.skip()); + } else { + console.log(`Forwarding time with ${seconds}s ...`); + web3.currentProvider.send( + { + jsonrpc: "2.0", + method: "evm_increaseTime", + params: [seconds], + id: 0 + }, + err => { + if (err) { + return reject(err); + } + return web3.currentProvider.send( + { + jsonrpc: "2.0", + method: "evm_mine", + params: [], + id: 0 + }, + (err2, res) => { + if (err2) { + return reject(err2); + } + return resolve(res); + } + ); + } + ); + } + }); + return p; +} + +export async function createSignatures(colony, taskId, signers, value, data) { + const sourceAddress = colony.address; + const destinationAddress = colony.address; + const nonce = await colony.getTaskChangeNonce.call(taskId); + const accountsJson = JSON.parse(fs.readFileSync("./ganache-accounts.json", "utf8")); + const input = `0x${sourceAddress.slice(2)}${destinationAddress.slice(2)}${web3Utils.padLeft(value.toString("16"), "64", "0")}${data.slice( + 2 + )}${web3Utils.padLeft(nonce.toString("16"), "64", "0")}`; // eslint-disable-line max-len + const sigV = []; + const sigR = []; + const sigS = []; + const msgHash = web3Utils.soliditySha3(input); + + for (let i = 0; i < signers.length; i += 1) { + const user = signers[i].toString(); + const privKey = accountsJson.private_keys[user]; + const prefixedMessageHash = ethUtils.hashPersonalMessage(Buffer.from(msgHash.slice(2), "hex")); + const sig = ethUtils.ecsign(prefixedMessageHash, Buffer.from(privKey, "hex")); + + sigV.push(sig.v); + sigR.push(`0x${sig.r.toString("hex")}`); + sigS.push(`0x${sig.s.toString("hex")}`); + } + + return { sigV, sigR, sigS }; +} + +export async function createSignaturesTrezor(colony, taskId, signers, value, data) { + const sourceAddress = colony.address; + const destinationAddress = colony.address; + const nonce = await colony.getTaskChangeNonce.call(taskId); + const accountsJson = JSON.parse(fs.readFileSync("./ganache-accounts.json", "utf8")); + const input = `0x${sourceAddress.slice(2)}${destinationAddress.slice(2)}${web3Utils.padLeft(value.toString("16"), "64", "0")}${data.slice( + 2 + )}${web3Utils.padLeft(nonce.toString("16"), "64", "0")}`; // eslint-disable-line max-len + const sigV = []; + const sigR = []; + const sigS = []; + const msgHash = web3Utils.soliditySha3(input); + + for (let i = 0; i < signers.length; i += 1) { + const user = signers[i].toString(); + const privKey = accountsJson.private_keys[user]; + const prefixedMessageHash = web3Utils.soliditySha3("\x19Ethereum Signed Message:\n\x20", msgHash); + const sig = ethUtils.ecsign(Buffer.from(prefixedMessageHash.slice(2), "hex"), Buffer.from(privKey, "hex")); + sigV.push(sig.v); + sigR.push(`0x${sig.r.toString("hex")}`); + sigS.push(`0x${sig.s.toString("hex")}`); + } + + return { sigV, sigR, sigS }; +} + +export function bnSqrt(bn) { + let a = bn.add(web3Utils.toBN(1)).div(web3Utils.toBN(2)); + let b = bn; + while (a.lt(b)) { + b = a; + a = bn + .div(a) + .add(a) + .div(web3Utils.toBN(2)); + } + return b; +} diff --git a/src/lib/colonyNetwork/helpers/upgradable-contracts.js b/src/lib/colonyNetwork/helpers/upgradable-contracts.js new file mode 100644 index 0000000..256e5f5 --- /dev/null +++ b/src/lib/colonyNetwork/helpers/upgradable-contracts.js @@ -0,0 +1,97 @@ +import web3Utils from "web3-utils"; +import assert from "assert"; +import fs from "fs"; + +export function parseImplementation(contractName, functionsToResolve, deployedImplementations) { + // Goes through a contract, and sees if anything in it is in the interface. If it is, then wire up the resolver to point at it + const { abi } = JSON.parse(fs.readFileSync(`./build/contracts/${contractName}.json`)); + abi.map(value => { + const fName = value.name; + if (functionsToResolve[fName]) { + if (functionsToResolve[fName].definedIn !== "") { + // It's a Friday afternoon, and I can't be bothered to deal with same name, different signature. + // Let's just resolve to not do it? We'd probably just trip ourselves up later. + // eslint-disable-next-line no-console + console.log( + "What are you doing!? Defining functions with the same name in different files!? You are going to do yourself a mischief. ", + "You seem to have two ", + fName, + " in ", + contractName, + "and ", + functionsToResolve[fName].definedIn + ); + process.exit(1); + } + functionsToResolve[fName].definedIn = deployedImplementations[contractName]; // eslint-disable-line no-param-reassign + } + return functionsToResolve[fName]; + }); +} + +export async function setupEtherRouter(interfaceContract, deployedImplementations, resolver) { + const functionsToResolve = {}; + + // Load ABI of the interface of the contract we're trying to stich together + const iAbi = JSON.parse(fs.readFileSync(`./build/contracts/${interfaceContract}.json`, "utf8")).abi; + iAbi.map(value => { + const fName = value.name; + const fType = value.type; + // These are from DSAuth, and so are on EtherRouter itself without any more help. + if (fName !== "authority" && fName !== "owner") { + // We only care about functions. + if (fType === "function") { + // Gets the types of the parameters, which is all we care about for function signatures. + const fInputs = value.inputs.map(parameter => parameter.type); + // Record function name + functionsToResolve[fName] = { inputs: fInputs, definedIn: "" }; + } + } + return functionsToResolve; + }); + Object.keys(deployedImplementations).map(name => parseImplementation(name, functionsToResolve, deployedImplementations)); + const promises = Object.keys(functionsToResolve).map(async fName => { + const sig = `${fName}(${functionsToResolve[fName].inputs.join(",")})`; + const address = functionsToResolve[fName].definedIn; + const sigHash = web3Utils.soliditySha3(sig).substr(0, 10); + await resolver.register(sig, address); + const destination = await resolver.lookup.call(sigHash); + assert.equal(destination, address, `${sig} has not been registered correctly. Is it defined?`); + }); + return Promise.all(promises); +} + +export async function setupUpgradableToken(token, resolver, etherRouter) { + const deployedImplementations = {}; + deployedImplementations.Token = token.address; + await setupEtherRouter("ERC20Extended", deployedImplementations, resolver); + + await etherRouter.setResolver(resolver.address); + const registeredResolver = await etherRouter.resolver.call(); + assert.equal(registeredResolver, resolver.address); +} + +export async function setupColonyVersionResolver(colony, colonyTask, colonyFunding, resolver, colonyNetwork) { + const deployedImplementations = {}; + deployedImplementations.Colony = colony.address; + deployedImplementations.ColonyTask = colonyTask.address; + deployedImplementations.ColonyFunding = colonyFunding.address; + + await setupEtherRouter("IColony", deployedImplementations, resolver); + + const version = await colony.version.call(); + await colonyNetwork.addColonyVersion(version.toNumber(), resolver.address); + const currentColonyVersion = await colonyNetwork.getCurrentColonyVersion.call(); + assert.equal(version, currentColonyVersion.toNumber()); +} + +export async function setupUpgradableColonyNetwork(etherRouter, resolver, colonyNetwork, colonyNetworkStaking, colonyNetworkAuction) { + const deployedImplementations = {}; + deployedImplementations.ColonyNetwork = colonyNetwork.address; + deployedImplementations.ColonyNetworkStaking = colonyNetworkStaking.address; + deployedImplementations.ColonyNetworkAuction = colonyNetworkAuction.address; + + await setupEtherRouter("IColonyNetwork", deployedImplementations, resolver); + + await etherRouter.setResolver(resolver.address); +} diff --git a/src/lib/colonyNetwork/migrations/1_initial_migration.js b/src/lib/colonyNetwork/migrations/1_initial_migration.js new file mode 100644 index 0000000..9eb14d4 --- /dev/null +++ b/src/lib/colonyNetwork/migrations/1_initial_migration.js @@ -0,0 +1,6 @@ +/* eslint-disable no-undef */ +const Migrations = artifacts.require("./Migrations"); + +module.exports = deployer => { + deployer.deploy(Migrations); +}; diff --git a/src/lib/colonyNetwork/migrations/2_deploy_contracts.js b/src/lib/colonyNetwork/migrations/2_deploy_contracts.js new file mode 100644 index 0000000..f29f573 --- /dev/null +++ b/src/lib/colonyNetwork/migrations/2_deploy_contracts.js @@ -0,0 +1,29 @@ +/* globals artifacts */ +/* eslint-disable no-undef, no-console */ + +const SafeMath = artifacts.require("./SafeMath"); +const ColonyFunding = artifacts.require("./ColonyFunding"); +const ColonyTask = artifacts.require("./ColonyTask"); +const ColonyNetwork = artifacts.require("./ColonyNetwork"); +const ColonyNetworkStaking = artifacts.require("./ColonyNetworkStaking"); +const ColonyNetworkAuction = artifacts.require("./ColonyNetworkAuction"); +const EtherRouter = artifacts.require("./EtherRouter"); +const Resolver = artifacts.require("./Resolver"); + +// We `require` the ReputationMiningCycle object to make sure +// it is injected in the `artifacts` variables during test +// preparation. We need this for the eth-gas-reporter. +// See https://github.com/cgewecke/eth-gas-reporter/issues/64 +artifacts.require("./ReputationMiningCycle"); + +module.exports = (deployer, network) => { + console.log(`## ${network} network ##`); + deployer.deploy([SafeMath]); + deployer.link(SafeMath, ColonyFunding); + deployer.link(SafeMath, ColonyTask); + deployer.deploy([ColonyNetwork]); + deployer.deploy([ColonyNetworkStaking]); + deployer.deploy([ColonyNetworkAuction]); + deployer.deploy([EtherRouter]); + deployer.deploy([Resolver]); +}; diff --git a/src/lib/colonyNetwork/migrations/3_setup_colony_network.js b/src/lib/colonyNetwork/migrations/3_setup_colony_network.js new file mode 100644 index 0000000..44314f3 --- /dev/null +++ b/src/lib/colonyNetwork/migrations/3_setup_colony_network.js @@ -0,0 +1,45 @@ +/* globals artifacts */ +/* eslint-disable no-console */ +const { setupUpgradableColonyNetwork } = require("../helpers/upgradable-contracts"); + +const ColonyNetwork = artifacts.require("./ColonyNetwork"); +const ColonyNetworkStaking = artifacts.require("./ColonyNetworkStaking"); +const ColonyNetworkAuction = artifacts.require("./ColonyNetworkAuction"); +const EtherRouter = artifacts.require("./EtherRouter"); +const Resolver = artifacts.require("./Resolver"); + +module.exports = deployer => { + let etherRouter; + let resolver; + let colonyNetwork; + let colonyNetworkStaking; + let colonyNetworkAuction; + deployer + .then(() => ColonyNetwork.deployed()) + .then(instance => { + colonyNetwork = instance; + return ColonyNetworkStaking.deployed(); + }) + .then(instance => { + colonyNetworkStaking = instance; + return ColonyNetworkAuction.deployed(); + }) + .then(instance => { + colonyNetworkAuction = instance; + return EtherRouter.deployed(); + }) + .then(instance => { + etherRouter = instance; + return Resolver.deployed(); + }) + .then(instance => { + resolver = instance; + return setupUpgradableColonyNetwork(etherRouter, resolver, colonyNetwork, colonyNetworkStaking, colonyNetworkAuction); + }) + .then(() => { + console.log("### Colony Network setup with Resolver", resolver.address, "and EtherRouter", etherRouter.address); + }) + .catch(err => { + console.log("### Error occurred ", err); + }); +}; diff --git a/src/lib/colonyNetwork/migrations/4_setup_colony_version_resolver.js b/src/lib/colonyNetwork/migrations/4_setup_colony_version_resolver.js new file mode 100644 index 0000000..ac2e13a --- /dev/null +++ b/src/lib/colonyNetwork/migrations/4_setup_colony_version_resolver.js @@ -0,0 +1,55 @@ +/* globals artifacts */ +/* eslint-disable no-console */ + +const { setupColonyVersionResolver } = require("../helpers/upgradable-contracts"); + +const Colony = artifacts.require("./Colony"); +const ColonyFunding = artifacts.require("./ColonyFunding"); +const ColonyTask = artifacts.require("./ColonyTask"); +const ColonyNetwork = artifacts.require("./ColonyNetwork"); +const EtherRouter = artifacts.require("./EtherRouter"); +const Resolver = artifacts.require("./Resolver"); + +module.exports = deployer => { + // Create a new Colony (version) and setup a new Resolver for it + let colony; + let colonyFunding; + let version; + let resolver; + let colonyNetwork; + let colonyTask; + deployer + .then(() => Colony.new()) + .then(instance => { + colony = instance; + return ColonyFunding.new(); + }) + .then(instance => { + colonyFunding = instance; + return ColonyTask.new(); + }) + .then(instance => { + colonyTask = instance; + return colony.version.call(); + }) + .then(_version => { + version = _version.toNumber(); + return Resolver.new(); + }) + .then(_resolver => { + resolver = _resolver; + return EtherRouter.deployed(); + }) + .then(_etherRouter => ColonyNetwork.at(_etherRouter.address)) + .then(instance => { + colonyNetwork = instance; + // Register the new Colony contract version with the newly setup Resolver + return setupColonyVersionResolver(colony, colonyTask, colonyFunding, resolver, colonyNetwork); + }) + .then(() => { + console.log("### Colony version", version, "set to Resolver", resolver.address); + }) + .catch(err => { + console.log("### Error occurred ", err); + }); +}; diff --git a/src/lib/colonyNetwork/migrations/5_setup_meta_colony.js b/src/lib/colonyNetwork/migrations/5_setup_meta_colony.js new file mode 100644 index 0000000..4fb0562 --- /dev/null +++ b/src/lib/colonyNetwork/migrations/5_setup_meta_colony.js @@ -0,0 +1,43 @@ +/* globals artifacts */ +/* eslint-disable no-console */ + +const assert = require("assert"); + +const IColonyNetwork = artifacts.require("./IColonyNetwork"); +const EtherRouter = artifacts.require("./EtherRouter"); +const Token = artifacts.require("./Token"); + +module.exports = deployer => { + // Create the meta colony + let colonyNetwork; + let token; + deployer + .then(() => EtherRouter.deployed()) + .then(_etherRouter => IColonyNetwork.at(_etherRouter.address)) + .then(instance => { + colonyNetwork = instance; + return Token.new("Colony Network Token", "CLNY", 18); + }) + .then(tokenInstance => { + token = tokenInstance; + return token.mint("10000000000000000"); + }) + // These commands add the first address as a reputation miner. This isn't necessary (or wanted!) for a real-world deployment, + // but is useful when playing around with the network to get reputation mining going. + .then(() => colonyNetwork.createMetaColony(token.address)) + .then(() => token.approve(colonyNetwork.address, "10000000000000000")) + .then(() => colonyNetwork.deposit("10000000000000000")) + .then(() => colonyNetwork.startNextCycle()) + .then(() => colonyNetwork.getSkillCount.call()) + .then(skillCount => { + assert.equal(skillCount.toNumber(), 2); + return colonyNetwork.getMetaColony.call(); + }) + .then(metaColonyAddress => { + token.setOwner(metaColonyAddress); + console.log("### Meta Colony created at", metaColonyAddress); + }) + .catch(err => { + console.log("### Error occurred ", err); + }); +}; diff --git a/src/lib/colonyNetwork/package-lock.json b/src/lib/colonyNetwork/package-lock.json new file mode 100644 index 0000000..fdccb52 --- /dev/null +++ b/src/lib/colonyNetwork/package-lock.json @@ -0,0 +1,3054 @@ +{ + "name": "@colony.io/colony-network-contracts", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "abbrev": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", + "dev": true + }, + "acorn": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.2.1.tgz", + "integrity": "sha512-jG0u7c4Ly+3QkkW18V+NRDN+4bWHdln30NL1ZL2AvFZZmQe/BfopYCtghCKKVBUSetZ4QKcyA0pY6/4Gw8Pv8w==", + "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 + } + } + }, + "ajv": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.3.0.tgz", + "integrity": "sha1-RBT/dKUIecII7l/cgm4ywwNUnto=", + "dev": true, + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.0.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + }, + "ajv-keywords": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", + "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=", + "dev": true + }, + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "dev": true, + "requires": { + "kind-of": "3.2.2", + "longest": "1.0.1", + "repeat-string": "1.6.1" + } + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "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" + } + }, + "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=", + "dev": true, + "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==", + "dev": true + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true + }, + "asn1.js": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.9.2.tgz", + "integrity": "sha512-b/OsSjvWEo8Pi8H0zsDd2P6Uqo2TK2pH8gNLSJtNLM2Db0v2QaAZ0pBQJXVjAn4gBuugeVDr7s63ZogpUIwWDg==", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "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" + } + }, + "async": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz", + "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==", + "dev": true, + "requires": { + "lodash": "4.17.4" + } + }, + "async-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", + "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base64-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz", + "integrity": "sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw==", + "dev": true + }, + "big.js": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", + "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", + "dev": true + }, + "bignumber.js": { + "version": "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2", + "dev": true + }, + "binary-extensions": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.10.0.tgz", + "integrity": "sha1-muuabF6IY4qtFx4Wf1kAq+JINdA=", + "dev": true + }, + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "dev": true, + "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=", + "dev": true, + "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=", + "dev": true + }, + "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.1.1", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.1.1.tgz", + "integrity": "sha512-UGnTYAnB2a3YuYKIRy1/4FB2HdM866E0qC46JXvVTYKlBlZlnvfpSfY6OKfXZAkv70eJ2a1SqzpAo5CRhZGDFg==", + "dev": true, + "requires": { + "buffer-xor": "1.0.3", + "cipher-base": "1.0.4", + "create-hash": "1.1.3", + "evp_bytestokey": "1.0.3", + "inherits": "2.0.3", + "safe-buffer": "5.1.1" + } + }, + "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.1.1", + "browserify-des": "1.0.0", + "evp_bytestokey": "1.0.3" + } + }, + "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.8", + "randombytes": "2.0.5" + } + }, + "browserify-sha3": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/browserify-sha3/-/browserify-sha3-0.0.1.tgz", + "integrity": "sha1-P/NKMAbvFcD7NWflQbkaI0ASPRE=", + "dev": true, + "requires": { + "js-sha3": "0.3.1" + } + }, + "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.8", + "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" + } + }, + "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-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "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 + }, + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true + }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "dev": true, + "requires": { + "align-text": "0.1.4", + "lazy-cache": "1.0.4" + } + }, + "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" + } + }, + "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==", + "dev": true, + "requires": { + "inherits": "2.0.3", + "safe-buffer": "5.1.1" + } + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wrap-ansi": "2.1.0" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "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=", + "dev": true + }, + "commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "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" + } + }, + "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 + }, + "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=", + "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.8", + "elliptic": "6.4.0" + } + }, + "create-hash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz", + "integrity": "sha1-YGBCrIuSYnUPSDyt2rD1gZFy2P0=", + "dev": true, + "requires": { + "cipher-base": "1.0.4", + "inherits": "2.0.3", + "ripemd160": "2.0.1", + "sha.js": "2.4.9" + } + }, + "create-hmac": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.6.tgz", + "integrity": "sha1-rLniIaThe9sHbpBlfEK5PjcmzwY=", + "dev": true, + "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.9" + } + }, + "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.3.0" + }, + "dependencies": { + "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" + } + } + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "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.14", + "public-encrypt": "4.0.0", + "randombytes": "2.0.5", + "randomfill": "1.0.3" + } + }, + "crypto-js": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.8.tgz", + "integrity": "sha1-cV8HC/YBTyrpkqmLOSkli3E/CNU=", + "dev": true + }, + "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.35" + } + }, + "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 + }, + "death": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/death/-/death-1.1.0.tgz", + "integrity": "sha1-AaqcQB7dknUFFEcLgmY5DGbGcxg=", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "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=", + "dev": true + }, + "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 + }, + "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" + } + }, + "diff": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz", + "integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==", + "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.8", + "miller-rabin": "4.0.1", + "randombytes": "2.0.5" + } + }, + "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 + }, + "elliptic": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", + "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "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=", + "dev": true + }, + "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.8" + } + }, + "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=", + "dev": true, + "requires": { + "is-arrayish": "0.2.1" + } + }, + "es5-ext": { + "version": "0.10.35", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.35.tgz", + "integrity": "sha1-GO6FjOajxFx9eekcFfzKnsVoSU8=", + "dev": true, + "requires": { + "es6-iterator": "2.0.3", + "es6-symbol": "3.1.1" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.35", + "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.35", + "es6-iterator": "2.0.3", + "es6-set": "0.1.5", + "es6-symbol": "3.1.1", + "event-emitter": "0.3.5" + } + }, + "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.35", + "es6-iterator": "2.0.3", + "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.35" + } + }, + "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.35", + "es6-iterator": "2.0.3", + "es6-symbol": "3.1.1" + } + }, + "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=", + "dev": true + }, + "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-plugin-node": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-5.2.0.tgz", + "integrity": "sha512-N9FLFwknT5LhRhjz1lmHguNss/MCwkrLCS4CjqqTZZTJaUhLRfDNK3zxSHL/Il3Aa0Mw+xY3T1gtsJrUNoJy8Q==", + "dev": true, + "requires": { + "ignore": "3.3.5", + "minimatch": "3.0.4", + "resolve": "1.4.0", + "semver": "5.3.0" + } + }, + "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=", + "dev": true + }, + "ethereumjs-testrpc": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/ethereumjs-testrpc/-/ethereumjs-testrpc-6.0.3.tgz", + "integrity": "sha512-lAxxsxDKK69Wuwqym2K49VpXtBvLEsXr1sryNG4AkvL5DomMdeCBbu3D87UEevKenLHBiT8GTjARwN6Yj039gA==", + "dev": true, + "requires": { + "webpack": "3.8.1" + } + }, + "ethereumjs-testrpc-sc": { + "version": "6.0.7", + "resolved": "https://registry.npmjs.org/ethereumjs-testrpc-sc/-/ethereumjs-testrpc-sc-6.0.7.tgz", + "integrity": "sha512-6X/FknTe702L0UGtJ3V3qlh6HNavJkuuRxB18fbITOuOyvCike7O5TVYOthqyCdxgW+ZW/FQGtFpoKeuRZnbNg==", + "dev": true, + "requires": { + "webpack": "3.8.1" + } + }, + "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.35" + } + }, + "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.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "requires": { + "md5.js": "1.3.4", + "safe-buffer": "5.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" + } + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "dev": true, + "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=", + "dev": true, + "requires": { + "fill-range": "2.2.3" + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "dev": true, + "requires": { + "is-extglob": "1.0.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=", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, + "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 + }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", + "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=", + "dev": true, + "requires": { + "is-number": "2.1.0", + "isobject": "2.1.0", + "randomatic": "1.1.7", + "repeat-element": "1.1.2", + "repeat-string": "1.6.1" + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "dev": true, + "requires": { + "for-in": "1.0.2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "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=", + "dev": true + }, + "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 + }, + "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" + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "dev": true, + "requires": { + "glob-parent": "2.0.0", + "is-glob": "2.0.1" + } + }, + "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" + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true + }, + "growl": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.2.tgz", + "integrity": "sha512-nidsnaoWVZIBLwA3sUIp3dA2DP2rT3dwEqINVacQ0+rZmc6UOwj2D729HTEjQYUKb+3wL9MeDbxpZtEiEJoUHQ==", + "dev": true, + "requires": { + "eslint-plugin-node": "5.2.0" + } + }, + "handlebars": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz", + "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", + "dev": true, + "requires": { + "async": "1.5.2", + "optimist": "0.6.1", + "source-map": "0.4.4", + "uglify-js": "2.8.29" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, + "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" + } + } + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "hash-base": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz", + "integrity": "sha1-ZuodhW206KVHDK32/OI65SRO8uE=", + "dev": true, + "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==", + "dev": true, + "requires": { + "inherits": "2.0.3", + "minimalistic-assert": "1.0.0" + } + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "requires": { + "hash.js": "1.1.3", + "minimalistic-assert": "1.0.0", + "minimalistic-crypto-utils": "1.0.1" + } + }, + "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==", + "dev": true + }, + "https-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-0.0.1.tgz", + "integrity": "sha1-P5E2XKvmC3ftDruiS0VOPgnZWoI=", + "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.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.5.tgz", + "integrity": "sha512-JLH93mL8amZQhh/p6mfQgVBH3M6epNq3DfsXsTSuSrInVjwyYlFE1nv2AgfRCC8PoOhM0jwQ5v8s9LgbK7yGDw==", + "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=", + "dev": true, + "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=", + "dev": true + }, + "interpret": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.0.4.tgz", + "integrity": "sha1-ggzdWIuGj/sZGoCVBtbJyPISsbA=", + "dev": true + }, + "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=", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "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.10.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "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=", + "dev": true, + "requires": { + "builtin-modules": "1.1.1" + } + }, + "is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", + "dev": true + }, + "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=", + "dev": true, + "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=", + "dev": true + }, + "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-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=", + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "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" + } + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "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=", + "dev": true + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + }, + "istanbul": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", + "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", + "dev": true, + "requires": { + "abbrev": "1.0.9", + "async": "1.5.2", + "escodegen": "1.8.1", + "esprima": "2.7.3", + "glob": "5.0.15", + "handlebars": "4.0.11", + "js-yaml": "3.10.0", + "mkdirp": "0.5.1", + "nopt": "3.0.6", + "once": "1.4.0", + "resolve": "1.1.7", + "supports-color": "3.2.3", + "which": "1.3.0", + "wordwrap": "1.0.0" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, + "glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "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" + } + }, + "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 + }, + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "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" + } + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + } + } + }, + "jade": { + "version": "0.26.3", + "resolved": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz", + "integrity": "sha1-jxDXl32NefL2/4YqgbBRPMslaGw=", + "dev": true, + "requires": { + "commander": "0.6.1", + "mkdirp": "0.3.0" + }, + "dependencies": { + "commander": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", + "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=", + "dev": true + }, + "mkdirp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", + "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=", + "dev": true + } + } + }, + "js-sha3": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.3.1.tgz", + "integrity": "sha1-hhIoAhQvCChQKg0d7h2V4lO7AkM=", + "dev": true + }, + "js-yaml": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz", + "integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==", + "dev": true, + "requires": { + "argparse": "1.0.9", + "esprima": "4.0.0" + }, + "dependencies": { + "esprima": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", + "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", + "dev": true + } + } + }, + "json-loader": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.7.tgz", + "integrity": "sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w==", + "dev": true + }, + "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=", + "dev": true + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, + "keccakjs": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/keccakjs/-/keccakjs-0.2.1.tgz", + "integrity": "sha1-HWM6+QfvMFu/ny+mFtVsRFYd+k0=", + "dev": true, + "requires": { + "browserify-sha3": "0.0.1", + "sha3": "1.2.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } + }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "dev": true + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true, + "requires": { + "invert-kv": "1.0.0" + } + }, + "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" + } + }, + "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=", + "dev": true, + "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": "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.2.0", + "emojis-list": "2.1.0", + "json5": "0.5.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.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + }, + "lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", + "dev": true + }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "dev": true + }, + "lru-cache": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", + "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", + "dev": true + }, + "md5.js": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", + "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", + "dev": true, + "requires": { + "hash-base": "3.0.4", + "inherits": "2.0.3" + }, + "dependencies": { + "hash-base": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "safe-buffer": "5.1.1" + } + } + } + }, + "mem": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", + "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", + "dev": true, + "requires": { + "mimic-fn": "1.1.0" + } + }, + "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" + } + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "dev": true, + "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.4" + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "brorand": "1.1.0" + } + }, + "mimic-fn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz", + "integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg=", + "dev": true + }, + "minimalistic-assert": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz", + "integrity": "sha1-cCvi3aazf0g2vLP121ZkG2Sh09M=", + "dev": true + }, + "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=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "1.1.8" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-4.0.0.tgz", + "integrity": "sha512-83e2QQWKbcBiPb1TuS80i4DxkpqQoOC9Y0TxOuML8NkzZWUkJJqWHAslhUS7x5nQcYMqnMwZDp5v3ABzV+ivCA==", + "dev": true, + "requires": { + "browser-stdout": "1.3.0", + "commander": "2.11.0", + "debug": "3.1.0", + "diff": "3.3.1", + "escape-string-regexp": "1.0.5", + "glob": "7.1.2", + "growl": "1.10.2", + "he": "1.1.1", + "mkdirp": "0.5.1", + "supports-color": "4.4.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "nan": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.7.0.tgz", + "integrity": "sha1-2Vv3IeyHfgjbJ27T/G63j5CDrUY=", + "dev": true + }, + "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.12.0", + "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.4", + "tty-browserify": "0.0.0", + "url": "0.11.0", + "util": "0.10.3", + "vm-browserify": "0.0.4" + }, + "dependencies": { + "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 + } + } + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, + "requires": { + "abbrev": "1.0.9" + } + }, + "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==", + "dev": true, + "requires": { + "hosted-git-info": "2.5.0", + "is-builtin-module": "1.0.0", + "semver": "5.3.0", + "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=", + "dev": true, + "requires": { + "remove-trailing-separator": "1.1.0" + } + }, + "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" + } + }, + "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=", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "dev": true, + "requires": { + "for-own": "0.1.5", + "is-extendable": "0.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "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.8", + "wordwrap": "0.0.2" + } + }, + "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 + } + } + }, + "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-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "dev": true, + "requires": { + "lcid": "1.0.0" + } + }, + "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" + } + }, + "pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=", + "dev": true + }, + "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.2", + "browserify-aes": "1.1.1", + "create-hash": "1.1.3", + "evp_bytestokey": "1.0.3", + "pbkdf2": "3.0.14" + } + }, + "parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "dev": true, + "requires": { + "glob-base": "0.3.0", + "is-dotfile": "1.0.3", + "is-extglob": "1.0.0", + "is-glob": "2.0.1" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "1.3.1" + } + }, + "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-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "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=", + "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-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "pbkdf2": { + "version": "3.0.14", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.14.tgz", + "integrity": "sha512-gjsZW9O34fm0R7PaLHRJmLLVfSoesxztjPjE9o6R+qtVJij90ltg1joIovN9GKrRW3t1PzhDDG3UMEMFfZ+1wA==", + "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.9" + } + }, + "pegjs": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/pegjs/-/pegjs-0.10.0.tgz", + "integrity": "sha1-z4uvrm7d/0tafvsYUmnqr0YQ3b0=", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "2.0.4" + } + }, + "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 + }, + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", + "dev": true + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "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=", + "dev": true + }, + "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.8", + "browserify-rsa": "4.0.1", + "create-hash": "1.1.3", + "parse-asn1": "5.1.0", + "randombytes": "2.0.5" + } + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "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 + }, + "randomatic": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", + "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", + "dev": true, + "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=", + "dev": true, + "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=", + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } + } + } + }, + "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" + } + }, + "randomfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.3.tgz", + "integrity": "sha512-YL6GrhrWoic0Eq8rXVbMptH7dAxCs0J+mh5Y0euNekPPYaxEmdVGim6GdoxoRzKW2yJoU8tueifS7mYxvcFDEQ==", + "dev": true, + "requires": { + "randombytes": "2.0.5", + "safe-buffer": "5.1.1" + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "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=", + "dev": true, + "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==", + "dev": true, + "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" + } + }, + "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" + } + }, + "regex-cache": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "dev": true, + "requires": { + "is-equal-shallow": "0.1.3" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "repeat-element": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", + "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "req-cwd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/req-cwd/-/req-cwd-1.0.1.tgz", + "integrity": "sha1-DXOurpJm5penj3l2AZZ352rPD/8=", + "dev": true, + "requires": { + "req-from": "1.0.1" + } + }, + "req-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/req-from/-/req-from-1.0.1.tgz", + "integrity": "sha1-v4HaUUeUfTLRO5R9wSpYrUWHNQ4=", + "dev": true, + "requires": { + "resolve-from": "2.0.0" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "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=", + "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": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", + "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=", + "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=", + "dev": true, + "requires": { + "align-text": "0.1.4" + } + }, + "ripemd160": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz", + "integrity": "sha1-D0WEKVxTo2KK9+bXmsohzlfRxuc=", + "dev": true, + "requires": { + "hash-base": "2.0.2", + "inherits": "2.0.3" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true + }, + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "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=", + "dev": true + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true + }, + "sha.js": { + "version": "2.4.9", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.9.tgz", + "integrity": "sha512-G8zektVqbiPHrylgew9Zg1VRB1L/DtXNUVAM6q4QLy8NE3qtHlFXTf8VLL4k1Yl6c7NMjtZUTdXV+X44nFaT6A==", + "dev": true, + "requires": { + "inherits": "2.0.3", + "safe-buffer": "5.1.1" + } + }, + "sha3": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/sha3/-/sha3-1.2.0.tgz", + "integrity": "sha1-aYnxtwpJhwWHajc+LGKs6WqpOZo=", + "dev": true, + "requires": { + "nan": "2.7.0" + } + }, + "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.4", + "rechoir": "0.6.2" + } + }, + "sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "sol-explore": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/sol-explore/-/sol-explore-1.6.2.tgz", + "integrity": "sha1-Q66MQZ/TrAVqBfip0fsQIs1B7MI=", + "dev": true + }, + "solidity-coverage": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.4.8.tgz", + "integrity": "sha512-myHdCANQqkLzfE3DEc+FnZnHmvB1X33zej4bp3bHn3t2UDPaiuQtP81A02wULApS+HlulL6HCfjWEpuXBrcWUA==", + "dev": true, + "requires": { + "death": "1.1.0", + "ethereumjs-testrpc-sc": "6.0.7", + "istanbul": "0.4.5", + "keccakjs": "0.2.1", + "req-cwd": "1.0.1", + "shelljs": "0.7.8", + "sol-explore": "1.6.2", + "solidity-parser-sc": "0.4.4", + "web3": "0.18.4" + }, + "dependencies": { + "commander": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz", + "integrity": "sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM=", + "dev": true + }, + "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" + } + }, + "diff": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", + "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", + "integrity": "sha1-Tbwv5nTnGUnK8/smlc5/LcHZqNE=", + "dev": true + }, + "glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", + "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "minimatch": "0.3.0" + } + }, + "growl": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", + "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", + "dev": true + }, + "minimatch": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", + "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", + "dev": true, + "requires": { + "lru-cache": "2.7.3", + "sigmund": "1.0.1" + } + }, + "mocha": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-2.5.3.tgz", + "integrity": "sha1-FhvlvetJZ3HrmzV0UFC2IrWu/Fg=", + "dev": true, + "requires": { + "commander": "2.3.0", + "debug": "2.2.0", + "diff": "1.4.0", + "escape-string-regexp": "1.0.2", + "glob": "3.2.11", + "growl": "1.9.2", + "jade": "0.26.3", + "mkdirp": "0.5.1", + "supports-color": "1.2.0", + "to-iso-string": "0.0.2" + } + }, + "ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true + }, + "solidity-parser-sc": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/solidity-parser-sc/-/solidity-parser-sc-0.4.4.tgz", + "integrity": "sha512-oPmn98FGxOZDnXzWTMH06plsqtncOJlC8dNlEYEsayyaAhAjkV7R8JWFfFTNtZOxaY1lT062estXbqRUclp1Zw==", + "dev": true, + "requires": { + "mocha": "2.5.3", + "pegjs": "0.10.0", + "yargs": "4.8.1" + } + }, + "supports-color": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz", + "integrity": "sha1-/x7R5hFp0Gs88tWI4YixjYhH4X4=", + "dev": true + } + } + }, + "source-list-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.0.tgz", + "integrity": "sha512-I2UmuJSRr/T8jisiROLU3A3ltr+swpniSmNPI4Ml3ZCX6tVnDsuZzK7F2hl5jTqbZBWCEKlj5HRQiPExXLgE8A==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "spdx-correct": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", + "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", + "dev": true, + "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=", + "dev": true + }, + "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=", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "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-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" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "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==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "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=", + "dev": true, + "requires": { + "is-utf8": "0.2.1" + } + }, + "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 + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + }, + "tapable": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.8.tgz", + "integrity": "sha1-mTcqXJmb8t8WCvwNdL7U9HlIzSI=", + "dev": true + }, + "timers-browserify": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.4.tgz", + "integrity": "sha512-uZYhyU3EX8O7HQP+J9fTVYwsq90Vr68xPEFo7yrVImIxYvHgukBEgOB/SgGoorWVTzGM/3Z+wUNnboA4M8jWrg==", + "dev": true, + "requires": { + "setimmediate": "1.0.5" + } + }, + "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-iso-string": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/to-iso-string/-/to-iso-string-0.0.2.tgz", + "integrity": "sha1-TcGeZk38y+Jb2NtQiwDG2hWCVdE=", + "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 + }, + "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" + } + }, + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "dev": true, + "requires": { + "source-map": "0.5.7", + "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=", + "dev": true + }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dev": true, + "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=", + "dev": true + }, + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dev": true, + "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=", + "dev": true, + "optional": true + }, + "uglifyjs-webpack-plugin": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-0.4.6.tgz", + "integrity": "sha1-uVH0q7a9YX5m9j64kUmOORdj4wk=", + "dev": true, + "requires": { + "source-map": "0.5.7", + "uglify-js": "2.8.29", + "webpack-sources": "1.0.2" + } + }, + "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 + } + } + }, + "utf8": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.2.tgz", + "integrity": "sha1-H6DZJw6b6FDZsFAn9jUZv0ZFfZY=", + "dev": true + }, + "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=", + "dev": true + }, + "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=", + "dev": true, + "requires": { + "spdx-correct": "1.0.2", + "spdx-expression-parse": "1.0.4" + } + }, + "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" + } + }, + "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.6.0", + "chokidar": "1.7.0", + "graceful-fs": "4.1.11" + } + }, + "web3": { + "version": "0.18.4", + "resolved": "https://registry.npmjs.org/web3/-/web3-0.18.4.tgz", + "integrity": "sha1-gewXhBRUkfLqqJVbMcBgSeB8Xn0=", + "dev": true, + "requires": { + "bignumber.js": "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2", + "crypto-js": "3.1.8", + "utf8": "2.1.2", + "xhr2": "0.1.4", + "xmlhttprequest": "1.8.0" + } + }, + "webpack": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.8.1.tgz", + "integrity": "sha512-5ZXLWWsMqHKFr5y0N3Eo5IIisxeEeRAajNq4mELb/WELOR7srdbQk2N5XiyNy2A/AgvlR3AmeBCZJW8lHrolbw==", + "dev": true, + "requires": { + "acorn": "5.2.1", + "acorn-dynamic-import": "2.0.2", + "ajv": "5.3.0", + "ajv-keywords": "2.1.1", + "async": "2.6.0", + "enhanced-resolve": "3.4.1", + "escope": "3.6.0", + "interpret": "1.0.4", + "json-loader": "0.5.7", + "json5": "0.5.1", + "loader-runner": "2.3.0", + "loader-utils": "1.1.0", + "memory-fs": "0.4.1", + "mkdirp": "0.5.1", + "node-libs-browser": "2.0.0", + "source-map": "0.5.7", + "supports-color": "4.4.0", + "tapable": "0.2.8", + "uglifyjs-webpack-plugin": "0.4.6", + "watchpack": "1.4.0", + "webpack-sources": "1.0.2", + "yargs": "8.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "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" + } + }, + "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 + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "strip-bom": "3.0.0" + } + }, + "os-locale": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", + "dev": true, + "requires": { + "execa": "0.7.0", + "lcid": "1.0.0", + "mem": "1.1.0" + } + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "2.3.0" + } + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "2.0.0", + "normalize-package-data": "2.4.0", + "path-type": "2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "2.1.0", + "read-pkg": "2.0.0" + } + }, + "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" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "yargs": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-8.0.2.tgz", + "integrity": "sha1-YpmpBVsc78lp/355wdkY3Osiw2A=", + "dev": true, + "requires": { + "camelcase": "4.1.0", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.2", + "os-locale": "2.1.0", + "read-pkg-up": "2.0.0", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "2.1.1", + "which-module": "2.0.0", + "y18n": "3.2.1", + "yargs-parser": "7.0.0" + } + }, + "yargs-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz", + "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", + "dev": true, + "requires": { + "camelcase": "4.1.0" + } + } + } + }, + "webpack-sources": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.0.2.tgz", + "integrity": "sha512-Y7UddMCv6dGjy81nBv6nuQeFFIt5aalHm7uyDsAsW86nZwfOVPGRr3XMjEQLaT+WKo8rlzhC9qtbJvYKLtAwaw==", + "dev": true, + "requires": { + "source-list-map": "2.0.0", + "source-map": "0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "which": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", + "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", + "dev": true, + "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=", + "dev": true + }, + "window-size": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", + "integrity": "sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU=", + "dev": true + }, + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "xhr2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/xhr2/-/xhr2-0.1.4.tgz", + "integrity": "sha1-f4dliEdxbbUCYyOBL4GMras4el8=", + "dev": true + }, + "xmlhttprequest": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", + "integrity": "sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw=", + "dev": true + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "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": "4.8.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", + "integrity": "sha1-wMQpJMpKqmsObaFznfshZDn53cA=", + "dev": true, + "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" + } + }, + "yargs-parser": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", + "integrity": "sha1-hVaN488VD/SfpRgl8DqMiA3cxcQ=", + "dev": true, + "requires": { + "camelcase": "3.0.0", + "lodash.assign": "4.2.0" + } + } + } +} diff --git a/src/lib/colonyNetwork/package.json b/src/lib/colonyNetwork/package.json new file mode 100644 index 0000000..e95f9dd --- /dev/null +++ b/src/lib/colonyNetwork/package.json @@ -0,0 +1,85 @@ +{ + "name": "@colony.io/colony-network-contracts", + "version": "1.0.0", + "description": "Contracts for Colony Network", + "scripts": { + "solium-staged": "bash ./scripts/solium.sh", + "eslint-staged": "bash ./scripts/eslint.sh", + "eslint": "eslint .", + "solium": "solium --dir .", + "check:storagevars": "./node_modules/babel-cli/bin/babel-node.js ./scripts/check-storage.js", + "version:contracts": "bash ./scripts/version-contracts.sh", + "generate:test:contracts": "bash ./scripts/generate-test-contracts.sh", + "clean:test:contracts": "rimraf ./contracts/*Updated*.*", + "clean:contracts": "rimraf ./build/contracts/*", + "start:blockchain:client": "bash ./scripts/start-blockchain-client.sh", + "stop:blockchain:client": "bash ./scripts/stop-blockchain-client.sh", + "test:contracts": "npm run start:blockchain:client & truffle migrate --reset --compile-all && truffle test --network development", + "test:contracts:upgrade": "npm run start:blockchain:client parity & npm run generate:test:contracts && truffle migrate --reset --compile-all && truffle test ./upgrade-test/* --network integration", + "test:contracts:gasCosts": "npm run start:blockchain:client & truffle migrate --reset --compile-all && truffle test gasCosts/gasCosts.js --network development", + "test:contracts:coverage": "SOLIDITY_COVERAGE=1 solidity-coverage && istanbul check-coverage --statements 94 --branches 88 --functions 92 --lines 94", + "pretest:contracts": "sed -ie \"s/eth-gas-reporter/mocha-circleci-reporter/g\" ./truffle.js && rimraf ./truffle.jse", + "pretest:contracts:upgrade": "sed -ie \"s/eth-gas-reporter/mocha-circleci-reporter/g\" ./truffle.js && rimraf ./truffle.jse", + "pretest:contracts:gasCosts": "sed -ie \"s/mocha-circleci-reporter/eth-gas-reporter/g\" ./truffle.js && rimraf ./truffle.jse", + "pretest:contracts:coverage": "sed -ie \"s/eth-gas-reporter/mocha-circleci-reporter/g\" ./truffle.js && rimraf ./truffle.jse", + "posttest:contracts": "npm run stop:blockchain:client", + "posttest:contracts:upgrade": "npm run clean:test:contracts | npm run stop:blockchain:client", + "posttest:contracts:gasCosts": "npm run stop:blockchain:client" + }, + "pre-commit": [ + "eslint-staged", + "solium-staged" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/JoinColony/colonyNetwork.git" + }, + "author": "Colony (https://colony.io/)", + "license": "GPL-3.0", + "bugs": { + "url": "https://github.com/JoinColony/colonyNetwork/issues" + }, + "homepage": "https://github.com/JoinColony/colonyNetwork#readme", + "devDependencies": { + "@colony/eslint-config-colony": "4.0.1", + "babel-cli": "^6.26.0", + "babel-eslint": "^8.2.3", + "babel-plugin-transform-runtime": "^6.23.0", + "babel-preset-es2015": "^6.24.1", + "babel-preset-stage-2": "^6.24.1", + "babel-register": "^6.26.0", + "bn.js": "^4.11.8", + "chai": "^4.1.2", + "eslint": "^4.19.1", + "eslint-config-airbnb-base": "^12.1.0", + "eslint-config-prettier": "^2.9.0", + "eslint-import-resolver-jest": "^2.1.1", + "eslint-plugin-flowtype": "^2.46.3", + "eslint-plugin-import": "^2.11.0", + "eslint-plugin-prettier": "^2.6.0", + "eth-gas-reporter": "^0.1.2", + "ethereumjs-util": "^5.2.0", + "ganache-cli": "6.1.0", + "ganache-core": "^2.0.2", + "istanbul": "^0.4.5", + "jsonfile": "^4.0.0", + "mocha": "^5.2.0", + "mocha-circleci-reporter": "^0.0.3", + "pre-commit": "^1.2.2", + "prettier": "^1.12.1", + "rimraf": "^2.6.2", + "shortid": "^2.2.8", + "solidity-coverage": "0.5.4", + "solidity-parser-antlr": "^0.2.11", + "solium": "^1.1.7", + "truffle": "^4.1.11", + "web3-utils": "^1.0.0-beta.34" + }, + "dependencies": { + "@colony/colony-js-contract-loader-fs": "^1.3.0" + }, + "private": true, + "workspaces": [ + "packages/*" + ] +} diff --git a/src/lib/colonyNetwork/packages/colony-contract-loader-network/.gitignore b/src/lib/colonyNetwork/packages/colony-contract-loader-network/.gitignore new file mode 100644 index 0000000..a65b417 --- /dev/null +++ b/src/lib/colonyNetwork/packages/colony-contract-loader-network/.gitignore @@ -0,0 +1 @@ +lib diff --git a/src/lib/colonyNetwork/packages/colony-contract-loader-network/Readme.md b/src/lib/colonyNetwork/packages/colony-contract-loader-network/Readme.md new file mode 100644 index 0000000..e080517 --- /dev/null +++ b/src/lib/colonyNetwork/packages/colony-contract-loader-network/Readme.md @@ -0,0 +1,20 @@ +# colonyJS Contract Loader for deployed contracts + +This package provides a means to load the Colony Network Ethereum smart contracts directly from this package. + +## Installation + +``` +yarn add @colony/colony-js-contract-loader-network +``` + +## Usage + +Please see [the full documentation](https://docs.colony.io/colonyjs/api-loaders/#networkloader). + + +## Contributing + +This package is part of the [colonyNetwork repo](https://github.com/JoinColony/colonyNetwork). + +Please read our [contributing guidelines](https://github.com/JoinColony/colonyNetwork/blob/develop/docs/CONTRIBUTING.md). diff --git a/src/lib/colonyNetwork/packages/colony-contract-loader-network/config.json b/src/lib/colonyNetwork/packages/colony-contract-loader-network/config.json new file mode 100644 index 0000000..f44b41d --- /dev/null +++ b/src/lib/colonyNetwork/packages/colony-contract-loader-network/config.json @@ -0,0 +1,4 @@ +{ + "VERSIONS": ["1"], + "LATEST_VERSION": "1" +} diff --git a/src/lib/colonyNetwork/packages/colony-contract-loader-network/contracts/static/EtherRouter.json b/src/lib/colonyNetwork/packages/colony-contract-loader-network/contracts/static/EtherRouter.json new file mode 100644 index 0000000..379bb62 --- /dev/null +++ b/src/lib/colonyNetwork/packages/colony-contract-loader-network/contracts/static/EtherRouter.json @@ -0,0 +1,129 @@ +{ + "contractName": "EtherRouter", + "abi": [ + { + "constant": true, + "inputs": [], + "name": "resolver", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner_", + "type": "address" + } + ], + "name": "setOwner", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "authority_", + "type": "address" + } + ], + "name": "setAuthority", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "owner", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "authority", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "authority", + "type": "address" + } + ], + "name": "LogSetAuthority", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + } + ], + "name": "LogSetOwner", + "type": "event" + }, + { + "constant": false, + "inputs": [ + { + "name": "_resolver", + "type": "address" + } + ], + "name": "setResolver", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } + ], + "compiler": { + "name": "solc", + "version": "0.4.24+commit.e67f0147.Emscripten.clang" + }, + "networks": { + "rinkeby": { + "address": "0xD4C145EbdC7f072d10a07b8ea4515AF996EE437c" + } + }, + "schemaVersion": "2.0.0", + "updatedAt": "2018-06-13T14:34:28.904Z" +} diff --git a/src/lib/colonyNetwork/packages/colony-contract-loader-network/contracts/static/Token.json b/src/lib/colonyNetwork/packages/colony-contract-loader-network/contracts/static/Token.json new file mode 100644 index 0000000..c957ad4 --- /dev/null +++ b/src/lib/colonyNetwork/packages/colony-contract-loader-network/contracts/static/Token.json @@ -0,0 +1,388 @@ +{ + "contractName": "Token", + "abi": [ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "guy", + "type": "address" + }, + { + "name": "wad", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner_", + "type": "address" + } + ], + "name": "setOwner", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "dst", + "type": "address" + }, + { + "name": "wad", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "src", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "authority_", + "type": "address" + } + ], + "name": "setAuthority", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "owner", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "dst", + "type": "address" + }, + { + "name": "wad", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "authority", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "src", + "type": "address" + }, + { + "name": "guy", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "name": "_name", + "type": "bytes32" + }, + { + "name": "_symbol", + "type": "bytes32" + }, + { + "name": "_decimals", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "guy", + "type": "address" + }, + { + "indexed": false, + "name": "wad", + "type": "uint256" + } + ], + "name": "Mint", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "guy", + "type": "address" + }, + { + "indexed": false, + "name": "wad", + "type": "uint256" + } + ], + "name": "Burn", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "authority", + "type": "address" + } + ], + "name": "LogSetAuthority", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + } + ], + "name": "LogSetOwner", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "src", + "type": "address" + }, + { + "indexed": true, + "name": "guy", + "type": "address" + }, + { + "indexed": false, + "name": "wad", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "src", + "type": "address" + }, + { + "indexed": true, + "name": "dst", + "type": "address" + }, + { + "indexed": false, + "name": "wad", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "constant": false, + "inputs": [ + { + "name": "wad", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "wad", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } + ], + "compiler": { + "name": "solc", + "version": "0.4.24+commit.e67f0147.Emscripten.clang" + }, + "networks": {}, + "schemaVersion": "2.0.0", + "updatedAt": "2018-06-13T14:34:28.952Z" +} diff --git a/src/lib/colonyNetwork/packages/colony-contract-loader-network/contracts/versioned/rinkeby-v1/Authority.json b/src/lib/colonyNetwork/packages/colony-contract-loader-network/contracts/versioned/rinkeby-v1/Authority.json new file mode 100644 index 0000000..a0749eb --- /dev/null +++ b/src/lib/colonyNetwork/packages/colony-contract-loader-network/contracts/versioned/rinkeby-v1/Authority.json @@ -0,0 +1,325 @@ +{ + "contractName": "Authority", + "abi": [ + { + "constant": true, + "inputs": [ + { + "name": "who", + "type": "address" + } + ], + "name": "getUserRoles", + "outputs": [ + { + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "owner_", + "type": "address" + } + ], + "name": "setOwner", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "code", + "type": "address" + }, + { + "name": "sig", + "type": "bytes4" + } + ], + "name": "getCapabilityRoles", + "outputs": [ + { + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "code", + "type": "address" + }, + { + "name": "sig", + "type": "bytes4" + } + ], + "name": "isCapabilityPublic", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "who", + "type": "address" + }, + { + "name": "role", + "type": "uint8" + }, + { + "name": "enabled", + "type": "bool" + } + ], + "name": "setUserRole", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "authority_", + "type": "address" + } + ], + "name": "setAuthority", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "role", + "type": "uint8" + }, + { + "name": "code", + "type": "address" + }, + { + "name": "sig", + "type": "bytes4" + }, + { + "name": "enabled", + "type": "bool" + } + ], + "name": "setRoleCapability", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "owner", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "who", + "type": "address" + }, + { + "name": "role", + "type": "uint8" + } + ], + "name": "hasUserRole", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "caller", + "type": "address" + }, + { + "name": "code", + "type": "address" + }, + { + "name": "sig", + "type": "bytes4" + } + ], + "name": "canCall", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "authority", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "code", + "type": "address" + }, + { + "name": "sig", + "type": "bytes4" + }, + { + "name": "enabled", + "type": "bool" + } + ], + "name": "setPublicCapability", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "who", + "type": "address" + }, + { + "name": "enabled", + "type": "bool" + } + ], + "name": "setRootUser", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "who", + "type": "address" + } + ], + "name": "isUserRoot", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "name": "colony", + "type": "address" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "authority", + "type": "address" + } + ], + "name": "LogSetAuthority", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + } + ], + "name": "LogSetOwner", + "type": "event" + } + ], + "compiler": { + "name": "solc", + "version": "0.4.24+commit.e67f0147.Emscripten.clang" + }, + "networks": {}, + "schemaVersion": "2.0.0", + "updatedAt": "2018-06-13T14:34:28.843Z" +} diff --git a/src/lib/colonyNetwork/packages/colony-contract-loader-network/contracts/versioned/rinkeby-v1/IColony.json b/src/lib/colonyNetwork/packages/colony-contract-loader-network/contracts/versioned/rinkeby-v1/IColony.json new file mode 100644 index 0000000..8808ab4 --- /dev/null +++ b/src/lib/colonyNetwork/packages/colony-contract-loader-network/contracts/versioned/rinkeby-v1/IColony.json @@ -0,0 +1,1074 @@ +{ + "contractName": "IColony", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "id", + "type": "uint256" + } + ], + "name": "TaskAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "id", + "type": "uint256" + } + ], + "name": "RewardPayoutCycleStarted", + "type": "event" + }, + { + "constant": true, + "inputs": [], + "name": "authority", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "owner", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "version", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_token", + "type": "address" + } + ], + "name": "setToken", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getToken", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_network", + "type": "address" + } + ], + "name": "initialiseColony", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_users", + "type": "address[]" + }, + { + "name": "_amount", + "type": "int256[]" + } + ], + "name": "bootstrapColony", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_wad", + "type": "uint256" + } + ], + "name": "mintTokens", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_wad", + "type": "uint256" + } + ], + "name": "mintTokensForColonyNetwork", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_parentSkillId", + "type": "uint256" + } + ], + "name": "addGlobalSkill", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_parentSkillId", + "type": "uint256" + } + ], + "name": "addDomain", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_id", + "type": "uint256" + } + ], + "name": "getDomain", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getDomainCount", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "key", + "type": "bytes" + }, + { + "name": "value", + "type": "bytes" + }, + { + "name": "branchMask", + "type": "uint256" + }, + { + "name": "siblings", + "type": "bytes32[]" + } + ], + "name": "verifyReputationProof", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_specificationHash", + "type": "bytes32" + }, + { + "name": "_domainId", + "type": "uint256" + } + ], + "name": "makeTask", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getTaskCount", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getTaskChangeNonce", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_sigV", + "type": "uint8[]" + }, + { + "name": "_sigR", + "type": "bytes32[]" + }, + { + "name": "_sigS", + "type": "bytes32[]" + }, + { + "name": "_mode", + "type": "uint8[]" + }, + { + "name": "_value", + "type": "uint256" + }, + { + "name": "_data", + "type": "bytes" + } + ], + "name": "executeTaskChange", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_id", + "type": "uint256" + }, + { + "name": "_role", + "type": "uint8" + }, + { + "name": "_ratingSecret", + "type": "bytes32" + } + ], + "name": "submitTaskWorkRating", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_id", + "type": "uint256" + }, + { + "name": "_role", + "type": "uint8" + }, + { + "name": "_rating", + "type": "uint8" + }, + { + "name": "_salt", + "type": "bytes32" + } + ], + "name": "revealTaskWorkRating", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_id", + "type": "uint256" + } + ], + "name": "assignWorkRating", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_salt", + "type": "bytes32" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "generateSecret", + "outputs": [ + { + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_id", + "type": "uint256" + } + ], + "name": "getTaskWorkRatings", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_id", + "type": "uint256" + }, + { + "name": "_role", + "type": "uint8" + } + ], + "name": "getTaskWorkRatingSecret", + "outputs": [ + { + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_id", + "type": "uint256" + }, + { + "name": "_role", + "type": "uint8" + }, + { + "name": "_user", + "type": "address" + } + ], + "name": "setTaskRoleUser", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_id", + "type": "uint256" + }, + { + "name": "_skillId", + "type": "uint256" + } + ], + "name": "setTaskSkill", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_id", + "type": "uint256" + }, + { + "name": "_domainId", + "type": "uint256" + } + ], + "name": "setTaskDomain", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_id", + "type": "uint256" + }, + { + "name": "_specificationHash", + "type": "bytes32" + } + ], + "name": "setTaskBrief", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_id", + "type": "uint256" + }, + { + "name": "_dueDate", + "type": "uint256" + } + ], + "name": "setTaskDueDate", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_id", + "type": "uint256" + }, + { + "name": "_deliverableHash", + "type": "bytes32" + } + ], + "name": "submitTaskDeliverable", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_id", + "type": "uint256" + } + ], + "name": "finalizeTask", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_id", + "type": "uint256" + } + ], + "name": "cancelTask", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_id", + "type": "uint256" + } + ], + "name": "getTask", + "outputs": [ + { + "name": "", + "type": "bytes32" + }, + { + "name": "", + "type": "bytes32" + }, + { + "name": "", + "type": "bool" + }, + { + "name": "", + "type": "bool" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256[]" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_id", + "type": "uint256" + }, + { + "name": "_role", + "type": "uint8" + } + ], + "name": "getTaskRole", + "outputs": [ + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "bool" + }, + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getFeeInverse", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getRewardInverse", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_id", + "type": "uint256" + }, + { + "name": "_role", + "type": "uint256" + }, + { + "name": "_token", + "type": "address" + } + ], + "name": "getTaskPayout", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_id", + "type": "uint256" + }, + { + "name": "_token", + "type": "address" + }, + { + "name": "_amount", + "type": "uint256" + } + ], + "name": "setTaskManagerPayout", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_id", + "type": "uint256" + }, + { + "name": "_token", + "type": "address" + }, + { + "name": "_amount", + "type": "uint256" + } + ], + "name": "setTaskEvaluatorPayout", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_id", + "type": "uint256" + }, + { + "name": "_token", + "type": "address" + }, + { + "name": "_amount", + "type": "uint256" + } + ], + "name": "setTaskWorkerPayout", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_id", + "type": "uint256" + }, + { + "name": "_role", + "type": "uint256" + }, + { + "name": "_token", + "type": "address" + } + ], + "name": "claimPayout", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_token", + "type": "address" + } + ], + "name": "startNextRewardPayout", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_payoutId", + "type": "uint256" + }, + { + "name": "_squareRoots", + "type": "uint256[7]" + }, + { + "name": "_userReputation", + "type": "uint256" + }, + { + "name": "_totalReputation", + "type": "uint256" + } + ], + "name": "claimRewardPayout", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_numPayouts", + "type": "uint256" + } + ], + "name": "waiveRewardPayouts", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_payoutId", + "type": "uint256" + } + ], + "name": "getRewardPayoutInfo", + "outputs": [ + { + "name": "", + "type": "bytes32" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "address" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_payoutId", + "type": "uint256" + } + ], + "name": "finalizeRewardPayout", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "getGlobalRewardPayoutCount", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_user", + "type": "address" + } + ], + "name": "getUserRewardPayoutCount", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_potId", + "type": "uint256" + }, + { + "name": "_token", + "type": "address" + } + ], + "name": "getPotBalance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_fromPot", + "type": "uint256" + }, + { + "name": "_toPot", + "type": "uint256" + }, + { + "name": "_amount", + "type": "uint256" + }, + { + "name": "_token", + "type": "address" + } + ], + "name": "moveFundsBetweenPots", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_token", + "type": "address" + } + ], + "name": "claimColonyFunds", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_token", + "type": "address" + } + ], + "name": "getNonRewardPotsTotal", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + } + ], + "compiler": { + "name": "solc", + "version": "0.4.24+commit.e67f0147.Emscripten.clang" + }, + "networks": {}, + "schemaVersion": "2.0.0", + "updatedAt": "2018-06-13T14:34:28.937Z" +} diff --git a/src/lib/colonyNetwork/packages/colony-contract-loader-network/contracts/versioned/rinkeby-v1/IColonyNetwork.json b/src/lib/colonyNetwork/packages/colony-contract-loader-network/contracts/versioned/rinkeby-v1/IColonyNetwork.json new file mode 100644 index 0000000..7f3d6dd --- /dev/null +++ b/src/lib/colonyNetwork/packages/colony-contract-loader-network/contracts/versioned/rinkeby-v1/IColonyNetwork.json @@ -0,0 +1,531 @@ +{ + "contractName": "IColonyNetwork", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "colonyId", + "type": "uint256" + }, + { + "indexed": true, + "name": "colonyAddress", + "type": "address" + } + ], + "name": "ColonyAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "skillId", + "type": "uint256" + }, + { + "indexed": false, + "name": "parentSkillId", + "type": "uint256" + } + ], + "name": "SkillAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "auction", + "type": "address" + }, + { + "indexed": false, + "name": "token", + "type": "address" + }, + { + "indexed": false, + "name": "quantity", + "type": "uint256" + } + ], + "name": "AuctionCreated", + "type": "event" + }, + { + "constant": true, + "inputs": [], + "name": "getMetaColony", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getColonyCount", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_parentSkillId", + "type": "uint256" + }, + { + "name": "_globalSkill", + "type": "bool" + } + ], + "name": "addSkill", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_skillId", + "type": "uint256" + } + ], + "name": "getSkill", + "outputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_skillId", + "type": "uint256" + } + ], + "name": "isGlobalSkill", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_user", + "type": "address" + }, + { + "name": "_amount", + "type": "int256" + }, + { + "name": "_skillId", + "type": "uint256" + } + ], + "name": "appendReputationUpdateLog", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getSkillCount", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getRootGlobalSkillId", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_tokenAddress", + "type": "address" + } + ], + "name": "createMetaColony", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_tokenAddress", + "type": "address" + } + ], + "name": "createColony", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_version", + "type": "uint256" + }, + { + "name": "_resolver", + "type": "address" + } + ], + "name": "addColonyVersion", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_id", + "type": "uint256" + } + ], + "name": "getColony", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getCurrentColonyVersion", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_id", + "type": "uint256" + }, + { + "name": "_newVersion", + "type": "uint256" + } + ], + "name": "upgradeColony", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_skillId", + "type": "uint256" + }, + { + "name": "_parentSkillIndex", + "type": "uint256" + } + ], + "name": "getParentSkillId", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_skillId", + "type": "uint256" + }, + { + "name": "_childSkillIndex", + "type": "uint256" + } + ], + "name": "getChildSkillId", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_active", + "type": "bool" + } + ], + "name": "getReputationMiningCycle", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_version", + "type": "uint256" + } + ], + "name": "getColonyVersionResolver", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_amount", + "type": "uint256" + } + ], + "name": "deposit", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "amount", + "type": "uint256" + } + ], + "name": "withdraw", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_user", + "type": "address" + } + ], + "name": "getStakedBalance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "newHash", + "type": "bytes32" + }, + { + "name": "newNNodes", + "type": "uint256" + }, + { + "name": "stakers", + "type": "address[]" + } + ], + "name": "setReputationRootHash", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "startNextCycle", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "stakers", + "type": "address[]" + } + ], + "name": "punishStakers", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getReputationRootHash", + "outputs": [ + { + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getReputationRootHashNNodes", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_token", + "type": "address" + } + ], + "name": "startTokenAuction", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } + ], + "compiler": { + "name": "solc", + "version": "0.4.24+commit.e67f0147.Emscripten.clang" + }, + "networks": {}, + "schemaVersion": "2.0.0", + "updatedAt": "2018-06-13T14:34:28.918Z" +} diff --git a/src/lib/colonyNetwork/packages/colony-contract-loader-network/jest.conf.json b/src/lib/colonyNetwork/packages/colony-contract-loader-network/jest.conf.json new file mode 100644 index 0000000..fe2d22a --- /dev/null +++ b/src/lib/colonyNetwork/packages/colony-contract-loader-network/jest.conf.json @@ -0,0 +1,3 @@ +{ + "rootDir": "src" +} diff --git a/src/lib/colonyNetwork/packages/colony-contract-loader-network/package.json b/src/lib/colonyNetwork/packages/colony-contract-loader-network/package.json new file mode 100644 index 0000000..dd3a47a --- /dev/null +++ b/src/lib/colonyNetwork/packages/colony-contract-loader-network/package.json @@ -0,0 +1,24 @@ +{ + "name": "@colony/colony-contract-loader-network", + "version": "1.0.0", + "description": "Load the Colony contract ABIs directly from this package", + "main": "lib/index.js", + "scripts": { + "build:lib": "babel src --out-dir lib --ignore __tests__ --source-maps", + "clean": "shx rm -rf lib", + "test": "jest --config=jest.conf.json" + }, + "author": "Christian Maniewski ", + "license": "GPL-3.0", + "dependencies": { + "@colony/colony-js-contract-loader": "^1.3.0", + "assert": "^1.4.1", + "babel-runtime": "^6.26.0" + }, + "devDependencies": { + "babel-cli": "^6.26.0", + "babel-jest": "^23.0.1", + "jest": "^23.1.0", + "shx": "^0.3.0" + } +} diff --git a/src/lib/colonyNetwork/packages/colony-contract-loader-network/src/NetworkLoader.js b/src/lib/colonyNetwork/packages/colony-contract-loader-network/src/NetworkLoader.js new file mode 100644 index 0000000..6548026 --- /dev/null +++ b/src/lib/colonyNetwork/packages/colony-contract-loader-network/src/NetworkLoader.js @@ -0,0 +1,58 @@ +import assert from "assert"; +import ContractLoader, { truffleTransform } from "@colony/colony-js-contract-loader"; + +import config from "../config.json"; + +const NETWORKS = ["rinkeby"]; +const { LATEST_VERSION, VERSIONS } = config; +const VERSIONED_CONTRACT_NAMES = ["IColony", "IColonyNetwork", "Authority"]; +const STATIC_CONTRACT_NAMES = ["EtherRouter", "Token"]; + +const STATIC_CONTRACTS = Object.assign( + {}, + ...STATIC_CONTRACT_NAMES.map(contract => ({ + // eslint-disable-next-line global-require, import/no-dynamic-require + [contract]: require(`../contracts/static/${contract}.json`) + })) +); + +const VERSIONED_CONTRACTS = {}; +// Define versioned contracts +NETWORKS.forEach(network => { + VERSIONS.forEach(version => { + VERSIONED_CONTRACT_NAMES.forEach(contract => { + VERSIONED_CONTRACTS[contract] = {}; + if (!VERSIONED_CONTRACTS[contract][network]) { + VERSIONED_CONTRACTS[contract][network] = {}; + } + // eslint-disable-next-line global-require, import/no-dynamic-require + VERSIONED_CONTRACTS[contract][network][version] = require(`../contracts/versioned/${network}-v${version}/${contract}.json`); + }); + }); +}); + +class NetworkLoader extends ContractLoader { + constructor({ network = "main" } = {}) { + super({ transform: truffleTransform }); + this._network = network; + } + async _load(query = {}, requiredProps) { + const { contractName = "", version = LATEST_VERSION } = query; + + assert(!!contractName, "A `contractName` option must be provided"); + assert(!!version, "A valid `version` option must be provided"); + + if (STATIC_CONTRACTS[contractName]) { + return this._transform(STATIC_CONTRACTS[contractName], query, requiredProps); + } else if ( + VERSIONED_CONTRACTS[contractName] && + VERSIONED_CONTRACTS[contractName][this._network] && + VERSIONED_CONTRACTS[contractName][this._network][version] + ) { + return this._transform(VERSIONED_CONTRACTS[contractName][this._network][version], query, requiredProps); + } + throw new Error(`Contract ${contractName} with version ${version} not found in ${this._network}`); + } +} + +module.exports = NetworkLoader; diff --git a/src/lib/colonyNetwork/packages/colony-contract-loader-network/src/__tests__/NetworkLoader.test.js b/src/lib/colonyNetwork/packages/colony-contract-loader-network/src/__tests__/NetworkLoader.test.js new file mode 100644 index 0000000..adc4d6f --- /dev/null +++ b/src/lib/colonyNetwork/packages/colony-contract-loader-network/src/__tests__/NetworkLoader.test.js @@ -0,0 +1,66 @@ +/* eslint-env jest */ + +import NetworkLoader from "../NetworkLoader"; + +describe("colony-contract-loader-network - NetworkLoader", () => { + const loader = new NetworkLoader({ network: "rinkeby" }); + const contractAddress = "0x7da82c7ab4771ff031b66538d2fb9b0b047f6cf9"; + + test("It should load a static contract that is defined", async () => { + const contract = await loader.load({ contractName: "EtherRouter", contractAddress }); + expect(contract).toHaveProperty("abi", expect.any(Array)); + expect(contract).toHaveProperty("address", contractAddress); + }); + + test("It should load a versioned contract that is defined", async () => { + const contract = await loader.load({ contractName: "IColony", contractAddress, version: "1" }); + expect(contract).toHaveProperty("abi", expect.any(Array)); + expect(contract).toHaveProperty("address", contractAddress); + }); + + test("It should fail to load a contract that does not exist", async () => { + try { + await loader.load({ contractName: "CryptoKitty", contractAddress }); + expect(false).toBe(true); // should be unreachable + } catch (error) { + expect(error.toString()).toMatch("Contract CryptoKitty with version 1 not found in rinkeby"); + } + }); + + test("It should fail to load a contract for a version that does not exist", async () => { + try { + await loader.load({ contractName: "IColony", contractAddress, version: "420" }); + expect(false).toBe(true); // should be unreachable + } catch (error) { + expect(error.toString()).toMatch("Contract IColony with version 420 not found in rinkeby"); + } + }); + + test("It should fail to load a contract for a network that does not exist", async () => { + const ropstenLoader = new NetworkLoader({ network: "ropsten" }); + try { + await ropstenLoader.load({ contractName: "IColony", contractAddress, version: "1" }); + expect(false).toBe(true); // should be unreachable + } catch (error) { + expect(error.toString()).toMatch("Contract IColony with version 1 not found in ropsten"); + } + }); + + test("It should fail to load a contract without a contractName", async () => { + try { + await loader.load({ contractAddress, version: "1" }); + expect(false).toBe(true); // should be unreachable + } catch (error) { + expect(error.toString()).toMatch("A `contractName` option must be provided"); + } + }); + + test("It should fail to load a contract without a version", async () => { + try { + await loader.load({ contractName: "IColony", contractAddress, version: null }); + expect(false).toBe(true); // should be unreachable + } catch (error) { + expect(error.toString()).toMatch("A valid `version` option must be provided"); + } + }); +}); diff --git a/src/lib/colonyNetwork/packages/colony-contract-loader-network/src/index.js b/src/lib/colonyNetwork/packages/colony-contract-loader-network/src/index.js new file mode 100644 index 0000000..a9fa3a3 --- /dev/null +++ b/src/lib/colonyNetwork/packages/colony-contract-loader-network/src/index.js @@ -0,0 +1 @@ +export { default } from "./NetworkLoader"; diff --git a/src/lib/colonyNetwork/packages/reputation-miner/ReputationMiner.js b/src/lib/colonyNetwork/packages/reputation-miner/ReputationMiner.js new file mode 100644 index 0000000..f0d9ebd --- /dev/null +++ b/src/lib/colonyNetwork/packages/reputation-miner/ReputationMiner.js @@ -0,0 +1,576 @@ +const BN = require("bn.js"); +const web3Utils = require("web3-utils"); +const ganache = require("ganache-core"); +const ethers = require("ethers"); + +// We don't need the account address right now for this secret key, but I'm leaving it in in case we +// do in the future. +// const accountAddress = "0xbb46703786c2049d4d6dd43f5b4edf52a20fefe4"; +const secretKey = "0xe5c050bb6bfdd9c29397b8fe6ed59ad2f7df83d6fd213b473f84b489205d9fc7"; + +// Adapted from https://github.com/ethers-io/ethers.js/issues/59 +// =================================== +function RPCSigner(minerAddress, provider) { + this.address = minerAddress; + this.provider = provider; + const signer = this; + this.sendTransaction = function sendTransaction(transaction) { + const tx = this.buildTx(transaction); + return signer.provider.send("eth_sendTransaction", [tx]); + }; + + this.estimateGas = async function estimateGas(transaction) { + const tx = this.buildTx(transaction); + const res = await signer.provider.send("eth_estimateGas", [tx]); + return ethers.utils.bigNumberify(res); + }; + + this.buildTx = function buildTx(transaction) { + const tx = { + from: this.address + }; + ["to", "data"].forEach(key => { + if (transaction[key] != null) { + tx[key] = transaction[key]; + } + }); + ["gasPrice", "nonce", "value"].forEach(key => { + if (transaction[key] != null) { + tx[key] = ethers.utils.hexlify(transaction[key]); + } + }); + if (transaction.gasLimit != null) { + tx.gas = ethers.utils.hexlify(transaction.gasLimit); + } + return tx; + }; +} +// =================================== + +class ReputationMiner { + /** + * Constructor for ReputationMiner + * @param {string} minerAddress The address that is staking CLNY that will allow the miner to submit reputation hashes + * @param {Number} [realProviderPort=8545] The port that the RPC node with the ability to sign transactions from `minerAddress` is responding on. The address is assumed to be `localhost`. + */ + constructor({ loader, minerAddress, privateKey, provider, realProviderPort = 8545 }) { + this.loader = loader; + this.minerAddress = minerAddress; + const ganacheProvider = ganache.provider({ + network_id: 515, + vmErrorsOnRPCResponse: false, + locked: false, + verbose: true, + accounts: [ + { + balance: "0x10000000000000000000000000", + secretKey + } + ] + }); + this.ganacheProvider = new ethers.providers.Web3Provider(ganacheProvider); + this.ganacheWallet = new ethers.Wallet(secretKey, this.ganacheProvider); + + if (provider) { + this.realProvider = provider; + } else { + this.realProvider = new ethers.providers.JsonRpcProvider(`http://localhost:${realProviderPort}`); + } + + if (minerAddress) { + this.realWallet = new RPCSigner(minerAddress, this.realProvider); + } else { + this.realWallet = new ethers.Wallet(privateKey, this.realProvider); + // TODO: Check that this wallet can stake? + console.log("Transactions will be signed from ", this.realWallet.address); + } + } + + /** + * Initialises the mining client so that it knows where to find the `ColonyNetwork` contract + * @param {string} colonyNetworkAddress The address of the current `ColonyNetwork` contract + * @return {Promise} + */ + async initialise(colonyNetworkAddress) { + this.patriciaTreeContractDef = await this.loader.load({ contractName: "PatriciaTree" }, { abi: true, address: false, bytecode: true }); + this.colonyNetworkContractDef = await this.loader.load({ contractName: "IColonyNetwork" }, { abi: true, address: false }); + this.repCycleContractDef = await this.loader.load({ contractName: "IReputationMiningCycle" }, { abi: true, address: false }); + + const patriciaTreeDeployTx = ethers.Contract.getDeployTransaction(this.patriciaTreeContractDef.bytecode, this.patriciaTreeContractDef.abi); + const tx = await this.ganacheWallet.sendTransaction(patriciaTreeDeployTx); + this.reputationTree = new ethers.Contract(ethers.utils.getContractAddress(tx), this.patriciaTreeContractDef.abi, this.ganacheWallet); + this.nReputations = 0; + this.reputations = {}; + this.colonyNetwork = new ethers.Contract(colonyNetworkAddress, this.colonyNetworkContractDef.abi, this.realWallet); + } + + /** + * When called, adds the entire contents of the current (inactive) log to its reputation tree. It also builds a Justification Tree as it does so + * in case a dispute is called which would require it. + * @return {Promise} + */ + async addLogContentsToReputationTree() { + const patriciaTreeDeployTx = ethers.Contract.getDeployTransaction(this.patriciaTreeContractDef.bytecode, this.patriciaTreeContractDef.abi); + + const tx = await this.ganacheWallet.sendTransaction(patriciaTreeDeployTx); + this.justificationTree = new ethers.Contract(ethers.utils.getContractAddress(tx), this.patriciaTreeContractDef.abi, this.ganacheWallet); + + this.justificationHashes = {}; + const addr = await this.colonyNetwork.getReputationMiningCycle(true); + const repCycle = new ethers.Contract(addr, this.repCycleContractDef.abi, this.realWallet); + + let nLogEntries = await repCycle.getReputationUpdateLogLength(); + nLogEntries = new BN(nLogEntries.toString()); + for (let i = new BN("0"); i.lte(nLogEntries); i.iadd(new BN("1"))) { + await this.addSingleLogEntry(i, i.eq(nLogEntries)); // eslint-disable-line no-await-in-loop + } + } + + /** + * Function called by `addLogContentsToReputationTree` to process a single log entry, updating the reputation tree and the justification tree + * as it does so. + * @param {Number} i The index of the log entry to process. Note that the final time this function is called, it is equal to the number of logs entries + * present, which could cause out-of-bounds errors if unchecke. In this case, `last` will be set to true to avoid errors. + * @param {Boolean} last Set to `true` if `i` is out of bounds of the log. + * @return {Promise} + */ + async addSingleLogEntry(i, last) { + let interimHash; + let jhLeafValue; + let justUpdatedProof; + let newestReputationProof; + interimHash = await this.reputationTree.getRootHash(); // eslint-disable-line no-await-in-loop + // console.log(interimHash); + jhLeafValue = this.getJRHEntryValueAsBytes(interimHash, this.nReputations); + // console.log(jhLeafValue); + let logEntry; + if (!last) { + const addr = await this.colonyNetwork.getReputationMiningCycle(true); + const repCycle = new ethers.Contract(addr, this.repCycleContractDef.abi, this.realWallet); + logEntry = await repCycle.getReputationUpdateLogEntry(i.toString()); // eslint-disable-line no-await-in-loop + } else { + logEntry = ["0x", 0, 0, "0x", 0]; + } + const score = this.getScore(i, logEntry); + if (i.toString() === "0") { + // TODO If it's not already this value, then something has gone wrong, and we're working with the wrong state. + // This 'if' statement is only in for now to make tests easier to write. + interimHash = await this.colonyNetwork.getReputationRootHash(); // eslint-disable-line no-await-in-loop + jhLeafValue = this.getJRHEntryValueAsBytes(interimHash, this.nReputations); + } else { + const prevKey = await this.getKeyForLogEntry(i.subn(1)); + justUpdatedProof = await this.getReputationProofObject(prevKey); + newestReputationProof = await this.getNewestReputationProofObject(i); + } + await this.justificationTree.insert(`0x${i.toString(16, 64)}`, jhLeafValue, { gasLimit: 4000000 }); // eslint-disable-line no-await-in-loop + + let key; + let nextUpdateProof = {}; + if (!last) { + key = await this.getKeyForLogEntry(i); + nextUpdateProof = await this.getReputationProofObject(key); + } + + this.justificationHashes[`0x${i.toString(16, 64)}`] = JSON.parse( + JSON.stringify({ + interimHash, + nNodes: this.nReputations, + jhLeafValue, + justUpdatedProof, + nextUpdateProof, + newestReputationProof + }) + ); + + // We have to process these sequentially - if two updates affected the + // same entry, we would have a potential race condition. + // Hence, we are awaiting inside these loops. + // TODO: Include updates for all parent skills (and child, if x.amount is negative) + // TODO: Include updates for colony-wide sums of skills. + await this.insert(logEntry[3], logEntry[2], logEntry[0], score, i); // eslint-disable-line no-await-in-loop + } + + /** + * Get an object containing the key, value, and branchMask and siblings of the merkle proof of the provided key in the current reputation state. If the key + * does not exist in the current state, returns valid 0-based values for each element (e.g. `0x0` for the branchMask); + * @return {Promise} The returned promise will resolve to `[key, value, branchMask, siblings]` + */ + async getReputationProofObject(key) { + let branchMask; + let siblings; + let value; + + try { + [branchMask, siblings] = await this.getProof(key); // eslint-disable-line no-await-in-loop + value = this.reputations[key]; + } catch (err) { + // Doesn't exist yet. + branchMask = 0x0; + siblings = []; + value = this.getValueAsBytes(0, 0); + } + return { branchMask: `${branchMask.toString(16)}`, siblings, key, value, nNodes: this.nReputations }; + } + + static async getKey(_colonyAddress, _skillId, _userAddress) { + let colonyAddress = _colonyAddress; + let userAddress = _userAddress; + + let isAddress = web3Utils.isAddress(colonyAddress); + // TODO should we return errors here? + if (!isAddress) { + return false; + } + isAddress = web3Utils.isAddress(userAddress); + if (!isAddress) { + return false; + } + if (colonyAddress.substring(0, 2) === "0x") { + colonyAddress = colonyAddress.slice(2); + } + if (userAddress.substring(0, 2) === "0x") { + userAddress = userAddress.slice(2); + } + colonyAddress = colonyAddress.toLowerCase(); + userAddress = userAddress.toLowerCase(); + const key = `0x${new BN(colonyAddress, 16).toString(16, 40)}${new BN(_skillId.toString()).toString(16, 64)}${new BN(userAddress, 16).toString( + 16, + 40 + )}`; + return key; + } + + /** + * For the supplied log entry, return the key in the reputation log that is affected by the update. + * @param {[type]} i The index of the entry of interest in the reputation log. + * @return {Promise} A promise that resolves to the key of the corresponding reputation. + */ + async getKeyForLogEntry(i) { + const addr = await this.colonyNetwork.getReputationMiningCycle(true); + const repCycle = new ethers.Contract(addr, this.repCycleContractDef.abi, this.realWallet); + + const logEntry = await repCycle.getReputationUpdateLogEntry(i); // eslint-disable-line no-await-in-loop + const colonyAddress = logEntry[3].slice(2); + const skillId = logEntry[2]; + const userAddress = logEntry[0].slice(2); + const key = `0x${new BN(colonyAddress, 16).toString(16, 40)}${new BN(skillId.toString()).toString(16, 64)}${new BN(userAddress, 16).toString( + 16, + 40 + )}`; + return key; + } + + /** + * Formats `_reputationState` and `nNodes` in to the format used for the Justification Tree + * @param {bigNumber or string} _reputationState The reputation state root hashes + * @param {bigNumber or string} nNodes The number of nodes in the reputation state Tree + * @return {string} The correctly formatted hex string for inclusion in the justification tree + */ + getJRHEntryValueAsBytes(_reputationState, nNodes) { //eslint-disable-line + let reputationState = _reputationState.toString(16); + if (reputationState.substring(0, 2) === "0x") { + reputationState = reputationState.slice(2); + } + return `0x${new BN(reputationState.toString(), 16).toString(16, 64)}${new BN(nNodes.toString()).toString(16, 64)}`; + } + + /** + * Formats `reputation` and `uid` in to the format used for the Reputation Tree + * @param {bigNumber or string} reputation The reputation score + * @param {bigNumber or string} uid The global UID assigned to this reputation + * @return {string} Appropriately formatted hex string + */ + getValueAsBytes(reputation, uid) { //eslint-disable-line + return `0x${new BN(reputation.toString()).toString(16, 64)}${new BN(uid.toString()).toString(16, 64)}`; + } + + /** + * Get the reputation change from the supplied logEntry + * @param {Number} i The number of the log entry. Not used here, but is in malicious.js to know whether to lie + * @param {Array} logEntry The log entry + * @return {BigNumber} The entry's reputation change + * @dev The version of this function in malicious.js uses `this`, but not this version. + */ + // eslint-disable-next-line class-methods-use-this + getScore(i, logEntry) { + return logEntry[1]; + } + + /** + * Get the key and value of the most recently added reputation (i.e. the one with the highest UID), + * and proof (branchMask and siblings) that it exists in the current reputation state. + * @return {Promise} The returned promise will resolve to `[key, value, branchMask, siblings]` + */ + // eslint-disable-next-line no-unused-vars + async getNewestReputationProofObject(i) { + // i is unused here, but is used in the Malicious3 mining client. + const key = Object.keys(this.reputations)[this.nReputations - 1]; + return this.getReputationProofObject(key); + } + + /** + * Submit what the client believes should be the next reputation state root hash to the `ReputationMiningCycle` contract + * @return {Promise} + */ + async submitRootHash() { + const addr = await this.colonyNetwork.getReputationMiningCycle(true); + const repCycle = new ethers.Contract(addr, this.repCycleContractDef.abi, this.realWallet); + + const hash = await this.getRootHash(); + // TODO: Work out what entry we should use when we submit + const gas = await repCycle.estimate.submitRootHash(hash, this.nReputations, 1); + return repCycle.submitRootHash(hash, this.nReputations, 1, { gasLimit: `0x${gas.mul(2).toString()}` }); + } + + /** + * Get what the client believes should be the next reputation state root hash. + * @return {Promise} Resolves to the root hash + */ + async getRootHash() { + return this.reputationTree.getRootHash(); + } + + /** + * Get a Merkle proof for `key` in the current (local) reputation state. + * @param {string} key The reputation key the proof is being asked for + * @return {Promise} Resolves to [branchMask, siblings] + */ + async getProof(key) { + const [branchMask, siblings] = await this.reputationTree.getProof(key); + const retBranchMask = branchMask.toHexString(); + return [retBranchMask, siblings]; + } + + /** + * Submit the Justification Root Hash (JRH) for the hash that (presumably) we submitted this round + * @return {Promise} + */ + async submitJustificationRootHash() { + const jrh = await this.justificationTree.getRootHash(); + const [branchMask1, siblings1] = await this.justificationTree.getProof(`0x${new BN("0").toString(16, 64)}`); + + const addr = await this.colonyNetwork.getReputationMiningCycle(true); + const repCycle = new ethers.Contract(addr, this.repCycleContractDef.abi, this.realWallet); + const nLogEntries = await repCycle.getReputationUpdateLogLength(); + + const [branchMask2, siblings2] = await this.justificationTree.getProof(`0x${new BN(nLogEntries.toString()).toString(16, 64)}`); + const [round, index] = await this.getMySubmissionRoundAndIndex(); + return repCycle.submitJustificationRootHash(round.toString(), index.toString(), jrh, branchMask1, siblings1, branchMask2, siblings2, { + gasLimit: 6000000 + }); + } + + /** + * Returns the round and index that our submission is currently at in the dispute cycle. + * @return {Promise} Resolves to [round, index] which are `BigNumber`. + */ + async getMySubmissionRoundAndIndex() { + const submittedHash = await this.reputationTree.getRootHash(); + const addr = await this.colonyNetwork.getReputationMiningCycle(true); + const repCycle = new ethers.Contract(addr, this.repCycleContractDef.abi, this.realWallet); + + let index = new BN("-1"); + const round = new BN("0"); + let submission = []; + while (submission[0] !== submittedHash) { + try { + index.iaddn(1); + submission = await repCycle.disputeRounds(round.toString(), index.toString()); // eslint-disable-line no-await-in-loop + } catch (err) { + round.iaddn(1); + index = new BN("-1"); + } + } + return [round, index]; + } + + /** + * Respond to the next stage in the binary search occurring on `ReputationMiningCycle` contract in order to find + * the first log entry where our submitted hash and the hash we are paired off against differ. + * @return {Promise} Resolves to the tx hash of the response + */ + async respondToBinarySearchForChallenge() { + const [round, index] = await this.getMySubmissionRoundAndIndex(); + const addr = await this.colonyNetwork.getReputationMiningCycle(true); + const repCycle = new ethers.Contract(addr, this.repCycleContractDef.abi, this.realWallet); + let submission = await repCycle.disputeRounds(round.toString(), index.toString()); + const targetNode = new BN( + submission[8] + .add(submission[9]) + .div(2) + .toString() + ); + const intermediateReputationHash = this.justificationHashes[`0x${targetNode.toString(16, 64)}`].jhLeafValue; + const [branchMask, siblings] = await this.justificationTree.getProof(`0x${targetNode.toString(16, 64)}`); + + const tx = await repCycle.respondToBinarySearchForChallenge( + round.toString(), + index.toString(), + intermediateReputationHash, + branchMask, + siblings, + { + gasLimit: 1000000 + } + ); + submission = await repCycle.disputeRounds(round.toString(), index.toString()); + return tx; + } + + /** + * Respond to a specific challenge over the effect of a specific log entry once the binary search has been completed to establish + * the log entry where the two submitted hashes differ. + * @return {Promise} Resolves to tx hash of the response + */ + async respondToChallenge() { + const [round, index] = await this.getMySubmissionRoundAndIndex(); + const addr = await this.colonyNetwork.getReputationMiningCycle(true); + const repCycle = new ethers.Contract(addr, this.repCycleContractDef.abi, this.realWallet); + const submission = await repCycle.disputeRounds(round.toString(), index.toString()); + // console.log(submission); + const firstDisagreeIdx = new BN(submission[8].toString()); + const lastAgreeIdx = firstDisagreeIdx.subn(1); + const logEntry = await repCycle.getReputationUpdateLogEntry(lastAgreeIdx.toString()); + const colonyAddress = logEntry[3]; + const skillId = logEntry[2]; + const userAddress = logEntry[0]; + const reputationKey = `0x${new BN(colonyAddress.slice(2), 16).toString(16, 40)}${new BN(skillId.toString()).toString(16, 64)}${new BN( + userAddress.slice(2), + 16 + ).toString(16, 40)}`; + // console.log('get justification tree'); + const [agreeStateBranchMask, agreeStateSiblings] = await this.justificationTree.getProof(`0x${lastAgreeIdx.toString(16, 64)}`); + const [disagreeStateBranchMask, disagreeStateSiblings] = await this.justificationTree.getProof(`0x${firstDisagreeIdx.toString(16, 64)}`); + // console.log('get justification tree done'); + + // These comments can help with debugging. This implied root is the intermediate root hash that is implied + // const impliedRoot = await this.justificationTree.getImpliedRoot( + // reputationKey, + // this.justificationHashes[`0x${new BN(lastAgreeIdx).toString(16, 64)}`].nextUpdateProof.value, + // this.justificationHashes[`0x${new BN(lastAgreeIdx).toString(16, 64)}`].nextUpdateProof.branchMask, + // this.justificationHashes[`0x${new BN(lastAgreeIdx).toString(16, 64)}`].nextUpdateProof.siblings + // ); + // console.log('intermediatRootHash', impliedRoot); + // // This one is the JRH implied by the proof provided alongside the above implied root - we expect this to + // // be the JRH that has been submitted. + // const impliedRoot2 = await this.justificationTree.getImpliedRoot( + // `0x${new BN(lastAgreeIdx).toString(16, 64)}`, + // impliedRoot, + // agreeStateBranchMask, + // agreeStateSiblings + // ); + // const jrh = await this.justificationTree.getRootHash(); + // console.log('implied jrh', impliedRoot2) + // console.log('actual jrh', jrh) + // const impliedRoot3 = await this.justificationTree.getImpliedRoot( + // reputationKey, + // this.justificationHashes[`0x${new BN(firstDisagreeIdx).toString(16, 64)}`].justUpdatedProof.value, + // this.justificationHashes[`0x${new BN(firstDisagreeIdx).toString(16, 64)}`].justUpdatedProof.branchMask, + // this.justificationHashes[`0x${new BN(firstDisagreeIdx).toString(16, 64)}`].justUpdatedProof.siblings + // ); + // const impliedRoot4 = await this.justificationTree.getImpliedRoot( + // `0x${new BN(firstDisagreeIdx).toString(16, 64)}`, + // impliedRoot3, + // disagreeStateBranchMask, + // disagreeStateSiblings + // ); + // console.log('intermediatRootHash2', impliedRoot3); + // console.log('implied jrh from irh2', impliedRoot4); + // console.log('about to respondToChallengeReal') + const tx = await repCycle.respondToChallenge( + [ + round.toString(), + index.toString(), + this.justificationHashes[`0x${new BN(firstDisagreeIdx).toString(16, 64)}`].justUpdatedProof.branchMask, + this.justificationHashes[`0x${new BN(lastAgreeIdx).toString(16, 64)}`].nextUpdateProof.nNodes, + agreeStateBranchMask.toHexString(), + this.justificationHashes[`0x${new BN(firstDisagreeIdx).toString(16, 64)}`].justUpdatedProof.nNodes, + disagreeStateBranchMask.toHexString(), + this.justificationHashes[`0x${new BN(lastAgreeIdx).toString(16, 64)}`].newestReputationProof.branchMask, + 0 + ], + reputationKey, + this.justificationHashes[`0x${new BN(firstDisagreeIdx).toString(16, 64)}`].justUpdatedProof.siblings, + this.justificationHashes[`0x${new BN(lastAgreeIdx).toString(16, 64)}`].nextUpdateProof.value, + agreeStateSiblings, + this.justificationHashes[`0x${new BN(firstDisagreeIdx).toString(16, 64)}`].justUpdatedProof.value, + disagreeStateSiblings, + this.justificationHashes[`0x${new BN(lastAgreeIdx).toString(16, 64)}`].newestReputationProof.key, + this.justificationHashes[`0x${new BN(lastAgreeIdx).toString(16, 64)}`].newestReputationProof.value, + this.justificationHashes[`0x${new BN(lastAgreeIdx).toString(16, 64)}`].newestReputationProof.siblings, + { gasLimit: 4000000 } + ); + return tx; + } + + /** + * Insert (or update) the reputation for a user in the local reputation tree + * @param {string} _colonyAddress Hex address of the colony in which the reputation is being updated + * @param {Number or BigNumber or String} skillId The id of the skill being updated + * @param {string} _userAddress Hex address of the user who is having their reputation being updated + * @param {Number of BigNumber or String} reputationScore The amount the reputation changes by + * @param {Number or BigNumber} index The index of the log entry being considered + * @return {Promise} Resolves to `true` or `false` depending on whether the insertion was successful + */ + async insert(_colonyAddress, skillId, _userAddress, _reputationScore, index) { + let colonyAddress = _colonyAddress; + let userAddress = _userAddress; + + let isAddress = web3Utils.isAddress(colonyAddress); + // TODO should we return errors here? + if (!isAddress) { + return false; + } + isAddress = web3Utils.isAddress(userAddress); + if (!isAddress) { + return false; + } + if (colonyAddress.substring(0, 2) === "0x") { + colonyAddress = colonyAddress.slice(2); + } + if (userAddress.substring(0, 2) === "0x") { + userAddress = userAddress.slice(2); + } + colonyAddress = colonyAddress.toLowerCase(); + userAddress = userAddress.toLowerCase(); + const key = `0x${new BN(colonyAddress, 16).toString(16, 40)}${new BN(skillId.toString()).toString(16, 64)}${new BN(userAddress, 16).toString( + 16, + 40 + )}`; + // const keyAlreadyExists = await this.keyExists(key); + // If we already have this key, then we lookup the unique identifier we assigned this key. + // Otherwise, give it the new one. + let value; + let newValue; + const keyAlreadyExists = this.reputations[key] !== undefined; + if (keyAlreadyExists) { + // Look up value from our JSON. + value = this.reputations[key]; + // Extract uid + const uid = ethers.utils.bigNumberify(`0x${value.slice(-64)}`); + const existingValue = ethers.utils.bigNumberify(`0x${value.slice(2, 66)}`); + newValue = existingValue.add(_reputationScore); + if (newValue.lt(new BN("0"))) { + newValue = new BN("0"); + } + if (newValue.gt(new BN("2").pow(new BN("256")).subn(1))) { + newValue = new BN("2").pow(new BN("256")).subn(1); + } + value = this.getValueAsBytes(newValue, uid, index); + } else { + newValue = _reputationScore; + if (newValue.lt(new BN("0"))) { + newValue = new BN("0"); + } + // A new value can never overflow, so we don't need a 'capping' check here + value = this.getValueAsBytes(newValue, this.nReputations + 1, index); + this.nReputations += 1; + } + await this.reputationTree.insert(key, value, { gasLimit: 4000000 }); + // If successful, add to our JSON. + this.reputations[key] = value; + return true; + } +} + +module.exports = ReputationMiner; diff --git a/src/lib/colonyNetwork/packages/reputation-miner/ReputationMinerClient.js b/src/lib/colonyNetwork/packages/reputation-miner/ReputationMinerClient.js new file mode 100644 index 0000000..c8f5a6e --- /dev/null +++ b/src/lib/colonyNetwork/packages/reputation-miner/ReputationMinerClient.js @@ -0,0 +1,140 @@ +const path = require("path"); +const jsonfile = require("jsonfile"); +const ethers = require("ethers"); +const express = require("express"); +const BN = require("bn.js"); + +const ReputationMiner = require("./ReputationMiner"); + +class ReputationMinerClient { + /** + * Constructor for ReputationMiner + * @param {string} minerAddress The address that is staking CLNY that will allow the miner to submit reputation hashes + * @param {Number} [realProviderPort=8545] The port that the RPC node with the ability to sign transactions from `minerAddress` is responding on. The address is assumed to be `localhost`. + */ + constructor({ file, minerAddress, loader, realProviderPort, seed, privateKey, provider }) { + this._loader = loader; + this._miner = new ReputationMiner({ minerAddress, loader, provider, privateKey, realProviderPort }); + this._seed = seed; + this._file = path.resolve(process.cwd(), file); + + this._app = express(); + this._app.get("/:colonyAddress/:skillId/:userAddress", async (req, res) => { + const key = await ReputationMiner.getKey(req.params.colonyAddress, req.params.skillId, req.params.userAddress); + if (this._miner.reputations[key]) { + const proof = await this._miner.getReputationProofObject(key); + delete proof.nNodes; + proof.reputationAmount = ethers.utils.bigNumberify(`0x${proof.value.slice(2, 66)}`).toString(); + + res.status(200).send(proof); + } else { + res.status(400).send({ message: "Requested reputation does not exist or invalid request" }); + } + }); + + this.server = this._app.listen(3000, () => { + console.log("⭐️ Reputation oracle running on port ", this.server.address().port); + }); + } + + /** + * Initialises the mining client so that it knows where to find the `ColonyNetwork` contract + * @param {string} colonyNetworkAddress The address of the current `ColonyNetwork` contract + * @return {Promise} + */ + async initialise(colonyNetworkAddress) { + await this._miner.initialise(colonyNetworkAddress); + + this.repCycleContractDef = await this._loader.load({ contractName: "IReputationMiningCycle" }, { abi: true, address: false }); + + try { + // TODO: I don't really like writing properties like that. We might need a setReputations() method on the miner + // It can also then set the nReputations + this._miner.reputations = jsonfile.readFileSync(this._file); + console.log("💾 Restored from JSON file"); + } catch (err) { + this._miner.reputations = {}; + console.log("No existing reputations found - starting from scratch"); + } + this._miner.nReputations = Object.keys(this._miner.reputations).length; + + if (this._miner.nReputations === 0 && this._seed) { + // Temporary data if --seed is set and there's nothing to restore from. + const ADDRESS1 = "0x309e642dbf573119ca75153b25f5b8462ff1b90b"; + const ADDRESS2 = "0xbc13dbc1a954b3443d6f75297a232faa513774b3"; + const ADDRESS3 = "0x2b183746bd1403cdec8e4fe45139339da20bcf3d"; + const ADDRESS4 = "0xcd0751d4181acda4f8edb2f3b33b915f91abeef0"; + const ADDRESS0 = "0x0000000000000000000000000000000000000000"; + await this._miner.insert(ADDRESS1, 1, ADDRESS2, new BN("999999999")); + await this._miner.insert(ADDRESS1, 1, ADDRESS0, new BN("999999999")); + await this._miner.insert(ADDRESS1, 2, ADDRESS2, new BN("888888888888888")); + await this._miner.insert(ADDRESS1, 2, ADDRESS0, new BN("888888888888888")); + await this._miner.insert(ADDRESS3, 1, ADDRESS2, new BN("100000000")); + await this._miner.insert(ADDRESS3, 1, ADDRESS4, new BN("100000000")); + await this._miner.insert(ADDRESS3, 1, ADDRESS0, new BN("200000000")); + console.log("💾 Writing initialised state with dummy data to JSON file"); + + jsonfile.writeFileSync(this._file, this._miner.reputations); + } else { + // TODO: It would be good to have an interface on the miner for that, I'm pretty sure this logic is already somewhere in there + for (let i = 0; i < Object.keys(this._miner.reputations).length; i += 1) { + const key = Object.keys(this._miner.reputations)[i]; + await this._miner.reputationTree.insert(key, this._miner.reputations[key], { gasLimit: 4000000 }); // eslint-disable-line no-await-in-loop + } + } + + console.log("🏁 Initialised"); + setTimeout(() => this.checkSubmissionWindow(), 0); + } + + async checkSubmissionWindow() { + // TODO: Check how much of this does actually belong into the Miner itself + // One could introduce lifecycle hooks in the miner to avoid code duplication + + // Check if it's been an hour since the window opened + const addr = await this._miner.colonyNetwork.getReputationMiningCycle(true); + const repCycle = new ethers.Contract(addr, this.repCycleContractDef.abi, this._miner.realWallet); + + const windowOpened = await repCycle.reputationMiningWindowOpenTimestamp(); + + const block = await this._miner.realProvider.getBlock("latest"); + const now = block.timestamp; + if (now - windowOpened > 3600) { + console.log("⏰ Looks like it's time to submit an update"); + // If so, process the log + await this._miner.addLogContentsToReputationTree(); + + console.log("💾 Writing new reputation state to JSON file"); + jsonfile.writeFileSync(this._file, this._miner.reputations); + + console.log("#️⃣ Submitting new reputation hash"); + + // Submit hash + let tx = await this._miner.submitRootHash(); + if (!tx.nonce) { + // Assume we've been given back the tx hash. + tx = await this._miner.realProvider.getTransaction(tx); + } + + console.log("Confirming new reputation hash..."); + + // Confirm hash + // We explicitly use the previous nonce +1, in case we're using Infura and we end up + // querying a node that hasn't had the above transaction propagate to it yet. + tx = await repCycle.confirmNewHash(0, { gasLimit: 3500000, nonce: tx.nonce + 1 }); + + console.log("✅ New reputation hash confirmed, via TX", tx); + // setTimeout(() => this.checkSubmissionWindow(), 3660000); + // console.log("⌛️ will next check in one hour and one minute"); + setTimeout(() => this.checkSubmissionWindow(), 10000); + } else { + // Set a timeout for 3610 - (now - windowOpened) + setTimeout(() => this.checkSubmissionWindow(), 10000); + // const timeout = Math.max(3610 - (now - windowOpened), 10); + // console.log("⌛️ will next check in ", timeout, "seconds"); + // setTimeout(() => this.checkSubmissionWindow(), timeout * 1000); + } + } +} + +module.exports = ReputationMinerClient; diff --git a/src/lib/colonyNetwork/packages/reputation-miner/bin/index.js b/src/lib/colonyNetwork/packages/reputation-miner/bin/index.js new file mode 100644 index 0000000..c8a019f --- /dev/null +++ b/src/lib/colonyNetwork/packages/reputation-miner/bin/index.js @@ -0,0 +1,25 @@ +const path = require("path"); +const { argv } = require("yargs"); +const { TruffleLoader } = require("@colony/colony-js-contract-loader-fs"); +const ethers = require("ethers"); + +const ReputationMinerClient = require("../ReputationMinerClient"); + +const { file, minerAddress, colonyNetworkAddress, rinkeby, privateKey, seed } = argv; + +if ((!minerAddress && !privateKey) || !colonyNetworkAddress || !file) { + console.log("❗️ You have to specify all of ( --minerAddress or --privateKey ), --colonyNetworkAddress and --file on the command line!"); + process.exit(); +} + +const loader = new TruffleLoader({ + contractDir: path.resolve(process.cwd(), "build", "contracts") +}); + +let provider; +if (rinkeby) { + provider = new ethers.providers.InfuraProvider("rinkeby"); +} + +const client = new ReputationMinerClient({ file, loader, minerAddress, privateKey, provider, seed }); +client.initialise(colonyNetworkAddress); diff --git a/src/lib/colonyNetwork/packages/reputation-miner/package.json b/src/lib/colonyNetwork/packages/reputation-miner/package.json new file mode 100644 index 0000000..2e0760c --- /dev/null +++ b/src/lib/colonyNetwork/packages/reputation-miner/package.json @@ -0,0 +1,26 @@ +{ + "name": "@colony/reputation-miner", + "version": "0.1.0", + "description": "Colony", + "main": "ReputationMinerClient.js", + "directories": { + "test": "test" + }, + "bin": "bin/index", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "@colony/colony-js-contract-loader-fs": "^1.3.0", + "bn.js": "^4.11.8", + "ethers": "^3.0.15", + "express": "^4.16.3", + "ganache-core": "^2.1.0", + "jsonfile": "^4.0.0", + "web3-utils": "^1.0.0-beta.34", + "yargs": "^11.0.0" + } +} diff --git a/src/lib/colonyNetwork/packages/reputation-miner/test/MaliciousReputationMinerExtraRep.js b/src/lib/colonyNetwork/packages/reputation-miner/test/MaliciousReputationMinerExtraRep.js new file mode 100644 index 0000000..ace5356 --- /dev/null +++ b/src/lib/colonyNetwork/packages/reputation-miner/test/MaliciousReputationMinerExtraRep.js @@ -0,0 +1,21 @@ +import ReputationMiner from "../ReputationMiner"; + +class MaliciousReputationMinerExtraRep extends ReputationMiner { + // Only difference between this and the 'real' client should be that it adds some extra + // reputation to the fourth entry being parsed. + constructor(opts, entryToFalsify, amountToFalsify) { + super(opts); + this.entryToFalsify = entryToFalsify.toString(); + this.amountToFalsify = amountToFalsify.toString(); + } + + getScore(i, logEntry) { + let score = logEntry[1]; + if (i.toString() === this.entryToFalsify) { + score = score.add(this.amountToFalsify); + } + return score; + } +} + +export default MaliciousReputationMinerExtraRep; diff --git a/src/lib/colonyNetwork/packages/reputation-miner/test/MaliciousReputationMinerReuseUID.js b/src/lib/colonyNetwork/packages/reputation-miner/test/MaliciousReputationMinerReuseUID.js new file mode 100644 index 0000000..bf95471 --- /dev/null +++ b/src/lib/colonyNetwork/packages/reputation-miner/test/MaliciousReputationMinerReuseUID.js @@ -0,0 +1,33 @@ +import BN from "bn.js"; +import ReputationMiner from "../ReputationMiner"; + +class MaliciousReputationMinerReuseUID extends ReputationMiner { + // This client will reuse a UID for a reputation + constructor(opts, entryToFalsify, amountToFalsify) { + super(opts); + this.entryToFalsify = entryToFalsify.toString(); + this.amountToFalsify = amountToFalsify.toString(); + } + + async getNewestReputationProofObject(logEntry) { + let key; + if (logEntry.toString() === this.entryToFalsify.toString()) { + key = Object.keys(this.reputations)[this.nReputations - 1 - parseInt(this.amountToFalsify, 10)]; + } else { + key = Object.keys(this.reputations)[this.nReputations - 1]; + } + return this.getReputationProofObject(key); + } + + getValueAsBytes(reputation, _uid, index) { //eslint-disable-line + let uid; + if (index && index.toString() === this.entryToFalsify) { + uid = new BN(_uid.toString()).sub(new BN(this.amountToFalsify)); + } else { + uid = _uid; + } + return `0x${new BN(reputation.toString()).toString(16, 64)}${new BN(uid.toString()).toString(16, 64)}`; + } +} + +export default MaliciousReputationMinerReuseUID; diff --git a/src/lib/colonyNetwork/packages/reputation-miner/test/MaliciousReputationMinerWrongUID.js b/src/lib/colonyNetwork/packages/reputation-miner/test/MaliciousReputationMinerWrongUID.js new file mode 100644 index 0000000..2ee62c5 --- /dev/null +++ b/src/lib/colonyNetwork/packages/reputation-miner/test/MaliciousReputationMinerWrongUID.js @@ -0,0 +1,23 @@ +import BN from "bn.js"; +import ReputationMiner from "../ReputationMiner"; + +class MaliciousReputationMinerWrongUID extends ReputationMiner { + // This client uses the wrong UID for a reputation (even an existing one) + constructor(opts, entryToFalsify, amountToFalsify) { + super(opts); + this.entryToFalsify = entryToFalsify.toString(); + this.amountToFalsify = amountToFalsify.toString(); + } + + getValueAsBytes(reputation, _uid, index) { //eslint-disable-line + let uid; + if (index && index.toString() === this.entryToFalsify) { + uid = new BN(_uid.toString()).add(new BN(this.amountToFalsify)); + } else { + uid = _uid; + } + return `0x${new BN(reputation.toString()).toString(16, 64)}${new BN(uid.toString()).toString(16, 64)}`; + } +} + +export default MaliciousReputationMinerWrongUID; diff --git a/src/lib/colonyNetwork/parity-genesis.template.json b/src/lib/colonyNetwork/parity-genesis.template.json new file mode 100644 index 0000000..0686cb1 --- /dev/null +++ b/src/lib/colonyNetwork/parity-genesis.template.json @@ -0,0 +1,42 @@ +{ + "name": "ethereum", + "engine": { + "instantSeal": null + }, + "params": { + "accountStartNonce": "0x0100000", + "gasLimitBoundDivisor": "0x400", + "maximumExtraDataSize": "0x20", + "minGasLimit": "0x1388", + "networkID" : "0x2", + "eip658Transition": "0x0", + "eip140Transition": "0x0", + "eip211Transition": "0x0", + "eip214Transition": "0x0", + "eip150Transition": "0x0" + }, + "genesis": { + "seal": { + "ethereum": { + "nonce": "0x00006d6f7264656e", + "mixHash": "0x00000000000000000000000000000000000000647572616c65787365646c6578" + } + }, + "difficulty": "0x20000", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x", + "gasLimit": "0x6ACFC0" + }, + "accounts": { + "0000000000000000000000000000000000000001": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, + "0000000000000000000000000000000000000002": { "balance": "1", "nonce": "1048576", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, + "0000000000000000000000000000000000000003": { "balance": "1", "nonce": "1048576", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0000000000000000000000000000000000000004": { "balance": "1", "nonce": "1048576", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, + "wwwww": { "balance": "1000000000000000000000", "nonce": "1048576" }, + "xxxxx": { "balance": "1000000000000000000000", "nonce": "1048576" }, + "yyyyy": { "balance": "1000000000000000000000", "nonce": "1048576" }, + "zzzzz": { "balance": "1000000000000000000000", "nonce": "1048576" } + } +} diff --git a/src/lib/colonyNetwork/scripts/check-storage.js b/src/lib/colonyNetwork/scripts/check-storage.js new file mode 100644 index 0000000..b3cfe6b --- /dev/null +++ b/src/lib/colonyNetwork/scripts/check-storage.js @@ -0,0 +1,47 @@ +/* eslint-disable no-console */ +import parser from "solidity-parser-antlr"; +import fs from "fs"; +import path from "path"; + +// Taken from https://gist.github.com/kethinov/6658166#gistcomment-1941504 +const walkSync = (dir, filelist = []) => { + fs.readdirSync(dir).forEach(file => { + filelist = fs.statSync(path.join(dir, file)).isDirectory() ? walkSync(path.join(dir, file), filelist) : filelist.concat(path.join(dir, file)); // eslint-disable-line no-param-reassign + }); + return filelist; +}; + +walkSync("./contracts/").forEach(contractName => { + // Contracts listed here are allowed to have storage variables + if ( + [ + "contracts/Authority.sol", + "contracts/ColonyNetworkStorage.sol", + "contracts/ColonyStorage.sol", + "contracts/EtherRouter.sol", + "contracts/Migrations.sol", + "contracts/Resolver.sol", + "contracts/ReputationMiningCycle.sol", // Does not use EtherRouter + "contracts/Token.sol", // Not directly used by any colony contracts + "contracts/PatriciaTree/PatriciaTree.sol", // Used by ReputationMiningCycle, which does not use EtherRouter + "contracts/gnosis/MultiSigWallet.sol" // Not directly used by any colony contracts + ].indexOf(contractName) > -1 + ) { + return; + } + const src = fs.readFileSync(`./${contractName}`, "utf8"); + + const result = parser.parse(src, { tolerant: true }); + // Filters out an unknown number of 'pragmas' that we have. + const contract = result.children.filter(child => child.type === "ContractDefinition")[0]; + // Check for non-constant storage variables + if (contract.subNodes.filter(child => child.type === "StateVariableDeclaration" && !child.variables[0].isDeclaredConst).length > 0) { + console.log( + "The contract ", + contractName, + " contains state variable declarations. ", + "Add new state variables to ColonyStorage instead to guarantee that the storage layout is the same between contracts." + ); + process.exit(1); + } +}); diff --git a/src/lib/colonyNetwork/scripts/eslint.sh b/src/lib/colonyNetwork/scripts/eslint.sh new file mode 100644 index 0000000..68391d0 --- /dev/null +++ b/src/lib/colonyNetwork/scripts/eslint.sh @@ -0,0 +1,8 @@ +for file in $(git diff --cached --name-only | grep -E '\.(js)$') +do + git show ":$file" | node_modules/.bin/eslint --stdin --stdin-filename "$file" # we only want to lint the staged changes, not any un-staged changes + if [ $? -ne 0 ]; then + echo "ESLint failed on staged file '$file'." + exit 1 # exit with failure status + fi +done \ No newline at end of file diff --git a/src/lib/colonyNetwork/scripts/generate-test-contracts.sh b/src/lib/colonyNetwork/scripts/generate-test-contracts.sh new file mode 100644 index 0000000..dba0044 --- /dev/null +++ b/src/lib/colonyNetwork/scripts/generate-test-contracts.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +version="$(grep 'function version() public pure returns (uint256) { return ' ./contracts/Colony.sol | sed 's/function version() public pure returns (uint256) { return //' | sed 's/; }//' | sed 's/ //g')" +echo "Current Colony contract version is $version" +updated_version=$(($version + 1)) +echo "Updating version to $updated_version" + +cp ./contracts/Resolver.sol ./contracts/UpdatedResolver.sol +sed -i.bak "s/Resolver/UpdatedResolver/g" ./contracts/UpdatedResolver.sol +sed -i.bak "s/function stringToSig/function isUpdated() public pure returns(bool) {return true;} function stringToSig/g" ./contracts/UpdatedResolver.sol +cp ./contracts/Colony.sol ./contracts/UpdatedColony.sol +cp ./contracts/IColony.sol ./contracts/IUpdatedColony.sol +cp ./contracts/ColonyNetwork.sol ./contracts/UpdatedColonyNetwork.sol +sed -i.bak "s/contract ColonyNetwork/contract UpdatedColonyNetwork/g" ./contracts/UpdatedColonyNetwork.sol +sed -i.bak "s/address resolver;/address resolver;function isUpdated() public pure returns(bool) {return true;}/g" ./contracts/UpdatedColonyNetwork.sol +sed -i.bak "s/contract Colony/contract UpdatedColony/g" ./contracts/UpdatedColony.sol +sed -i.bak "s/function version() public pure returns (uint256) { return ${version}/function version() public pure returns (uint256) { return ${updated_version}/g" ./contracts/UpdatedColony.sol +sed -i.bak "s/contract UpdatedColony is ColonyStorage, PatriciaTreeProofs {/contract UpdatedColony is ColonyStorage, PatriciaTreeProofs {function isUpdated() public pure returns(bool) {return true;}/g" ./contracts/UpdatedColony.sol +sed -i.bak "s/contract IColony/contract IUpdatedColony/g" ./contracts/IUpdatedColony.sol +sed -i.bak "s/contract IUpdatedColony {/contract IUpdatedColony {function isUpdated() public pure returns(bool);/g" ./contracts/IUpdatedColony.sol diff --git a/src/lib/colonyNetwork/scripts/resetParity.sh b/src/lib/colonyNetwork/scripts/resetParity.sh new file mode 100644 index 0000000..2ac94be --- /dev/null +++ b/src/lib/colonyNetwork/scripts/resetParity.sh @@ -0,0 +1,26 @@ +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +cd $DIR +cd .. + +if [ ! -e "./parityPassword" ] +then + echo "password" > ./parityPassword +fi + +rm -rf ./keys +rm -rf ./parity-genesis.json +mkdir ./keys + +cp ./parity-genesis.template.json ./parity-genesis.json +# We need to use gsed if it exists (i.e if we're on OSX) +# for cross-platform compatability. +if hash gsed 2>/dev/null; then + SED='gsed' +else + SED='sed' +fi +$SED -i "s/wwwww/$(parity --keys-path ./keys --password ./parityPassword account new)/g" ./parity-genesis.json +$SED -i "s/xxxxx/$(parity --keys-path ./keys --password ./parityPassword account new)/g" ./parity-genesis.json +$SED -i "s/yyyyy/$(parity --keys-path ./keys --password ./parityPassword account new)/g" ./parity-genesis.json +$SED -i "s/zzzzz/$(parity --keys-path ./keys --password ./parityPassword account new)/g" ./parity-genesis.json \ No newline at end of file diff --git a/src/lib/colonyNetwork/scripts/solium.sh b/src/lib/colonyNetwork/scripts/solium.sh new file mode 100644 index 0000000..9176dd4 --- /dev/null +++ b/src/lib/colonyNetwork/scripts/solium.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +for file in $(git diff --cached --name-only | grep -E '\.sol$') +do + git show ":$file" | node_modules/.bin/solium --stdin "$file" # we only want to lint the staged changes, not any un-staged changes + if [ $? -ne 0 ]; then + echo "Solium failed on staged file '$file'." + exit 1 # exit with failure status + fi +done diff --git a/src/lib/colonyNetwork/scripts/start-blockchain-client.sh b/src/lib/colonyNetwork/scripts/start-blockchain-client.sh new file mode 100644 index 0000000..6a32a19 --- /dev/null +++ b/src/lib/colonyNetwork/scripts/start-blockchain-client.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash + +# Exit script as soon as a command fails. +set -o errexit + +# Get the choice of client: ganache-cli is default +if [ "$1" == "parity" ]; then + bc_client=$1 +else + bc_client="ganache-cli" +fi + +echo "Chosen client $bc_client" + +bc_client_port=8545 + +bc_client_running() { + nc -z localhost "$bc_client_port" +} + +start_ganache() { + node_modules/.bin/ganache-cli --acctKeys="./ganache-accounts.json" --noVMErrorsOnRPCResponse --gasLimit 7000000 \ + --account="0x0355596cdb5e5242ad082c4fe3f8bbe48c9dba843fe1f99dd8272f487e70efae, 100000000000000000000" \ + --account="0xe9aebe8791ad1ebd33211687e9c53f13fe8cca53b271a6529c7d7ba05eda5ce2, 100000000000000000000" \ + --account="0x6f36842c663f5afc0ef3ac986ec62af9d09caa1bbf59a50cdb7334c9cc880e65, 100000000000000000000" \ + --account="0xf184b7741073fc5983df87815e66425928fa5da317ef18ef23456241019bd9c7, 100000000000000000000" \ + --account="0x7770023bfebe3c8e832b98d6c0874f75580730baba76d7ec05f2780444cc7ed3, 100000000000000000000" \ + --account="0xa9442c0092fe38933fcf2319d5cf9fd58e3be5409a26e2045929f9d2a16fb090, 100000000000000000000" \ + --account="0x06af2c8000ab1b096f2ee31539b1e8f3783236eba5284808c2b17cfb49f0f538, 100000000000000000000" \ + --account="0x7edaec9e5f8088a10b74c1d86108ce879dccded88fa9d4a5e617353d2a88e629, 100000000000000000000" \ + --account="0xe31c452e0631f67a629e88790d3119ea9505fae758b54976d2bf12bd8300ef4a, 100000000000000000000" \ + --account="0x5e383d2f98ac821c555333e5bb6109ca41ae89d613cb84887a2bdb933623c4e3, 100000000000000000000" \ + --account="0x33d2f6f6cc410c1d46d58f17efdd2b53a71527b27eaa7f2edcade351feb87425, 100000000000000000000" \ + --account="0x32400a48ff16119c134eef44e2627502ce6e367bc4810be07642275a9db47bf7, 100000000000000000000" >/dev/null 2>&1 +} + +start_parity() { + mapfile -t addresses < <( parity --keys-path ./keys account list ) + if [ ${#addresses[@]} -eq 0 ]; then + echo "No parity addresses found. Did you initialise it correctly?" + exit 1; + else + parity --chain ./parity-genesis.json \ + --author ${addresses[0]} \ + --unlock ${addresses[0]},${addresses[1]},${addresses[2]},${addresses[3]} \ + --keys-path ./keys --geth --no-dapps \ + --tx-gas-limit 0x6ACFC0 --gasprice 0x0 --gas-floor-target 0x6ACFC0 \ + --reseal-on-txs all --reseal-min-period 0 \ + --jsonrpc-interface all --jsonrpc-hosts all --jsonrpc-cors="http://localhost:3000" \ + --password ./parityPassword >/dev/null 2>&1 + fi +} + +if bc_client_running; then + echo "Using existing bc client instance at port $bc_client_port" +else + echo "Starting our own $bc_client client instance at port $bc_client_port" + if [ "$bc_client" == "parity" ]; then + start_parity + else + start_ganache + fi +fi diff --git a/src/lib/colonyNetwork/scripts/stop-blockchain-client.sh b/src/lib/colonyNetwork/scripts/stop-blockchain-client.sh new file mode 100644 index 0000000..93c3544 --- /dev/null +++ b/src/lib/colonyNetwork/scripts/stop-blockchain-client.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +pid=$(lsof -i:8545 -t); + +echo "Killing blockchain client process $pid on port 8545" +kill -TERM $pid || kill -KILL $pid \ No newline at end of file diff --git a/src/lib/colonyNetwork/scripts/version-contracts.sh b/src/lib/colonyNetwork/scripts/version-contracts.sh new file mode 100644 index 0000000..47b2b54 --- /dev/null +++ b/src/lib/colonyNetwork/scripts/version-contracts.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +version="$(grep 'function version() public pure returns (uint256) { return ' ./contracts/Colony.sol | sed 's/function version() public pure returns (uint256) { return //' | sed 's/; }//' | sed 's/ //g')" +echo "Current Colony contract version is $version" +mv ./build/contracts/Colony.json ./build/contracts/Colony_${version}.json \ No newline at end of file diff --git a/src/lib/colonyNetwork/test/colony-funding.js b/src/lib/colonyNetwork/test/colony-funding.js new file mode 100755 index 0000000..d8f1bb4 --- /dev/null +++ b/src/lib/colonyNetwork/test/colony-funding.js @@ -0,0 +1,811 @@ +/* globals artifacts */ + +import { toBN } from "web3-utils"; + +import { + MANAGER, + EVALUATOR, + WORKER, + MANAGER_ROLE, + EVALUATOR_ROLE, + WORKER_ROLE, + SPECIFICATION_HASH, + WORKER_PAYOUT, + INITIAL_FUNDING +} from "../helpers/constants"; +import { getTokenArgs, checkErrorRevert, web3GetBalance, forwardTime, bnSqrt } from "../helpers/test-helper"; +import { fundColonyWithTokens, setupRatedTask } from "../helpers/test-data-generator"; + +const EtherRouter = artifacts.require("EtherRouter"); +const IColony = artifacts.require("IColony"); +const IColonyNetwork = artifacts.require("IColonyNetwork"); +const Token = artifacts.require("Token"); + +contract("Colony Funding", addresses => { + let colony; + let token; + let otherToken; + let colonyNetwork; + + before(async () => { + const etherRouter = await EtherRouter.deployed(); + colonyNetwork = await IColonyNetwork.at(etherRouter.address); + }); + + beforeEach(async () => { + const tokenArgs = getTokenArgs(); + token = await Token.new(...tokenArgs); + const { logs } = await colonyNetwork.createColony(token.address); + const { colonyAddress } = logs[0].args; + await token.setOwner(colonyAddress); + colony = await IColony.at(colonyAddress); + const otherTokenArgs = getTokenArgs(); + otherToken = await Token.new(...otherTokenArgs); + }); + + describe("when receiving tokens", () => { + it("should not put the tokens straight in to the pot", async () => { + await otherToken.mint(100); + await otherToken.transfer(colony.address, 100); + let colonyRewardPotBalance = await colony.getPotBalance.call(0, otherToken.address); + let colonyPotBalance = await colony.getPotBalance.call(1, otherToken.address); + let colonyTokenBalance = await otherToken.balanceOf.call(colony.address); + assert.equal(colonyTokenBalance.toNumber(), 100); + assert.equal(colonyPotBalance.toNumber(), 0); + assert.equal(colonyRewardPotBalance.toNumber(), 0); + await colony.claimColonyFunds(otherToken.address); + colonyRewardPotBalance = await colony.getPotBalance.call(0, otherToken.address); + colonyPotBalance = await colony.getPotBalance.call(1, otherToken.address); + colonyTokenBalance = await otherToken.balanceOf.call(colony.address); + assert.equal(colonyTokenBalance.toNumber(), 100); + assert.equal(colonyPotBalance.toNumber(), 99); + assert.equal(colonyRewardPotBalance.toNumber(), 1); + }); + + it("should not put its own tokens in to the reward pot", async () => { + await fundColonyWithTokens(colony, token, 100); + const colonyRewardPotBalance = await colony.getPotBalance.call(0, token.address); + const colonyPotBalance = await colony.getPotBalance.call(1, token.address); + const colonyTokenBalance = await token.balanceOf.call(colony.address); + assert.equal(colonyTokenBalance.toNumber(), 100); + assert.equal(colonyPotBalance.toNumber(), 100); + assert.equal(colonyRewardPotBalance.toNumber(), 0); + }); + + it("should let tokens be moved between pots", async () => { + await fundColonyWithTokens(colony, otherToken, 100); + await colony.makeTask(SPECIFICATION_HASH, 1); + await colony.moveFundsBetweenPots(1, 2, 51, otherToken.address); + const colonyPotBalance = await colony.getPotBalance.call(1, otherToken.address); + const colonyTokenBalance = await otherToken.balanceOf.call(colony.address); + const pot2Balance = await colony.getPotBalance.call(2, otherToken.address); + assert.equal(colonyTokenBalance.toNumber(), 100); + assert.equal(colonyPotBalance.toNumber(), 48); + assert.equal(pot2Balance.toNumber(), 51); + }); + + it("should not let tokens be moved from the pot for payouts to token holders", async () => { + await fundColonyWithTokens(colony, otherToken, 100); + await colony.makeTask(SPECIFICATION_HASH, 1); + + await checkErrorRevert(colony.moveFundsBetweenPots(0, 2, 1, otherToken.address), "colonyFunding-cannot-move-funds-from-pot-0"); + const colonyPotBalance = await colony.getPotBalance.call(1, otherToken.address); + const colonyRewardPotBalance = await colony.getPotBalance.call(0, otherToken.address); + const colonyTokenBalance = await otherToken.balanceOf.call(colony.address); + const pot2Balance = await colony.getPotBalance.call(2, otherToken.address); + assert.equal(colonyTokenBalance.toNumber(), 100); + assert.equal(colonyPotBalance.toNumber(), 99); + assert.equal(pot2Balance.toNumber(), 0); + assert.equal(colonyRewardPotBalance.toNumber(), 1); + }); + + it("should not let tokens be moved by non-admins", async () => { + await fundColonyWithTokens(colony, otherToken, 100); + await colony.makeTask(SPECIFICATION_HASH, 1); + + await checkErrorRevert(colony.moveFundsBetweenPots(1, 2, 51, otherToken.address, { from: EVALUATOR })); + const colonyPotBalance = await colony.getPotBalance.call(1, otherToken.address); + const colonyTokenBalance = await otherToken.balanceOf.call(colony.address); + const pot2Balance = await colony.getPotBalance.call(2, otherToken.address); + assert.equal(colonyTokenBalance.toNumber(), 100); + assert.equal(colonyPotBalance.toNumber(), 99); + assert.equal(pot2Balance.toNumber(), 0); + }); + + it("should not allow more tokens to leave a pot than the pot has (even if the colony has that many)", async () => { + await fundColonyWithTokens(colony, otherToken, 100); + await colony.makeTask(SPECIFICATION_HASH, 1); + await colony.makeTask(SPECIFICATION_HASH, 1); + await colony.moveFundsBetweenPots(1, 2, 40, otherToken.address); + + await checkErrorRevert(colony.moveFundsBetweenPots(2, 3, 50, otherToken.address)); + const colonyPotBalance = await colony.getPotBalance.call(1, otherToken.address); + const colonyTokenBalance = await otherToken.balanceOf.call(colony.address); + const pot2Balance = await colony.getPotBalance.call(2, otherToken.address); + const pot3Balance = await colony.getPotBalance.call(3, otherToken.address); + assert.equal(colonyTokenBalance.toNumber(), 100); + assert.equal(colonyPotBalance.toNumber(), 59); + assert.equal(pot2Balance.toNumber(), 40); + assert.equal(pot3Balance.toNumber(), 0); + }); + + it("should correctly track if we are able to make token payouts", async () => { + // There are eighteen scenarios to test here. + // Pot was below payout, now equal (1 + 2) + // Pot was below payout, now above (3 + 4) + // Pot was equal to payout, now above (5 + 6) + // Pot was equal to payout, now below (7 + 8) + // Pot was above payout, now below (9 + 10) + // Pot was above payout, now equal (11 + 12) + // Pot was below payout, still below (13 + 14) + // Pot was above payout, still above (15 + 16) + // Pot was equal to payout, still equal (17 + 18) + // + // And, for each of these, we have to check that the update is correctly tracked when + // the pot changes (odd numbers), and when the payout changes (even numbers) + // + // NB We do not need to be this exhaustive when using ether, because this test is testing + // that updateTaskPayoutsWeCannotMakeAfterPotChange and updateTaskPayoutsWeCannotMakeAfterBudgetChange + // are correct, which are used in both cases. + await fundColonyWithTokens(colony, otherToken, 100); + await colony.makeTask(SPECIFICATION_HASH, 1); + await colony.setTaskRoleUser(1, WORKER_ROLE, WORKER); + // Pot 0, Payout 0 + // Pot was equal to payout, transition to pot being equal by changing payout (18) + await colony.setTaskManagerPayout(1, otherToken.address, 0); + let task = await colony.getTask.call(1); + assert.equal(task[5].toNumber(), 0); + // Pot 0, Payout 0 + // Pot was equal to payout, transition to pot being equal by changing pot (17) + await colony.moveFundsBetweenPots(1, 2, 0, otherToken.address); + task = await colony.getTask.call(1); + assert.equal(task[5].toNumber(), 0); + // Pot 0, Payout 0 + // Pot was equal to payout, transition to pot being lower by increasing payout (8) + await colony.setTaskManagerPayout(1, otherToken.address, 40); + task = await colony.getTask.call(1); + assert.equal(task[5].toNumber(), 1); + // Pot 0, Payout 40 + // Pot was below payout, transition to being equal by increasing pot (1) + await colony.moveFundsBetweenPots(1, 2, 40, otherToken.address); + task = await colony.getTask.call(1); + assert.equal(task[5].toNumber(), 0); + // Pot 40, Payout 40 + // Pot was equal to payout, transition to being above by increasing pot (5) + await colony.moveFundsBetweenPots(1, 2, 40, otherToken.address); + task = await colony.getTask.call(1); + assert.equal(task[5].toNumber(), 0); + // Pot 80, Payout 40 + // Pot was above payout, transition to being equal by increasing payout (12) + await colony.setTaskManagerPayout(1, otherToken.address, 80); + + task = await colony.getTask.call(1); + assert.equal(task[5].toNumber(), 0); + // Pot 80, Payout 80 + // Pot was equal to payout, transition to being above by decreasing payout (6) + await colony.setTaskManagerPayout(1, otherToken.address, 40); + + task = await colony.getTask.call(1); + assert.equal(task[5].toNumber(), 0); + // Pot 80, Payout 40 + // Pot was above payout, transition to being equal by decreasing pot (11) + await colony.moveFundsBetweenPots(2, 1, 40, otherToken.address); + task = await colony.getTask.call(1); + assert.equal(task[5].toNumber(), 0); + // Pot 40, Payout 40 + // Pot was equal to payout, transition to pot being below payout by changing pot (7) + await colony.moveFundsBetweenPots(2, 1, 20, otherToken.address); + task = await colony.getTask.call(1); + assert.equal(task[5].toNumber(), 1); + // Pot 20, Payout 40 + // Pot was below payout, change to being above by changing pot (3) + await colony.moveFundsBetweenPots(1, 2, 60, otherToken.address); + task = await colony.getTask.call(1); + assert.equal(task[5].toNumber(), 0); + // Pot 80, Payout 40 + // Pot was above payout, change to being below by changing pot (9) + await colony.moveFundsBetweenPots(2, 1, 60, otherToken.address); + task = await colony.getTask.call(1); + assert.equal(task[5].toNumber(), 1); + // Pot 20, Payout 40 + // Pot was below payout, change to being above by changing payout (4) + await colony.setTaskManagerPayout(1, otherToken.address, 10); + task = await colony.getTask.call(1); + assert.equal(task[5].toNumber(), 0); + // Pot 20, Payout 10 + // Pot was above, change to being above by changing payout (16) + await colony.setTaskManagerPayout(1, otherToken.address, 5); + task = await colony.getTask.call(1); + assert.equal(task[5].toNumber(), 0); + // Pot 20, Payout 5 + // Pot was above, change to being above by changing pot (15) + await colony.moveFundsBetweenPots(2, 1, 10, otherToken.address); + task = await colony.getTask.call(1); + assert.equal(task[5].toNumber(), 0); + // Pot 10, Payout 5 + // Pot was above payout, change to being below by changing payout (10) + await colony.setTaskManagerPayout(1, otherToken.address, 40); + task = await colony.getTask.call(1); + assert.equal(task[5].toNumber(), 1); + // Pot 10, Payout 40 + // Pot was below payout, change to being below by changing payout (14) + await colony.setTaskManagerPayout(1, otherToken.address, 30); + task = await colony.getTask.call(1); + assert.equal(task[5].toNumber(), 1); + // Pot 10, Payout 30 + // Pot was below payout, change to being below by changing pot (13) + await colony.moveFundsBetweenPots(2, 1, 5, otherToken.address); + task = await colony.getTask.call(1); + assert.equal(task[5].toNumber(), 1); + // Pot 5, Payout 30 + // Pot was below payout, change to being equal by changing payout (2) + await colony.setTaskManagerPayout(1, otherToken.address, 5); + task = await colony.getTask.call(1); + assert.equal(task[5].toNumber(), 0); + // Pot 5, Payout 5 + }); + + it("should pay fees on revenue correctly", async () => { + await fundColonyWithTokens(colony, otherToken, 100); + await fundColonyWithTokens(colony, otherToken, 200); + const colonyPotBalance = await colony.getPotBalance.call(1, otherToken.address); + const colonyRewardPotBalance = await colony.getPotBalance.call(0, otherToken.address); + const colonyTokenBalance = await otherToken.balanceOf.call(colony.address); + assert.equal(colonyTokenBalance.toNumber(), 300); + assert.equal(colonyRewardPotBalance.toNumber(), 3); + assert.equal(colonyPotBalance.toNumber(), 297); + }); + + it("should not allow contributions to nonexistent pots", async () => { + await fundColonyWithTokens(colony, otherToken, 100); + await checkErrorRevert(colony.moveFundsBetweenPots(1, 5, 40, otherToken.address)); + const colonyPotBalance = await colony.getPotBalance.call(1, otherToken.address); + assert.equal(colonyPotBalance.toNumber(), 99); + }); + + it("should not allow funds to be removed from a task with payouts to go", async () => { + await fundColonyWithTokens(colony, otherToken, INITIAL_FUNDING); + const taskId = await setupRatedTask({ colonyNetwork, colony, token: otherToken }); + await colony.finalizeTask(taskId); + await checkErrorRevert(colony.moveFundsBetweenPots(2, 1, 40, otherToken.address)); + const colonyPotBalance = await colony.getPotBalance.call(2, otherToken.address); + assert.equal(colonyPotBalance.toNumber(), 350 * 1e18); + }); + + it("should allow funds to be removed from a task if there are no more payouts of that token to be claimed", async () => { + await fundColonyWithTokens(colony, otherToken, 363 * 1e18); + const taskId = await setupRatedTask({ colonyNetwork, colony, token: otherToken }); + await colony.moveFundsBetweenPots(1, 2, 10, otherToken.address); + await colony.finalizeTask(taskId); + await colony.claimPayout(taskId, MANAGER_ROLE, otherToken.address); + await colony.claimPayout(taskId, WORKER_ROLE, otherToken.address, { from: WORKER }); + await colony.claimPayout(taskId, EVALUATOR_ROLE, otherToken.address, { from: EVALUATOR }); + await colony.moveFundsBetweenPots(2, 1, 10, otherToken.address); + + const colonyPotBalance = await colony.getPotBalance.call(2, otherToken.address); + assert.equal(colonyPotBalance.toNumber(), 0); + }); + + it("should not allow user to claim payout if rating is 1", async () => { + await fundColonyWithTokens(colony, token, INITIAL_FUNDING); + const taskId = await setupRatedTask({ + colonyNetwork, + colony, + token, + workerRating: 1 + }); + await colony.finalizeTask(taskId); + const payout = await colony.getTaskPayout.call(taskId, WORKER_ROLE, token.address); + assert.equal(payout.toNumber(), 0, "should have worker payout of 0"); + + const taskInfo = await colony.getTask.call(taskId); + await colony.claimPayout(taskId, MANAGER_ROLE, token.address, { + from: MANAGER + }); + await colony.claimPayout(taskId, EVALUATOR_ROLE, token.address, { + from: EVALUATOR + }); + await colony.claimPayout(taskId, WORKER_ROLE, token.address, { + from: WORKER + }); + const remainingPotBalance = await colony.getPotBalance(taskInfo[6].toNumber(), token.address); + assert.equal(remainingPotBalance.toString(), WORKER_PAYOUT.toString(), "should have remaining pot balance equal to worker payout"); + + await colony.moveFundsBetweenPots(taskInfo[6].toNumber(), 1, remainingPotBalance.toString(), token.address); + + const potBalance = await colony.getPotBalance(taskInfo[6].toNumber(), token.address); + assert.equal(potBalance, 0, "should have pot balance of 0"); + }); + }); + + describe("when receiving ether", () => { + it("should not put the ether straight in to the pot", async () => { + await colony.send(100); + let colonyPotBalance = await colony.getPotBalance.call(1, 0x0); + let colonyEtherBalance = await web3GetBalance(colony.address); + let colonyRewardBalance = await colony.getPotBalance.call(0, 0x0); + assert.equal(colonyEtherBalance.toNumber(), 100); + assert.equal(colonyPotBalance.toNumber(), 0); + await colony.claimColonyFunds(0x0); + colonyPotBalance = await colony.getPotBalance.call(1, 0x0); + colonyEtherBalance = await web3GetBalance(colony.address); + colonyRewardBalance = await colony.getPotBalance.call(0, 0x0); + assert.equal(colonyEtherBalance.toNumber(), 100); + assert.equal(colonyRewardBalance.toNumber(), 1); + assert.equal(colonyPotBalance.toNumber(), 99); + }); + + it("should let ether be moved between pots", async () => { + await colony.send(100); + await colony.claimColonyFunds(0x0); + await colony.makeTask(SPECIFICATION_HASH, 1); + await colony.moveFundsBetweenPots(1, 2, 51, 0x0); + const colonyPotBalance = await colony.getPotBalance.call(1, 0x0); + const colonyEtherBalance = await web3GetBalance(colony.address); + const pot2Balance = await colony.getPotBalance.call(2, 0x0); + assert.equal(colonyEtherBalance.toNumber(), 100); + assert.equal(colonyPotBalance.toNumber(), 48); + assert.equal(pot2Balance.toNumber(), 51); + }); + + it("should not allow more ether to leave a pot than the pot has (even if the colony has that many)", async () => { + await colony.send(100); + await colony.claimColonyFunds(0x0); + await colony.makeTask(SPECIFICATION_HASH, 1); + await colony.makeTask(SPECIFICATION_HASH, 1); + await colony.moveFundsBetweenPots(1, 2, 40, 0x0); + + await checkErrorRevert(colony.moveFundsBetweenPots(2, 3, 50, 0x0)); + const colonyEtherBalance = await web3GetBalance(colony.address); + const colonyPotBalance = await colony.getPotBalance.call(1, 0x0); + const pot2Balance = await colony.getPotBalance.call(2, 0x0); + const pot3Balance = await colony.getPotBalance.call(3, 0x0); + assert.equal(colonyEtherBalance.toNumber(), 100); + assert.equal(colonyPotBalance.toNumber(), 59); + assert.equal(pot2Balance.toNumber(), 40); + assert.equal(pot3Balance.toNumber(), 0); + }); + + it("should correctly track if we are able to make ether payouts", async () => { + await colony.send(100); + await colony.claimColonyFunds(0x0); + await colony.makeTask(SPECIFICATION_HASH, 1); + await colony.setTaskRoleUser(1, WORKER_ROLE, WORKER); + + await colony.setTaskManagerPayout(1, 0x0, 40); + + let task = await colony.getTask.call(1); + assert.equal(task[5].toNumber(), 1); + await colony.moveFundsBetweenPots(1, 2, 40, 0x0); + task = await colony.getTask.call(1); + assert.equal(task[5].toNumber(), 0); + await colony.moveFundsBetweenPots(2, 1, 30, 0x0); + task = await colony.getTask.call(1); + assert.equal(task[5].toNumber(), 1); + + await colony.setTaskManagerPayout(1, 0x0, 10); + + task = await colony.getTask.call(1); + assert.equal(task[5].toNumber(), 0); + }); + + it("should pay fees on revenue correctly", async () => { + await colony.send(100); + await colony.claimColonyFunds(0x0); + await colony.send(200); + await colony.claimColonyFunds(0x0); + const colonyPotBalance = await colony.getPotBalance.call(1, 0x0); + const colonyRewardPotBalance = await colony.getPotBalance.call(0, 0x0); + const colonyEtherBalance = await web3GetBalance(colony.address); + const nonRewardPotsTotal = await colony.getNonRewardPotsTotal.call(0x0); + assert.equal(colonyEtherBalance.toNumber(), 300); + assert.equal(colonyPotBalance.toNumber(), 297); + assert.equal(colonyRewardPotBalance.toNumber(), 3); + assert.equal(nonRewardPotsTotal.toNumber(), 297); + }); + }); + + describe("when creating reward payouts", async () => { + const initialFunding = toBN(100 * 1e18); + const totalReputation = toBN(80 * 1e18); + const userReputation1 = toBN(50 * 1e18); + const userReputation2 = toBN(30 * 1e18); + const userAddress1 = addresses[0]; + const userAddress2 = addresses[1]; + const userAddress3 = addresses[2]; + let initialSquareRoots1; + let initialSquareRoots2; + + beforeEach(async () => { + await fundColonyWithTokens(colony, otherToken, initialFunding.toString()); + await colony.mintTokens(initialFunding.toString()); + await colony.bootstrapColony([userAddress1, userAddress2], [userReputation1.toString(), userReputation2.toString()]); + + const userReputation1Sqrt = bnSqrt(userReputation1); + const userReputation2Sqrt = bnSqrt(userReputation2); + + const totalReputationSqrt = bnSqrt(totalReputation); + const totalTokensSqrt = bnSqrt(userReputation1.add(userReputation2)); + + const numerator1Sqrt = bnSqrt(userReputation1Sqrt.mul(userReputation1Sqrt)); + const numerator2Sqrt = bnSqrt(userReputation2Sqrt.mul(userReputation2Sqrt)); + const denominatorSqrt = bnSqrt(totalReputationSqrt.mul(totalTokensSqrt)); + + const totalAmountSqrt = bnSqrt(initialFunding.div(toBN(100))); + + initialSquareRoots1 = [ + userReputation1Sqrt.toString(), + userReputation1Sqrt.toString(), + totalReputationSqrt.toString(), + totalTokensSqrt.toString(), + numerator1Sqrt.toString(), + denominatorSqrt.toString(), + totalAmountSqrt.toString() + ]; + + initialSquareRoots2 = [ + userReputation2Sqrt.toString(), + userReputation2Sqrt.toString(), + totalReputationSqrt.toString(), + totalTokensSqrt.toString(), + numerator2Sqrt.toString(), + denominatorSqrt.toString(), + totalAmountSqrt.toString() + ]; + }); + + it("should be able to get global reward payout count", async () => { + await colony.startNextRewardPayout(otherToken.address); + + const count = await colony.getGlobalRewardPayoutCount.call(); + assert.equal(count.toNumber(), 1); + }); + + it("should be able to get user reward payout count", async () => { + const tx = await colony.startNextRewardPayout(otherToken.address); + const payoutId = tx.logs[0].args.id; + + await colony.claimRewardPayout(payoutId, initialSquareRoots1, userReputation1.toString(), totalReputation.toString(), { + from: userAddress1 + }); + + const count = await colony.getUserRewardPayoutCount.call(userAddress1); + assert.equal(count.toNumber(), 1); + }); + + it("should not be able to create parallel payouts of the same token", async () => { + await colony.startNextRewardPayout(otherToken.address); + + await checkErrorRevert(colony.startNextRewardPayout(otherToken.address), "colony-reward-payout-token-active"); + }); + + it("should be able to collect rewards from multiple payouts of different token", async () => { + const tokenArgs = getTokenArgs(); + const newToken = await Token.new(...tokenArgs); + await fundColonyWithTokens(colony, newToken, initialFunding.toString()); + + const tx1 = await colony.startNextRewardPayout(newToken.address); + const payoutId1 = tx1.logs[0].args.id; + + const tx2 = await colony.startNextRewardPayout(otherToken.address); + const payoutId2 = tx2.logs[0].args.id; + + await colony.claimRewardPayout(payoutId1, initialSquareRoots1, userReputation1.toString(), totalReputation.toString(), { + from: userAddress1 + }); + + await colony.claimRewardPayout(payoutId2, initialSquareRoots1, userReputation1.toString(), totalReputation.toString(), { + from: userAddress1 + }); + }); + + it("should not be able to claim tokens if user does not have any tokens", async () => { + const userReputation3 = toBN(10 * 1e18); + await colony.bootstrapColony([userAddress3], [userReputation3.toString()]); + await token.transfer(colony.address, userReputation3.toString(), { + from: userAddress3 + }); + + const { logs } = await colony.startNextRewardPayout(otherToken.address); + const payoutId = logs[0].args.id; + + const userReputation3Sqrt = bnSqrt(userReputation3); + const totalReputation3 = userReputation1.add(userReputation2).add(userReputation3); + const totalReputationSqrt = bnSqrt(totalReputation3); + const totalTokensSqrt = bnSqrt(userReputation1.add(userReputation2)); + const denominatorSqrt = bnSqrt(totalReputation.mul(totalReputation3)); + const info = await colony.getRewardPayoutInfo(payoutId); + const amountSqrt = bnSqrt(info[2]); + + const squareRoots = [ + userReputation3Sqrt.toString(), + 0, + totalReputationSqrt.toString(), + totalTokensSqrt.toString(), + 0, + denominatorSqrt.toString(), + amountSqrt.toString() + ]; + + await checkErrorRevert( + colony.claimRewardPayout(payoutId, squareRoots, userReputation3.toString(), totalReputation.toString(), { + from: userAddress3 + }), + "colony-reward-payout-invalid-user-tokens" + ); + }); + + it("should not be able to claim tokens if user does not have any reputation", async () => { + const userTokens3 = toBN(1e3); + await token.transfer(userAddress3, userTokens3.toString()); + + const { logs } = await colony.startNextRewardPayout(otherToken.address); + const payoutId = logs[0].args.id; + + const userTokens3Sqrt = bnSqrt(userTokens3); + const totalReputationSqrt = bnSqrt(totalReputation); + const totalTokensSqrt = bnSqrt(userReputation1.add(userReputation2).add(userTokens3)); + const denominatorSqrt = bnSqrt(totalReputation.mul(totalTokensSqrt)); + const info = await colony.getRewardPayoutInfo(payoutId); + const amountSqrt = bnSqrt(info[2]); + + const squareRoots = [ + 0, + userTokens3Sqrt.toString(), + totalReputationSqrt.toString(), + totalTokensSqrt.toString(), + 0, + denominatorSqrt.toString(), + amountSqrt.toString() + ]; + + await checkErrorRevert( + colony.claimRewardPayout(payoutId, squareRoots, 0, totalReputation.toString(), { + from: userAddress3 + }), + "colony-reward-payout-invalid-user-reputation" + ); + }); + + it.skip("should lock tokens when new payout cycle has started", async () => { + await colony.startNextRewardPayout(otherToken.address); + + await checkErrorRevert(otherToken.transfer(userAddress1, 1e3)); + }); + + it.skip("should be able to send tokens after claiming the reward", async () => { + const { logs } = await colony.startNextRewardPayout(otherToken.address); + const payoutId = logs[0].args.id; + + await colony.claimRewardPayout(payoutId, initialSquareRoots1, userReputation1.toString(), totalReputation.toString(), { + from: userAddress1 + }); + + await colony.claimRewardPayout(payoutId, initialSquareRoots2, userReputation2.toString(), totalReputation.toString(), { + from: userAddress2 + }); + + await otherToken.transfer(userAddress2, 1e3, { + from: userAddress1 + }); + }); + + it("should not be able to claim tokens after the payout period has expired", async () => { + const { logs } = await colony.startNextRewardPayout(otherToken.address); + const payoutId = logs[0].args.id; + + await forwardTime(5184001, this); + await checkErrorRevert( + colony.claimRewardPayout(payoutId, initialSquareRoots1, userReputation1.toString(), totalReputation.toString(), { + from: userAddress1 + }), + "colony-reward-payout-not-active" + ); + }); + + it("should be able to waive the payout", async () => { + const { logs } = await colony.startNextRewardPayout(otherToken.address); + const payoutId = logs[0].args.id; + + await colony.waiveRewardPayouts(1, { + from: userAddress1 + }); + await checkErrorRevert( + colony.claimRewardPayout(payoutId, initialSquareRoots1, userReputation1.toString(), totalReputation.toString(), { + from: userAddress1 + }), + "colony-reward-payout-bad-id" + ); + }); + + it("should not be able to waive more payouts than there are unclaimed payouts", async () => { + await colony.startNextRewardPayout(otherToken.address); + + await checkErrorRevert( + colony.waiveRewardPayouts(2, { + from: userAddress1 + }), + "colony-reward-payout-invalid-num-payouts" + ); + }); + + it("should not be able to claim funds if previous payout is not claimed", async () => { + await colony.startNextRewardPayout(otherToken.address); + + const { logs } = await colony.startNextRewardPayout(token.address); + const payoutId2 = logs[0].args.id; + + await checkErrorRevert( + colony.claimRewardPayout(payoutId2, initialSquareRoots1, userReputation1.toString(), totalReputation.toString(), { + from: userAddress1 + }), + "colony-reward-payout-bad-id" + ); + }); + + it("should not be able to claim payout if squareRoots are not valid", async () => { + const tx = await colony.startNextRewardPayout(otherToken.address); + const payoutId = tx.logs[0].args.id; + + const errorMessages = [ + "colony-reward-payout-invalid-parametar-user-reputation", + "colony-reward-payout-invalid-parametar-user-token", + "colony-reward-payout-invalid-parametar-total-reputation", + "colony-reward-payout-invalid-parametar-total-tokens", + "colony-reward-payout-invalid-parametar-amount", + "colony-reward-payout-invalid-parametar-numerator", + "colony-reward-payout-invalid-parametar-denominator" + ]; + + initialSquareRoots1.forEach(async (param, i) => { + const squareRoots = [...initialSquareRoots1]; + squareRoots[i] = toBN(squareRoots[i]) + .mul(toBN(2)) + .toString(); + + await checkErrorRevert( + colony.claimRewardPayout(payoutId, squareRoots, userReputation1.toString(), totalReputation.toString(), { + from: userAddress1 + }), + errorMessages[i] + ); + }); + }); + + it("should be able to finalize reward payout and start new one", async () => { + const tx = await colony.startNextRewardPayout(otherToken.address); + const payoutId = tx.logs[0].args.id; + + await forwardTime(5184001, this); + await colony.finalizeRewardPayout(payoutId); + + await colony.startNextRewardPayout(otherToken.address); + }); + + const reputations = [ + { + totalReputation: toBN(3), + totalAmount: toBN(90000000) + }, + { + totalReputation: toBN(30), + totalAmount: toBN(90000000) + }, + { + totalReputation: toBN(30000000000), + totalAmount: toBN(90000000000) + }, + { + totalReputation: toBN(3).mul(toBN(10).pow(toBN(76))), + totalAmount: toBN(9).mul(toBN(10).pow(toBN(76))) + }, + { + totalReputation: toBN(2) + .pow(toBN(256)) + .sub(toBN(1)), + totalAmount: toBN(2) + .pow(toBN(256)) + .sub(toBN(1)) + } + ]; + + reputations.forEach(data => + it(`should calculate fairly precise reward payout for: + user reputation/tokens: ${data.totalReputation.div(toBN(3)).toString()} + total reputation/tokens: ${data.totalReputation.toString()}`, async () => { + const tokenArgs = getTokenArgs(); + const newToken = await Token.new(...tokenArgs); + let { logs } = await colonyNetwork.createColony(newToken.address); + const { colonyAddress } = logs[0].args; + await newToken.setOwner(colonyAddress); + const newColony = await IColony.at(colonyAddress); + + const payoutTokenArgs = getTokenArgs(); + const payoutToken = await Token.new(...payoutTokenArgs); + await fundColonyWithTokens(newColony, payoutToken, data.totalAmount.toString()); + await newColony.mintTokens(data.totalAmount.toString()); + + const userReputation = data.totalReputation.div(toBN(3)); + await newColony.bootstrapColony( + [userAddress1, userAddress2, userAddress3], + [userReputation.toString(), userReputation.toString(), userReputation.toString()] + ); + + ({ logs } = await newColony.startNextRewardPayout(payoutToken.address)); + const payoutId = logs[0].args.id.toNumber(); + + const rewardPayoutInfo = await newColony.getRewardPayoutInfo(payoutId); + const amount = rewardPayoutInfo[2]; + + const totalSupply = await newToken.totalSupply(); + const colonyTokens = await newToken.balanceOf(newColony.address); + const totalTokens = totalSupply.sub(colonyTokens); + const userTokens = await newToken.balanceOf(userAddress1); + + const numerator = userTokens.mul(userReputation).sqrt(); + const denominator = totalTokens.mul(data.totalReputation).sqrt(); + const factor = toBN(10).pow(toBN(100)); + const a = numerator.mul(factor).div(denominator); + const reward = amount.mul(a).div(factor); + + const userReputationSqrt = bnSqrt(userReputation); + const userTokensSqrt = bnSqrt(userTokens); + const totalReputationSqrt = bnSqrt(data.totalReputation); + const totalTokensSqrt = bnSqrt(totalTokens); + const numeratorSqrt = bnSqrt(numerator); + const denominatorSqrt = bnSqrt(denominator); + const amountSqrt = bnSqrt(amount); + + const squareRoots = [ + userReputationSqrt.toString(), + userTokensSqrt.toString(), + totalReputationSqrt.toString(), + totalTokensSqrt.toString(), + numeratorSqrt.toString(), + denominatorSqrt.toString(), + amountSqrt.toString() + ]; + + await newColony.claimRewardPayout(payoutId, squareRoots, userReputation.toString(), data.totalReputation.toString(), { + from: userAddress1 + }); + + const remainingAfterClaim1 = await newColony.getPotBalance(0, payoutToken.address); + + const solidityReward = amount.sub(remainingAfterClaim1); + console.log("\nCorrect (Javascript): ", reward.toString()); + console.log("Approximation (Solidity): ", solidityReward.toString()); + + console.log( + "Percentage Wrong: ", + solidityReward + .minus(reward) + .div(reward) + .times(100) + .toString(), + "%" + ); + console.log("Absolute Wrong: ", solidityReward.sub(reward).toString(), "\n"); + + console.log("Total Amount: ", amount.toString()); + console.log("Remaining after claim 1: ", remainingAfterClaim1.toString()); + + await newColony.claimRewardPayout(payoutId, squareRoots, userReputation.toString(), data.totalReputation.toString(), { + from: userAddress2 + }); + + const remainingAfterClaim2 = await newColony.getPotBalance(0, payoutToken.address); + + console.log("Remaining after claim 2: ", remainingAfterClaim2.toString()); + + await newColony.claimRewardPayout(payoutId, squareRoots, userReputation.toString(), data.totalReputation.toString(), { + from: userAddress3 + }); + + const remainingAfterClaim3 = await newColony.getPotBalance(0, payoutToken.address); + + console.log("Remaining after claim 3: ", remainingAfterClaim3.toString()); + }) + ); + }); +}); diff --git a/src/lib/colonyNetwork/test/colony-network-auction.js b/src/lib/colonyNetwork/test/colony-network-auction.js new file mode 100644 index 0000000..acefb7f --- /dev/null +++ b/src/lib/colonyNetwork/test/colony-network-auction.js @@ -0,0 +1,448 @@ +/* globals artifacts */ +import { BN } from "bn.js"; + +import { getTokenArgs, web3GetTransactionReceipt, web3GetCode, checkErrorRevert, forwardTime, getBlockTime } from "../helpers/test-helper"; +import { giveUserCLNYTokens } from "../helpers/test-data-generator"; + +const EtherRouter = artifacts.require("EtherRouter"); +const IColony = artifacts.require("IColony"); +const IColonyNetwork = artifacts.require("IColonyNetwork"); +const DutchAuction = artifacts.require("DutchAuction"); +const Token = artifacts.require("Token"); + +contract("ColonyNetworkAuction", accounts => { + const BIDDER_1 = accounts[1]; + const BIDDER_2 = accounts[2]; + const BIDDER_3 = accounts[3]; + + let metaColony; + let colonyNetwork; + let tokenAuction; + let quantity; + let clnyNeededForMaxPriceAuctionSellout; + let clny; + let token; + + before(async () => { + quantity = new BN(10).pow(new BN(36)).muln(3); + clnyNeededForMaxPriceAuctionSellout = new BN(10).pow(new BN(54)).muln(3); + const etherRouter = await EtherRouter.deployed(); + colonyNetwork = IColonyNetwork.at(etherRouter.address); + + const metaColonyAddress = await colonyNetwork.getMetaColony.call(); + metaColony = IColony.at(metaColonyAddress); + }); + + beforeEach(async () => { + clny = await Token.new("Colony Network Token", "CLNY", 18); + await metaColony.setToken(clny.address); + await clny.setOwner(metaColony.address); + + const args = getTokenArgs(); + token = await Token.new(...args); + await token.mint(quantity.toString()); + await token.transfer(colonyNetwork.address, quantity.toString()); + const { logs } = await colonyNetwork.startTokenAuction(token.address); + const auctionAddress = logs[0].args.auction; + tokenAuction = DutchAuction.at(auctionAddress); + }); + + describe("when initialising an auction", async () => { + it("should initialise auction with correct given parameters", async () => { + const clnyAddress = await tokenAuction.clnyToken.call(); + assert.equal(clnyAddress, clny.address); + const tokenAddress = await tokenAuction.token.call(); + assert.equal(tokenAddress, token.address); + }); + + it("should fail with 0x0 token", async () => { + await checkErrorRevert(colonyNetwork.startTokenAuction("0x0")); + }); + + it("should fail if auction is initialised for the CLNY token", async () => { + await checkErrorRevert(colonyNetwork.startTokenAuction(clny.address)); + }); + + it("should fail with zero quantity", async () => { + const args = getTokenArgs(); + const otherToken = await Token.new(...args); + const { logs } = await colonyNetwork.startTokenAuction(otherToken.address); + const auctionAddress = logs[0].args.auction; + tokenAuction = DutchAuction.at(auctionAddress); + await checkErrorRevert(tokenAuction.start()); + }); + }); + + describe("when starting an auction", async () => { + it("should set the `quantity` correctly and minPrice to 1", async () => { + await tokenAuction.start(); + const quantityNow = await tokenAuction.quantity.call(); + assert.equal(quantityNow.toString(10), quantity.toString()); + + const minPrice = await tokenAuction.minPrice.call(); + assert.equal(minPrice.toString(10), 1); + }); + + it("should set the minimum price correctly for quantity < 1e18", async () => { + const args = getTokenArgs(); + const otherToken = await Token.new(...args); + await otherToken.mint(1e17); + await otherToken.transfer(colonyNetwork.address, 1e17); + const { logs } = await colonyNetwork.startTokenAuction(otherToken.address); + const auctionAddress = logs[0].args.auction; + tokenAuction = DutchAuction.at(auctionAddress); + await tokenAuction.start(); + const minPrice = await tokenAuction.minPrice.call(); + assert.equal(minPrice.toString(10), 10); + }); + + it("should set the `startTime` correctly", async () => { + const tx = await tokenAuction.start(); + const txReceiptBlockNumber = tx.receipt.blockNumber; + const blockTime = await getBlockTime(txReceiptBlockNumber); + + const startTime = await tokenAuction.startTime.call(); + assert.equal(startTime.toNumber(), blockTime); + }); + + it("should set the `started` property correctly", async () => { + await tokenAuction.start(); + + const started = await tokenAuction.started.call(); + assert.isTrue(started); + }); + + it("should fail starting the auction twice", async () => { + await tokenAuction.start(); + await checkErrorRevert(tokenAuction.start()); + }); + + it("cannot bid before the auction is open", async () => { + await giveUserCLNYTokens(colonyNetwork, BIDDER_1, "1000000000000000000"); + await clny.approve(tokenAuction.address, "1000000000000000000", { from: BIDDER_1 }); + await checkErrorRevert(tokenAuction.bid("1000000000000000000", { from: BIDDER_1 })); + }); + + const auctionProps = [ + { + duration: 1000, + price: new BN("989583333333333333333333333333333333") + }, + { + duration: 72000, + price: new BN("250000000000000000000000000000000000") + }, + { + duration: 86400, + price: new BN(10).pow(new BN(35)) + }, + { + duration: 144000, + price: new BN("40000000000000000000000000000000000") + }, + { + duration: 172800, + price: new BN(10).pow(new BN(34)) + }, + { + duration: 259200, + price: new BN(10).pow(new BN(33)) + }, + { + duration: 345600, + price: new BN(10).pow(new BN(32)) + }, + { + duration: 432000, + price: new BN(10).pow(new BN(31)) + }, + { + duration: 518400, + price: new BN(10).pow(new BN(30)) + }, + { + duration: 1382400, + price: new BN(10).pow(new BN(20)) + }, + { + duration: 2937600, + price: new BN(100) + }, + { + duration: 3110400, + price: new BN(1) + }, + { + duration: 3193200, // Crosses the boundary where price of 1 is always returned (for quantity > 1e18) + price: new BN(1) + } + ]; + + auctionProps.forEach(async auctionProp => { + it(`should correctly calculate price and remaining CLNY amount to end auction at duration ${auctionProp.duration}`, async () => { + await tokenAuction.start(); + + await forwardTime(auctionProp.duration, this); + const currentPrice = await tokenAuction.price.call(); + // Expect up to 1% error margin because of forwarding block time inaccuracies + const errorMarginPrice = auctionProp.price.divn(100); + const currentPriceString = currentPrice.toString(10); + // Chai assert.closeTo does not work with Big Numbers so some manual comaring to error margin is required + const differencePrices = auctionProp.price.sub(new BN(currentPriceString)); + assert.isTrue(differencePrices.lte(errorMarginPrice)); + + const totalToEndAuction = await tokenAuction.totalToEndAuction.call(); + const amount = new BN(currentPriceString).mul(quantity).div(new BN(10).pow(new BN(18))); + const errorMarginQuantity = amount.divn(100); + const differenceQuantity = totalToEndAuction.sub(amount); + assert.isTrue(differenceQuantity.lte(errorMarginQuantity)); + }); + }); + }); + + describe("when bidding", async () => { + beforeEach(async () => { + await tokenAuction.start(); + }); + + it("can bid", async () => { + await giveUserCLNYTokens(colonyNetwork, BIDDER_1, "1000000000000000000"); + await clny.approve(tokenAuction.address, "1000000000000000000", { from: BIDDER_1 }); + await tokenAuction.bid("1000000000000000000", { from: BIDDER_1 }); + const bid = await tokenAuction.bids.call(BIDDER_1); + assert.equal(bid, "1000000000000000000"); + const bidCount = await tokenAuction.bidCount.call(); + assert.equal(bidCount.toNumber(), 1); + }); + + it("bid tokens are locked", async () => { + await giveUserCLNYTokens(colonyNetwork, BIDDER_1, "1000000000000000000"); + await clny.approve(tokenAuction.address, "1000000000000000000", { from: BIDDER_1 }); + await tokenAuction.bid("1000000000000000000", { from: BIDDER_1 }); + const lockedTokens = await clny.balanceOf.call(tokenAuction.address); + assert.equal(lockedTokens.toString(), "1000000000000000000"); + }); + + it("can bid more than once", async () => { + await giveUserCLNYTokens(colonyNetwork, BIDDER_1, "2000000000000000000"); + await clny.approve(tokenAuction.address, "2000000000000000000", { from: BIDDER_1 }); + await tokenAuction.bid("1100000000000000000", { from: BIDDER_1 }); + await tokenAuction.bid("900000000000000000", { from: BIDDER_1 }); + const bidCount = await tokenAuction.bidCount.call(); + assert.equal(bidCount.toNumber(), 1); + }); + + it("once target reached, endTime is set correctly", async () => { + const amount = clnyNeededForMaxPriceAuctionSellout.divn(3).toString(); + await giveUserCLNYTokens(colonyNetwork, BIDDER_1, amount); + await giveUserCLNYTokens(colonyNetwork, BIDDER_2, amount); + await giveUserCLNYTokens(colonyNetwork, BIDDER_3, amount); + await clny.approve(tokenAuction.address, amount, { from: BIDDER_1 }); + await clny.approve(tokenAuction.address, amount, { from: BIDDER_2 }); + await clny.approve(tokenAuction.address, amount, { from: BIDDER_3 }); + await tokenAuction.bid(amount, { from: BIDDER_1 }); + await tokenAuction.bid(amount, { from: BIDDER_2 }); + + const { tx } = await tokenAuction.bid(amount, { from: BIDDER_3 }); + const receipt = await web3GetTransactionReceipt(tx); + const bidReceiptBlock = receipt.blockNumber; + const blockTime = await getBlockTime(bidReceiptBlock); + const endTime = await tokenAuction.endTime.call(); + assert.equal(endTime.toString(), blockTime); + + const bidCount = await tokenAuction.bidCount.call(); + assert.equal(bidCount.toNumber(), 3); + }); + + it("if bid overshoots the target quantity, it is only partially accepted", async () => { + const amount = clnyNeededForMaxPriceAuctionSellout.addn(20).toString(); + await giveUserCLNYTokens(colonyNetwork, BIDDER_1, amount); + await clny.approve(tokenAuction.address, amount, { from: BIDDER_1 }); + const totalToEndAuction = await tokenAuction.totalToEndAuction.call(); + await tokenAuction.bid(amount, { from: BIDDER_1 }); + const receivedTotal = await tokenAuction.receivedTotal.call(); + const bid = await tokenAuction.bids.call(BIDDER_1); + assert(bid.lte(totalToEndAuction)); + assert(receivedTotal.lte(totalToEndAuction)); + assert.equal(receivedTotal.toString(), bid.toString()); + }); + + it("after target is sold, bid is rejected", async () => { + await giveUserCLNYTokens(colonyNetwork, BIDDER_1, clnyNeededForMaxPriceAuctionSellout.addn(1).toString()); + await clny.approve(tokenAuction.address, clnyNeededForMaxPriceAuctionSellout.addn(1).toString(), { from: BIDDER_1 }); + await tokenAuction.bid(clnyNeededForMaxPriceAuctionSellout.toString(), { from: BIDDER_1 }); + await checkErrorRevert(tokenAuction.bid(1, { from: BIDDER_1 })); + }); + + it("cannot finalize when target not reached", async () => { + await giveUserCLNYTokens(colonyNetwork, BIDDER_1, "3000"); + await clny.approve(tokenAuction.address, "3000", { from: BIDDER_1 }); + await tokenAuction.bid("3000", { from: BIDDER_1 }); + await checkErrorRevert(tokenAuction.finalize()); + }); + + it("cannot bid with 0 tokens", async () => { + await checkErrorRevert(tokenAuction.bid(0)); + }); + }); + + describe("when finalizing auction", async () => { + beforeEach(async () => { + await tokenAuction.start(); + await giveUserCLNYTokens(colonyNetwork, BIDDER_1, clnyNeededForMaxPriceAuctionSellout.toString()); + await clny.approve(tokenAuction.address, clnyNeededForMaxPriceAuctionSellout.toString(), { from: BIDDER_1 }); + await tokenAuction.bid(clnyNeededForMaxPriceAuctionSellout.toString(), { from: BIDDER_1 }); + }); + + it("sets correct final token price", async () => { + await tokenAuction.finalize(); + const receivedTotal = await tokenAuction.receivedTotal.call(); + const endPrice = new BN(10) + .pow(new BN(18)) + .mul(new BN(receivedTotal.toString(10))) + .div(quantity) + .addn(1); + const finalPrice = await tokenAuction.finalPrice.call(); + assert.equal(endPrice.toString(), finalPrice.toString(10)); + }); + + it("sets the finalized property", async () => { + await tokenAuction.finalize(); + const finalized = await tokenAuction.finalized.call(); + assert.isTrue(finalized); + }); + + it("Colony network gets all CLNY sent to the auction in bids", async () => { + const balanceBefore = await clny.balanceOf.call(colonyNetwork.address); + await tokenAuction.finalize(); + const receivedTotal = await tokenAuction.receivedTotal.call(); + assert.notEqual(receivedTotal.toNumber(), 0); + const balanceAfter = await clny.balanceOf.call(colonyNetwork.address); + assert.equal(balanceBefore.add(receivedTotal).toString(), balanceAfter.toString()); + }); + + it("cannot bid after finalized", async () => { + await tokenAuction.finalize(); + await giveUserCLNYTokens(colonyNetwork, BIDDER_1, 1000); + await clny.approve(tokenAuction.address, 1000, { from: BIDDER_1 }); + await checkErrorRevert(tokenAuction.bid(1000, { from: BIDDER_1 })); + }); + + it("cannot finalize after finalized once", async () => { + await tokenAuction.finalize(); + await checkErrorRevert(tokenAuction.finalize()); + }); + + it("cannot claim if not finalized", async () => { + await checkErrorRevert(tokenAuction.claim({ from: BIDDER_1 })); + }); + }); + + describe("when claiming tokens", async () => { + it("should transfer to bidder correct number of tokens at finalPrice", async () => { + const bidAmount1 = new BN(10).pow(new BN(36)); + const bidAmount2 = new BN(10).pow(new BN(38)); + const bidAmount3 = new BN(10).pow(new BN(36)).muln(199); + + await giveUserCLNYTokens(colonyNetwork, BIDDER_1, bidAmount1.toString()); + await giveUserCLNYTokens(colonyNetwork, BIDDER_2, bidAmount2.toString()); + await giveUserCLNYTokens(colonyNetwork, BIDDER_3, bidAmount3.toString()); + await clny.approve(tokenAuction.address, bidAmount1.toString(), { from: BIDDER_1 }); + await clny.approve(tokenAuction.address, bidAmount2.toString(), { from: BIDDER_2 }); + await clny.approve(tokenAuction.address, bidAmount3.toString(), { from: BIDDER_3 }); + + await tokenAuction.start(); + await tokenAuction.bid(bidAmount1.toString(), { from: BIDDER_1 }); // Bids at near max price of 1e36 CLNY per 1e18 Tokens + await forwardTime(1382400, this); // Gets us near price of 1e20 CLNY per 1e18 Tokens + await tokenAuction.bid(bidAmount2.toString(), { from: BIDDER_2 }); + await tokenAuction.bid(bidAmount3.toString(), { from: BIDDER_3 }); + + await tokenAuction.finalize(); + const finalPrice = await tokenAuction.finalPrice.call(); + const finalPriceString = finalPrice.toString(); + + let claimCount; + let tokenBidderBalance; + let tokensToClaim; + + await tokenAuction.claim({ from: BIDDER_1 }); + claimCount = await tokenAuction.claimCount.call(); + assert.equal(claimCount.toNumber(), 1); + + tokenBidderBalance = await token.balanceOf.call(BIDDER_1); + tokensToClaim = new BN(10) + .pow(new BN(18)) + .mul(bidAmount1) + .div(new BN(finalPriceString)); + assert.equal(tokenBidderBalance.toString(10), tokensToClaim.toString()); + + await tokenAuction.claim({ from: BIDDER_2 }); + claimCount = await tokenAuction.claimCount.call(); + assert.equal(claimCount.toNumber(), 2); + tokenBidderBalance = await token.balanceOf.call(BIDDER_2); + tokensToClaim = new BN(10) + .pow(new BN(18)) + .mul(bidAmount2) + .div(new BN(finalPriceString)); + assert.equal(tokenBidderBalance.toString(10), tokensToClaim.toString()); + + const bid3 = await tokenAuction.bids.call(BIDDER_3); + await tokenAuction.claim({ from: BIDDER_3 }); + claimCount = await tokenAuction.claimCount.call(); + assert.equal(claimCount.toNumber(), 3); + tokenBidderBalance = await token.balanceOf.call(BIDDER_3); + const bid3BN = new BN(bid3.toString(10)); + tokensToClaim = new BN(10) + .pow(new BN(18)) + .mul(bid3BN) + .div(new BN(finalPriceString)); + assert.equal(tokenBidderBalance.toString(10), tokensToClaim.toString()); + }); + + it("should set the bid amount to 0", async () => { + await tokenAuction.start(); + await giveUserCLNYTokens(colonyNetwork, BIDDER_1, clnyNeededForMaxPriceAuctionSellout.toString()); + await clny.approve(tokenAuction.address, clnyNeededForMaxPriceAuctionSellout.toString(), { from: BIDDER_1 }); + await tokenAuction.bid(clnyNeededForMaxPriceAuctionSellout.toString(), { from: BIDDER_1 }); + await tokenAuction.finalize(); + await tokenAuction.claim({ from: BIDDER_1 }); + const bid = await tokenAuction.bids.call(BIDDER_1); + assert.equal(bid.toNumber(), 0); + }); + }); + + describe("when closing the auction", async () => { + beforeEach(async () => { + await tokenAuction.start(); + await giveUserCLNYTokens(colonyNetwork, BIDDER_1, clnyNeededForMaxPriceAuctionSellout.toString()); + await clny.approve(tokenAuction.address, clnyNeededForMaxPriceAuctionSellout.toString(), { from: BIDDER_1 }); + await tokenAuction.bid(clnyNeededForMaxPriceAuctionSellout.toString(), { from: BIDDER_1 }); + }); + + it("should be able to close the auction and kill the auction contract", async () => { + await tokenAuction.finalize(); + await tokenAuction.claim({ from: BIDDER_1 }); + await tokenAuction.close(); + const code = await web3GetCode(tokenAuction.address); + assert.equal(code, 0); + }); + + it("should fail if auction not finalized", async () => { + await checkErrorRevert(tokenAuction.close()); + }); + + it("should fail if not all bids have been claimed", async () => { + await tokenAuction.finalize(); + await checkErrorRevert(tokenAuction.close()); + }); + + it("should fail if there are CLNY tokens left owned by the auction", async () => { + await tokenAuction.finalize(); + await tokenAuction.claim({ from: BIDDER_1 }); + await metaColony.mintTokens(100); + await giveUserCLNYTokens(colonyNetwork, BIDDER_1, 100); + await clny.transfer(tokenAuction.address, 100, { from: BIDDER_1 }); + await checkErrorRevert(tokenAuction.close()); + }); + }); +}); diff --git a/src/lib/colonyNetwork/test/colony-network-mining.js b/src/lib/colonyNetwork/test/colony-network-mining.js new file mode 100755 index 0000000..25210ca --- /dev/null +++ b/src/lib/colonyNetwork/test/colony-network-mining.js @@ -0,0 +1,1696 @@ +/* globals artifacts */ + +import path from "path"; +import BN from "bn.js"; +import { TruffleLoader } from "@colony/colony-js-contract-loader-fs"; + +import { forwardTime, checkErrorRevert, web3GetTransactionReceipt } from "../helpers/test-helper"; +import { giveUserCLNYTokens, giveUserCLNYTokensAndStake, setupRatedTask, fundColonyWithTokens } from "../helpers/test-data-generator"; + +import ReputationMiner from "../packages/reputation-miner/ReputationMiner"; +import MaliciousReputationMinerExtraRep from "../packages/reputation-miner/test/MaliciousReputationMinerExtraRep"; +import MaliciousReputationMinerWrongUID from "../packages/reputation-miner/test/MaliciousReputationMinerWrongUID"; +import MaliciousReputationMinerReuseUID from "../packages/reputation-miner/test/MaliciousReputationMinerReuseUID"; + +const EtherRouter = artifacts.require("EtherRouter"); +const IColony = artifacts.require("IColony"); +const IColonyNetwork = artifacts.require("IColonyNetwork"); +const Token = artifacts.require("Token"); +const ReputationMiningCycle = artifacts.require("ReputationMiningCycle"); + +const contractLoader = new TruffleLoader({ + contractDir: path.resolve(__dirname, "..", "build", "contracts") +}); + +contract("ColonyNetworkStaking", accounts => { + const MAIN_ACCOUNT = accounts[0]; + const OTHER_ACCOUNT = accounts[1]; + + let metaColony; + let colonyNetwork; + let clny; + let goodClient; + let badClient; + let badClient2; + const REAL_PROVIDER_PORT = process.env.SOLIDITY_COVERAGE ? 8555 : 8545; + + before(async () => { + const etherRouter = await EtherRouter.deployed(); + colonyNetwork = await IColonyNetwork.at(etherRouter.address); + const metaColonyAddress = await colonyNetwork.getMetaColony.call(); + metaColony = IColony.at(metaColonyAddress); + clny = await Token.new("Colony Network Token", "CLNY", 18); + await metaColony.setToken(clny.address); + await clny.setOwner(metaColony.address); + }); + + beforeEach(async () => { + goodClient = new ReputationMiner({ loader: contractLoader, minerAddress: MAIN_ACCOUNT, realProviderPort: REAL_PROVIDER_PORT }); + // Mess up the second calculation. There will always be one if giveUserCLNYTokens has been called. + badClient = new MaliciousReputationMinerExtraRep( + { loader: contractLoader, minerAddress: OTHER_ACCOUNT, realProviderPort: REAL_PROVIDER_PORT }, + 1, + 0xfffffffff + ); + // Mess up the second calculation in a different way + badClient2 = new MaliciousReputationMinerExtraRep( + { loader: contractLoader, minerAddress: accounts[2], realProviderPort: REAL_PROVIDER_PORT }, + 1, + 0xeeeeeeeee + ); + await goodClient.initialise(colonyNetwork.address); + await badClient.initialise(colonyNetwork.address); + await badClient2.initialise(colonyNetwork.address); + + // Kick off reputation mining. + // TODO: Tests for the first reputation cycle (when log empty) should be done in another file + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, new BN("1000000000000000000")); + + const addr = await colonyNetwork.getReputationMiningCycle.call(true); + const repCycle = ReputationMiningCycle.at(addr); + await forwardTime(3600, this); + await repCycle.submitRootHash("0x0", 0, 10); + await repCycle.confirmNewHash(0); + // The inactive reputation log now has the reward for this miner, and the accepted state is empty. + // This is the same starting point for all tests. + + // Finally, we discard the staked tokens we used to get to this point so that `MAIN_ACCOUNT` has no + // tokens staked, just like all other accounts, at the start of each test. + const stakedBalance = await colonyNetwork.getStakedBalance.call(MAIN_ACCOUNT); + await colonyNetwork.withdraw(stakedBalance.toNumber()); + const userBalance = await clny.balanceOf.call(MAIN_ACCOUNT); + await clny.transfer(0x0, userBalance, { from: MAIN_ACCOUNT }); + }); + + async function accommodateChallengeAndInvalidateHash(test, client1, client2) { + const reputationMiningCycleAddress = await colonyNetwork.getReputationMiningCycle.call(true); + const repCycle = ReputationMiningCycle.at(reputationMiningCycleAddress); + let round2; + let idx2; + let toInvalidateIdx; + const [round1, idx1] = await client1.getMySubmissionRoundAndIndex(); + const submission1before = await repCycle.disputeRounds(round1.toString(), idx1.toString()); + if (client2 !== undefined) { + // Submit JRH for submission 1 if needed + // We only do this if client2 is defined so that we test JRH submission in rounds other than round 0. + if (submission1before[4] === "0x0000000000000000000000000000000000000000000000000000000000000000") { + await client1.submitJustificationRootHash(); + } + + [round2, idx2] = await client2.getMySubmissionRoundAndIndex(); + assert(round1.eq(round2), "Clients do not have submissions in the same round"); + const submission2before = await repCycle.disputeRounds(round2.toString(), idx2.toString()); + + assert( + idx1 + .sub(idx2) + .abs() + .eqn(1), + "Clients are not facing each other in this round" + ); + if (submission2before[4] === "0x0000000000000000000000000000000000000000000000000000000000000000") { + await client2.submitJustificationRootHash(); + } + // Loop while doing the binary search, checking we were successful at each point + // Binary search will error when it is complete. + let noError = true; + while (noError) { + let txHash = await client1.respondToBinarySearchForChallenge(); // eslint-disable-line no-await-in-loop + let tx = await web3GetTransactionReceipt(txHash); // eslint-disable-line no-await-in-loop + if (tx.status === "0x00") { + noError = false; + } + txHash = await client2.respondToBinarySearchForChallenge(); // eslint-disable-line no-await-in-loop + tx = await web3GetTransactionReceipt(txHash); // eslint-disable-line no-await-in-loop + if (tx.status === "0x00") { + noError = false; + } + } + // Respond to the challenge - usually, only one of these should work. + // If both work, then the starting reputation is 0 and one client is lying + // about whether the key already exists. + noError = true; + await client1.respondToChallenge(); + await client2.respondToChallenge(); + + // Work out which submission is to be invalidated. + const submission1 = await repCycle.disputeRounds(round1.toString(), idx1.toString()); + const challengeStepsCompleted1 = new BN(submission1[3].toString()); + const submission2 = await repCycle.disputeRounds(round2.toString(), idx2.toString()); + const challengeStepsCompleted2 = new BN(submission2[3].toString()); + if (challengeStepsCompleted1.gt(challengeStepsCompleted2)) { + toInvalidateIdx = idx2; + } else { + // Note that if they're equal, they're both going to be invalidated, so we can call + // either + toInvalidateIdx = idx1; + } + // Forward time, so that whichever has failed to respond by now has timed out. + await forwardTime(600, test); + } else { + // idx1.modn returns a javascript number, which is surprising! + toInvalidateIdx = idx1.modn(2) === 1 ? idx1.subn(1) : idx1.addn(1); + } + await repCycle.invalidateHash(round1.toString(), toInvalidateIdx.toString()); + } + + afterEach(async () => { + // Finish the current cycle. Can only do this at the start of a new cycle, if anyone has submitted a hash in this current cycle. + const addr = await colonyNetwork.getReputationMiningCycle.call(true); + const repCycle = ReputationMiningCycle.at(addr); + let nSubmittedHashes = await repCycle.nSubmittedHashes.call(); + nSubmittedHashes = nSubmittedHashes.toNumber(); + if (nSubmittedHashes > 0) { + let nInvalidatedHashes = await repCycle.nInvalidatedHashes.call(); + nInvalidatedHashes = nInvalidatedHashes.toNumber(); + if (nSubmittedHashes - nInvalidatedHashes === 1) { + await repCycle.confirmNewHash(nSubmittedHashes === 1 ? 0 : 1); // Not a general solution - only works for one or two submissions. + // But for now, that's okay. + } else { + // We shouldn't get here. If this fires during a test, you haven't finished writing the test. + console.log("We're mid dispute process, and can't untangle from here"); // eslint-disable-line no-console + // process.exit(1); + return; + } + } + + // Actually do the withdrawal. + await Promise.all( + accounts.map(async address => { + const stakedBalance = await colonyNetwork.getStakedBalance.call(address); + if (stakedBalance.toNumber() > 0) { + await colonyNetwork.withdraw(stakedBalance.toNumber(), { from: address }); + } + const userBalance = await clny.balanceOf.call(address); + return clny.transfer(0x0, userBalance, { from: address }); + }) + ); + }); + + describe("Basic Functionality - no client used", () => { + it("should allow miners to stake CLNY", async () => { + await giveUserCLNYTokens(colonyNetwork, OTHER_ACCOUNT, 9000); + await clny.approve(colonyNetwork.address, 5000, { from: OTHER_ACCOUNT }); + await colonyNetwork.deposit(5000, { from: OTHER_ACCOUNT }); + const userBalance = await clny.balanceOf.call(OTHER_ACCOUNT); + assert.equal(userBalance.toNumber(), 4000); + const stakedBalance = await colonyNetwork.getStakedBalance.call(OTHER_ACCOUNT); + assert.equal(stakedBalance.toNumber(), 5000); + }); + + it("should allow miners to withdraw staked CLNY", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, OTHER_ACCOUNT, 5000); + await colonyNetwork.withdraw(5000, { from: OTHER_ACCOUNT }); + const stakedBalance = await colonyNetwork.getStakedBalance.call(OTHER_ACCOUNT); + assert.equal(stakedBalance.toNumber(), 0); + }); + + it("should not allow miners to deposit more CLNY than they have", async () => { + await giveUserCLNYTokens(colonyNetwork, OTHER_ACCOUNT, 9000); + await clny.approve(colonyNetwork.address, 10000, { from: OTHER_ACCOUNT }); + await checkErrorRevert(colonyNetwork.deposit(10000, { from: OTHER_ACCOUNT })); + const userBalance = await clny.balanceOf.call(OTHER_ACCOUNT); + assert.equal(userBalance.toNumber(), 9000); + const stakedBalance = await colonyNetwork.getStakedBalance.call(OTHER_ACCOUNT); + assert.equal(stakedBalance.toNumber(), 0); + }); + + it("should not allow miners to withdraw more CLNY than they staked, even if enough has been staked total", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, 9000); + await giveUserCLNYTokensAndStake(colonyNetwork, OTHER_ACCOUNT, 9000); + await checkErrorRevert(colonyNetwork.withdraw(10000, { from: OTHER_ACCOUNT })); + const stakedBalance = await colonyNetwork.getStakedBalance.call(OTHER_ACCOUNT); + assert.equal(stakedBalance.toNumber(), 9000); + const userBalance = await clny.balanceOf.call(OTHER_ACCOUNT); + assert.equal(userBalance.toNumber(), 0); + }); + + it("should allow a new reputation hash to be submitted", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, new BN("1000000000000000000")); + + const addr = await colonyNetwork.getReputationMiningCycle.call(true); + await forwardTime(3600); + const repCycle = ReputationMiningCycle.at(addr); + await repCycle.submitRootHash("0x12345678", 10, 10); + const submitterAddress = await repCycle.submittedHashes.call("0x12345678", 10, 0); + assert.equal(submitterAddress, MAIN_ACCOUNT); + }); + + it("should not allow someone to submit a new reputation hash if they are not staking", async () => { + const addr = await colonyNetwork.getReputationMiningCycle.call(true); + await forwardTime(3600); + const repCycle = ReputationMiningCycle.at(addr); + await checkErrorRevert(repCycle.submitRootHash("0x12345678", 10, 0)); + const nSubmittedHashes = await repCycle.nSubmittedHashes.call(); + assert(nSubmittedHashes.equals(0)); + }); + + it("should not allow someone to withdraw their stake if they have submitted a hash this round", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, new BN("1000000000000000000")); + + const addr = await colonyNetwork.getReputationMiningCycle.call(true); + await forwardTime(3600, this); + const repCycle = ReputationMiningCycle.at(addr); + await repCycle.submitRootHash("0x12345678", 10, 10); + let stakedBalance = await colonyNetwork.getStakedBalance.call(MAIN_ACCOUNT); + await checkErrorRevert(colonyNetwork.withdraw(stakedBalance.toNumber(), { from: MAIN_ACCOUNT })); + stakedBalance = await colonyNetwork.getStakedBalance.call(MAIN_ACCOUNT); + assert(stakedBalance.equals("1000000000000000000")); + }); + + it("should allow a new reputation hash to be set if only one was submitted", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, new BN("1000000000000000000")); + + const addr = await colonyNetwork.getReputationMiningCycle.call(true); + await forwardTime(3600, this); + const repCycle = ReputationMiningCycle.at(addr); + await repCycle.submitRootHash("0x12345678", 10, 10); + await repCycle.confirmNewHash(0); + const newAddr = await colonyNetwork.getReputationMiningCycle.call(true); + assert(newAddr !== 0x0); + assert(addr !== 0x0); + assert(newAddr !== addr); + const rootHash = await colonyNetwork.getReputationRootHash.call(); + assert.equal(rootHash, "0x1234567800000000000000000000000000000000000000000000000000000000"); + const rootHashNNodes = await colonyNetwork.getReputationRootHashNNodes.call(); + assert(rootHashNNodes.equals(10)); + }); + + it("should not allow someone who is not ColonyNetwork to appendReputationUpdateLog", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, new BN("1000000000000000000")); + + const addr = await colonyNetwork.getReputationMiningCycle.call(false); + const repCycle = ReputationMiningCycle.at(addr); + const nLogEntriesBefore = repCycle.getReputationUpdateLogLength(); + checkErrorRevert(repCycle.appendReputationUpdateLog(MAIN_ACCOUNT, 100, 0, metaColony.address, 0, 1)); + const nLogEntriesAfter = repCycle.getReputationUpdateLogLength(); + assert.equal(nLogEntriesBefore.toString(), nLogEntriesAfter.toString()); + }); + + it("should not allow someone who is not ColonyNetwork to reset the ReputationMiningCycle window", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, new BN("1000000000000000000")); + + const addr = await colonyNetwork.getReputationMiningCycle.call(true); + const repCycle = ReputationMiningCycle.at(addr); + const windowOpenTimestampBefore = await repCycle.reputationMiningWindowOpenTimestamp(); + await checkErrorRevert(repCycle.resetWindow()); + const windowOpenTimestampAfter = await repCycle.reputationMiningWindowOpenTimestamp(); + assert.equal(windowOpenTimestampBefore.toString(), windowOpenTimestampAfter.toString()); + }); + }); + + describe("Elimination of submissions", () => { + it("should allow a new reputation hash to be set if all but one submitted have been eliminated", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, new BN("1000000000000000000")); + await giveUserCLNYTokensAndStake(colonyNetwork, OTHER_ACCOUNT, new BN("1000000000000000000")); + const addr = await colonyNetwork.getReputationMiningCycle.call(true); + await forwardTime(3600, this); + const repCycle = ReputationMiningCycle.at(addr); + await goodClient.addLogContentsToReputationTree(); + await badClient.addLogContentsToReputationTree(); + + await goodClient.submitRootHash(); + await badClient.submitRootHash(); + await accommodateChallengeAndInvalidateHash(this, goodClient, badClient); + await repCycle.confirmNewHash(1); + const newAddr = await colonyNetwork.getReputationMiningCycle.call(true); + assert(newAddr !== 0x0); + assert(addr !== 0x0); + assert(newAddr !== addr); + const rootHash = await colonyNetwork.getReputationRootHash.call(); + const clientRootHash = await goodClient.getRootHash(); + assert.equal(rootHash, clientRootHash); + const rootHashNNodes = await colonyNetwork.getReputationRootHashNNodes.call(); + assert.equal(rootHashNNodes.toString(), goodClient.nReputations.toString()); + }); + + it("should allow a new reputation hash to be moved to the next stage of competition even if it does not have a partner", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokensAndStake(colonyNetwork, OTHER_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokensAndStake(colonyNetwork, accounts[2], "1000000000000000000"); + + const addr = await colonyNetwork.getReputationMiningCycle.call(true); + await forwardTime(3600, this); + const repCycle = ReputationMiningCycle.at(addr); + + await goodClient.addLogContentsToReputationTree(); + await badClient.addLogContentsToReputationTree(); + await badClient2.addLogContentsToReputationTree(); + + await goodClient.submitRootHash(); + await badClient.submitRootHash(); + await badClient2.submitRootHash(); + await accommodateChallengeAndInvalidateHash(this, goodClient, badClient); + await accommodateChallengeAndInvalidateHash(this, badClient2); // Invalidate the 'null' that partners the third hash submitted. + await accommodateChallengeAndInvalidateHash(this, goodClient, badClient2); + + await repCycle.confirmNewHash(2); + const newAddr = await colonyNetwork.getReputationMiningCycle.call(true); + assert(newAddr !== 0x0); + assert(addr !== 0x0); + assert(newAddr !== addr); + const rootHash = await colonyNetwork.getReputationRootHash.call(); + const clientRootHash = await goodClient.getRootHash(); + assert.equal(rootHash, clientRootHash); + const rootHashNNodes = await colonyNetwork.getReputationRootHashNNodes.call(); + assert.equal(rootHashNNodes.toString(), goodClient.nReputations.toString()); + }); + + it("should not allow a new reputation hash to be set if more than one was submitted and they have not been elimintated", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokensAndStake(colonyNetwork, OTHER_ACCOUNT, "1000000000000000000"); + + const addr = await colonyNetwork.getReputationMiningCycle.call(true); + await forwardTime(3600, this); + const repCycle = ReputationMiningCycle.at(addr); + + await goodClient.addLogContentsToReputationTree(); + await badClient.addLogContentsToReputationTree(); + + await goodClient.submitRootHash(); + await badClient.submitRootHash(); + + await checkErrorRevert(repCycle.confirmNewHash(0)); + const newAddr = await colonyNetwork.getReputationMiningCycle.call(true); + assert(newAddr !== 0x0); + assert(addr !== 0x0); + assert(newAddr === addr); + // Eliminate one so that the afterAll works. + await accommodateChallengeAndInvalidateHash(this, goodClient, badClient); + }); + + it("should not allow the last reputation hash to be eliminated", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, new BN("1000000000000000000")); + await giveUserCLNYTokensAndStake(colonyNetwork, OTHER_ACCOUNT, new BN("1000000000000000000")); + + await forwardTime(3600, this); + + await goodClient.addLogContentsToReputationTree(); + await badClient.addLogContentsToReputationTree(); + + await goodClient.submitRootHash(); + await badClient.submitRootHash(); + + await accommodateChallengeAndInvalidateHash(this, goodClient, badClient); + await checkErrorRevert(accommodateChallengeAndInvalidateHash(this, goodClient)); + }); + + it("should fail if one tries to invalidate a hash that does not exist", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokensAndStake(colonyNetwork, OTHER_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokensAndStake(colonyNetwork, accounts[2], "1000000000000000000"); + + const addr = await colonyNetwork.getReputationMiningCycle.call(true); + await forwardTime(3600, this); + const repCycle = ReputationMiningCycle.at(addr); + + await goodClient.addLogContentsToReputationTree(); + await badClient.addLogContentsToReputationTree(); + await badClient2.addLogContentsToReputationTree(); + + await goodClient.submitRootHash(); + await badClient.submitRootHash(); + await badClient2.submitRootHash(); + + await accommodateChallengeAndInvalidateHash(this, goodClient, badClient); + await accommodateChallengeAndInvalidateHash(this, badClient2); + await forwardTime(600, this); + await checkErrorRevert(repCycle.invalidateHash(1, 2)); + // Cleanup after test + await accommodateChallengeAndInvalidateHash(this, goodClient, badClient2); + await repCycle.confirmNewHash(2); + }); + + it("should fail if one tries to invalidate a hash that has completed more challenge rounds than its opponent", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokensAndStake(colonyNetwork, OTHER_ACCOUNT, "1000000000000000000"); + + const addr = await colonyNetwork.getReputationMiningCycle.call(true); + await forwardTime(3600, this); + const repCycle = ReputationMiningCycle.at(addr); + + await goodClient.addLogContentsToReputationTree(); + await badClient.addLogContentsToReputationTree(); + + await goodClient.submitRootHash(); + await badClient.submitRootHash(); + + await goodClient.submitJustificationRootHash(); + await forwardTime(600, this); + + await checkErrorRevert(repCycle.invalidateHash(0, 0)); + // Cleanup after test + await repCycle.invalidateHash(0, 1); + await repCycle.confirmNewHash(1); + }); + + it("should not allow a hash to be invalidated multiple times, which would move extra copies of its opponent to the next stage", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokensAndStake(colonyNetwork, OTHER_ACCOUNT, "1000000000000000000"); + + const addr = await colonyNetwork.getReputationMiningCycle.call(true); + await forwardTime(3600, this); + const repCycle = ReputationMiningCycle.at(addr); + + await goodClient.addLogContentsToReputationTree(); + await badClient.addLogContentsToReputationTree(); + + await goodClient.submitRootHash(); + await badClient.submitRootHash(); + + await accommodateChallengeAndInvalidateHash(this, goodClient, badClient); + await checkErrorRevert(repCycle.invalidateHash(0, 1)); + }); + + it("should invalidate a hash and its partner if both have timed out", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokensAndStake(colonyNetwork, OTHER_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokensAndStake(colonyNetwork, accounts[2], "1000000000000000000"); + + const addr = await colonyNetwork.getReputationMiningCycle.call(true); + await forwardTime(3600, this); + const repCycle = ReputationMiningCycle.at(addr); + + await goodClient.addLogContentsToReputationTree(); + await badClient.addLogContentsToReputationTree(); + await badClient2.addLogContentsToReputationTree(); + + await badClient.submitRootHash(); + await badClient2.submitRootHash(); + await goodClient.submitRootHash(); + + await forwardTime(600, this); + await repCycle.invalidateHash(0, 1); + await accommodateChallengeAndInvalidateHash(this, goodClient); + await repCycle.confirmNewHash(1); + }); + + it("should prevent invalidation of hashes before they have timed out on a challenge", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokensAndStake(colonyNetwork, OTHER_ACCOUNT, "1000000000000000000"); + + const addr = await colonyNetwork.getReputationMiningCycle.call(true); + await forwardTime(3600, this); + const repCycle = ReputationMiningCycle.at(addr); + + await goodClient.addLogContentsToReputationTree(); + await badClient.addLogContentsToReputationTree(); + + await goodClient.submitRootHash(); + await badClient.submitRootHash(); + + await checkErrorRevert(repCycle.invalidateHash(0, 1)); + await checkErrorRevert(repCycle.confirmNewHash(1)); + await accommodateChallengeAndInvalidateHash(this, goodClient, badClient); + await repCycle.confirmNewHash(1); + }); + }); + + describe("Submission eligibility", () => { + it("should not allow someone to submit a new reputation hash if they are ineligible", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, new BN("1000000000000000000")); + + const addr = await colonyNetwork.getReputationMiningCycle.call(true); + const repCycle = ReputationMiningCycle.at(addr); + await checkErrorRevert(repCycle.submitRootHash("0x12345678", 10, 10)); + const nSubmittedHashes = await repCycle.nSubmittedHashes.call(); + assert(nSubmittedHashes.equals(0)); + }); + + it("should not allow someone to submit a new reputation hash to the next ReputationMiningCycle", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, new BN("1000000000000000000")); + + const addr = await colonyNetwork.getReputationMiningCycle.call(false); + const repCycle = ReputationMiningCycle.at(addr); + await checkErrorRevert(repCycle.submitRootHash("0x12345678", 10, 10)); + const nSubmittedHashes = await repCycle.nSubmittedHashes.call(); + assert.equal(nSubmittedHashes.toString(), "0"); + }); + + it("should allow someone to submit a new reputation hash if they are eligible inside the window", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, new BN("1000000000000000000")); + + const addr = await colonyNetwork.getReputationMiningCycle.call(true); + const repCycle = ReputationMiningCycle.at(addr); + // Find an entry that will be eligible in the last 60 seconds of the window + let i; + // 1 will almost always be okay here. But there's a 60/3600 chance that it wouldn't be. + // We don't want this test to be flickery, so let's make sure 1 is going to be okay or use a higher + // number if not. There is a 1 in 10**3555 chance of this test failing if this is the only thing that + // can be wrong, so there's a much better chance that I've written this test poorly if it starts + // failing - don't just dismiss it! + for (i = 1; i < 1000; i += 1) { + const hash = await repCycle.getEntryHash.call(MAIN_ACCOUNT, i, "0x12345678"); // eslint-disable-line no-await-in-loop + if (parseInt(hash.substring(2, 4), 16) < 0xfb) { + break; + } + } + await forwardTime(3540, this); + await repCycle.submitRootHash("0x12345678", 10, i); + }); + + it("should not allow a user to back more than one hash in a single cycle", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + + const addr = await colonyNetwork.getReputationMiningCycle.call(true); + const repCycle = ReputationMiningCycle.at(addr); + await forwardTime(3600, this); + await repCycle.submitRootHash("0x12345678", 10, 10); + await checkErrorRevert(repCycle.submitRootHash("0x87654321", 10, 10)); + const nSubmittedHashes = await repCycle.nSubmittedHashes.call(); + assert(nSubmittedHashes.equals(1)); + }); + + it("should not allow a user to back the same hash with different number of nodes in a single cycle", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + + const addr = await colonyNetwork.getReputationMiningCycle.call(true); + const repCycle = ReputationMiningCycle.at(addr); + await forwardTime(3600, this); + await repCycle.submitRootHash("0x12345678", 10, 10); + + await checkErrorRevert(repCycle.submitRootHash("0x12345678", 11, 9)); + const nSubmittedHashes = await repCycle.nSubmittedHashes.call(); + assert(nSubmittedHashes.equals(1)); + }); + + it("should not allow a user to submit the same entry for the same hash twice in a single cycle", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + + const addr = await colonyNetwork.getReputationMiningCycle.call(true); + const repCycle = ReputationMiningCycle.at(addr); + await forwardTime(3600, this); + await repCycle.submitRootHash("0x12345678", 10, 10); + await checkErrorRevert(repCycle.submitRootHash("0x12345678", 10, 10)); + const nSubmittedHashes = await repCycle.nSubmittedHashes.call(); + assert(nSubmittedHashes.equals(1)); + }); + + it("should allow a user to back the same hash more than once in a same cycle with different entries, and be rewarded", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + + let addr = await colonyNetwork.getReputationMiningCycle.call(true); + let repCycle = ReputationMiningCycle.at(addr); + await forwardTime(3600, this); + await repCycle.submitRootHash("0x12345678", 10, 10); + await repCycle.submitRootHash("0x12345678", 10, 9); + const nSubmittedHashes = await repCycle.nSubmittedHashes.call(); + assert(nSubmittedHashes.equals(1)); + await repCycle.confirmNewHash(0); + + // Check that they have had their staked balance increase + const balance1Updated = await colonyNetwork.getStakedBalance(MAIN_ACCOUNT); + assert.equal(balance1Updated.toString(), new BN("3").mul(new BN("10").pow(new BN("18"))).toString(), "Account was not rewarded properly"); + + addr = await colonyNetwork.getReputationMiningCycle.call(false); + repCycle = ReputationMiningCycle.at(addr); + + // Check that they will be getting the reputation owed to them. + let repLogEntryMiner = await repCycle.getReputationUpdateLogEntry.call(0); + assert.equal(repLogEntryMiner[0], MAIN_ACCOUNT); + assert.equal(repLogEntryMiner[1].toString(), new BN("1").mul(new BN("10").pow(new BN("18"))).toString()); + assert.equal(repLogEntryMiner[2].toString(), "0"); + assert.equal(repLogEntryMiner[3], metaColony.address); + assert.equal(repLogEntryMiner[4].toString(), "4"); + assert.equal(repLogEntryMiner[5].toString(), "0"); + + repLogEntryMiner = await repCycle.getReputationUpdateLogEntry.call(1); + assert.equal(repLogEntryMiner[0], MAIN_ACCOUNT); + assert.equal(repLogEntryMiner[1].toString(), new BN("1").mul(new BN("10").pow(new BN("18"))).toString()); + assert.equal(repLogEntryMiner[2].toString(), "0"); + assert.equal(repLogEntryMiner[3], metaColony.address); + assert.equal(repLogEntryMiner[4].toString(), "4"); + assert.equal(repLogEntryMiner[5].toString(), "4"); + + const reputationUpdateLogLength = await repCycle.getReputationUpdateLogLength(); + assert.equal(reputationUpdateLogLength.toString(), 2); + }); + + it("should only allow 12 entries to back a single hash in each cycle", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + + const addr = await colonyNetwork.getReputationMiningCycle.call(true); + await forwardTime(3600, this); + const repCycle = ReputationMiningCycle.at(addr); + await repCycle.submitRootHash("0x12345678", 10, 1); + await repCycle.submitRootHash("0x12345678", 10, 2); + await repCycle.submitRootHash("0x12345678", 10, 3); + await repCycle.submitRootHash("0x12345678", 10, 4); + await repCycle.submitRootHash("0x12345678", 10, 5); + await repCycle.submitRootHash("0x12345678", 10, 6); + await repCycle.submitRootHash("0x12345678", 10, 7); + await repCycle.submitRootHash("0x12345678", 10, 8); + await repCycle.submitRootHash("0x12345678", 10, 9); + await repCycle.submitRootHash("0x12345678", 10, 10); + await repCycle.submitRootHash("0x12345678", 10, 11); + await repCycle.submitRootHash("0x12345678", 10, 12); + await checkErrorRevert(repCycle.submitRootHash("0x12345678", 10, 13)); + }); + + it("should prevent submission of hashes with an invalid entry for the balance of a user", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokensAndStake(colonyNetwork, OTHER_ACCOUNT, "1000000000000000000"); + + const addr = await colonyNetwork.getReputationMiningCycle.call(true); + await forwardTime(3600, this); + const repCycle = ReputationMiningCycle.at(addr); + await checkErrorRevert(repCycle.submitRootHash("0x12345678", 10, 1000000000000)); + await repCycle.submitRootHash("0x87654321", 10, 10, { from: OTHER_ACCOUNT }); + }); + + it("should prevent submission of hashes with a valid entry, but invalid hash for the current time", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + + const addr = await colonyNetwork.getReputationMiningCycle.call(true); + const repCycle = ReputationMiningCycle.at(addr); + await checkErrorRevert(repCycle.submitRootHash("0x12345678", 10, 1)); + }); + }); + + describe("Rewards and punishments of good and bad submissions", () => { + it("should punish all stakers if they misbehave (and report a bad hash)", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokensAndStake(colonyNetwork, OTHER_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokensAndStake(colonyNetwork, accounts[2], "1000000000000000000"); + + let balance = await colonyNetwork.getStakedBalance(OTHER_ACCOUNT); + assert(balance.equals("1000000000000000000")); + let balance2 = await colonyNetwork.getStakedBalance(accounts[2]); + assert(balance.equals("1000000000000000000")); + + await forwardTime(3600, this); + + // We want badclient2 to submit the same hash as badclient for this test. + badClient2 = new MaliciousReputationMinerExtraRep( + { loader: contractLoader, minerAddress: accounts[2], realProviderPort: REAL_PROVIDER_PORT }, + 1, + "0xfffffffff" + ); + badClient2.initialise(colonyNetwork.address); + + await goodClient.addLogContentsToReputationTree(); + await badClient.addLogContentsToReputationTree(); + await badClient2.addLogContentsToReputationTree(); + + await goodClient.submitRootHash(); + await badClient.submitRootHash(); + await badClient2.submitRootHash(); + + await accommodateChallengeAndInvalidateHash(this, goodClient, badClient); + balance = await colonyNetwork.getStakedBalance(OTHER_ACCOUNT); + assert.equal(balance.toString(), "0", "Account was not punished properly"); + balance2 = await colonyNetwork.getStakedBalance(accounts[2]); + assert.equal(balance2.toString(), "0", "Account was not punished properly"); + }); + + it("should reward all stakers if they submitted the agreed new hash", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokensAndStake(colonyNetwork, OTHER_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokensAndStake(colonyNetwork, accounts[2], "1000000000000000000"); + + let addr = await colonyNetwork.getReputationMiningCycle.call(true); + await forwardTime(3600, this); + let repCycle = ReputationMiningCycle.at(addr); + await repCycle.submitRootHash("0x12345678", 10, 10); + await repCycle.submitRootHash("0x12345678", 10, 8, { from: OTHER_ACCOUNT }); + await repCycle.confirmNewHash(0); + + // Check that they have had their staked balance increase + const balance1Updated = await colonyNetwork.getStakedBalance(MAIN_ACCOUNT); + assert.equal(balance1Updated.toString(), new BN("2").mul(new BN("10").pow(new BN("18"))).toString(), "Account was not rewarded properly"); + const balance2Updated = await colonyNetwork.getStakedBalance(OTHER_ACCOUNT); + assert.equal(balance2Updated.toString(), new BN("2").mul(new BN("10").pow(new BN("18"))).toString(), "Account was not rewarded properly"); + + addr = await colonyNetwork.getReputationMiningCycle.call(false); + repCycle = ReputationMiningCycle.at(addr); + + // Check that they will be getting the reputation owed to them. + let repLogEntryMiner = await repCycle.getReputationUpdateLogEntry.call(0); + assert.equal(repLogEntryMiner[0], MAIN_ACCOUNT); + assert.equal(repLogEntryMiner[1].toString(), new BN("1").mul(new BN("10").pow(new BN("18"))).toString()); + assert.equal(repLogEntryMiner[2].toString(), "0"); + assert.equal(repLogEntryMiner[3], metaColony.address); + assert.equal(repLogEntryMiner[4].toString(), "4"); + assert.equal(repLogEntryMiner[5].toString(), "0"); + + repLogEntryMiner = await repCycle.getReputationUpdateLogEntry.call(1); + assert.equal(repLogEntryMiner[0], OTHER_ACCOUNT); + assert.equal(repLogEntryMiner[1].toString(), new BN("1").mul(new BN("10").pow(new BN("18"))).toString()); + assert.equal(repLogEntryMiner[2].toString(), "0"); + assert.equal(repLogEntryMiner[3], metaColony.address); + assert.equal(repLogEntryMiner[4].toString(), "4"); + assert.equal(repLogEntryMiner[5].toString(), "4"); + + const reputationUpdateLogLength = await repCycle.getReputationUpdateLogLength(); + assert.equal(reputationUpdateLogLength.toString(), 2); + }); + }); + + describe("Function permissions", () => { + it('should not allow "setReputationRootHash" to be called from an account that is not not reputationMiningCycle', async () => { + await checkErrorRevert(colonyNetwork.setReputationRootHash("0x000001", 10, [accounts[0], accounts[1]])); + }); + + it('should not allow "punishStakers" to be called from an account that is not not reputationMiningCycle', async () => { + await checkErrorRevert(colonyNetwork.punishStakers([accounts[0], accounts[1]])); + }); + + it('should not allow "startNextCycle" to be called if a cycle is in progress', async () => { + const addr = await colonyNetwork.getReputationMiningCycle.call(true); + await forwardTime(3600, this); + assert(parseInt(addr, 16) !== 0); + await checkErrorRevert(colonyNetwork.startNextCycle()); + }); + }); + + describe("Types of disagreement", () => { + it("In the event of a disagreement, allows a user to submit a JRH with proofs for a submission", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokensAndStake(colonyNetwork, OTHER_ACCOUNT, "1000000000000000000"); + + let addr = await colonyNetwork.getReputationMiningCycle.call(true); + let repCycle = ReputationMiningCycle.at(addr); + await forwardTime(3600, this); + await repCycle.submitRootHash("0x12345678", 10, 10); + await repCycle.confirmNewHash(0); + + await giveUserCLNYTokens(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokens(colonyNetwork, OTHER_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokens(colonyNetwork, accounts[2], "1000000000000000000"); + addr = await colonyNetwork.getReputationMiningCycle.call(true); + repCycle = ReputationMiningCycle.at(addr); + await forwardTime(3600, this); + await repCycle.submitRootHash("0x0", 0, 10); + await repCycle.confirmNewHash(0); + addr = await colonyNetwork.getReputationMiningCycle.call(true); + repCycle = ReputationMiningCycle.at(addr); + + // The update log should contain the person being rewarded for the previous + // update cycle, and reputation updates for three task completions (manager, worker, evaluator); + // That's seven in total. + const nInactiveLogEntries = await repCycle.getReputationUpdateLogLength(); + assert.equal(nInactiveLogEntries.toNumber(), 13); + + await goodClient.addLogContentsToReputationTree(); + + await badClient.addLogContentsToReputationTree(); + + let righthash = await goodClient.getRootHash(); + let wronghash = await badClient.getRootHash(); + righthash = await goodClient.getRootHash(); + wronghash = await badClient.getRootHash(); + assert(righthash !== wronghash, "Hashes from clients are equal, surprisingly"); + await forwardTime(3600, this); + + await goodClient.submitRootHash(); + await badClient.submitRootHash(); + + const nSubmittedHashes = await repCycle.nSubmittedHashes(); + assert.equal(nSubmittedHashes, 2); + const submission = await repCycle.disputeRounds(0, 0); + assert.equal(submission[4], "0x0000000000000000000000000000000000000000000000000000000000000000"); + await forwardTime(10, this); // This is just to ensure that the timestamps checked below will be different if JRH was submitted. + + await goodClient.submitJustificationRootHash(); + + // Check that we can't re-submit a JRH + await checkErrorRevert(goodClient.submitJustificationRootHash()); + + const submissionAfterJRHSubmitted = await repCycle.disputeRounds(0, 0); + const jrh = await goodClient.justificationTree.getRootHash(); + assert.equal(submissionAfterJRHSubmitted[4], jrh); + + // Check 'last response' was updated. + assert.notEqual(submission[2].toString(), submissionAfterJRHSubmitted[2].toString()); + + // Cleanup + await accommodateChallengeAndInvalidateHash(this, goodClient, badClient); + await repCycle.confirmNewHash(1); + }); + + it("In the event of a disagreement, allows a binary search between opponents to take place to find their first disagreement", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokensAndStake(colonyNetwork, OTHER_ACCOUNT, "1000000000000000000"); + + let addr = await colonyNetwork.getReputationMiningCycle.call(true); + let repCycle = ReputationMiningCycle.at(addr); + await forwardTime(3600, this); + await repCycle.submitRootHash("0x12345678", 10, 10); + await repCycle.confirmNewHash(0); + + await giveUserCLNYTokens(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokens(colonyNetwork, OTHER_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokens(colonyNetwork, accounts[2], "1000000000000000000"); + addr = await colonyNetwork.getReputationMiningCycle.call(true); + repCycle = ReputationMiningCycle.at(addr); + await forwardTime(3600, this); + await repCycle.submitRootHash("0x0", 0, 10); + await repCycle.confirmNewHash(0); + addr = await colonyNetwork.getReputationMiningCycle.call(true); + repCycle = ReputationMiningCycle.at(addr); + + // The update log should contain the person being rewarded for the previous + // update cycle, and reputation updates for three task completions (manager, worker (skill and domain), evaluator); + // That's thirteen in total. + const nInactiveLogEntries = await repCycle.getReputationUpdateLogLength(); + assert.equal(nInactiveLogEntries.toNumber(), 13); + + await goodClient.addLogContentsToReputationTree(); + + badClient = new MaliciousReputationMinerExtraRep( + { loader: contractLoader, minerAddress: OTHER_ACCOUNT, realProviderPort: REAL_PROVIDER_PORT }, + 5, + "0xfffffffff" + ); + await badClient.initialise(colonyNetwork.address); + await badClient.addLogContentsToReputationTree(); + + let righthash = await goodClient.getRootHash(); + let wronghash = await badClient.getRootHash(); + righthash = await goodClient.getRootHash(); + wronghash = await badClient.getRootHash(); + assert(righthash !== wronghash, "Hashes from clients are equal, surprisingly"); + await forwardTime(3600, this); + + await goodClient.submitRootHash(); + await badClient.submitRootHash(); + + const nSubmittedHashes = await repCycle.nSubmittedHashes(); + assert.equal(nSubmittedHashes, 2); + const submission = await repCycle.disputeRounds(0, 0); + assert.equal(submission[4], "0x0000000000000000000000000000000000000000000000000000000000000000"); + await goodClient.submitJustificationRootHash(); + const submissionAfterJRHSubmitted = await repCycle.disputeRounds(0, 0); + const jrh = await goodClient.justificationTree.getRootHash(); + assert.equal(submissionAfterJRHSubmitted[4], jrh); + await badClient.submitJustificationRootHash(); + const badSubmissionAfterJRHSubmitted = await repCycle.disputeRounds(0, 1); + const badJrh = await badClient.justificationTree.getRootHash(); + assert.equal(badSubmissionAfterJRHSubmitted[4], badJrh); + + let goodSubmission = await repCycle.disputeRounds(0, 0); + let badSubmission = await repCycle.disputeRounds(0, 1); + assert.equal(goodSubmission[3].toNumber(), 1); // Challenge steps completed + assert.equal(goodSubmission[8].toNumber(), 0); // Lower bound for binary search + assert.equal(goodSubmission[9].toNumber(), 14); // Upper bound for binary search + assert.equal(badSubmission[3].toNumber(), 1); + assert.equal(badSubmission[8].toNumber(), 0); + assert.equal(badSubmission[9].toNumber(), 14); + await goodClient.respondToBinarySearchForChallenge(); + + goodSubmission = await repCycle.disputeRounds(0, 0); + badSubmission = await repCycle.disputeRounds(0, 1); + assert.equal(goodSubmission[3].toNumber(), 2); + assert.equal(goodSubmission[8].toNumber(), 0); + assert.equal(goodSubmission[9].toNumber(), 14); + assert.equal(badSubmission[3].toNumber(), 1); + assert.equal(badSubmission[8].toNumber(), 0); + assert.equal(badSubmission[9].toNumber(), 14); + + await badClient.respondToBinarySearchForChallenge(); + goodSubmission = await repCycle.disputeRounds(0, 0); + badSubmission = await repCycle.disputeRounds(0, 1); + assert.equal(goodSubmission[8].toNumber(), 0); + assert.equal(goodSubmission[9].toNumber(), 7); + assert.equal(badSubmission[8].toNumber(), 0); + assert.equal(badSubmission[9].toNumber(), 7); + + await goodClient.respondToBinarySearchForChallenge(); + await badClient.respondToBinarySearchForChallenge(); + goodSubmission = await repCycle.disputeRounds(0, 0); + badSubmission = await repCycle.disputeRounds(0, 1); + assert.equal(goodSubmission[8].toNumber(), 4); + assert.equal(goodSubmission[9].toNumber(), 7); + assert.equal(badSubmission[8].toNumber(), 4); + assert.equal(badSubmission[9].toNumber(), 7); + + await goodClient.respondToBinarySearchForChallenge(); + await badClient.respondToBinarySearchForChallenge(); + goodSubmission = await repCycle.disputeRounds(0, 0); + badSubmission = await repCycle.disputeRounds(0, 1); + assert.equal(goodSubmission[8].toNumber(), 6); + assert.equal(goodSubmission[9].toNumber(), 7); + assert.equal(badSubmission[8].toNumber(), 6); + assert.equal(badSubmission[9].toNumber(), 7); + + await goodClient.respondToBinarySearchForChallenge(); + await badClient.respondToBinarySearchForChallenge(); + goodSubmission = await repCycle.disputeRounds(0, 0); + badSubmission = await repCycle.disputeRounds(0, 1); + assert.equal(goodSubmission[8].toNumber(), 6); + assert.equal(goodSubmission[9].toNumber(), 6); + assert.equal(badSubmission[8].toNumber(), 6); + assert.equal(badSubmission[9].toNumber(), 6); + + // TODO: Split off in to another test here, but can't be bothered to refactor right now. + await goodClient.respondToChallenge(); + await checkErrorRevert(badClient.respondToChallenge()); + + // Check + const goodSubmissionAfterResponseToChallenge = await repCycle.disputeRounds(0, 0); + const badSubmissionAfterResponseToChallenge = await repCycle.disputeRounds(0, 1); + assert.equal(goodSubmissionAfterResponseToChallenge[3].sub(badSubmissionAfterResponseToChallenge[3]).toNumber(), 2); + // checks that challengeStepCompleted is two more for the good submission than the bad one. + // it's two, because we proved the starting reputation was in the starting reputation state, rather than claiming + // it was a new reputation not in the tree with value 0. + + await forwardTime(600, this); + await repCycle.invalidateHash(0, 1); + }); + + it("If an existing reputation's uniqueID is changed, that disagreement should be handled correctly", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokensAndStake(colonyNetwork, OTHER_ACCOUNT, "1000000000000000000"); + + let addr = await colonyNetwork.getReputationMiningCycle.call(true); + let repCycle = ReputationMiningCycle.at(addr); + await forwardTime(3600, this); + await repCycle.submitRootHash("0x12345678", 10, 10); + await repCycle.confirmNewHash(0); + + await giveUserCLNYTokens(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokens(colonyNetwork, OTHER_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokens(colonyNetwork, accounts[2], "1000000000000000000"); + addr = await colonyNetwork.getReputationMiningCycle.call(true); + repCycle = ReputationMiningCycle.at(addr); + await forwardTime(3600, this); + await repCycle.submitRootHash("0x0", 0, 10); + await repCycle.confirmNewHash(0); + addr = await colonyNetwork.getReputationMiningCycle.call(true); + repCycle = ReputationMiningCycle.at(addr); + + // The update log should contain the person being rewarded for the previous + // update cycle, and reputation updates for three task completions (manager, worker (skill and domain), evaluator); + // That's thirteen in total. + const nInactiveLogEntries = await repCycle.getReputationUpdateLogLength(); + assert.equal(nInactiveLogEntries.toNumber(), 13); + + await goodClient.addLogContentsToReputationTree(); + + badClient = new MaliciousReputationMinerWrongUID( + { loader: contractLoader, minerAddress: OTHER_ACCOUNT, realProviderPort: REAL_PROVIDER_PORT }, + 5, + "0xfffffffff" + ); + await badClient.initialise(colonyNetwork.address); + await badClient.addLogContentsToReputationTree(); + + let righthash = await goodClient.getRootHash(); + let wronghash = await badClient.getRootHash(); + righthash = await goodClient.getRootHash(); + wronghash = await badClient.getRootHash(); + assert(righthash !== wronghash, "Hashes from clients are equal, surprisingly"); + await forwardTime(3600, this); + + await goodClient.submitRootHash(); + await badClient.submitRootHash(); + + await goodClient.submitJustificationRootHash(); + await badClient.submitJustificationRootHash(); + + await goodClient.respondToBinarySearchForChallenge(); + await badClient.respondToBinarySearchForChallenge(); + + await goodClient.respondToBinarySearchForChallenge(); + await badClient.respondToBinarySearchForChallenge(); + + await goodClient.respondToBinarySearchForChallenge(); + await badClient.respondToBinarySearchForChallenge(); + + await goodClient.respondToBinarySearchForChallenge(); + await badClient.respondToBinarySearchForChallenge(); + + await goodClient.respondToChallenge(); + await checkErrorRevert(badClient.respondToChallenge()); + + // Check + const goodSubmissionAfterResponseToChallenge = await repCycle.disputeRounds(0, 0); + const badSubmissionAfterResponseToChallenge = await repCycle.disputeRounds(0, 1); + assert.equal(goodSubmissionAfterResponseToChallenge[3].sub(badSubmissionAfterResponseToChallenge[3]).toNumber(), 2); + // checks that challengeStepCompleted is two more for the good submission than the bad one. + // it's two, because we proved the starting reputation was in the starting reputation state, rather than claiming + // it was a new reputation not in the tree with value 0. + + await forwardTime(600, this); + await repCycle.invalidateHash(0, 1); + }); + + it("If a new reputation's uniqueID is wrong, that disagreement should be handled correctly", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokensAndStake(colonyNetwork, OTHER_ACCOUNT, "1000000000000000000"); + + let addr = await colonyNetwork.getReputationMiningCycle.call(true); + let repCycle = ReputationMiningCycle.at(addr); + await forwardTime(3600, this); + await repCycle.submitRootHash("0x12345678", 10, 10); + await repCycle.confirmNewHash(0); + + await giveUserCLNYTokens(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokens(colonyNetwork, OTHER_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokens(colonyNetwork, accounts[2], "1000000000000000000"); + addr = await colonyNetwork.getReputationMiningCycle.call(true); + repCycle = ReputationMiningCycle.at(addr); + await forwardTime(3600, this); + await repCycle.submitRootHash("0x0", 0, 10); + await repCycle.confirmNewHash(0); + addr = await colonyNetwork.getReputationMiningCycle.call(true); + repCycle = ReputationMiningCycle.at(addr); + + // The update log should contain the person being rewarded for the previous + // update cycle, and reputation updates for three task completions (manager, worker (skill and domain), evaluator); + // That's thirteen in total. + const nInactiveLogEntries = await repCycle.getReputationUpdateLogLength(); + assert.equal(nInactiveLogEntries.toNumber(), 13); + + await goodClient.addLogContentsToReputationTree(); + + badClient = new MaliciousReputationMinerReuseUID( + { loader: contractLoader, minerAddress: OTHER_ACCOUNT, realProviderPort: REAL_PROVIDER_PORT }, + 3, + 1 + ); + await badClient.initialise(colonyNetwork.address); + await badClient.addLogContentsToReputationTree(); + + let righthash = await goodClient.getRootHash(); + let wronghash = await badClient.getRootHash(); + righthash = await goodClient.getRootHash(); + wronghash = await badClient.getRootHash(); + assert(righthash !== wronghash, "Hashes from clients are equal, surprisingly"); + await forwardTime(3600, this); + + await goodClient.submitRootHash(); + await badClient.submitRootHash(); + + await goodClient.submitJustificationRootHash(); + await badClient.submitJustificationRootHash(); + + await goodClient.respondToBinarySearchForChallenge(); + await badClient.respondToBinarySearchForChallenge(); + + await goodClient.respondToBinarySearchForChallenge(); + await badClient.respondToBinarySearchForChallenge(); + + await goodClient.respondToBinarySearchForChallenge(); + await badClient.respondToBinarySearchForChallenge(); + + await goodClient.respondToBinarySearchForChallenge(); + await badClient.respondToBinarySearchForChallenge(); + + await goodClient.respondToChallenge(); + await badClient.respondToChallenge(); + + // Check + const goodSubmissionAfterResponseToChallenge = await repCycle.disputeRounds(0, 0); + const badSubmissionAfterResponseToChallenge = await repCycle.disputeRounds(0, 1); + assert.equal(goodSubmissionAfterResponseToChallenge[3].sub(badSubmissionAfterResponseToChallenge[3]).toNumber(), 0); + // Both sides have completed the same amount of challenges, but one has proved that a large number already exists + // than the other, so when we call invalidate hash, only one will be eliminated. + + await forwardTime(600, this); + // Check that we can't invalidate the one that proved a higher reputation already existed + await checkErrorRevert(repCycle.invalidateHash(0, 0)); + + await repCycle.invalidateHash(0, 1); + await repCycle.confirmNewHash(1); + const confirmedHash = await colonyNetwork.getReputationRootHash(); + assert.equal(confirmedHash, righthash); + }); + }); + + describe("Misbehaviour during dispute resolution", () => { + it("should prevent a hash from advancing if it might still get an opponent", async function advancingTest() { + this.timeout(10000000); + assert(accounts.length >= 8, "Not enough accounts for test to run"); + const accountsForTest = accounts.slice(0, 8); + for (let i = 0; i < 8; i += 1) { + await giveUserCLNYTokensAndStake(colonyNetwork, accountsForTest[i], "1000000000000000000"); // eslint-disable-line no-await-in-loop + // These have to be done sequentially because this function uses the total number of tasks as a proxy for getting the + // right taskId, so if they're all created at once it messes up. + } + + // We need to complete the current reputation cycle so that all the required log entries are present + let reputationMiningCycleAddress = await colonyNetwork.getReputationMiningCycle.call(true); + let repCycle = ReputationMiningCycle.at(reputationMiningCycleAddress); + await forwardTime(3600, this); + await repCycle.submitRootHash("0x0", 0, 10); + await repCycle.confirmNewHash(0); + + const clients = await Promise.all( + accountsForTest.map(async (addr, index) => { + const client = new MaliciousReputationMinerExtraRep( + { loader: contractLoader, minerAddress: addr, realProviderPort: REAL_PROVIDER_PORT }, + accountsForTest.length - index, + index + ); + // Each client will get a different reputation update entry wrong by a different amount, apart from the first one which + // will submit a correct hash. + await client.initialise(colonyNetwork.address); + return client; + }) + ); + + reputationMiningCycleAddress = await colonyNetwork.getReputationMiningCycle.call(true); + repCycle = ReputationMiningCycle.at(reputationMiningCycleAddress); + await forwardTime(3600, this); + for (let i = 0; i < clients.length; i += 1) { + // Doing these individually rather than in a big loop because with many instances of the EVM + // churning away at once, I *think* it's slower. + await clients[i].addLogContentsToReputationTree(); // eslint-disable-line no-await-in-loop + await clients[i].submitRootHash(); // eslint-disable-line no-await-in-loop + await clients[i].submitJustificationRootHash(); // eslint-disable-line no-await-in-loop + } + + await forwardTime(3600, this); + await accommodateChallengeAndInvalidateHash(this, clients[0], clients[1]); + await accommodateChallengeAndInvalidateHash(this, clients[2], clients[3]); + await accommodateChallengeAndInvalidateHash(this, clients[4], clients[5]); + await accommodateChallengeAndInvalidateHash(this, clients[0], clients[2]); // This is the first pairing in round 2 + await checkErrorRevert(accommodateChallengeAndInvalidateHash(this, clients[4])); + // Now clean up + await accommodateChallengeAndInvalidateHash(this, clients[6], clients[7]); + await accommodateChallengeAndInvalidateHash(this, clients[4], clients[6]); + await accommodateChallengeAndInvalidateHash(this, clients[0], clients[4]); + await repCycle.confirmNewHash(3); + }); + + it("should only allow the last hash standing to be confirmed", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokensAndStake(colonyNetwork, OTHER_ACCOUNT, "1000000000000000000"); + + const addr = await colonyNetwork.getReputationMiningCycle.call(true); + await forwardTime(3600, this); + const repCycle = ReputationMiningCycle.at(addr); + + await goodClient.addLogContentsToReputationTree(); + await badClient.addLogContentsToReputationTree(); + + await goodClient.submitRootHash(); + await badClient.submitRootHash(); + + await goodClient.submitJustificationRootHash(); + await badClient.submitJustificationRootHash(); + + await accommodateChallengeAndInvalidateHash(this, goodClient, badClient); + await checkErrorRevert(repCycle.confirmNewHash(0)); + await repCycle.confirmNewHash(1); + }); + + it("should fail to respondToChallenge if any part of the key is wrong", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokensAndStake(colonyNetwork, OTHER_ACCOUNT, "1000000000000000000"); + + const addr = await colonyNetwork.getReputationMiningCycle.call(true); + await forwardTime(3600, this); + const repCycle = ReputationMiningCycle.at(addr); + + await goodClient.addLogContentsToReputationTree(); + await badClient.addLogContentsToReputationTree(); + + await goodClient.submitRootHash(); + await badClient.submitRootHash(); + + await goodClient.submitJustificationRootHash(); + await badClient.submitJustificationRootHash(); + + await goodClient.respondToBinarySearchForChallenge(); + await badClient.respondToBinarySearchForChallenge(); + await badClient.respondToBinarySearchForChallenge(); + await goodClient.respondToBinarySearchForChallenge(); + await badClient.respondToBinarySearchForChallenge(); + await goodClient.respondToBinarySearchForChallenge(); + + // Get the log entry we're arguing over. + const submission = await repCycle.disputeRounds(0, 0); + const firstDisagreeIdx = submission[8]; + + const logEntry = await repCycle.getReputationUpdateLogEntry.call(firstDisagreeIdx - 1); + const colonyAddress = logEntry[3].slice(2); + const userAddress = logEntry[0].slice(2); + const skillId = logEntry[2]; + + const wrongColonyKey = `0x${new BN(0, 16).toString(16, 40)}${new BN(skillId.toString()).toString(16, 64)}${new BN(userAddress, 16).toString( + 16, + 40 + )}`; + const wrongReputationKey = `0x${new BN(colonyAddress, 16).toString(16, 40)}${new BN(0).toString(16, 64)}${new BN(userAddress, 16).toString( + 16, + 40 + )}`; + const wrongUserKey = `0x${new BN(colonyAddress, 16).toString(16, 40)}${new BN(skillId.toString()).toString(16, 64)}${new BN(0, 16).toString( + 16, + 40 + )}`; + + await checkErrorRevert(repCycle.respondToChallenge([0, 0, 0, 0, 0, 0, 0, 0, 0], wrongColonyKey, [], 0x0, [], 0x0, [], 0, 0, [])); + await checkErrorRevert(repCycle.respondToChallenge([0, 0, 0, 0, 0, 0, 0, 0, 0], wrongReputationKey, [], 0x0, [], 0x0, [], 0, 0, [])); + await checkErrorRevert(repCycle.respondToChallenge([0, 0, 0, 0, 0, 0, 0, 0, 0], wrongUserKey, [], 0x0, [], 0x0, [], 0, 0, [])); + + await forwardTime(600, this); + await goodClient.respondToChallenge(); + await repCycle.invalidateHash(0, 1); + await repCycle.confirmNewHash(1); + }); + + it("should fail to respondToChallenge if binary search for challenge is not complete yet", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokensAndStake(colonyNetwork, OTHER_ACCOUNT, "1000000000000000000"); + + const addr = await colonyNetwork.getReputationMiningCycle.call(true); + await forwardTime(3600, this); + const repCycle = ReputationMiningCycle.at(addr); + + await goodClient.addLogContentsToReputationTree(); + await badClient.addLogContentsToReputationTree(); + + await goodClient.submitRootHash(); + await badClient.submitRootHash(); + + await goodClient.submitJustificationRootHash(); + await badClient.submitJustificationRootHash(); + + await goodClient.respondToBinarySearchForChallenge(); + await badClient.respondToBinarySearchForChallenge(); + await badClient.respondToBinarySearchForChallenge(); + await goodClient.respondToBinarySearchForChallenge(); + + await checkErrorRevert(repCycle.respondToChallenge([0, 0, 0, 0, 0, 0, 0, 0, 0], 0x0, [], 0x0, [], 0x0, [], 0, 0, [])); + + // Cleanup + await badClient.respondToBinarySearchForChallenge(); + await goodClient.respondToBinarySearchForChallenge(); + + await forwardTime(600, this); + await goodClient.respondToChallenge(); + await repCycle.invalidateHash(0, 1); + await repCycle.confirmNewHash(1); + }); + }); + + describe("Intended ('happy path') behaviours", () => { + it("should cope with many hashes being submitted and eliminated before a winner is assigned", async function manySubmissionTest() { + this.timeout(100000000); + const nClients = Math.min(accounts.length, 7); + // TODO: This test probably needs to be written more carefully to make sure all possible edge cases are dealt with + for (let i = 0; i < nClients; i += 1) { + await giveUserCLNYTokensAndStake(colonyNetwork, accounts[i], "1000000000000000000"); // eslint-disable-line no-await-in-loop + // These have to be done sequentially because this function uses the total number of tasks as a proxy for getting the + // right taskId, so if they're all created at once it messes up. + } + + // We need to complete the current reputation cycle so that all the required log entries are present + let reputationMiningCycleAddress = await colonyNetwork.getReputationMiningCycle.call(true); + let repCycle = ReputationMiningCycle.at(reputationMiningCycleAddress); + await forwardTime(3600, this); + await repCycle.submitRootHash("0x0", 0, 10); + await repCycle.confirmNewHash(0); + const clients = await Promise.all( + accounts.slice(0, nClients).map(async (addr, index) => { + const client = new MaliciousReputationMinerExtraRep( + { loader: contractLoader, minerAddress: addr, realProviderPort: REAL_PROVIDER_PORT }, + accounts.length - index, + index + ); + // Each client will get a different reputation update entry wrong by a different amount, apart from the first one which + // will submit a correct hash. + await client.initialise(colonyNetwork.address); + return client; + }) + ); + + reputationMiningCycleAddress = await colonyNetwork.getReputationMiningCycle.call(true); + repCycle = ReputationMiningCycle.at(reputationMiningCycleAddress); + await forwardTime(3600, this); + for (let i = 0; i < clients.length; i += 1) { + // Doing these individually rather than in a big loop because with many instances of the EVM + // churning away at once, I *think* it's slower. + await clients[i].addLogContentsToReputationTree(); // eslint-disable-line no-await-in-loop + await clients[i].submitRootHash(); // eslint-disable-line no-await-in-loop + } + + const nSubmittedHashes = await repCycle.nSubmittedHashes.call(); + let nRemainingHashes = nSubmittedHashes.toNumber(); + let cycle = 0; + while (nRemainingHashes > 1) { + for (let i = 0; i < clients.length; i += 2 * 2 ** cycle) { + const [client1round] = await clients[i].getMySubmissionRoundAndIndex(); // eslint-disable-line no-await-in-loop + let client2round = new BN("-1"); + let client2idx = i; + while (!client1round.eq(client2round)) { + client2idx += 2 ** cycle; + if (!clients[client2idx]) { + break; + } + [client2round] = await clients[client2idx].getMySubmissionRoundAndIndex(); // eslint-disable-line no-await-in-loop + } + await accommodateChallengeAndInvalidateHash(this, clients[i], clients[client2idx]); // eslint-disable-line no-await-in-loop + // These could all be done simultaneously, but the one-liner with Promise.all is very hard to read. + // It involved spread syntax and everything. If someone can come up with an easy-to-read version, I'll + // be all for it + } + cycle += 1; + const nInvalidatedHashes = await repCycle.nInvalidatedHashes.call(); // eslint-disable-line no-await-in-loop + nRemainingHashes = nSubmittedHashes.sub(nInvalidatedHashes).toNumber(); + } + await repCycle.confirmNewHash(cycle); + }); + + it("should be able to process a large reputation update log", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + // TODO It would be so much better if we could do these in parallel, but until colonyNetwork#192 is fixed, we can't. + for (let i = 0; i < 30; i += 1) { + const taskId = await setupRatedTask( // eslint-disable-line + { + colonyNetwork, + colony: metaColony, + colonyToken: clny, + workerRating: 1, + managerPayout: 1, + evaluatorPayout: 1, + workerPayout: 1 + } + ); + await metaColony.finalizeTask(taskId); // eslint-disable-line no-await-in-loop + } + // Complete this reputation cycle + + let addr = await colonyNetwork.getReputationMiningCycle.call(true); + await forwardTime(3600, this); + let repCycle = ReputationMiningCycle.at(addr); + await repCycle.submitRootHash("0x12345678", 10, 10); + await repCycle.confirmNewHash(0); + // Do it again + addr = await colonyNetwork.getReputationMiningCycle.call(true); + await forwardTime(3600, this); + repCycle = ReputationMiningCycle.at(addr); + await repCycle.submitRootHash("0x12345678", 10, 10); + await repCycle.confirmNewHash(0); + }); + + it("should allow submitted hashes to go through multiple responses to a challenge", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokensAndStake(colonyNetwork, OTHER_ACCOUNT, "1000000000000000000"); + + const addr = await colonyNetwork.getReputationMiningCycle.call(true); + await forwardTime(3600, this); + const repCycle = ReputationMiningCycle.at(addr); + + await goodClient.addLogContentsToReputationTree(); + await badClient.addLogContentsToReputationTree(); + + await goodClient.submitRootHash(); + await badClient.submitRootHash(); + + await goodClient.submitJustificationRootHash(); + await badClient.submitJustificationRootHash(); + + await goodClient.respondToBinarySearchForChallenge(); + await badClient.respondToBinarySearchForChallenge(); + await badClient.respondToBinarySearchForChallenge(); + await goodClient.respondToBinarySearchForChallenge(); + await badClient.respondToBinarySearchForChallenge(); + await goodClient.respondToBinarySearchForChallenge(); + + await forwardTime(600, this); + await goodClient.respondToChallenge(); + await repCycle.invalidateHash(0, 1); + await repCycle.confirmNewHash(1); + }); + + it("should cope if someone's existing reputation would go negative, setting it to zero instead", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokensAndStake(colonyNetwork, OTHER_ACCOUNT, "1000000000000000000"); + badClient = new MaliciousReputationMinerExtraRep( + { loader: contractLoader, minerAddress: OTHER_ACCOUNT, realProviderPort: REAL_PROVIDER_PORT }, + 11, + 0xffffffffffff + ); + await badClient.initialise(colonyNetwork.address); + + await forwardTime(3600, this); + let addr = await colonyNetwork.getReputationMiningCycle.call(true); + let repCycle = ReputationMiningCycle.at(addr); + + const taskId = await setupRatedTask({ + colonyNetwork, + colony: metaColony, + managerPayout: 1000000000000, + evaluatorPayout: 1000000000000, + workerPayout: 1000000000000, + managerRating: 1, + workerRating: 1 + }); + await metaColony.finalizeTask(taskId); + await repCycle.submitRootHash("0x0", 0, 10); + await repCycle.confirmNewHash(0); + await forwardTime(3600, this); + + addr = await colonyNetwork.getReputationMiningCycle.call(true); + repCycle = ReputationMiningCycle.at(addr); + await goodClient.addLogContentsToReputationTree(); + await badClient.addLogContentsToReputationTree(); + + await goodClient.submitRootHash(); + await badClient.submitRootHash(); + + await goodClient.submitJustificationRootHash(); + await badClient.submitJustificationRootHash(); + + await accommodateChallengeAndInvalidateHash(this, goodClient, badClient); + await repCycle.confirmNewHash(1); + }); + + it("should cope if someone's new reputation would be negative, setting it to zero instead", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokensAndStake(colonyNetwork, OTHER_ACCOUNT, "1000000000000000000"); + badClient = new MaliciousReputationMinerExtraRep( + { loader: contractLoader, minerAddress: OTHER_ACCOUNT, realProviderPort: REAL_PROVIDER_PORT }, + 11, + 0xffffffffffff + ); + await badClient.initialise(colonyNetwork.address); + + await forwardTime(3600, this); + let addr = await colonyNetwork.getReputationMiningCycle.call(true); + let repCycle = ReputationMiningCycle.at(addr); + + const taskId = await setupRatedTask({ + colonyNetwork, + colony: metaColony, + worker: accounts[4], + managerPayout: 1000000000000, + evaluatorPayout: 1000000000000, + workerPayout: 1000000000000, + managerRating: 1, + workerRating: 1 + }); + await metaColony.finalizeTask(taskId); + + await repCycle.submitRootHash("0x0", 0, 10); + await repCycle.confirmNewHash(0); + await forwardTime(3600, this); + + addr = await colonyNetwork.getReputationMiningCycle.call(true); + repCycle = ReputationMiningCycle.at(addr); + await goodClient.addLogContentsToReputationTree(); + await badClient.addLogContentsToReputationTree(); + + await goodClient.submitRootHash(); + await badClient.submitRootHash(); + + await goodClient.submitJustificationRootHash(); + await badClient.submitJustificationRootHash(); + + await accommodateChallengeAndInvalidateHash(this, goodClient, badClient); + await repCycle.confirmNewHash(1); + }); + + it("should cope if someone's reputation would be overflow, setting it to the maximum value instead", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokensAndStake(colonyNetwork, OTHER_ACCOUNT, "1000000000000000000"); + badClient = new MaliciousReputationMinerExtraRep( + { loader: contractLoader, minerAddress: OTHER_ACCOUNT, realProviderPort: REAL_PROVIDER_PORT }, + 12, + new BN("-1000000000000000000000000000000000000000000") + ); + await badClient.initialise(colonyNetwork.address); + + await forwardTime(3600, this); + let addr = await colonyNetwork.getReputationMiningCycle.call(true); + let repCycle = ReputationMiningCycle.at(addr); + const rootGlobalSkill = await colonyNetwork.getRootGlobalSkillId.call(); + + await goodClient.insert(metaColony.address, rootGlobalSkill, MAIN_ACCOUNT, new BN("2").pow(new BN("256")).subn(2), 0); + await badClient.insert(metaColony.address, rootGlobalSkill, MAIN_ACCOUNT, new BN("2").pow(new BN("256")).subn(2), 0); + const rootHash = await goodClient.getRootHash(); + const taskId = await setupRatedTask({ + colonyNetwork, + colony: metaColony, + worker: MAIN_ACCOUNT, + managerPayout: 1000000000000, + evaluatorPayout: 1000000000000, + workerPayout: 1000000000000, + managerRating: 3, + workerRating: 3 + }); + await metaColony.finalizeTask(taskId); + + await repCycle.submitRootHash(rootHash, 1, 10); + await repCycle.confirmNewHash(0); + await forwardTime(3600, this); + + addr = await colonyNetwork.getReputationMiningCycle.call(true); + repCycle = ReputationMiningCycle.at(addr); + await goodClient.addLogContentsToReputationTree(); + await badClient.addLogContentsToReputationTree(); + + await goodClient.submitRootHash(); + await badClient.submitRootHash(); + + await goodClient.submitJustificationRootHash(); + await badClient.submitJustificationRootHash(); + + await accommodateChallengeAndInvalidateHash(this, goodClient, badClient); + await repCycle.confirmNewHash(1); + }); + + it("should keep reputation updates that occur during one update window for the next window", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + + let addr = await colonyNetwork.getReputationMiningCycle.call(true); + await forwardTime(3600, this); + const repCycle = ReputationMiningCycle.at(addr); + await repCycle.submitRootHash("0x12345678", 10, 10); + await fundColonyWithTokens(metaColony, clny, "350000000000000000000"); + const taskId1 = await setupRatedTask({ colonyNetwork, colony: metaColony }); + await metaColony.finalizeTask(taskId1); // Creates an entry in the reputation log for the worker and manager + addr = await colonyNetwork.getReputationMiningCycle.call(false); + let inactiveReputationMiningCycle = ReputationMiningCycle.at(addr); + + const initialRepLogLength = await inactiveReputationMiningCycle.getReputationUpdateLogLength.call(); + await repCycle.confirmNewHash(0); + // This confirmation should freeze the reputation log that we added the above task entries to + // and move it to the inactive rep log + const addr2 = await colonyNetwork.getReputationMiningCycle.call(true); + assert.equal(addr, addr2); + const reputationMiningCycle = ReputationMiningCycle.at(addr2); + const finalRepLogLength = await reputationMiningCycle.getReputationUpdateLogLength.call(); + assert.equal(finalRepLogLength.toNumber(), initialRepLogLength.toNumber()); + // Check the active log now has one entry in it (which will be the rewards for the miner who submitted + // the accepted hash. + addr = await colonyNetwork.getReputationMiningCycle.call(false); + inactiveReputationMiningCycle = ReputationMiningCycle.at(addr); + const activeRepLogLength = await inactiveReputationMiningCycle.getReputationUpdateLogLength.call(); + assert.equal(activeRepLogLength.toNumber(), 1); + }); + + it("The reputation mining client should insert reputation updates from the log", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + + let addr = await colonyNetwork.getReputationMiningCycle.call(true); + let repCycle = ReputationMiningCycle.at(addr); + await forwardTime(3600, this); + await repCycle.submitRootHash("0x12345678", 10, 10); + await repCycle.confirmNewHash(0); + + await giveUserCLNYTokens(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokens(colonyNetwork, OTHER_ACCOUNT, "1000000000000000000"); + await giveUserCLNYTokens(colonyNetwork, accounts[2], "1000000000000000000"); + addr = await colonyNetwork.getReputationMiningCycle.call(true); + repCycle = ReputationMiningCycle.at(addr); + await forwardTime(3600, this); + await repCycle.submitRootHash("0x12345678", 10, 10); + await repCycle.confirmNewHash(0); + + // The update log should contain the person being rewarded for the previous + // update cycle, and reputation updates for three task completions (manager, worker (domain and skill), evaluator); + // That's thirteen in total. + addr = await colonyNetwork.getReputationMiningCycle.call(true); + repCycle = ReputationMiningCycle.at(addr); + const nInactiveLogEntries = await repCycle.getReputationUpdateLogLength(); + assert.equal(nInactiveLogEntries.toNumber(), 13); + + const client = new ReputationMiner({ loader: contractLoader, minerAddress: MAIN_ACCOUNT, realProviderPort: REAL_PROVIDER_PORT }); + await client.initialise(colonyNetwork.address); + await client.addLogContentsToReputationTree(); + + // Check the client's tree has four entries. + // manager, worker (domain skill and task skill), evalutator + last log used for disputes + assert.equal(Object.keys(client.reputations).length, 5); + // These should be: + // 1. Reputation reward for MAIN_ACCOUNT for submitting the previous reputaiton hash + // (currently skill 0, needs to change to indicate a special mining skill) + let key1 = `0x${new BN(metaColony.address.slice(2), 16).toString(16, 40)}`; // Colony address as bytes + key1 += `${new BN("0").toString(16, 64)}`; // SkillId as uint256 + key1 += `${new BN(MAIN_ACCOUNT.slice(2), 16).toString(16, 40)}`; // User address as bytes + assert.equal( + client.reputations[key1], + `0x`+`0000000000000000000000000000000000000000000000000de0b6b3a7640000`+`0000000000000000000000000000000000000000000000000000000000000001` // eslint-disable-line + ); + // 2. Reputation reward for MAIN_ACCOUNT for being the manager for the tasks created by giveUserCLNYTokens + let key2 = `0x${new BN(metaColony.address.slice(2), 16).toString(16, 40)}`; + key2 += `${new BN("2").toString(16, 64)}`; + key2 += `${new BN(MAIN_ACCOUNT.slice(2), 16).toString(16, 40)}`; + assert.equal( + client.reputations[key2], + `0x`+`00000000000000000000000000000000000000000000000053444835ec580000`+`0000000000000000000000000000000000000000000000000000000000000002` // eslint-disable-line + ); + // 3. Reputation reward for OTHER_ACCOUNT for being the evaluator for the tasks created by giveUserCLNYTokens + let key3 = `0x${new BN(metaColony.address.slice(2), 16).toString(16, 40)}`; + key3 += `${new BN("2").toString(16, 64)}`; + key3 += `${new BN(OTHER_ACCOUNT.slice(2), 16).toString(16, 40)}`; + assert.equal( + client.reputations[key3], + `0x`+`0000000000000000000000000000000000000000000000000000000000000000`+`0000000000000000000000000000000000000000000000000000000000000003` // eslint-disable-line + ); + // 4. Reputation reward for accounts[2] for being the worker for the tasks created by giveUserCLNYTokens + // NB at the moment, the reputation reward for the worker is 0. + let key4 = `0x${new BN(metaColony.address.slice(2), 16).toString(16, 40)}`; + key4 += `${new BN("2").toString(16, 64)}`; + key4 += `${new BN(accounts[2].slice(2), 16).toString(16, 40)}`; + assert.equal( + client.reputations[key4], + `0x`+`0000000000000000000000000000000000000000000000000000000000000000`+`0000000000000000000000000000000000000000000000000000000000000004` // eslint-disable-line + ); + }); + + it("Should allow a user to prove their reputation", async () => { + await giveUserCLNYTokensAndStake(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + + let addr = await colonyNetwork.getReputationMiningCycle.call(true); + let repCycle = ReputationMiningCycle.at(addr); + await forwardTime(3600, this); + await repCycle.submitRootHash("0x12345678", 10, 10); + await repCycle.confirmNewHash(0); + await giveUserCLNYTokens(colonyNetwork, MAIN_ACCOUNT, "1000000000000000000"); + await forwardTime(3600, this); + addr = await colonyNetwork.getReputationMiningCycle.call(true); + repCycle = ReputationMiningCycle.at(addr); + await repCycle.submitRootHash("0x123456789", 10, 10); + await repCycle.confirmNewHash(0); + + const client = new ReputationMiner({ loader: contractLoader, minerAddress: MAIN_ACCOUNT, realProviderPort: REAL_PROVIDER_PORT }); + await client.initialise(colonyNetwork.address); + await client.addLogContentsToReputationTree(); + const newRootHash = await client.getRootHash(); + + await forwardTime(3600, this); + addr = await colonyNetwork.getReputationMiningCycle.call(true); + repCycle = ReputationMiningCycle.at(addr); + await repCycle.submitRootHash(newRootHash, 10, 10); + await repCycle.confirmNewHash(0); + let key = `0x${new BN(metaColony.address.slice(2), 16).toString(16, 40)}`; // Colony address as bytes + key += `${new BN("2").toString(16, 64)}`; // SkillId as uint256 + key += `${new BN(MAIN_ACCOUNT.slice(2), 16).toString(16, 40)}`; // User address as bytes + + const value = client.reputations[key]; + const proof = await client.getProof(key); + const [branchMask, siblings] = proof; + const validProof = await metaColony.verifyReputationProof(`${key}`, `${value}`, branchMask, siblings); + assert.equal(validProof, true); + }); + + it("The reputation mining clinent should calculate reputation decay correctly"); + it("should abort if a deposit did not complete correctly"); + }); +}); diff --git a/src/lib/colonyNetwork/test/colony-network.js b/src/lib/colonyNetwork/test/colony-network.js new file mode 100755 index 0000000..a896887 --- /dev/null +++ b/src/lib/colonyNetwork/test/colony-network.js @@ -0,0 +1,278 @@ +/* globals artifacts */ +import { getTokenArgs, web3GetNetwork, web3GetBalance, checkErrorRevert, checkErrorNonPayableFunction, expectEvent } from "../helpers/test-helper"; + +import { setupColonyVersionResolver } from "../helpers/upgradable-contracts"; + +const EtherRouter = artifacts.require("EtherRouter"); +const Colony = artifacts.require("Colony"); +const Token = artifacts.require("Token"); +const ColonyFunding = artifacts.require("ColonyFunding"); +const ColonyTask = artifacts.require("ColonyTask"); +const IColonyNetwork = artifacts.require("IColonyNetwork"); +const Resolver = artifacts.require("Resolver"); + +contract("ColonyNetwork", accounts => { + const TOKEN_ARGS = getTokenArgs(); + const OTHER_ACCOUNT = accounts[1]; + let colonyFunding; + let colonyTask; + let resolver; + let resolverColonyNetworkDeployed; + let colonyNetwork; + let createColonyGas; + let version; + + before(async () => { + const network = await web3GetNetwork(); + createColonyGas = network === "coverage" ? "0xfffffffffff" : 4e6; + resolverColonyNetworkDeployed = await Resolver.deployed(); + }); + + beforeEach(async () => { + const colony = await Colony.new(); + version = await colony.version.call(); + resolver = await Resolver.new(); + colonyFunding = await ColonyFunding.new(); + colonyTask = await ColonyTask.new(); + + const etherRouter = await EtherRouter.new(); + await etherRouter.setResolver(resolverColonyNetworkDeployed.address); + colonyNetwork = await IColonyNetwork.at(etherRouter.address); + await setupColonyVersionResolver(colony, colonyFunding, colonyTask, resolver, colonyNetwork); + }); + + describe("when initialised", () => { + it("should accept ether", async () => { + await colonyNetwork.send(1); + const colonyNetworkBalance = await web3GetBalance(colonyNetwork.address); + assert.equal(colonyNetworkBalance.toNumber(), 1); + }); + + it("should have the correct current Colony version set", async () => { + const currentColonyVersion = await colonyNetwork.getCurrentColonyVersion.call(); + assert.equal(version.toNumber(), currentColonyVersion.toNumber()); + }); + + it("should have the Resolver for current Colony version set", async () => { + const currentResolver = await colonyNetwork.getColonyVersionResolver.call(version.toNumber()); + assert.equal(currentResolver, resolver.address); + }); + + it("should be able to register a higher Colony contract version", async () => { + const sampleResolver = "0x65a760e7441cf435086ae45e14a0c8fc1080f54c"; + const currentColonyVersion = await colonyNetwork.getCurrentColonyVersion.call(); + const updatedVersion = currentColonyVersion.add(1).toNumber(); + await colonyNetwork.addColonyVersion(updatedVersion, sampleResolver); + + const updatedColonyVersion = await colonyNetwork.getCurrentColonyVersion.call(); + assert.equal(updatedColonyVersion.toNumber(), updatedVersion); + const currentResolver = await colonyNetwork.getColonyVersionResolver.call(updatedVersion); + assert.equal(currentResolver, sampleResolver); + }); + + it("when registering a lower version of the Colony contract, should NOT update the current (latest) colony version", async () => { + const sampleResolver = "0x65a760e7441cf435086ae45e14a0c8fc1080f54c"; + const currentColonyVersion = await colonyNetwork.getCurrentColonyVersion.call(); + await colonyNetwork.addColonyVersion(currentColonyVersion.sub(1).toNumber(), sampleResolver); + + const updatedColonyVersion = await colonyNetwork.getCurrentColonyVersion.call(); + assert.equal(updatedColonyVersion.toNumber(), currentColonyVersion.toNumber()); + }); + }); + + describe("when creating new colonies", () => { + it("should allow users to create new colonies", async () => { + const token = await Token.new(...TOKEN_ARGS); + const { logs } = await colonyNetwork.createColony(token.address); + const { colonyAddress } = logs[0].args; + const colonyCount = await colonyNetwork.getColonyCount.call(); + assert.notEqual(colonyAddress, 0x0); + assert.equal(colonyCount.toNumber(), 1); + }); + + it("should maintain correct count of colonies", async () => { + const token = await Token.new(...getTokenArgs()); + await colonyNetwork.createColony(token.address); + await colonyNetwork.createColony(token.address); + await colonyNetwork.createColony(token.address); + await colonyNetwork.createColony(token.address); + await colonyNetwork.createColony(token.address); + await colonyNetwork.createColony(token.address); + await colonyNetwork.createColony(token.address); + const colonyCount = await colonyNetwork.getColonyCount.call(); + assert.equal(colonyCount.toNumber(), 7); + }); + + it("when meta colony is created, should have the root global and local skills initialised", async () => { + const token = await Token.new(...TOKEN_ARGS); + await colonyNetwork.createMetaColony(token.address); + const skillCount = await colonyNetwork.getSkillCount.call(); + assert.equal(skillCount.toNumber(), 2); + const rootGlobalSkill = await colonyNetwork.getSkill.call(1); + assert.equal(rootGlobalSkill[0].toNumber(), 0); + assert.equal(rootGlobalSkill[1].toNumber(), 0); + + const globalSkill1 = await colonyNetwork.isGlobalSkill.call(1); + assert.isTrue(globalSkill1); + + const globalSkill2 = await colonyNetwork.isGlobalSkill.call(2); + assert.isFalse(globalSkill2); + + const rootGlobalSkillId = await colonyNetwork.getRootGlobalSkillId.call(); + assert.equal(rootGlobalSkillId, 1); + }); + + it("should fail to create meta colony if it already exists", async () => { + const token = await Token.new(...TOKEN_ARGS); + await colonyNetwork.createMetaColony(token.address); + const metaColonyAddress1 = await colonyNetwork.getMetaColony.call(); + + await checkErrorRevert(colonyNetwork.createMetaColony(token.address)); + const metaColonyAddress2 = await colonyNetwork.getMetaColony.call(); + assert.equal(metaColonyAddress1, metaColonyAddress2); + }); + + it("when any colony is created, should have the root local skill initialised", async () => { + const token = await Token.new(...TOKEN_ARGS); + const { logs } = await colonyNetwork.createColony(token.address); + const rootLocalSkill = await colonyNetwork.getSkill.call(1); + assert.equal(rootLocalSkill[0].toNumber(), 0); + assert.equal(rootLocalSkill[1].toNumber(), 0); + + const isGlobal = await colonyNetwork.isGlobalSkill.call(2); + assert.isFalse(isGlobal); + + const { colonyAddress } = logs[0].args; + const colony = await Colony.at(colonyAddress); + const rootDomain = await colony.getDomain.call(1); + assert.equal(rootDomain[0].toNumber(), 1); + assert.equal(rootDomain[1].toNumber(), 1); + + const domainCount = await colony.getDomainCount.call(); + assert.equal(domainCount.toNumber(), 1); + }); + + it("should fail if ETH is sent", async () => { + try { + const token = await Token.new(...TOKEN_ARGS); + await colonyNetwork.createColony(token.address, { value: 1, gas: createColonyGas }); + } catch (err) { + checkErrorNonPayableFunction(err); + } + const colonyNetworkBalance = await web3GetBalance(colonyNetwork.address); + assert.equal(0, colonyNetworkBalance.toNumber()); + }); + + it("should log a ColonyAdded event", async () => { + const token = await Token.new(...TOKEN_ARGS); + await expectEvent(colonyNetwork.createColony(token.address), "ColonyAdded"); + }); + }); + + describe("when getting existing colonies", () => { + it("should allow users to get the address of a colony by its index", async () => { + const token = await Token.new(...TOKEN_ARGS); + await colonyNetwork.createColony(token.address); + await colonyNetwork.createColony(token.address); + await colonyNetwork.createColony(token.address); + const colonyAddress = await colonyNetwork.getColony.call(3); + assert.notEqual(colonyAddress, "0x0000000000000000000000000000000000000000"); + }); + + it("should return an empty address if there is no colony for the index provided", async () => { + const colonyAddress = await colonyNetwork.getColony.call(15); + assert.equal(colonyAddress, "0x0000000000000000000000000000000000000000"); + }); + + it("should be able to get the Colony version", async () => { + const token = await Token.new(...TOKEN_ARGS); + const { logs } = await colonyNetwork.createColony(token.address); + const { colonyAddress } = logs[0].args; + const colony = await Colony.at(colonyAddress); + const actualColonyVersion = await colony.version.call(); + assert.equal(version.toNumber(), actualColonyVersion.toNumber()); + }); + }); + + describe("when upgrading a colony", () => { + it("should be able to upgrade a colony, if a colony owner", async () => { + const token = await Token.new(...TOKEN_ARGS); + const { logs } = await colonyNetwork.createColony(token.address); + const { colonyId, colonyAddress } = logs[0].args; + const colony = await EtherRouter.at(colonyAddress); + + const sampleResolver = "0x65a760e7441cf435086ae45e14a0c8fc1080f54c"; + const currentColonyVersion = await colonyNetwork.getCurrentColonyVersion.call(); + const newVersion = currentColonyVersion.add(1).toNumber(); + await colonyNetwork.addColonyVersion(newVersion, sampleResolver); + + await colonyNetwork.upgradeColony(colonyId, newVersion); + const colonyResolver = await colony.resolver.call(); + assert.equal(colonyResolver, sampleResolver); + }); + + it("should NOT be able to upgrade a colony to a lower version", async () => { + const token = await Token.new(...TOKEN_ARGS); + const { logs } = await colonyNetwork.createColony(token.address); + const { colonyId, colonyAddress } = logs[0].args; + await Colony.at(colonyAddress); + + const sampleResolver = "0x65a760e7441cf435086ae45e14a0c8fc1080f54c"; + const currentColonyVersion = await colonyNetwork.getCurrentColonyVersion.call(); + const newVersion = currentColonyVersion.sub(1).toNumber(); + await colonyNetwork.addColonyVersion(newVersion, sampleResolver); + + await checkErrorRevert(colonyNetwork.upgradeColony(colonyId, newVersion)); + assert.equal(version.toNumber(), currentColonyVersion.toNumber()); + }); + + it("should NOT be able to upgrade a colony to a nonexistent version", async () => { + const token = await Token.new(...TOKEN_ARGS); + const { logs } = await colonyNetwork.createColony(token.address); + const { colonyId } = logs[0].args; + const currentColonyVersion = await colonyNetwork.getCurrentColonyVersion.call(); + const newVersion = currentColonyVersion.add(1).toNumber(); + + await checkErrorRevert(colonyNetwork.upgradeColony(colonyId, newVersion)); + assert.equal(version.toNumber(), currentColonyVersion.toNumber()); + }); + + it("should NOT be able to upgrade a colony if not a colony owner", async () => { + const token = await Token.new(...TOKEN_ARGS); + const { logs } = await colonyNetwork.createColony(token.address); + const { colonyId, colonyAddress } = logs[0].args; + const colony = await EtherRouter.at(colonyAddress); + const colonyResolver = await colony.resolver.call(); + + const sampleResolver = "0x65a760e7441cf435086ae45e14a0c8fc1080f54c"; + const currentColonyVersion = await colonyNetwork.getCurrentColonyVersion.call(); + const newVersion = currentColonyVersion.add(1).toNumber(); + await colonyNetwork.addColonyVersion(newVersion, sampleResolver); + + await checkErrorRevert(colonyNetwork.upgradeColony(colonyId, newVersion, { from: OTHER_ACCOUNT })); + assert.notEqual(colonyResolver, sampleResolver); + }); + }); + + describe("when adding a skill", () => { + beforeEach(async () => { + const token = await Token.new(...TOKEN_ARGS); + const { logs } = await colonyNetwork.createColony(token.address); + const { colonyAddress } = logs[0].args; + await token.setOwner(colonyAddress); + }); + + it("should not be able to add a global skill, by an address that is not the meta colony ", async () => { + await checkErrorRevert(colonyNetwork.addSkill(1, true)); + const skillCount = await colonyNetwork.getSkillCount.call(); + assert.equal(skillCount.toNumber(), 1); + }); + + it("should NOT be able to add a local skill, by an address that is not a Colony", async () => { + await checkErrorRevert(colonyNetwork.addSkill(2, false)); + + const skillCount = await colonyNetwork.getSkillCount.call(); + assert.equal(skillCount.toNumber(), 1); + }); + }); +}); diff --git a/src/lib/colonyNetwork/test/colony-task-work-rating.js b/src/lib/colonyNetwork/test/colony-task-work-rating.js new file mode 100644 index 0000000..abccec5 --- /dev/null +++ b/src/lib/colonyNetwork/test/colony-task-work-rating.js @@ -0,0 +1,289 @@ +/* globals artifacts */ + +import { + EVALUATOR, + WORKER, + OTHER, + MANAGER_RATING, + WORKER_RATING, + RATING_1_SALT, + RATING_2_SALT, + RATING_1_SECRET, + RATING_2_SECRET, + MANAGER_ROLE, + EVALUATOR_ROLE, + WORKER_ROLE, + DELIVERABLE_HASH, + INITIAL_FUNDING, + SECONDS_PER_DAY +} from "../helpers/constants"; +import { getTokenArgs, currentBlockTime, checkErrorRevert, forwardTime } from "../helpers/test-helper"; +import { fundColonyWithTokens, setupAssignedTask, setupRatedTask } from "../helpers/test-data-generator"; + +const IColony = artifacts.require("IColony"); +const IColonyNetwork = artifacts.require("IColonyNetwork"); +const EtherRouter = artifacts.require("EtherRouter"); +const Token = artifacts.require("Token"); + +contract("Colony Task Work Rating", () => { + let colony; + let colonyNetwork; + let token; + + before(async () => { + const etherRouter = await EtherRouter.deployed(); + colonyNetwork = await IColonyNetwork.at(etherRouter.address); + }); + + beforeEach(async () => { + const tokenArgs = getTokenArgs(); + const colonyToken = await Token.new(...tokenArgs); + const { logs } = await colonyNetwork.createColony(colonyToken.address); + const { colonyAddress } = logs[0].args; + colony = await IColony.at(colonyAddress); + const otherTokenArgs = getTokenArgs(); + token = await Token.new(...otherTokenArgs); + }); + + describe("when rating task work", () => { + it("should allow rating, before the due date but after the work has been submitted", async () => { + let dueDate = await currentBlockTime(); + dueDate += SECONDS_PER_DAY * 7; + const taskId = await setupAssignedTask({ colonyNetwork, colony, dueDate }); + await colony.submitTaskDeliverable(taskId, DELIVERABLE_HASH, { from: WORKER }); + + await colony.submitTaskWorkRating(taskId, WORKER_ROLE, RATING_2_SECRET, { from: EVALUATOR }); + const currentTime1 = await currentBlockTime(); + const rating1 = await colony.getTaskWorkRatings.call(taskId); + assert.equal(rating1[0], 1); + assert.closeTo(rating1[1].toNumber(), currentTime1, 2); + const ratingSecret1 = await colony.getTaskWorkRatingSecret.call(taskId, WORKER_ROLE); + assert.equal(ratingSecret1, RATING_2_SECRET); + + await colony.submitTaskWorkRating(taskId, MANAGER_ROLE, RATING_1_SECRET, { from: WORKER }); + const currentTime2 = await currentBlockTime(); + const rating2 = await colony.getTaskWorkRatings.call(taskId); + assert.equal(rating2[0].toNumber(), 2); + assert.closeTo(rating2[1].toNumber(), currentTime2, 2); + const ratingSecret2 = await colony.getTaskWorkRatingSecret.call(taskId, MANAGER_ROLE); + assert.equal(ratingSecret2, RATING_1_SECRET); + }); + + it("should allow rating, after the due date has passed, when no work has been submitted", async () => { + const taskId = await setupAssignedTask({ colonyNetwork, colony }); + await colony.submitTaskWorkRating(taskId, MANAGER_ROLE, RATING_1_SECRET, { from: WORKER }); + await colony.submitTaskWorkRating(taskId, WORKER_ROLE, RATING_2_SECRET, { from: EVALUATOR }); + + const ratingSecret2 = await colony.getTaskWorkRatingSecret.call(taskId, MANAGER_ROLE); + assert.equal(ratingSecret2, RATING_1_SECRET); + const ratingSecret1 = await colony.getTaskWorkRatingSecret.call(taskId, WORKER_ROLE); + assert.equal(ratingSecret1, RATING_2_SECRET); + }); + + it("should fail if I try to rate before task's due date has passed and work has not been submitted", async () => { + let dueDate = await currentBlockTime(); + dueDate += SECONDS_PER_DAY * 7; + const taskId = await setupAssignedTask({ colonyNetwork, colony, dueDate }); + await checkErrorRevert(colony.submitTaskWorkRating(taskId, WORKER_ROLE, RATING_2_SECRET, { from: EVALUATOR })); + const ratingSecrets = await colony.getTaskWorkRatings.call(taskId); + assert.equal(ratingSecrets[0].toNumber(), 0); + }); + + it("should fail if I try to rate work on behalf of a worker", async () => { + const taskId = await setupAssignedTask({ colonyNetwork, colony }); + await checkErrorRevert(colony.submitTaskWorkRating(taskId, MANAGER_ROLE, RATING_1_SECRET, { from: OTHER })); + const ratingSecrets = await colony.getTaskWorkRatings.call(taskId); + assert.equal(ratingSecrets[0], 0); + }); + + it("should fail if I try to rate work for a role that's not setup to be rated", async () => { + const taskId = await setupAssignedTask({ colonyNetwork, colony }); + await checkErrorRevert(colony.submitTaskWorkRating(taskId, EVALUATOR_ROLE, RATING_2_SECRET, { from: EVALUATOR })); + const ratingSecrets = await colony.getTaskWorkRatings.call(taskId); + assert.equal(ratingSecrets[0].toNumber(), 0); + }); + + it("should fail, if I try to rate work twice", async () => { + const taskId = await setupAssignedTask({ colonyNetwork, colony }); + await colony.submitTaskWorkRating(taskId, WORKER_ROLE, RATING_2_SECRET, { from: EVALUATOR }); + + await checkErrorRevert(colony.submitTaskWorkRating(taskId, WORKER_ROLE, RATING_1_SECRET, { from: EVALUATOR })); + const ratingSecrets = await colony.getTaskWorkRatings.call(taskId); + assert.equal(ratingSecrets[0], 1); + const ratingSecret = await colony.getTaskWorkRatingSecret.call(taskId, WORKER_ROLE); + assert.equal(ratingSecret, RATING_2_SECRET); + }); + + it("should fail if I try to rate a task too late", async () => { + const taskId = await setupAssignedTask({ colonyNetwork, colony }); + + await forwardTime(SECONDS_PER_DAY * 5 + 1, this); + await checkErrorRevert(colony.submitTaskWorkRating(taskId, WORKER_ROLE, RATING_2_SECRET, { from: EVALUATOR })); + const ratingSecrets = await colony.getTaskWorkRatings.call(taskId); + assert.equal(ratingSecrets[0].toNumber(), 0); + }); + + it("should fail if I try to submit work for a task using an invalid id", async () => { + const taskId = await setupAssignedTask({ colonyNetwork, colony }); + + await checkErrorRevert(colony.submitTaskWorkRating(10, WORKER_ROLE, RATING_2_SECRET, { from: EVALUATOR })); + const ratingSecrets = await colony.getTaskWorkRatings.call(taskId); + assert.equal(ratingSecrets[0], 0); + }); + }); + + describe("when revealing a task work rating", () => { + it("should allow revealing a rating by evaluator and worker", async () => { + await fundColonyWithTokens(colony, token, INITIAL_FUNDING); + const taskId = await setupRatedTask({ colonyNetwork, colony, token }); + + const roleManager = await colony.getTaskRole.call(taskId, MANAGER_ROLE); + assert.equal(roleManager[2].toNumber(), MANAGER_RATING); + + const roleWorker = await colony.getTaskRole.call(taskId, WORKER_ROLE); + assert.isFalse(roleWorker[1]); + assert.equal(roleWorker[2].toNumber(), WORKER_RATING); + + const roleEvaluator = await colony.getTaskRole.call(taskId, EVALUATOR_ROLE); + assert.isFalse(roleEvaluator[1]); + }); + + it("should allow revealing a rating from the evaluator after the 5 days wait for rating commits expires", async () => { + let dueDate = await currentBlockTime(); + dueDate += SECONDS_PER_DAY * 8; + const taskId = await setupAssignedTask({ colonyNetwork, colony, dueDate }); + await colony.submitTaskDeliverable(1, DELIVERABLE_HASH, { from: WORKER }); + await colony.submitTaskWorkRating(1, WORKER_ROLE, RATING_2_SECRET, { from: EVALUATOR }); + + await forwardTime(SECONDS_PER_DAY * 5 + 1, this); + await colony.revealTaskWorkRating(1, WORKER_ROLE, WORKER_RATING, RATING_2_SALT, { from: EVALUATOR }); + + const roleWorker = await colony.getTaskRole.call(taskId, WORKER_ROLE); + assert.equal(roleWorker[2].toNumber(), WORKER_RATING); + + const roleEvaluator = await colony.getTaskRole.call(taskId, EVALUATOR_ROLE); + assert.isFalse(roleEvaluator[1]); + }); + + it("should fail if I try to reveal rating with an incorrect secret", async () => { + const taskId = await setupAssignedTask({ colonyNetwork, colony }); + await colony.submitTaskWorkRating(taskId, MANAGER_ROLE, RATING_1_SECRET, { from: WORKER }); + await colony.submitTaskWorkRating(taskId, WORKER_ROLE, RATING_2_SECRET, { from: EVALUATOR }); + await checkErrorRevert(colony.revealTaskWorkRating(taskId, MANAGER_ROLE, MANAGER_RATING, RATING_2_SALT, { from: WORKER })); + + const roleManager = await colony.getTaskRole.call(taskId, MANAGER_ROLE); + assert.equal(roleManager[2].toNumber(), 0); + }); + + it("should fail if there are two rating secrets and I try to reveal the one from the evaluator late", async () => { + const taskId = await setupAssignedTask({ colonyNetwork, colony }); + await colony.submitTaskWorkRating(taskId, MANAGER_ROLE, RATING_1_SECRET, { from: WORKER }); + await colony.submitTaskWorkRating(taskId, WORKER_ROLE, RATING_2_SECRET, { from: EVALUATOR }); + + await forwardTime(SECONDS_PER_DAY * 5 + 2, this); + await checkErrorRevert(colony.revealTaskWorkRating(taskId, WORKER_ROLE, WORKER_RATING, RATING_2_SALT, { from: EVALUATOR })); + + const roleWorker = await colony.getTaskRole.call(taskId, WORKER_ROLE); + assert.equal(roleWorker[2].toNumber(), 0); + }); + + it("should fail if there are two rating secrets and I try to reveal the one from the worker late", async () => { + const taskId = await setupAssignedTask({ colonyNetwork, colony }); + await colony.submitTaskWorkRating(taskId, MANAGER_ROLE, RATING_1_SECRET, { from: WORKER }); + await colony.submitTaskWorkRating(taskId, WORKER_ROLE, RATING_2_SECRET, { from: EVALUATOR }); + + await forwardTime(SECONDS_PER_DAY * 5 + 2, this); + await checkErrorRevert(colony.revealTaskWorkRating(taskId, MANAGER_ROLE, MANAGER_RATING, RATING_1_SALT, { from: WORKER })); + + const roleManager = await colony.getTaskRole.call(1, MANAGER_ROLE); + assert.equal(roleManager[2].toNumber(), 0); + }); + + it("should fail if evaluator tries to reveal rating before the 5 days wait for rating commits expires", async () => { + const taskId = await setupAssignedTask({ colonyNetwork, colony }); + await colony.submitTaskWorkRating(taskId, WORKER_ROLE, RATING_2_SECRET, { from: EVALUATOR }); + await forwardTime(SECONDS_PER_DAY * 4, this); + await checkErrorRevert(colony.revealTaskWorkRating(taskId, WORKER_ROLE, WORKER_RATING, RATING_2_SALT, { from: EVALUATOR })); + + const roleWorker = await colony.getTaskRole.call(taskId, WORKER_ROLE); + assert.equal(roleWorker[2].toNumber(), 0); + }); + + it("should fail if evaluator tries to reveal rating after 5 days wait for rating reveal expires", async () => { + const taskId = await setupAssignedTask({ colonyNetwork, colony }); + await colony.submitTaskWorkRating(taskId, WORKER_ROLE, RATING_2_SECRET, { from: EVALUATOR }); + + await forwardTime(SECONDS_PER_DAY * 10 + 1, this); + await checkErrorRevert(colony.revealTaskWorkRating(taskId, WORKER_ROLE, WORKER_RATING, RATING_2_SALT, { from: EVALUATOR })); + + const roleWorker = await colony.getTaskRole.call(taskId, WORKER_ROLE); + assert.equal(roleWorker[2].toNumber(), 0); + }); + }); + + describe("when assigning work ratings after the user not commiting or revealing on time", () => { + it("should assign rating 3 to manager and penalise worker, when they haven't submitted rating on time", async () => { + const taskId = await setupAssignedTask({ colonyNetwork, colony }); + await colony.submitTaskWorkRating(taskId, WORKER_ROLE, RATING_2_SECRET, { from: EVALUATOR }); + await forwardTime(SECONDS_PER_DAY * 5 + 1, this); + await colony.revealTaskWorkRating(taskId, WORKER_ROLE, WORKER_RATING, RATING_2_SALT, { from: EVALUATOR }); + await forwardTime(SECONDS_PER_DAY * 5 + 1, this); + await colony.assignWorkRating(taskId); + + const roleWorker = await colony.getTaskRole.call(taskId, WORKER_ROLE); + assert.isTrue(roleWorker[1]); + assert.equal(roleWorker[2].toNumber(), WORKER_RATING); + + const roleManager = await colony.getTaskRole.call(taskId, MANAGER_ROLE); + assert.equal(roleManager[2].toNumber(), 3); + + const roleEvaluator = await colony.getTaskRole.call(taskId, EVALUATOR_ROLE); + assert.isFalse(roleEvaluator[1]); + }); + + it("should assign rating 3 to worker, when evaluator hasn't submitted rating on time", async () => { + const taskId = await setupAssignedTask({ colonyNetwork, colony }); + await colony.submitTaskWorkRating(taskId, MANAGER_ROLE, RATING_1_SECRET, { from: WORKER }); + await forwardTime(SECONDS_PER_DAY * 5 + 1, this); + await colony.revealTaskWorkRating(taskId, MANAGER_ROLE, MANAGER_RATING, RATING_1_SALT, { from: WORKER }); + await forwardTime(SECONDS_PER_DAY * 5 + 1, this); + await colony.assignWorkRating(taskId); + + const roleWorker = await colony.getTaskRole.call(taskId, WORKER_ROLE); + assert.isFalse(roleWorker[1]); + assert.equal(roleWorker[2].toNumber(), 3); + + const roleManager = await colony.getTaskRole.call(taskId, MANAGER_ROLE); + assert.isFalse(roleManager[1]); + assert.equal(roleManager[2].toNumber(), MANAGER_RATING); + + const roleEvaluator = await colony.getTaskRole.call(taskId, EVALUATOR_ROLE); + assert.isTrue(roleEvaluator[1]); + }); + + it("should assign rating 3 to manager and 3 to worker, with penalties, when no one has submitted any ratings", async () => { + const taskId = await setupAssignedTask({ colonyNetwork, colony }); + await forwardTime(SECONDS_PER_DAY * 10 + 1, this); + await colony.assignWorkRating(taskId); + + const roleWorker = await colony.getTaskRole.call(taskId, WORKER_ROLE); + assert.isTrue(roleWorker[1]); + assert.equal(roleWorker[2].toNumber(), 3); + + const roleManager = await colony.getTaskRole.call(taskId, MANAGER_ROLE); + assert.isFalse(roleManager[1]); + assert.equal(roleManager[2].toNumber(), 3); + + const roleEvaluator = await colony.getTaskRole.call(taskId, EVALUATOR_ROLE); + assert.isTrue(roleEvaluator[1]); + }); + + it("should revert if I try to assign ratings before the reveal period is over", async () => { + await setupAssignedTask({ colonyNetwork, colony }); + await forwardTime(SECONDS_PER_DAY * 6, this); + await checkErrorRevert(colony.assignWorkRating(1)); + const roleWorker = await colony.getTaskRole.call(1, WORKER_ROLE); + assert.isFalse(roleWorker[1]); + }); + }); +}); diff --git a/src/lib/colonyNetwork/test/colony.js b/src/lib/colonyNetwork/test/colony.js new file mode 100755 index 0000000..754a41a --- /dev/null +++ b/src/lib/colonyNetwork/test/colony.js @@ -0,0 +1,844 @@ +/* globals artifacts */ + +import { toBN } from "web3-utils"; + +import { + MANAGER, + EVALUATOR, + WORKER, + OTHER, + MANAGER_ROLE, + EVALUATOR_ROLE, + WORKER_ROLE, + SPECIFICATION_HASH, + SPECIFICATION_HASH_UPDATED, + DELIVERABLE_HASH, + INITIAL_FUNDING, + SECONDS_PER_DAY, + MANAGER_RATING, + WORKER_RATING, + RATING_1_SALT, + RATING_2_SALT, + RATING_1_SECRET, + RATING_2_SECRET +} from "../helpers/constants"; +import { + getTokenArgs, + web3GetBalance, + checkErrorRevert, + expectEvent, + currentBlockTime, + createSignatures, + createSignaturesTrezor +} from "../helpers/test-helper"; +import { fundColonyWithTokens, setupRatedTask, setupAssignedTask, setupFundedTask } from "../helpers/test-data-generator"; + +import { setupColonyVersionResolver } from "../helpers/upgradable-contracts"; + +const Colony = artifacts.require("Colony"); +const Resolver = artifacts.require("Resolver"); +const EtherRouter = artifacts.require("EtherRouter"); +const IColony = artifacts.require("IColony"); +const IColonyNetwork = artifacts.require("IColonyNetwork"); +const Token = artifacts.require("Token"); +const Authority = artifacts.require("Authority"); +const ColonyFunding = artifacts.require("ColonyFunding"); +const ColonyTask = artifacts.require("ColonyTask"); +const ReputationMiningCycle = artifacts.require("ReputationMiningCycle"); + +contract("Colony", addresses => { + let colony; + let token; + let otherToken; + let authority; + let colonyNetwork; + + before(async () => { + const resolverColonyNetworkDeployed = await Resolver.deployed(); + const colonyTemplate = await Colony.new(); + const colonyFunding = await ColonyFunding.new(); + const colonyTask = await ColonyTask.new(); + const resolver = await Resolver.new(); + const etherRouter = await EtherRouter.new(); + await etherRouter.setResolver(resolverColonyNetworkDeployed.address); + colonyNetwork = await IColonyNetwork.at(etherRouter.address); + await setupColonyVersionResolver(colonyTemplate, colonyTask, colonyFunding, resolver, colonyNetwork); + + const clnyToken = await Token.new("Colony Network Token", "CLNY", 18); + await colonyNetwork.createMetaColony(clnyToken.address); + + await colonyNetwork.startNextCycle(); + }); + + beforeEach(async () => { + const tokenArgs = getTokenArgs(); + token = await Token.new(...tokenArgs); + const { logs } = await colonyNetwork.createColony(token.address); + const { colonyAddress } = logs[0].args; + await token.setOwner(colonyAddress); + colony = await IColony.at(colonyAddress); + const authorityAddress = await colony.authority.call(); + authority = await Authority.at(authorityAddress); + const otherTokenArgs = getTokenArgs(); + otherToken = await Token.new(...otherTokenArgs); + }); + + describe("when initialised", () => { + it("should accept ether", async () => { + await colony.send(1); + const colonyBalance = await web3GetBalance(colony.address); + assert.equal(colonyBalance.toNumber(), 1); + }); + + it("should take colony network as an owner", async () => { + const owner = await colony.owner.call(); + assert.equal(owner, colonyNetwork.address); + }); + + it("should return zero task count", async () => { + const taskCount = await colony.getTaskCount.call(); + assert.equal(taskCount, 0); + }); + + it("should return zero for taskChangeNonce", async () => { + const taskChangeNonce = await colony.getTaskChangeNonce.call(1); + assert.equal(taskChangeNonce, 0); + }); + + it("should fail if a non-admin tries to mint tokens", async () => { + await checkErrorRevert(colony.mintTokens(100, { from: OTHER })); + }); + + it("should not allow reinitialisation", async () => { + await checkErrorRevert(colony.initialiseColony(0x0)); + }); + + it("should correctly generate a rating secret", async () => { + const ratingSecret1 = await colony.generateSecret.call(RATING_1_SALT, MANAGER_RATING); + assert.equal(ratingSecret1, RATING_1_SECRET); + const ratingSecret2 = await colony.generateSecret.call(RATING_2_SALT, WORKER_RATING); + assert.equal(ratingSecret2, RATING_2_SECRET); + }); + }); + + describe("when working with permissions", () => { + it("should be able to add a colony owner", async () => { + await authority.setUserRole(OTHER, 0, true); + const owner = await authority.hasUserRole.call(OTHER, 0); + assert.isTrue(owner); + }); + + it("should be able to add a colony admin", async () => { + await authority.setUserRole(OTHER, 1, true); + const admin = await authority.hasUserRole.call(OTHER, 1); + assert.isTrue(admin); + }); + + it("should be able to remove a colony owner", async () => { + await authority.setUserRole(OTHER, 0, true); + await authority.setUserRole(OTHER, 0, false); + const owner = await authority.hasUserRole.call(OTHER, 0); + assert.isFalse(owner); + }); + + it("should be able to remove a colony admin", async () => { + await authority.setUserRole(OTHER, 1, true); + await authority.setUserRole(OTHER, 1, false); + const admin = await authority.hasUserRole.call(OTHER, 1); + assert.isFalse(admin); + }); + }); + + describe("when creating tasks", () => { + it("should allow admins to make task", async () => { + await colony.makeTask(SPECIFICATION_HASH, 1); + const task = await colony.getTask.call(1); + assert.equal(task[0], SPECIFICATION_HASH); + assert.equal(task[1], "0x0000000000000000000000000000000000000000000000000000000000000000"); + assert.isFalse(task[2]); + assert.isFalse(task[3]); + assert.equal(task[4].toNumber(), 0); + assert.equal(task[5].toNumber(), 0); + }); + + it("should fail if a non-admin user tries to make a task", async () => { + await checkErrorRevert(colony.makeTask(SPECIFICATION_HASH, 1, { from: OTHER })); + const taskCount = await colony.getTaskCount.call(); + assert.equal(taskCount.toNumber(), 0); + }); + + it("should set the task manager as the creator", async () => { + await colony.makeTask(SPECIFICATION_HASH, 1); + const taskCount = await colony.getTaskCount.call(); + assert.equal(taskCount.toNumber(), 1); + const taskManager = await colony.getTaskRole.call(1, MANAGER_ROLE); + assert.equal(taskManager[0], MANAGER); + }); + + it("should return the correct number of tasks", async () => { + await colony.makeTask(SPECIFICATION_HASH, 1); + await colony.makeTask(SPECIFICATION_HASH, 1); + await colony.makeTask(SPECIFICATION_HASH, 1); + await colony.makeTask(SPECIFICATION_HASH, 1); + await colony.makeTask(SPECIFICATION_HASH, 1); + const taskCount = await colony.getTaskCount.call(); + + assert.equal(taskCount.toNumber(), 5); + }); + + it("should set the task domain correctly", async () => { + const skillCount = await colonyNetwork.getSkillCount.call(); + await colony.addDomain(skillCount.toNumber()); + await colony.makeTask(SPECIFICATION_HASH, 2); + const task = await colony.getTask.call(1); + assert.equal(task[8].toNumber(), 2); + }); + + it("should log a TaskAdded event", async () => { + await expectEvent(colony.makeTask(SPECIFICATION_HASH, 1), "TaskAdded"); + }); + }); + + describe("when bootstrapping the colony", () => { + const INITIAL_REPUTATIONS = [toBN(5 * 1e18).toString(), toBN(4 * 1e18).toString(), toBN(3 * 1e18).toString(), toBN(2 * 1e18).toString()]; + const INITIAL_ADDRESSES = addresses.slice(0, 4); + + it("should assign reputation correctly when bootstrapping the colony", async () => { + const skillCount = await colonyNetwork.getSkillCount.call(); + + await colony.mintTokens(toBN(14 * 1e18).toString()); + await colony.bootstrapColony(INITIAL_ADDRESSES, INITIAL_REPUTATIONS); + const inactiveReputationMiningCycleAddress = await colonyNetwork.getReputationMiningCycle(false); + const inactiveReputationMiningCycle = ReputationMiningCycle.at(inactiveReputationMiningCycleAddress); + const numberOfReputationLogs = await inactiveReputationMiningCycle.getReputationUpdateLogLength(); + assert.equal(numberOfReputationLogs.toNumber(), INITIAL_ADDRESSES.length); + const updateLog = await inactiveReputationMiningCycle.getReputationUpdateLogEntry(0); + assert.equal(updateLog[0], INITIAL_ADDRESSES[0]); + assert.equal(updateLog[1].toString(), INITIAL_REPUTATIONS[0]); + assert.equal(updateLog[2].toString(), skillCount.toNumber()); + }); + + it("should assign tokens correctly when bootstrapping the colony", async () => { + await colony.mintTokens(toBN(14 * 1e18).toString()); + await colony.bootstrapColony(INITIAL_ADDRESSES, INITIAL_REPUTATIONS); + + const balance = await token.balanceOf(INITIAL_ADDRESSES[0]); + assert.equal(balance.toString(), INITIAL_REPUTATIONS[0]); + }); + + it("should be able to bootstrap colony more than once", async () => { + const amount = toBN(10 * 1e18).toString(); + await colony.mintTokens(amount); + await colony.bootstrapColony([INITIAL_ADDRESSES[0]], [INITIAL_REPUTATIONS[0]]); + await colony.bootstrapColony([INITIAL_ADDRESSES[0]], [INITIAL_REPUTATIONS[0]]); + + const balance = await token.balanceOf(INITIAL_ADDRESSES[0]); + assert.equal(balance.toString(), amount); + }); + + it("should throw if length of inputs is not equal", async () => { + await colony.mintTokens(toBN(14 * 1e18).toString()); + await checkErrorRevert(colony.bootstrapColony([INITIAL_ADDRESSES[0]], INITIAL_REPUTATIONS)); + await checkErrorRevert(colony.bootstrapColony(INITIAL_ADDRESSES, [INITIAL_REPUTATIONS[0]])); + }); + + it("should not allow negative number", async () => { + await colony.mintTokens(toBN(14 * 1e18).toString()); + await checkErrorRevert( + colony.bootstrapColony( + [INITIAL_ADDRESSES[0]], + [ + toBN(5 * 1e18) + .neg() + .toString() + ] + ) + ); + }); + + it("should throw if there is not enough funds to send", async () => { + await colony.mintTokens(toBN(10 * 1e18).toString()); + await checkErrorRevert(colony.bootstrapColony(INITIAL_ADDRESSES, INITIAL_REPUTATIONS)); + + const balance = await token.balanceOf(INITIAL_ADDRESSES[0]); + assert.equal(balance.toString(), "0"); + }); + + it("should not allow non-creator to bootstrap reputation", async () => { + await colony.mintTokens(toBN(14 * 1e18).toString()); + await checkErrorRevert( + colony.bootstrapColony(INITIAL_ADDRESSES, INITIAL_REPUTATIONS, { + from: addresses[1] + }) + ); + }); + + it("should not allow bootstrapping if colony is not in bootstrap state", async () => { + await colony.mintTokens(toBN(14 * 1e18).toString()); + await colony.makeTask(SPECIFICATION_HASH, 1); + await checkErrorRevert(colony.bootstrapColony(INITIAL_REPUTATIONS, INITIAL_ADDRESSES)); + }); + }); + + describe("when updating tasks", () => { + it("should allow the worker and evaluator roles to be assigned", async () => { + await colony.makeTask(SPECIFICATION_HASH, 1); + await colony.setTaskRoleUser(1, EVALUATOR_ROLE, EVALUATOR); + const evaluator = await colony.getTaskRole.call(1, EVALUATOR_ROLE); + assert.equal(evaluator[0], EVALUATOR); + + await colony.setTaskRoleUser(1, WORKER_ROLE, WORKER); + const worker = await colony.getTaskRole.call(1, WORKER_ROLE); + assert.equal(worker[0], WORKER); + }); + + it("should not allow the worker or evaluator roles to be assigned by an address that is not the manager", async () => { + await colony.makeTask(SPECIFICATION_HASH, 1); + await checkErrorRevert(colony.setTaskRoleUser(1, EVALUATOR_ROLE, EVALUATOR, { from: OTHER })); + const evaluator = await colony.getTaskRole.call(1, EVALUATOR_ROLE); + assert.equal(evaluator[0], "0x0000000000000000000000000000000000000000"); + + await checkErrorRevert(colony.setTaskRoleUser(1, WORKER_ROLE, WORKER, { from: OTHER })); + const worker = await colony.getTaskRole.call(1, WORKER_ROLE); + assert.equal(worker[0], "0x0000000000000000000000000000000000000000"); + }); + + it("should correctly increment `taskChangeNonce` for multiple updates on a single task", async () => { + await colony.makeTask(SPECIFICATION_HASH, 1); + await colony.setTaskRoleUser(1, WORKER_ROLE, WORKER); + + // Change the task brief + let txData = await colony.contract.setTaskBrief.getData(1, SPECIFICATION_HASH_UPDATED); + const signers = [MANAGER, WORKER]; + let sigs = await createSignatures(colony, 1, signers, 0, txData); + await colony.executeTaskChange(sigs.sigV, sigs.sigR, sigs.sigS, [0, 0], 0, txData); + + let taskChangeNonce = await colony.getTaskChangeNonce.call(1); + assert.equal(taskChangeNonce, 1); + + // Change the due date + const dueDate = await currentBlockTime(); + txData = await colony.contract.setTaskDueDate.getData(1, dueDate); + sigs = await createSignatures(colony, 1, signers, 0, txData); + await colony.executeTaskChange(sigs.sigV, sigs.sigR, sigs.sigS, [0, 0], 0, txData); + + taskChangeNonce = await colony.getTaskChangeNonce.call(1); + assert.equal(taskChangeNonce, 2); + }); + + it("should correctly increment `taskChangeNonce` for multiple updates on multiple tasks", async () => { + await colony.makeTask(SPECIFICATION_HASH, 1); + await colony.setTaskRoleUser(1, WORKER_ROLE, WORKER); + + await colony.makeTask(SPECIFICATION_HASH, 1); + await colony.setTaskRoleUser(2, WORKER_ROLE, WORKER); + + const signers = [MANAGER, WORKER]; + + // Change the task1 brief + const txData1 = await colony.contract.setTaskBrief.getData(1, SPECIFICATION_HASH_UPDATED); + const sigs1 = await createSignatures(colony, 1, signers, 0, txData1); + + // Change the task2 brief + const txData2 = await colony.contract.setTaskBrief.getData(2, SPECIFICATION_HASH_UPDATED); + const sigs2 = await createSignatures(colony, 2, signers, 0, txData2); + + // Execute the above 2 changes + await colony.executeTaskChange(sigs1.sigV, sigs1.sigR, sigs1.sigS, [0, 0], 0, txData1); + let taskChangeNonce = await colony.getTaskChangeNonce.call(1); + assert.equal(taskChangeNonce, 1); + await colony.executeTaskChange(sigs2.sigV, sigs2.sigR, sigs2.sigS, [0, 0], 0, txData2); + taskChangeNonce = await colony.getTaskChangeNonce.call(2); + assert.equal(taskChangeNonce, 1); + + // Change the task2 due date + const dueDate = await currentBlockTime(); + const txData3 = await colony.contract.setTaskDueDate.getData(2, dueDate); + const sigs3 = await createSignatures(colony, 2, signers, 0, txData3); + + await colony.executeTaskChange(sigs3.sigV, sigs3.sigR, sigs3.sigS, [0, 0], 0, txData3); + taskChangeNonce = await colony.getTaskChangeNonce.call(2); + assert.equal(taskChangeNonce, 2); + }); + + it("should allow update of task brief signed by manager only when worker has not been assigned", async () => { + await colony.makeTask(SPECIFICATION_HASH, 1); + const txData = await colony.contract.setTaskBrief.getData(1, SPECIFICATION_HASH_UPDATED); + const sigs = await createSignatures(colony, 1, [MANAGER], 0, txData); + await colony.executeTaskChange(sigs.sigV, sigs.sigR, sigs.sigS, [0], 0, txData); + const task = await colony.getTask.call(1); + assert.equal(task[0], SPECIFICATION_HASH_UPDATED); + }); + + it("should allow update of task brief signed by manager and worker", async () => { + await colony.makeTask(SPECIFICATION_HASH, 1); + await colony.setTaskRoleUser(1, WORKER_ROLE, WORKER); + const txData = await colony.contract.setTaskBrief.getData(1, SPECIFICATION_HASH_UPDATED); + const signers = [MANAGER, WORKER]; + const sigs = await createSignatures(colony, 1, signers, 0, txData); + await colony.executeTaskChange(sigs.sigV, sigs.sigR, sigs.sigS, [0, 0], 0, txData); + const task = await colony.getTask.call(1); + assert.equal(task[0], SPECIFICATION_HASH_UPDATED); + }); + + it("should allow update of task brief signed by manager and worker using Trezor-style signatures", async () => { + await colony.makeTask(SPECIFICATION_HASH, 1); + await colony.setTaskRoleUser(1, WORKER_ROLE, WORKER); + const txData = await colony.contract.setTaskBrief.getData(1, SPECIFICATION_HASH_UPDATED); + const signers = [MANAGER, WORKER]; + const sigs = await createSignaturesTrezor(colony, 1, signers, 0, txData); + await colony.executeTaskChange(sigs.sigV, sigs.sigR, sigs.sigS, [1, 1], 0, txData); + const task = await colony.getTask.call(1); + assert.equal(task[0], SPECIFICATION_HASH_UPDATED); + }); + + it("should allow update of task brief signed by manager and worker if one uses Trezor-style signatures and the other does not", async () => { + await colony.makeTask(SPECIFICATION_HASH, 1); + await colony.setTaskRoleUser(1, WORKER_ROLE, WORKER); + const txData = await colony.contract.setTaskBrief.getData(1, SPECIFICATION_HASH_UPDATED); + const sigs = await createSignatures(colony, 1, [MANAGER], 0, txData); + const trezorSigs = await createSignaturesTrezor(colony, 1, [WORKER], 0, txData); + await colony.executeTaskChange( + [sigs.sigV[0], trezorSigs.sigV[0]], + [sigs.sigR[0], trezorSigs.sigR[0]], + [sigs.sigS[0], trezorSigs.sigS[0]], + [0, 1], + 0, + txData + ); + const task = await colony.getTask.call(1); + assert.equal(task[0], SPECIFICATION_HASH_UPDATED); + }); + + it("should not allow update of task brief signed by manager twice, with two different signature styles", async () => { + await colony.makeTask(SPECIFICATION_HASH, 1); + await colony.setTaskRoleUser(1, WORKER_ROLE, WORKER); + const txData = await colony.contract.setTaskBrief.getData(1, SPECIFICATION_HASH_UPDATED); + const sigs = await createSignatures(colony, 1, [MANAGER], 0, txData); + const trezorSigs = await createSignaturesTrezor(colony, 1, [MANAGER], 0, txData); + await checkErrorRevert( + colony.executeTaskChange( + [sigs.sigV[0], trezorSigs.sigV[0]], + [sigs.sigR[0], trezorSigs.sigR[0]], + [sigs.sigS[0], trezorSigs.sigS[0]], + [0, 1], + 0, + txData + ) + ); + const task = await colony.getTask.call(1); + assert.equal(task[0], SPECIFICATION_HASH); + }); + + it("should allow update of task due date signed by manager and worker", async () => { + const dueDate = await currentBlockTime(); + + await colony.makeTask(SPECIFICATION_HASH, 1); + await colony.setTaskRoleUser(1, WORKER_ROLE, WORKER); + const txData = await colony.contract.setTaskDueDate.getData(1, dueDate); + const signers = [MANAGER, WORKER]; + const sigs = await createSignatures(colony, 1, signers, 0, txData); + await colony.executeTaskChange(sigs.sigV, sigs.sigR, sigs.sigS, [0, 0], 0, txData); + + const task = await colony.getTask.call(1); + assert.equal(task[4], dueDate); + }); + + it("should fail if a non-colony call is made to the task update functions", async () => { + await colony.makeTask(SPECIFICATION_HASH, 1); + await checkErrorRevert(colony.setTaskBrief(1, SPECIFICATION_HASH_UPDATED, { from: OTHER })); + }); + + it("should fail update of task brief signed by a non-registered role", async () => { + await colony.makeTask(SPECIFICATION_HASH, 1); + await colony.setTaskRoleUser(1, EVALUATOR_ROLE, EVALUATOR); + + const txData = await colony.contract.setTaskBrief.getData(1, SPECIFICATION_HASH_UPDATED); + const signers = [MANAGER, OTHER]; + const sigs = await createSignatures(colony, 1, signers, 0, txData); + + await checkErrorRevert(colony.executeTaskChange(sigs.sigV, sigs.sigR, sigs.sigS, [0, 0], 0, txData)); + }); + + it("should fail update of task brief signed by manager and evaluator", async () => { + await colony.makeTask(SPECIFICATION_HASH, 1); + await colony.setTaskRoleUser(1, EVALUATOR_ROLE, EVALUATOR); + await colony.setTaskRoleUser(1, WORKER_ROLE, WORKER); + + const txData = await colony.contract.setTaskBrief.getData(1, SPECIFICATION_HASH_UPDATED); + const signers = [MANAGER, EVALUATOR]; + const sigs = await createSignatures(colony, 1, signers, 0, txData); + + await checkErrorRevert(colony.executeTaskChange(sigs.sigV, sigs.sigR, sigs.sigS, [0, 0], 0, txData)); + }); + + it("should fail to execute task change for a non-registered function signature", async () => { + await colony.makeTask(SPECIFICATION_HASH, 1); + const txData = await colony.contract.getTaskRole.getData(1, 0); + const signers = [MANAGER, EVALUATOR]; + const sigs = await createSignatures(colony, 1, signers, 0, txData); + + await checkErrorRevert(colony.executeTaskChange(sigs.sigV, sigs.sigR, sigs.sigS, [0, 0], 0, txData)); + }); + + it("should fail to execute change of task brief, using an invalid task id", async () => { + await colony.makeTask(SPECIFICATION_HASH, 1); + const txData = await colony.contract.setTaskBrief.getData(10, SPECIFICATION_HASH_UPDATED); + const signers = [MANAGER, EVALUATOR]; + const sigs = await createSignatures(colony, 1, signers, 0, txData); + + await checkErrorRevert(colony.executeTaskChange(sigs.sigV, sigs.sigR, sigs.sigS, [0, 0], 0, txData)); + }); + + it("should fail to execute task change, if the task is already finalized", async () => { + await fundColonyWithTokens(colony, token, INITIAL_FUNDING); + const taskId = await setupRatedTask({ colonyNetwork, colony, token }); + await colony.finalizeTask(taskId); + + const txData = await colony.contract.setTaskBrief.getData(taskId, SPECIFICATION_HASH_UPDATED); + const signers = [MANAGER, EVALUATOR]; + const sigs = await createSignatures(colony, 1, signers, 0, txData); + + await checkErrorRevert(colony.executeTaskChange(sigs.sigV, sigs.sigR, sigs.sigS, [0, 0], 0, txData)); + }); + + it("should log a TaskBriefChanged event, if the task brief gets changed", async () => { + await colony.makeTask(SPECIFICATION_HASH, 1); + const txData = await colony.contract.setTaskBrief.getData(1, SPECIFICATION_HASH_UPDATED); + const sigs = await createSignatures(colony, 1, [MANAGER], 0, txData); + await expectEvent(colony.executeTaskChange(sigs.sigV, sigs.sigR, sigs.sigS, [0], 0, txData), "TaskBriefChanged"); + }); + + it("should log a TaskDueDateChanged event, if the task due date gets changed", async () => { + await colony.makeTask(SPECIFICATION_HASH, 1); + const dueDate = await currentBlockTime(); + const txData = await colony.contract.setTaskDueDate.getData(1, dueDate); + const sigs = await createSignatures(colony, 1, [MANAGER], 0, txData); + await expectEvent(colony.executeTaskChange(sigs.sigV, sigs.sigR, sigs.sigS, [0, 0], 0, txData), "TaskDueDateChanged"); + }); + + it("should log a TaskSkillChanged event, if the task skill gets changed", async () => { + await colony.makeTask(SPECIFICATION_HASH, 1); + // Acquire meta colony, create new global skill, assign new task's skill + const metaColonyAddress = await colonyNetwork.getMetaColony.call(); + const metaColony = await IColony.at(metaColonyAddress); + await metaColony.addGlobalSkill(1); + + const skillCount = await colonyNetwork.getSkillCount.call(); + await expectEvent(colony.setTaskSkill(1, skillCount.toNumber()), "TaskSkillChanged"); + }); + + it("should log a TaskDomainChanged event, if the task domain gets changed", async () => { + await colony.makeTask(SPECIFICATION_HASH, 1); + // Create a domain, change task's domain + const skillCount = await colonyNetwork.getSkillCount.call(); + await colony.addDomain(skillCount.toNumber()); + + await expectEvent(colony.setTaskDomain(1, 2), "TaskDomainChanged"); + }); + + it("should log a TaskRoleUserChanged event, if a task role's user gets changed", async () => { + await colony.makeTask(SPECIFICATION_HASH, 1); + + // Change the task role's user + await expectEvent(colony.setTaskRoleUser(1, WORKER_ROLE, WORKER), "TaskRoleUserChanged"); + }); + }); + + describe("when submitting task deliverable", () => { + it("should update task", async () => { + let dueDate = await currentBlockTime(); + dueDate += SECONDS_PER_DAY * 4; + await setupAssignedTask({ colonyNetwork, colony, dueDate }); + + let task = await colony.getTask.call(1); + assert.equal(task[1], "0x0000000000000000000000000000000000000000000000000000000000000000"); + + const currentTime = await currentBlockTime(); + await colony.submitTaskDeliverable(1, DELIVERABLE_HASH, { from: WORKER }); + task = await colony.getTask.call(1); + assert.equal(task[1], DELIVERABLE_HASH); + assert.closeTo(task[7].toNumber(), currentTime, 2); + }); + + it("should fail if I try to submit work for a task that is finalized", async () => { + await fundColonyWithTokens(colony, token, INITIAL_FUNDING); + const taskId = await setupRatedTask({ colonyNetwork, colony, token }); + await colony.finalizeTask(taskId); + await checkErrorRevert(colony.submitTaskDeliverable(taskId, DELIVERABLE_HASH)); + }); + + it("should fail if I try to submit work for a task that is past its due date", async () => { + let dueDate = await currentBlockTime(); + dueDate -= 1; + await setupAssignedTask({ colonyNetwork, colony, dueDate }); + await checkErrorRevert(colony.submitTaskDeliverable(1, DELIVERABLE_HASH)); + }); + + it("should fail if I try to submit work for a task using an invalid id", async () => { + await checkErrorRevert(colony.submitTaskDeliverable(10, DELIVERABLE_HASH)); + }); + + it("should fail if I try to submit work twice", async () => { + let dueDate = await currentBlockTime(); + dueDate += SECONDS_PER_DAY * 4; + await setupAssignedTask({ colonyNetwork, colony, dueDate }); + await colony.submitTaskDeliverable(1, DELIVERABLE_HASH, { from: WORKER }); + + await checkErrorRevert(colony.submitTaskDeliverable(1, SPECIFICATION_HASH, { from: WORKER })); + const task = await colony.getTask.call(1); + assert.equal(task[1], DELIVERABLE_HASH); + }); + + it("should fail if I try to submit work if I'm not the assigned worker", async () => { + let dueDate = await currentBlockTime(); + dueDate += SECONDS_PER_DAY * 4; + await setupAssignedTask({ colonyNetwork, colony, dueDate }); + + await checkErrorRevert(colony.submitTaskDeliverable(1, SPECIFICATION_HASH, { from: OTHER })); + const task = await colony.getTask.call(1); + assert.notEqual(task[1], DELIVERABLE_HASH); + }); + }); + + describe("when finalizing a task", () => { + it('should set the task "finalized" property to "true"', async () => { + await fundColonyWithTokens(colony, token, INITIAL_FUNDING); + const taskId = await setupRatedTask({ colonyNetwork, colony, token }); + await colony.finalizeTask(taskId); + const task = await colony.getTask.call(taskId); + assert.isTrue(task[2]); + }); + + it("should fail if the task work ratings have not been assigned", async () => { + await fundColonyWithTokens(colony, token, INITIAL_FUNDING); + const taskId = await setupFundedTask({ colonyNetwork, colony, token }); + await checkErrorRevert(colony.finalizeTask(taskId)); + }); + + it("should fail if a non-admin tries to accept the task", async () => { + await fundColonyWithTokens(colony, token, INITIAL_FUNDING); + const taskId = await setupRatedTask({ colonyNetwork, colony, token }); + await checkErrorRevert(colony.finalizeTask(taskId, { from: OTHER })); + }); + + it("should fail if I try to accept a task that was finalized before", async () => { + await fundColonyWithTokens(colony, token, INITIAL_FUNDING); + const taskId = await setupRatedTask({ colonyNetwork, colony, token }); + await colony.finalizeTask(taskId); + await checkErrorRevert(colony.finalizeTask(taskId)); + }); + + it("should fail if I try to accept a task using an invalid id", async () => { + await fundColonyWithTokens(colony, token, INITIAL_FUNDING); + await setupRatedTask({ colonyNetwork, colony, token }); + await checkErrorRevert(colony.finalizeTask(10)); + }); + + it("should log a TaskFinalized event", async () => { + await fundColonyWithTokens(colony, token, INITIAL_FUNDING); + const taskId = await setupRatedTask({ colonyNetwork, colony, token }); + await expectEvent(colony.finalizeTask(taskId), "TaskFinalized"); + }); + }); + + describe("when cancelling a task", () => { + it('should set the task "cancelled" property to "true"', async () => { + await fundColonyWithTokens(colony, token, INITIAL_FUNDING); + const taskId = await setupRatedTask({ colonyNetwork, colony, token }); + + await colony.cancelTask(taskId); + const task = await colony.getTask.call(taskId); + assert.isTrue(task[3]); + }); + + it("should be possible to return funds back to the domain", async () => { + await fundColonyWithTokens(colony, token, INITIAL_FUNDING); + const taskId = await setupFundedTask({ colonyNetwork, colony, token }); + const task = await colony.getTask.call(taskId); + const domainId = task[8].toNumber(); + const domain = await colony.getDomain.call(domainId); + const taskPotId = task[6]; + const domainPotId = domain[1]; + + // Our test-data-generator already set up some task fund with tokens, + // but we need some Ether, too + await colony.send(101); + await colony.claimColonyFunds(0x0); + await colony.moveFundsBetweenPots(1, taskPotId, 100, 0x0); + + // And another token + await otherToken.mint(101); + await otherToken.transfer(colony.address, 101); + await colony.claimColonyFunds(otherToken.address); + await colony.moveFundsBetweenPots(1, taskPotId, 100, otherToken.address); + + // Keep track of original Ether balance in pots + const originalDomainEtherBalance = await colony.getPotBalance.call(domainPotId, 0x0); + const originalTaskEtherBalance = await colony.getPotBalance.call(taskPotId, 0x0); + // And same for the token + const originalDomainTokenBalance = await colony.getPotBalance.call(domainPotId, token.address); + const originalTaskTokenBalance = await colony.getPotBalance.call(taskPotId, token.address); + // And the other token + const originalDomainOtherTokenBalance = await colony.getPotBalance.call(domainPotId, otherToken.address); + const originalTaskOtherTokenBalance = await colony.getPotBalance.call(taskPotId, otherToken.address); + + // Now that everything is set up, let's cancel the task, move funds and compare pots afterwards + await colony.cancelTask(taskId); + await colony.moveFundsBetweenPots(taskPotId, domainPotId, originalTaskEtherBalance, 0x0); + await colony.moveFundsBetweenPots(taskPotId, domainPotId, originalTaskTokenBalance, token.address); + await colony.moveFundsBetweenPots(taskPotId, domainPotId, originalTaskOtherTokenBalance, otherToken.address); + + const cancelledTaskEtherBalance = await colony.getPotBalance.call(taskPotId, 0x0); + const cancelledDomainEtherBalance = await colony.getPotBalance.call(domainPotId, 0x0); + const cancelledTaskTokenBalance = await colony.getPotBalance.call(taskPotId, token.address); + const cancelledDomainTokenBalance = await colony.getPotBalance.call(domainPotId, token.address); + const cancelledTaskOtherTokenBalance = await colony.getPotBalance.call(taskPotId, otherToken.address); + const cancelledDomainOtherTokenBalance = await colony.getPotBalance.call(domainPotId, otherToken.address); + assert.notEqual(originalTaskEtherBalance.toNumber(), cancelledTaskEtherBalance.toNumber()); + assert.notEqual(originalDomainEtherBalance.toNumber(), cancelledDomainEtherBalance.toNumber()); + assert.notEqual(originalTaskTokenBalance.toNumber(), cancelledTaskTokenBalance.toNumber()); + assert.notEqual(originalDomainTokenBalance.toNumber(), cancelledDomainTokenBalance.toNumber()); + assert.notEqual(originalTaskOtherTokenBalance.toNumber(), cancelledTaskOtherTokenBalance.toNumber()); + assert.notEqual(originalDomainOtherTokenBalance.toNumber(), cancelledDomainOtherTokenBalance.toNumber()); + assert.equal(cancelledTaskEtherBalance.toNumber(), 0); + assert.equal(cancelledTaskTokenBalance.toNumber(), 0); + assert.equal(cancelledTaskOtherTokenBalance.toNumber(), 0); + assert.equal(originalDomainEtherBalance.plus(originalTaskEtherBalance).toNumber(), cancelledDomainEtherBalance.toNumber()); + assert.equal(originalDomainTokenBalance.plus(originalTaskTokenBalance).toNumber(), cancelledDomainTokenBalance.toNumber()); + assert.equal(originalDomainOtherTokenBalance.plus(originalTaskOtherTokenBalance).toNumber(), cancelledDomainOtherTokenBalance.toNumber()); + }); + + it("should fail if manager tries to cancel a task that was finalized", async () => { + await fundColonyWithTokens(colony, token, INITIAL_FUNDING); + const taskId = await setupRatedTask({ colonyNetwork, colony, token }); + await colony.finalizeTask(taskId); + await checkErrorRevert(colony.cancelTask(taskId)); + }); + + it("should fail if manager tries to cancel a task with invalid id", async () => { + await checkErrorRevert(colony.cancelTask(10)); + }); + + it("should log a TaskCanceled event", async () => { + await fundColonyWithTokens(colony, token, INITIAL_FUNDING); + const taskId = await setupRatedTask({ colonyNetwork, colony, token }); + await expectEvent(colony.cancelTask(taskId), "TaskCanceled"); + }); + }); + + describe("when funding tasks", () => { + it("should be able to set the task payouts for different roles", async () => { + await colony.makeTask(SPECIFICATION_HASH, 1); + await colony.setTaskRoleUser(1, WORKER_ROLE, WORKER); + await colony.setTaskRoleUser(1, EVALUATOR_ROLE, EVALUATOR); + await colony.mintTokens(100); + // Set the manager payout as 5000 wei and 100 colony tokens + await colony.setTaskManagerPayout(1, 0x0, 5000); + await colony.setTaskManagerPayout(1, token.address, 100); + + // Set the evaluator payout as 1000 ethers + const txData1 = await colony.contract.setTaskEvaluatorPayout.getData(1, 0x0, 1000); + const sigs = await createSignatures(colony, 1, [MANAGER, EVALUATOR], 0, txData1); + await colony.executeTaskChange(sigs.sigV, sigs.sigR, sigs.sigS, [0, 0], 0, txData1); + + // Set the evaluator payout as 40 colony tokens + const txData2 = await colony.contract.setTaskEvaluatorPayout.getData(1, token.address, 40); + const sigs2 = await createSignatures(colony, 1, [MANAGER, EVALUATOR], 0, txData2); + await colony.executeTaskChange(sigs2.sigV, sigs2.sigR, sigs2.sigS, [0, 0], 0, txData2); + + // Set the worker payout as 98000 wei and 200 colony tokens + const txData3 = await colony.contract.setTaskWorkerPayout.getData(1, 0x0, 98000); + const sigs3 = await createSignatures(colony, 1, [MANAGER, WORKER], 0, txData3); + await colony.executeTaskChange(sigs3.sigV, sigs3.sigR, sigs3.sigS, [0, 0], 0, txData3); + + const txData4 = await colony.contract.setTaskWorkerPayout.getData(1, token.address, 200); + const sigs4 = await createSignatures(colony, 1, [MANAGER, WORKER], 0, txData4); + await colony.executeTaskChange(sigs4.sigV, sigs4.sigR, sigs4.sigS, [0, 0], 0, txData4); + + const taskPayoutManager1 = await colony.getTaskPayout.call(1, MANAGER_ROLE, 0x0); + assert.equal(taskPayoutManager1.toNumber(), 5000); + const taskPayoutManager2 = await colony.getTaskPayout.call(1, MANAGER_ROLE, token.address); + assert.equal(taskPayoutManager2.toNumber(), 100); + + const taskPayoutEvaluator1 = await colony.getTaskPayout.call(1, EVALUATOR_ROLE, 0x0); + assert.equal(taskPayoutEvaluator1.toNumber(), 1000); + const taskPayoutEvaluator2 = await colony.getTaskPayout.call(1, EVALUATOR_ROLE, token.address); + assert.equal(taskPayoutEvaluator2.toNumber(), 40); + + const taskPayoutWorker1 = await colony.getTaskPayout.call(1, WORKER_ROLE, 0x0); + assert.equal(taskPayoutWorker1.toNumber(), 98000); + const taskPayoutWorker2 = await colony.getTaskPayout.call(1, WORKER_ROLE, token.address); + assert.equal(taskPayoutWorker2.toNumber(), 200); + }); + + it("should log a TaskWorkerPayoutChanged event, if the task's worker's payout changed", async () => { + await colony.makeTask(SPECIFICATION_HASH, 1); + await colony.setTaskRoleUser(1, WORKER_ROLE, WORKER); + await colony.mintTokens(100); + + // Set the evaluator payout as 1000 ethers + const txData = await colony.contract.setTaskWorkerPayout.getData(1, 0x0, 98000); + const sigs = await createSignatures(colony, 1, [MANAGER, WORKER], 0, txData); + + await expectEvent(colony.executeTaskChange(sigs.sigV, sigs.sigR, sigs.sigS, [0, 0], 0, txData), "TaskWorkerPayoutChanged"); + }); + }); + + describe("when claiming payout for a task", () => { + it("should payout agreed tokens for a task", async () => { + await fundColonyWithTokens(colony, token, INITIAL_FUNDING); + const taskId = await setupRatedTask({ colonyNetwork, colony, token }); + await colony.finalizeTask(taskId); + const networkBalanceBefore = await token.balanceOf.call(colonyNetwork.address); + await colony.claimPayout(taskId, MANAGER_ROLE, token.address); + const networkBalanceAfter = await token.balanceOf.call(colonyNetwork.address); + assert.equal(networkBalanceAfter.minus(networkBalanceBefore).toNumber(), 1 * 1e18); + const balance = await token.balanceOf.call(MANAGER); + assert.equal(balance.toNumber(), 99 * 1e18); + const potBalance = await colony.getPotBalance.call(2, token.address); + assert.equal(potBalance.toNumber(), 250 * 1e18); + }); + + it("should payout agreed ether for a task", async () => { + await colony.send(353); + await colony.claimColonyFunds(0x0); + let dueDate = await currentBlockTime(); + dueDate -= 1; + const taskId = await setupRatedTask({ + colonyNetwork, + colony, + token: 0x0, + dueDate, + managerPayout: 100, + evaluatorPayout: 50, + workerPayout: 200 + }); + await colony.finalizeTask(taskId); + const metaColonyAddress = await colonyNetwork.getMetaColony.call(); + const balanceBefore = await web3GetBalance(MANAGER); + const metaBalanceBefore = await web3GetBalance(metaColonyAddress); + await colony.claimPayout(taskId, MANAGER_ROLE, 0x0, { gasPrice: 0 }); + const balanceAfter = await web3GetBalance(MANAGER); + const metaBalanceAfter = await web3GetBalance(metaColonyAddress); + assert.equal(balanceAfter.minus(balanceBefore).toNumber(), 99); + assert.equal(metaBalanceAfter.minus(metaBalanceBefore).toNumber(), 1); + const potBalance = await colony.getPotBalance.call(2, 0x0); + assert.equal(potBalance.toNumber(), 250); + }); + + it("should return error when task is not finalized", async () => { + await fundColonyWithTokens(colony, token, INITIAL_FUNDING); + const taskId = await setupRatedTask({ colonyNetwork, colony, token }); + await checkErrorRevert(colony.claimPayout(taskId, MANAGER_ROLE, token.address)); + }); + + it("should return error when called by account that doesn't match the role", async () => { + await fundColonyWithTokens(colony, token, INITIAL_FUNDING); + const taskId = await setupRatedTask({ colonyNetwork, colony, token }); + await colony.finalizeTask(taskId); + + await checkErrorRevert(colony.claimPayout(taskId, MANAGER_ROLE, token.address, { from: OTHER })); + }); + }); +}); diff --git a/src/lib/colonyNetwork/test/meta-colony.js b/src/lib/colonyNetwork/test/meta-colony.js new file mode 100644 index 0000000..552f8be --- /dev/null +++ b/src/lib/colonyNetwork/test/meta-colony.js @@ -0,0 +1,471 @@ +/* globals artifacts */ +import { SPECIFICATION_HASH, INITIAL_FUNDING } from "../helpers/constants"; +import { checkErrorRevert, getTokenArgs } from "../helpers/test-helper"; +import { fundColonyWithTokens, setupRatedTask } from "../helpers/test-data-generator"; + +const upgradableContracts = require("../helpers/upgradable-contracts"); + +const EtherRouter = artifacts.require("EtherRouter"); +const Resolver = artifacts.require("Resolver"); +const Colony = artifacts.require("Colony"); +const IColonyNetwork = artifacts.require("IColonyNetwork"); +const IColony = artifacts.require("IColony"); +const ColonyFunding = artifacts.require("ColonyFunding"); +const ColonyTask = artifacts.require("ColonyTask"); +const Token = artifacts.require("Token"); + +contract("Meta Colony", accounts => { + let TOKEN_ARGS; + const OTHER_ACCOUNT = accounts[1]; + + let metaColony; + let metaColonyToken; + let colony; + let token; + let colonyNetwork; + let resolverColonyNetworkDeployed; + + before(async () => { + resolverColonyNetworkDeployed = await Resolver.deployed(); + }); + + beforeEach(async () => { + const colonyTemplate = await Colony.new(); + const colonyFunding = await ColonyFunding.new(); + const colonyTask = await ColonyTask.new(); + const resolver = await Resolver.new(); + const etherRouter = await EtherRouter.new(); + await etherRouter.setResolver(resolverColonyNetworkDeployed.address); + colonyNetwork = await IColonyNetwork.at(etherRouter.address); + await upgradableContracts.setupColonyVersionResolver(colonyTemplate, colonyTask, colonyFunding, resolver, colonyNetwork); + await colonyNetwork.startNextCycle(); + + metaColonyToken = await Token.new("Colony Network Token", "CLNY", 18); + await colonyNetwork.createMetaColony(metaColonyToken.address); + const metaColonyAddress = await colonyNetwork.getMetaColony.call(); + metaColony = await IColony.at(metaColonyAddress); + }); + + describe("when working with ERC20 properties of Meta Colony token", () => { + it("token `symbol` property is correct", async () => { + const tokenSymbol = await metaColonyToken.symbol(); + assert.equal(web3.toUtf8(tokenSymbol), "CLNY"); + }); + + it("token `decimals` property is correct", async () => { + const tokenDecimals = await metaColonyToken.decimals.call(); + assert.equal(tokenDecimals.toString(), "18"); + }); + + it("token `name` property is correct", async () => { + const tokenName = await metaColonyToken.name.call(); + assert.equal(web3.toUtf8(tokenName), "Colony Network Token"); + }); + }); + + describe("when adding a new global skill", () => { + it("should be able to add a new skill as a child to the root skill", async () => { + await metaColony.addGlobalSkill(1); + + const skillCount = await colonyNetwork.getSkillCount.call(); + assert.equal(skillCount.toNumber(), 3); + + const newSkill = await colonyNetwork.getSkill.call(skillCount); + assert.equal(newSkill[0].toNumber(), 1); + assert.equal(newSkill[1].toNumber(), 0); + + // Check rootSkill.nChildren is now 1 + const rootSkill = await colonyNetwork.getSkill.call(1); + assert.equal(rootSkill[1].toNumber(), 1); + + // Check rootSkill.children first element is the id of the new skill + const rootSkillChild = await colonyNetwork.getChildSkillId.call(1, 0); + assert.equal(rootSkillChild.toNumber(), 3); + }); + + it("should not allow a non-owner of the metacolony to add a global skill", async () => { + await checkErrorRevert(metaColony.addGlobalSkill(1, { from: OTHER_ACCOUNT })); + }); + + it("should be able to add multiple child skills to the root global skill", async () => { + await metaColony.addGlobalSkill(1); + await metaColony.addGlobalSkill(1); + await metaColony.addGlobalSkill(1); + + const skillCount = await colonyNetwork.getSkillCount.call(); + assert.equal(skillCount.toNumber(), 5); + + const newSkill1 = await colonyNetwork.getSkill.call(3); + assert.equal(newSkill1[0].toNumber(), 1); + assert.equal(newSkill1[1].toNumber(), 0); + + const newSkill2 = await colonyNetwork.getSkill.call(4); + assert.equal(newSkill2[0].toNumber(), 1); + assert.equal(newSkill2[1].toNumber(), 0); + + const newSkill3 = await colonyNetwork.getSkill.call(5); + assert.equal(newSkill3[0].toNumber(), 1); + assert.equal(newSkill3[1].toNumber(), 0); + + // Check rootSkill.nChildren is now 3 + const rootSkill = await colonyNetwork.getSkill.call(1); + assert.equal(rootSkill[1].toNumber(), 3); + + // Check rootSkill.children contains the ids of the new skills + const rootSkillChild1 = await colonyNetwork.getChildSkillId.call(1, 0); + assert.equal(rootSkillChild1.toNumber(), 3); + const rootSkillChild2 = await colonyNetwork.getChildSkillId.call(1, 1); + assert.equal(rootSkillChild2.toNumber(), 4); + const rootSkillChild3 = await colonyNetwork.getChildSkillId.call(1, 2); + assert.equal(rootSkillChild3.toNumber(), 5); + }); + + it("should be able to add child skills a few levels down the skills tree", async () => { + // Add 2 skill nodes to root skill + await metaColony.addGlobalSkill(1); + await metaColony.addGlobalSkill(1); + // Add a child skill to skill id 3 + await metaColony.addGlobalSkill(3); + + const newDeepSkill = await colonyNetwork.getSkill.call(5); + assert.equal(newDeepSkill[0].toNumber(), 2); + assert.equal(newDeepSkill[1].toNumber(), 0); + + const parentSkill1 = await colonyNetwork.getParentSkillId.call(5, 0); + assert.equal(parentSkill1.toNumber(), 3); + + const parentSkill2 = await colonyNetwork.getParentSkillId.call(5, 1); + assert.equal(parentSkill2.toNumber(), 1); + }); + + it("should NOT be able to add a child skill for a non existent parent", async () => { + // Add 2 skill nodes to root skill + await metaColony.addGlobalSkill(1); + await metaColony.addGlobalSkill(1); + + await checkErrorRevert(metaColony.addGlobalSkill(5)); + const skillCount = await colonyNetwork.getSkillCount.call(); + assert.equal(skillCount.toNumber(), 4); + }); + + it("should NOT be able to add a child skill to a local skill parent", async () => { + await checkErrorRevert(metaColony.addGlobalSkill(2)); + const skillCount = await colonyNetwork.getSkillCount.call(); + assert.equal(skillCount.toNumber(), 2); + }); + + it("should be able to add skills in the middle of the skills tree", async () => { + await metaColony.addGlobalSkill(1); + await metaColony.addGlobalSkill(1); + await metaColony.addGlobalSkill(4); + await metaColony.addGlobalSkill(1); + await metaColony.addGlobalSkill(3); + await metaColony.addGlobalSkill(4); + + const rootSkill = await colonyNetwork.getSkill.call(1); + assert.equal(rootSkill[0].toNumber(), 0); + assert.equal(rootSkill[1].toNumber(), 6); + const rootSkillChildSkillId1 = await colonyNetwork.getChildSkillId.call(1, 0); + assert.equal(rootSkillChildSkillId1.toNumber(), 3); + const rootSkillChildSkillId2 = await colonyNetwork.getChildSkillId.call(1, 1); + assert.equal(rootSkillChildSkillId2.toNumber(), 4); + const rootSkillChildSkillId3 = await colonyNetwork.getChildSkillId.call(1, 2); + assert.equal(rootSkillChildSkillId3.toNumber(), 5); + const rootSkillChildSkillId4 = await colonyNetwork.getChildSkillId.call(1, 3); + assert.equal(rootSkillChildSkillId4.toNumber(), 6); + const rootSkillChildSkillId5 = await colonyNetwork.getChildSkillId.call(1, 4); + assert.equal(rootSkillChildSkillId5.toNumber(), 7); + const rootSkillChildSkillId6 = await colonyNetwork.getChildSkillId.call(1, 5); + assert.equal(rootSkillChildSkillId6.toNumber(), 8); + + const skill1 = await colonyNetwork.getSkill.call(3); + assert.equal(skill1[0].toNumber(), 1); + assert.equal(skill1[1].toNumber(), 1); + const skill1ParentSkillId1 = await colonyNetwork.getParentSkillId.call(3, 0); + assert.equal(skill1ParentSkillId1.toNumber(), 1); + const skill1ChildSkillId1 = await colonyNetwork.getChildSkillId.call(3, 0); + assert.equal(skill1ChildSkillId1.toNumber(), 7); + + const skill2 = await colonyNetwork.getSkill.call(4); + assert.equal(skill2[0].toNumber(), 1); + assert.equal(skill2[1].toNumber(), 2); + const skill2ParentSkillId1 = await colonyNetwork.getParentSkillId.call(4, 0); + assert.equal(skill2ParentSkillId1.toNumber(), 1); + const skill2ChildSkillId1 = await colonyNetwork.getChildSkillId.call(4, 0); + assert.equal(skill2ChildSkillId1.toNumber(), 5); + const skill2ChildSkillId2 = await colonyNetwork.getChildSkillId.call(4, 1); + assert.equal(skill2ChildSkillId2.toNumber(), 8); + + const skill3 = await colonyNetwork.getSkill.call(5); + assert.equal(skill3[0].toNumber(), 2); + assert.equal(skill3[1].toNumber(), 0); + const skill3ParentSkillId1 = await colonyNetwork.getParentSkillId.call(5, 0); + assert.equal(skill3ParentSkillId1.toNumber(), 4); + const skill3ParentSkillId2 = await colonyNetwork.getParentSkillId.call(5, 1); + assert.equal(skill3ParentSkillId2.toNumber(), 1); + + const skill4 = await colonyNetwork.getSkill.call(6); + assert.equal(skill4[0].toNumber(), 1); + assert.equal(skill4[1].toNumber(), 0); + const skill4ParentSkillId1 = await colonyNetwork.getParentSkillId.call(6, 0); + assert.equal(skill4ParentSkillId1.toNumber(), 1); + + const skill5 = await colonyNetwork.getSkill.call(7); + assert.equal(skill5[0].toNumber(), 2); + assert.equal(skill5[1].toNumber(), 0); + const skill5ParentSkillId1 = await colonyNetwork.getParentSkillId.call(7, 0); + assert.equal(skill5ParentSkillId1.toNumber(), 3); + const skill5ParentSkillId2 = await colonyNetwork.getParentSkillId.call(7, 1); + assert.equal(skill5ParentSkillId2.toNumber(), 1); + + const skill6 = await colonyNetwork.getSkill.call(8); + assert.equal(skill6[0].toNumber(), 2); + assert.equal(skill6[1].toNumber(), 0); + const skill6ParentSkillId1 = await colonyNetwork.getParentSkillId.call(8, 0); + assert.equal(skill6ParentSkillId1.toNumber(), 4); + const skill6ParentSkillId2 = await colonyNetwork.getParentSkillId.call(8, 1); + assert.equal(skill6ParentSkillId2.toNumber(), 1); + }); + + it("when N parents are there, should record parent skill ids for N = integer powers of 2", async () => { + await metaColony.addGlobalSkill(1); + await metaColony.addGlobalSkill(3); + await metaColony.addGlobalSkill(4); + await metaColony.addGlobalSkill(5); + await metaColony.addGlobalSkill(6); + await metaColony.addGlobalSkill(7); + await metaColony.addGlobalSkill(8); + await metaColony.addGlobalSkill(9); + await metaColony.addGlobalSkill(10); + + const skill11 = await colonyNetwork.getSkill.call(11); + assert.equal(skill11[0].toNumber(), 9); + assert.equal(skill11[1].toNumber(), 0); + + const skill11ParentSkillId1 = await colonyNetwork.getParentSkillId.call(11, 0); + assert.equal(skill11ParentSkillId1.toNumber(), 10); + const skill11ParentSkillId2 = await colonyNetwork.getParentSkillId.call(11, 1); + assert.equal(skill11ParentSkillId2.toNumber(), 9); + const skill11ParentSkillId3 = await colonyNetwork.getParentSkillId.call(11, 2); + assert.equal(skill11ParentSkillId3.toNumber(), 7); + const skill11ParentSkillId4 = await colonyNetwork.getParentSkillId.call(11, 3); + assert.equal(skill11ParentSkillId4.toNumber(), 3); + }); + + it("should NOT be able to add a new root global skill", async () => { + await checkErrorRevert(metaColony.addGlobalSkill(0)); + + const skillCount = await colonyNetwork.getSkillCount.call(); + assert.equal(skillCount.toNumber(), 2); + }); + }); + + describe("when adding domains in the meta colony", () => { + it("should be able to add new domains as children to the root domain", async () => { + await metaColony.addDomain(2); + + const skillCount = await colonyNetwork.getSkillCount.call(); + assert.equal(skillCount.toNumber(), 3); + const domainCount = await metaColony.getDomainCount.call(); + assert.equal(domainCount.toNumber(), 2); + + const newDomain = await metaColony.getDomain.call(1); + assert.equal(newDomain[0].toNumber(), 2); + assert.equal(newDomain[1].toNumber(), 1); + + // Check root local skill.nChildren is now 1 + const rootLocalSkill = await colonyNetwork.getSkill.call(2); + assert.equal(rootLocalSkill[1].toNumber(), 1); + + // Check root local skill.children first element is the id of the new skill + const rootSkillChild = await colonyNetwork.getChildSkillId.call(2, 0); + assert.equal(rootSkillChild.toNumber(), 3); + }); + + it("should NOT be able to add a child local skill more than one level from the root local skill", async () => { + await metaColony.addDomain(2); + await checkErrorRevert(metaColony.addDomain(3)); + + const skillCount = await colonyNetwork.getSkillCount.call(); + assert.equal(skillCount.toNumber(), 3); + const domainCount = await metaColony.getDomainCount.call(); + assert.equal(domainCount.toNumber(), 2); + }); + }); + + describe("when adding domains in a regular colony", () => { + beforeEach(async () => { + TOKEN_ARGS = getTokenArgs(); + const newToken = await Token.new(...TOKEN_ARGS); + const { logs } = await colonyNetwork.createColony(newToken.address); + const { colonyAddress } = logs[0].args; + colony = await IColony.at(colonyAddress); + const tokenAddress = await colony.getToken.call(); + token = await Token.at(tokenAddress); + }); + + it("someone who is not the colony owner should not be able to add domains", async () => { + await checkErrorRevert(colony.addDomain(3, { from: OTHER_ACCOUNT })); + }); + + it("should be able to add new domains as children to the root domain", async () => { + await colony.addDomain(3); + await colony.addDomain(3); + await colony.addDomain(3); + + const skillCount = await colonyNetwork.getSkillCount.call(); + assert.equal(skillCount.toNumber(), 6); + const domainCount = await colony.getDomainCount.call(); + assert.equal(domainCount.toNumber(), 4); + + const newDomain1 = await colony.getDomain.call(1); + assert.equal(newDomain1[0].toNumber(), 3); + assert.equal(newDomain1[1].toNumber(), 1); + + const newDomain2 = await colony.getDomain.call(2); + assert.equal(newDomain2[0].toNumber(), 4); + assert.equal(newDomain2[1].toNumber(), 2); + + const newDomain3 = await colony.getDomain.call(3); + assert.equal(newDomain3[0].toNumber(), 5); + assert.equal(newDomain3[1].toNumber(), 3); + + // Check root local skill.nChildren is now 3 + const rootLocalSkill = await colonyNetwork.getSkill.call(3); + assert.equal(rootLocalSkill[1].toNumber(), 3); + + // Check root local skill.children are the ids of the new skills + const rootSkillChild1 = await colonyNetwork.getChildSkillId.call(3, 0); + assert.equal(rootSkillChild1.toNumber(), 4); + const rootSkillChild2 = await colonyNetwork.getChildSkillId.call(3, 1); + assert.equal(rootSkillChild2.toNumber(), 5); + const rootSkillChild3 = await colonyNetwork.getChildSkillId.call(3, 2); + assert.equal(rootSkillChild3.toNumber(), 6); + }); + + it("should NOT be able to add a child local skill more than one level from the root local skill", async () => { + await colony.addDomain(3); + await checkErrorRevert(colony.addDomain(4)); + + const skillCount = await colonyNetwork.getSkillCount.call(); + assert.equal(skillCount.toNumber(), 4); + const domainCount = await colony.getDomainCount.call(); + assert.equal(domainCount.toNumber(), 2); + }); + + it("should NOT be able to add a child local skill to a global skill parent", async () => { + await checkErrorRevert(colony.addDomain(1)); + + const skillCount = await colonyNetwork.getSkillCount.call(); + assert.equal(skillCount.toNumber(), 3); + const domainCount = await colony.getDomainCount.call(); + assert.equal(domainCount.toNumber(), 1); + }); + + it("should NOT be able to add a new local skill by anyone but a Colony", async () => { + await checkErrorRevert(colonyNetwork.addSkill(2, false)); + + const skillCount = await colonyNetwork.getSkillCount.call(); + assert.equal(skillCount.toNumber(), 3); + }); + + it("should NOT be able to add a new root local skill", async () => { + await checkErrorRevert(colonyNetwork.addSkill(0, false)); + + const skillCount = await colonyNetwork.getSkillCount.call(); + assert.equal(skillCount.toNumber(), 3); + }); + }); + + describe("when setting domain and skill on task", () => { + beforeEach(async () => { + TOKEN_ARGS = getTokenArgs(); + token = await Token.new(...TOKEN_ARGS); + const { logs } = await colonyNetwork.createColony(token.address); + const { colonyAddress } = logs[0].args; + await token.setOwner(colonyAddress); + colony = await IColony.at(colonyAddress); + }); + + it("should be able to set domain on task", async () => { + await colony.addDomain(3); + await colony.makeTask(SPECIFICATION_HASH, 1); + await colony.setTaskDomain(1, 2); + const task = await colony.getTask.call(1); + assert.equal(task[8].toNumber(), 2); + }); + + it("should NOT allow a non-manager to set domain on task", async () => { + await colony.addDomain(3); + await colony.makeTask(SPECIFICATION_HASH, 1); + await checkErrorRevert(colony.setTaskDomain(1, 2, { from: OTHER_ACCOUNT })); + const task = await colony.getTask.call(1); + assert.equal(task[8].toNumber(), 1); + }); + + it("should NOT be able to set a domain on nonexistent task", async () => { + await checkErrorRevert(colony.setTaskDomain(10, 3)); + }); + + it("should NOT be able to set a nonexistent domain on task", async () => { + await colony.makeTask(SPECIFICATION_HASH, 1); + await checkErrorRevert(colony.setTaskDomain(1, 20)); + + const task = await colony.getTask.call(1); + assert.equal(task[8].toNumber(), 1); + }); + + it("should NOT be able to set a domain on finalized task", async () => { + await fundColonyWithTokens(colony, token, INITIAL_FUNDING); + const taskId = await setupRatedTask({ colonyNetwork, colony }); + await colony.finalizeTask(taskId); + await checkErrorRevert(colony.setTaskDomain(taskId, 1)); + }); + + it("should be able to set global skill on task", async () => { + await metaColony.addGlobalSkill(1); + await metaColony.addGlobalSkill(4); + + await colony.makeTask(SPECIFICATION_HASH, 1); + await colony.setTaskSkill(1, 5); + const task = await colony.getTask.call(1); + assert.equal(task[9][0].toNumber(), 5); + }); + + it("should not allow a non-manager to set global skill on task", async () => { + await metaColony.addGlobalSkill(1); + await metaColony.addGlobalSkill(4); + + await colony.makeTask(SPECIFICATION_HASH, 1); + await checkErrorRevert(colony.setTaskSkill(1, 5, { from: OTHER_ACCOUNT })); + const task = await colony.getTask.call(1); + assert.equal(task[9][0].toNumber(), 0); + }); + + it("should NOT be able to set global skill on nonexistent task", async () => { + await checkErrorRevert(colony.setTaskSkill(10, 1)); + }); + + it("should NOT be able to set global skill on finalized task", async () => { + await metaColony.addGlobalSkill(1); + await metaColony.addGlobalSkill(4); + await fundColonyWithTokens(colony, token, INITIAL_FUNDING); + const taskId = await setupRatedTask({ colonyNetwork, colony }); + await colony.finalizeTask(taskId); + await checkErrorRevert(colony.setTaskSkill(taskId, 5)); + + const task = await colony.getTask.call(taskId); + assert.equal(task[9][0].toNumber(), 1); + }); + + it("should NOT be able to set nonexistent skill on task", async () => { + await colony.makeTask(SPECIFICATION_HASH, 1); + await checkErrorRevert(colony.setTaskSkill(1, 5)); + }); + + it("should NOT be able to set local skill on task", async () => { + await colony.makeTask(SPECIFICATION_HASH, 1); + await checkErrorRevert(colony.setTaskSkill(1, 3)); + }); + }); +}); diff --git a/src/lib/colonyNetwork/test/reputation-update.js b/src/lib/colonyNetwork/test/reputation-update.js new file mode 100755 index 0000000..955f298 --- /dev/null +++ b/src/lib/colonyNetwork/test/reputation-update.js @@ -0,0 +1,217 @@ +/* globals artifacts */ +import web3Utils from "web3-utils"; +import { BN } from "bn.js"; + +import { MANAGER, WORKER, EVALUATOR, OTHER, MANAGER_PAYOUT, WORKER_PAYOUT } from "../helpers/constants"; +import { getTokenArgs, checkErrorRevert } from "../helpers/test-helper"; +import { fundColonyWithTokens, setupRatedTask } from "../helpers/test-data-generator"; + +import { setupColonyVersionResolver } from "../helpers/upgradable-contracts"; + +const EtherRouter = artifacts.require("EtherRouter"); +const IColony = artifacts.require("IColony"); +const IColonyNetwork = artifacts.require("IColonyNetwork"); +const Resolver = artifacts.require("Resolver"); +const Colony = artifacts.require("Colony"); +const ColonyFunding = artifacts.require("ColonyFunding"); +const ColonyTask = artifacts.require("ColonyTask"); +const Token = artifacts.require("Token"); +const ReputationMiningCycle = artifacts.require("ReputationMiningCycle"); + +contract("Colony Reputation Updates", () => { + let colonyNetwork; + let metaColony; + let resolverColonyNetworkDeployed; + let colonyToken; + let inactiveReputationMiningCycle; + + before(async () => { + resolverColonyNetworkDeployed = await Resolver.deployed(); + }); + + beforeEach(async () => { + const colony = await Colony.new(); + const colonyFunding = await ColonyFunding.new(); + const colonyTask = await ColonyTask.new(); + const resolver = await Resolver.new(); + const etherRouter = await EtherRouter.new(); + await etherRouter.setResolver(resolverColonyNetworkDeployed.address); + colonyNetwork = await IColonyNetwork.at(etherRouter.address); + await setupColonyVersionResolver(colony, colonyTask, colonyFunding, resolver, colonyNetwork); + await colonyNetwork.startNextCycle(); + const tokenArgs = getTokenArgs(); + colonyToken = await Token.new(...tokenArgs); + await colonyNetwork.createMetaColony(colonyToken.address); + const metaColonyAddress = await colonyNetwork.getMetaColony.call(); + await colonyToken.setOwner(metaColonyAddress); + metaColony = await IColony.at(metaColonyAddress); + const amount = new BN(10) + .pow(new BN(18)) + .mul(new BN(1000)) + .toString(); + await fundColonyWithTokens(metaColony, colonyToken, amount); + const inactiveReputationMiningCycleAddress = await colonyNetwork.getReputationMiningCycle(false); + inactiveReputationMiningCycle = ReputationMiningCycle.at(inactiveReputationMiningCycleAddress); + }); + + describe("when added", () => { + it("should be readable", async () => { + const taskId = await setupRatedTask({ colonyNetwork, colony: metaColony }); + await metaColony.finalizeTask(taskId); + + const repLogEntryManager = await inactiveReputationMiningCycle.getReputationUpdateLogEntry(0); + assert.equal(repLogEntryManager[0], MANAGER); + assert.equal(repLogEntryManager[1].toNumber(), 100 * 1e18); + assert.equal(repLogEntryManager[2].toNumber(), 2); + assert.equal(repLogEntryManager[3], metaColony.address); + assert.equal(repLogEntryManager[4].toNumber(), 2); + assert.equal(repLogEntryManager[5].toNumber(), 0); + + const repLogEntryEvaluator = await inactiveReputationMiningCycle.getReputationUpdateLogEntry(1); + assert.equal(repLogEntryEvaluator[0], EVALUATOR); + assert.equal(repLogEntryEvaluator[1].toNumber(), 50 * 1e18); + assert.equal(repLogEntryEvaluator[2].toNumber(), 2); + assert.equal(repLogEntryEvaluator[3], metaColony.address); + assert.equal(repLogEntryEvaluator[4].toNumber(), 2); + assert.equal(repLogEntryEvaluator[5].toNumber(), 2); + + const repLogEntryWorker = await inactiveReputationMiningCycle.getReputationUpdateLogEntry(2); + assert.equal(repLogEntryWorker[0], WORKER); + assert.equal(repLogEntryWorker[1].toNumber(), 300 * 1e18); + assert.equal(repLogEntryWorker[2].toNumber(), 2); + assert.equal(repLogEntryWorker[3], metaColony.address); + assert.equal(repLogEntryWorker[4].toNumber(), 2); + assert.equal(repLogEntryWorker[5].toNumber(), 4); + }); + + const ratings = [ + { + manager: 1, + reputationChangeManager: MANAGER_PAYOUT.neg(), + worker: 1, + reputationChangeWorker: WORKER_PAYOUT.neg() + }, + { + manager: 2, + reputationChangeManager: MANAGER_PAYOUT, + worker: 2, + reputationChangeWorker: WORKER_PAYOUT + }, + { + manager: 3, + reputationChangeManager: MANAGER_PAYOUT.muln(3).divn(2), + worker: 3, + reputationChangeWorker: WORKER_PAYOUT.muln(3).divn(2) + } + ]; + + ratings.forEach(async rating => { + it(`should set the correct reputation change amount in log for rating ${rating.worker}`, async () => { + const taskId = await setupRatedTask({ + colonyNetwork, + colony: metaColony, + managerRating: rating.manager, + workerRating: rating.worker + }); + await metaColony.finalizeTask(taskId); + + const repLogEntryManager = await inactiveReputationMiningCycle.getReputationUpdateLogEntry(0); + assert.equal(repLogEntryManager[0], MANAGER); + assert.equal(repLogEntryManager[1].toString(), rating.reputationChangeManager.toString()); + assert.equal(repLogEntryManager[2].toNumber(), 2); + assert.equal(repLogEntryManager[3], metaColony.address); + assert.equal(repLogEntryManager[4].toNumber(), 2); + assert.equal(repLogEntryManager[5].toNumber(), 0); + + const repLogEntryWorker = await inactiveReputationMiningCycle.getReputationUpdateLogEntry(2); + assert.equal(repLogEntryWorker[0], WORKER); + assert.equal(repLogEntryWorker[1].toString(), rating.reputationChangeWorker.toString()); + assert.equal(repLogEntryWorker[2].toNumber(), 2); + assert.equal(repLogEntryWorker[3], metaColony.address); + assert.equal(repLogEntryWorker[4].toNumber(), 2); + assert.equal(repLogEntryWorker[5].toNumber(), 4); + }); + }); + + it("should not be able to be appended by an account that is not a colony", async () => { + const lengthBefore = await inactiveReputationMiningCycle.getReputationUpdateLogLength(); + await checkErrorRevert(colonyNetwork.appendReputationUpdateLog(OTHER, 1, 2)); + const lengthAfter = await inactiveReputationMiningCycle.getReputationUpdateLogLength(); + assert.equal(lengthBefore.toNumber(), lengthAfter.toNumber()); + }); + + it("should populate nPreviousUpdates correctly", async () => { + let initialRepLogLength = await inactiveReputationMiningCycle.getReputationUpdateLogLength(); + initialRepLogLength = initialRepLogLength.toNumber(); + const taskId1 = await setupRatedTask({ colonyNetwork, colony: metaColony }); + await metaColony.finalizeTask(taskId1); + let repLogEntry = await inactiveReputationMiningCycle.getReputationUpdateLogEntry.call(initialRepLogLength); + const nPrevious = repLogEntry[5].toNumber(); + repLogEntry = await inactiveReputationMiningCycle.getReputationUpdateLogEntry.call(initialRepLogLength + 1); + assert.equal(repLogEntry[5].toNumber(), 2 + nPrevious); + + const taskId2 = await setupRatedTask({ colonyNetwork, colony: metaColony }); + await metaColony.finalizeTask(taskId2); + repLogEntry = await inactiveReputationMiningCycle.getReputationUpdateLogEntry.call(initialRepLogLength + 2); + assert.equal(repLogEntry[5].toNumber(), 4 + nPrevious); + }); + + it("should calculate nUpdates correctly when making a log", async () => { + await metaColony.addGlobalSkill(1); + await metaColony.addGlobalSkill(3); + await metaColony.addGlobalSkill(4); + await metaColony.addGlobalSkill(5); + const taskId1 = await setupRatedTask({ + colonyNetwork, + colony: metaColony, + skill: 4 + }); + await metaColony.finalizeTask(taskId1); + let repLogEntryWorker = await inactiveReputationMiningCycle.getReputationUpdateLogEntry(3); + const result = web3Utils + .toBN(WORKER_PAYOUT) + .muln(3) + .divn(2); + assert.equal(repLogEntryWorker[1].toString(), result.toString()); + assert.equal(repLogEntryWorker[4].toNumber(), 6); + + const taskId2 = await setupRatedTask({ + colonyNetwork, + colony: metaColony, + skill: 5 + }); + await metaColony.finalizeTask(taskId2); + repLogEntryWorker = await inactiveReputationMiningCycle.getReputationUpdateLogEntry(7); + assert.equal(repLogEntryWorker[1].toString(), result.toString()); + assert.equal(repLogEntryWorker[4].toNumber(), 8); // Negative reputation change means children change as well. + }); + + it("should revert on reputation amount overflow", async () => { + // Fund colony with maximum possible int number of tokens + const maxUIntNumber = new BN(2) + .pow(new BN(255)) + .sub(new BN(1)) + .toString(10); + await fundColonyWithTokens(metaColony, colonyToken, maxUIntNumber); + // Split the tokens as payouts between the manager and worker + const managerPayout = new BN("2"); + const evaluatorPayout = new BN("1"); + const workerPayout = new BN(maxUIntNumber).sub(managerPayout).sub(evaluatorPayout); + const taskId = await setupRatedTask({ + colonyNetwork, + colony: metaColony, + token: colonyToken, + managerPayout, + evaluatorPayout, + workerPayout, + workerRating: 1 + }); + + // Check the task pot is correctly funded with the max amount + const taskPotBalance = await metaColony.getPotBalance.call(2, colonyToken.address); + assert.isTrue(taskPotBalance.equals(maxUIntNumber)); + + await checkErrorRevert(metaColony.finalizeTask(taskId)); + }); + }); +}); diff --git a/src/lib/colonyNetwork/test/router-resolver.js b/src/lib/colonyNetwork/test/router-resolver.js new file mode 100644 index 0000000..72026e6 --- /dev/null +++ b/src/lib/colonyNetwork/test/router-resolver.js @@ -0,0 +1,66 @@ +/* globals artifacts */ +import { checkErrorRevert } from "../helpers/test-helper"; + +const MultiSigWallet = artifacts.require("gnosis/MultiSigWallet"); +const EtherRouter = artifacts.require("EtherRouter"); +const Resolver = artifacts.require("Resolver"); +const ColonyNetwork = artifacts.require("ColonyNetwork"); + +contract("EtherRouter / Resolver", accounts => { + const COINBASE_ACCOUNT = accounts[0]; + const ACCOUNT_TWO = accounts[1]; + const ACCOUNT_THREE = accounts[2]; + + let etherRouter; + let resolver; + let multisig; + + before(async () => { + resolver = await Resolver.deployed(); + }); + + beforeEach(async () => { + etherRouter = await EtherRouter.new(); + await etherRouter.setResolver(resolver.address); + // Need at least 2 confirmations for EtherRouter owner-required transactions + multisig = await MultiSigWallet.new([ACCOUNT_TWO, ACCOUNT_THREE], 2); + await etherRouter.setOwner(multisig.address); + }); + + describe("EtherRouter", () => { + it("should revert if non-owner tries to change the Resolver on EtherRouter", async () => { + await checkErrorRevert(etherRouter.setResolver("0xb3e2b6020926af4763d706b5657446b95795de57", { from: COINBASE_ACCOUNT })); + const resolverUpdated = await etherRouter.resolver.call(); + assert.equal(resolverUpdated, resolver.address); + }); + + it("should not change resolver on EtherRouter if there have been insufficient number of confirmations", async () => { + const txData = await etherRouter.contract.setResolver.getData("0xb3e2b6020926af4763d706b5657446b95795de57"); + const tx = await multisig.submitTransaction(etherRouter.address, 0, txData, { from: ACCOUNT_TWO }); + const { transactionId } = tx.logs[0].args; + const isConfirmed = await multisig.isConfirmed.call(transactionId); + const resolverUpdated = await etherRouter.resolver.call(); + assert.isFalse(isConfirmed); + assert.equal(resolverUpdated, resolver.address); + }); + }); + + describe("Resolver", () => { + it("should return correct destination for given function", async () => { + const deployedColonyNetwork = await ColonyNetwork.deployed(); + const signature = await resolver.stringToSig.call("createColony(address)"); + const destination = await resolver.lookup.call(signature); + assert.equal(destination, deployedColonyNetwork.address); + }); + + it("when checking destination for a function that doesn't exist, should return 0", async () => { + const destination = await resolver.lookup.call("0xdeadbeef"); + assert.equal(destination, 0); + }); + + it("should return correctly encoded function signature", async () => { + const signature = await resolver.stringToSig.call("transferFrom(address,address,uint256)"); + assert.equal(signature, "0x23b872dd"); + }); + }); +}); diff --git a/src/lib/colonyNetwork/truffle.js b/src/lib/colonyNetwork/truffle.js new file mode 100644 index 0000000..0f175fd --- /dev/null +++ b/src/lib/colonyNetwork/truffle.js @@ -0,0 +1,41 @@ +require("babel-register"); + +module.exports = { + networks: { + development: { + host: "localhost", + port: 8545, + gas: 7000000, + gasPrice: 0, + network_id: "*" + }, + integration: { + host: "localhost", + port: 8545, + gas: 7000000, + gasPrice: 0, + network_id: "integration" + }, + coverage: { + host: "localhost", + network_id: "*", + port: 8555, // <-- Use port 8555 + gas: 0xfffffffffff, // <-- Use this high gas value + gasPrice: 0x01 // <-- Use this low gas price + } + }, + mocha: { + reporter: "mocha-circleci-reporter", + reporterOptions: { + currency: "USD", + gasPrice: 5, + onlyCalledMethods: true + } + }, + solc: { + optimizer: { + enabled: true, + runs: 200 + } + } +}; diff --git a/src/lib/colonyNetwork/upgrade-test/colony-network-upgrade.js b/src/lib/colonyNetwork/upgrade-test/colony-network-upgrade.js new file mode 100644 index 0000000..36b181d --- /dev/null +++ b/src/lib/colonyNetwork/upgrade-test/colony-network-upgrade.js @@ -0,0 +1,53 @@ +/* globals artifacts */ +import { getTokenArgs } from "../helpers/test-helper"; + +const Token = artifacts.require("Token"); +const IColonyNetwork = artifacts.require("IColonyNetwork"); +const EtherRouter = artifacts.require("EtherRouter"); +const Resolver = artifacts.require("Resolver"); +const UpdatedColonyNetwork = artifacts.require("UpdatedColonyNetwork"); + +contract("ColonyNetwork contract upgrade", () => { + let colonyAddress1; + let colonyAddress2; + let colonyNetwork; + let updatedColonyNetwork; + + before(async () => { + const etherRouter = await EtherRouter.deployed(); + colonyNetwork = await IColonyNetwork.at(etherRouter.address); + + // Setup 2 test colonies + const tokenArgs1 = getTokenArgs(); + const newToken = await Token.new(...tokenArgs1); + let { logs } = await colonyNetwork.createColony(newToken.address); + colonyAddress1 = logs[0].args.colonyAddress; + + const tokenArgs2 = getTokenArgs(); + const newToken2 = await Token.new(...tokenArgs2); + ({ logs } = await colonyNetwork.createColony(newToken2.address)); + colonyAddress2 = logs[0].args.colonyAddress; + + // Setup new Colony contract version on the Network + const updatedColonyNetworkContract = await UpdatedColonyNetwork.new(); + const resolver = await Resolver.deployed(); + await resolver.register("isUpdated()", updatedColonyNetworkContract.address); + + updatedColonyNetwork = await UpdatedColonyNetwork.at(etherRouter.address); + }); + + describe("when upgrading ColonyNetwork contract", () => { + it("should return correct total number of colonies", async () => { + const updatedColonyCount = await updatedColonyNetwork.getColonyCount.call(); + assert.equal(3, updatedColonyCount.toNumber()); + }); + + it("should return correct colonies by index", async () => { + const colony1 = await updatedColonyNetwork.getColony(2); + assert.equal(colony1, colonyAddress1); + + const colony2 = await updatedColonyNetwork.getColony(3); + assert.equal(colony2, colonyAddress2); + }); + }); +}); diff --git a/src/lib/colonyNetwork/upgrade-test/colony-upgrade.js b/src/lib/colonyNetwork/upgrade-test/colony-upgrade.js new file mode 100644 index 0000000..490fdb5 --- /dev/null +++ b/src/lib/colonyNetwork/upgrade-test/colony-upgrade.js @@ -0,0 +1,103 @@ +/* globals artifacts */ +import { getTokenArgs } from "../helpers/test-helper"; +import { setupColonyVersionResolver } from "../helpers/upgradable-contracts"; +import { SPECIFICATION_HASH, SPECIFICATION_HASH_UPDATED } from "../helpers/constants"; + +const IColonyNetwork = artifacts.require("IColonyNetwork"); +const EtherRouter = artifacts.require("EtherRouter"); +const Resolver = artifacts.require("Resolver"); +const IColony = artifacts.require("IColony"); +const ColonyTask = artifacts.require("ColonyTask"); +const ColonyFunding = artifacts.require("ColonyFunding"); +const UpdatedColony = artifacts.require("UpdatedColony"); +const IUpdatedColony = artifacts.require("IUpdatedColony"); +const Authority = artifacts.require("Authority"); +const Token = artifacts.require("Token"); + +contract("Colony contract upgrade", accounts => { + const ACCOUNT_TWO = accounts[1]; + + let colony; + let colonyTask; + let colonyFunding; + let authority; + let token; + let colonyNetwork; + let updatedColony; + let updatedColonyVersion; + + before(async () => { + const etherRouterColonyNetwork = await EtherRouter.deployed(); + colonyNetwork = await IColonyNetwork.at(etherRouterColonyNetwork.address); + + const tokenArgs = getTokenArgs(); + const colonyToken = await Token.new(...tokenArgs); + const { logs } = await colonyNetwork.createColony(colonyToken.address); + const { colonyId, colonyAddress } = logs[0].args; + colony = await IColony.at(colonyAddress); + colonyTask = await ColonyTask.new(); + colonyFunding = await ColonyFunding.new(); + const authorityAddress = await colony.authority.call(); + authority = await Authority.at(authorityAddress); + const tokenAddress = await colony.getToken.call(); + token = await Token.at(tokenAddress); + + await authority.setUserRole(ACCOUNT_TWO, 0, true); + await colony.makeTask(SPECIFICATION_HASH, 1); + await colony.makeTask(SPECIFICATION_HASH_UPDATED, 1); + // Setup new Colony contract version on the Network + const updatedColonyContract = await UpdatedColony.new(); + const resolver = await Resolver.new(); + await resolver.register("isUpdated()", updatedColonyContract.address); + await setupColonyVersionResolver(updatedColonyContract, colonyTask, colonyFunding, resolver, colonyNetwork); + // Check new Colony contract version is registered successfully + updatedColonyVersion = await colonyNetwork.getCurrentColonyVersion.call(); + + // Upgrade our existing colony + await colonyNetwork.upgradeColony(colonyId, updatedColonyVersion.toNumber()); + updatedColony = await IUpdatedColony.at(colonyAddress); + }); + + describe("when upgrading Colony contract", () => { + it("should have updated the version number", async () => { + const newVersion = await updatedColony.version.call(); + assert.equal(newVersion.toNumber(), updatedColonyVersion.toNumber()); + }); + + it("should be able to lookup newly registered function on Colony", async () => { + const y = await updatedColony.isUpdated.call(); + assert.isTrue(y); + }); + + it("should return correct total number of tasks", async () => { + const updatedTaskCount = await updatedColony.getTaskCount.call(); + assert.equal(2, updatedTaskCount.toNumber()); + }); + + it("should return correct tasks", async () => { + const task1 = await updatedColony.getTask.call(1); + assert.equal(task1[0], SPECIFICATION_HASH); + assert.isFalse(task1[2]); + assert.isFalse(task1[3]); + assert.equal(task1[4].toNumber(), 0); + assert.equal(task1[5].toNumber(), 0); + + const task2 = await updatedColony.getTask.call(2); + assert.equal(task2[0], SPECIFICATION_HASH_UPDATED); + assert.isFalse(task2[2]); + assert.isFalse(task2[3]); + assert.equal(task2[4].toNumber(), 0); + assert.equal(task2[5].toNumber(), 0); + }); + + it("should return correct permissions", async () => { + const owner = await authority.hasUserRole.call(ACCOUNT_TWO, 0); + assert.isTrue(owner); + }); + + it("should return correct token address", async () => { + const tokenAddress = await updatedColony.getToken.call(); + assert.equal(token.address, tokenAddress); + }); + }); +}); diff --git a/src/lib/colonyNetwork/yarn.lock b/src/lib/colonyNetwork/yarn.lock new file mode 100644 index 0000000..4f214d9 --- /dev/null +++ b/src/lib/colonyNetwork/yarn.lock @@ -0,0 +1,9133 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz#2a02643368de80916162be70865c97774f3adbd9" + dependencies: + "@babel/highlight" "7.0.0-beta.44" + +"@babel/code-frame@^7.0.0-beta.35": + version "7.0.0-beta.51" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.51.tgz#bd71d9b192af978df915829d39d4094456439a0c" + dependencies: + "@babel/highlight" "7.0.0-beta.51" + +"@babel/generator@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0-beta.44.tgz#c7e67b9b5284afcf69b309b50d7d37f3e5033d42" + dependencies: + "@babel/types" "7.0.0-beta.44" + jsesc "^2.5.1" + lodash "^4.2.0" + source-map "^0.5.0" + trim-right "^1.0.1" + +"@babel/helper-function-name@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.44.tgz#e18552aaae2231100a6e485e03854bc3532d44dd" + dependencies: + "@babel/helper-get-function-arity" "7.0.0-beta.44" + "@babel/template" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + +"@babel/helper-get-function-arity@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.44.tgz#d03ca6dd2b9f7b0b1e6b32c56c72836140db3a15" + dependencies: + "@babel/types" "7.0.0-beta.44" + +"@babel/helper-split-export-declaration@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.44.tgz#c0b351735e0fbcb3822c8ad8db4e583b05ebd9dc" + dependencies: + "@babel/types" "7.0.0-beta.44" + +"@babel/highlight@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.44.tgz#18c94ce543916a80553edcdcf681890b200747d5" + dependencies: + chalk "^2.0.0" + esutils "^2.0.2" + js-tokens "^3.0.0" + +"@babel/highlight@7.0.0-beta.51": + version "7.0.0-beta.51" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.51.tgz#e8844ae25a1595ccfd42b89623b4376ca06d225d" + dependencies: + chalk "^2.0.0" + esutils "^2.0.2" + js-tokens "^3.0.0" + +"@babel/template@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.44.tgz#f8832f4fdcee5d59bf515e595fc5106c529b394f" + dependencies: + "@babel/code-frame" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + babylon "7.0.0-beta.44" + lodash "^4.2.0" + +"@babel/traverse@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.44.tgz#a970a2c45477ad18017e2e465a0606feee0d2966" + dependencies: + "@babel/code-frame" "7.0.0-beta.44" + "@babel/generator" "7.0.0-beta.44" + "@babel/helper-function-name" "7.0.0-beta.44" + "@babel/helper-split-export-declaration" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + babylon "7.0.0-beta.44" + debug "^3.1.0" + globals "^11.1.0" + invariant "^2.2.0" + lodash "^4.2.0" + +"@babel/types@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.44.tgz#6b1b164591f77dec0a0342aca995f2d046b3a757" + dependencies: + esutils "^2.0.2" + lodash "^4.2.0" + to-fast-properties "^2.0.0" + +"@colony/colony-js-contract-loader-fs@^1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@colony/colony-js-contract-loader-fs/-/colony-js-contract-loader-fs-1.3.0.tgz#dc32f03b9bd3501b3f67db89537a7fe542c09121" + dependencies: + "@colony/colony-js-contract-loader" "^1.3.0" + jsonfile "^4.0.0" + +"@colony/colony-js-contract-loader@^1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@colony/colony-js-contract-loader/-/colony-js-contract-loader-1.3.0.tgz#280b406fd9da9232b0281e95672ce08deef5fc68" + dependencies: + assert "^1.4.1" + babel-runtime "^6.26.0" + +"@colony/eslint-config-colony@4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@colony/eslint-config-colony/-/eslint-config-colony-4.0.1.tgz#74495655bf461ef196edc262983c471b42cf2d75" + +"@mrmlnc/readdir-enhanced@^2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" + dependencies: + call-me-maybe "^1.0.1" + glob-to-regexp "^0.3.0" + +"@sindresorhus/is@^0.7.0": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" + +"@types/concat-stream@^1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@types/concat-stream/-/concat-stream-1.6.0.tgz#394dbe0bb5fee46b38d896735e8b68ef2390d00d" + dependencies: + "@types/node" "*" + +"@types/form-data@0.0.33": + version "0.0.33" + resolved "https://registry.yarnpkg.com/@types/form-data/-/form-data-0.0.33.tgz#c9ac85b2a5fd18435b8c85d9ecb50e6d6c893ff8" + dependencies: + "@types/node" "*" + +"@types/node@*": + version "10.0.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.0.3.tgz#1f89840c7aac2406cc43a2ecad98fc02a8e130e4" + +"@types/node@^8.0.0": + version "8.10.11" + resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.11.tgz#971ea8cb91adbe0b74e3fbd867dec192d5893a5f" + +"@types/node@^9.3.0", "@types/node@^9.4.1": + version "9.6.9" + resolved "https://registry.yarnpkg.com/@types/node/-/node-9.6.9.tgz#1fa47c22fdc357a808535edd522b3d34facfa419" + +"@types/qs@^6.2.31": + version "6.5.1" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.5.1.tgz#a38f69c62528d56ba7bd1f91335a8004988d72f7" + +abab@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.4.tgz#5faad9c2c07f60dd76770f71cf025b62a63cfd4e" + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + +abbrev@1.0.x: + version "1.0.9" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" + +abi-decoder@^1.0.8: + version "1.1.0" + resolved "https://registry.yarnpkg.com/abi-decoder/-/abi-decoder-1.1.0.tgz#07f063e2a8f0ca1750fe4cd0dd112f6103ce3455" + dependencies: + babel-core "^6.23.1" + babel-loader "^6.3.2" + babel-plugin-add-module-exports "^0.2.1" + babel-plugin-transform-es2015-modules-amd "^6.22.0" + babel-plugin-transform-runtime "^6.23.0" + babel-preset-es2015 "^6.22.0" + chai "^3.5.0" + web3 "^0.18.4" + webpack "^2.7.0" + +abstract-leveldown@0.12.3: + version "0.12.3" + resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-0.12.3.tgz#116b1ec5c7710ef7a2d5706768bbdb4440be1070" + dependencies: + xtend "~3.0.0" + +abstract-leveldown@^2.4.1, abstract-leveldown@~2.7.1: + version "2.7.2" + resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-2.7.2.tgz#87a44d7ebebc341d59665204834c8b7e0932cc93" + dependencies: + xtend "~4.0.0" + +abstract-leveldown@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-3.0.0.tgz#5cb89f958a44f526779d740d1440e743e0c30a57" + dependencies: + xtend "~4.0.0" + +abstract-leveldown@~0.12.1: + version "0.12.4" + resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-0.12.4.tgz#29e18e632e60e4e221d5810247852a63d7b2e410" + dependencies: + xtend "~3.0.0" + +abstract-leveldown@~2.6.0: + version "2.6.3" + resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-2.6.3.tgz#1c5e8c6a5ef965ae8c35dfb3a8770c476b82c4b8" + dependencies: + xtend "~4.0.0" + +accepts@~1.3.5: + version "1.3.5" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" + dependencies: + mime-types "~2.1.18" + negotiator "0.6.1" + +acorn-dynamic-import@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz#c752bd210bef679501b6c6cb7fc84f8f47158cc4" + dependencies: + acorn "^4.0.3" + +acorn-globals@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.1.0.tgz#ab716025dbe17c54d3ef81d32ece2b2d99fe2538" + dependencies: + acorn "^5.0.0" + +acorn-jsx@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" + dependencies: + acorn "^3.0.4" + +acorn@^3.0.4: + version "3.3.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" + +acorn@^4.0.3: + version "4.0.13" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" + +acorn@^5.0.0, acorn@^5.5.0: + version "5.5.3" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.5.3.tgz#f473dd47e0277a08e28e9bec5aeeb04751f0b8c9" + +acorn@^5.3.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8" + +aes-js@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" + +aes-js@^0.2.3: + version "0.2.4" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-0.2.4.tgz#94b881ab717286d015fa219e08fb66709dda5a3d" + +ajv-keywords@^1.1.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" + +ajv-keywords@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" + +ajv@^4.7.0: + version "4.11.8" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" + dependencies: + co "^4.6.0" + json-stable-stringify "^1.0.1" + +ajv@^5.1.0, ajv@^5.2.2, ajv@^5.2.3, ajv@^5.3.0: + version "5.5.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" + dependencies: + co "^4.6.0" + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" + +align-text@^0.1.1, align-text@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" + dependencies: + kind-of "^3.0.2" + longest "^1.0.1" + repeat-string "^1.5.2" + +amdefine@>=0.0.4: + version "1.0.1" + resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + +ansi-escapes@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" + +ansi-escapes@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + dependencies: + color-convert "^1.9.0" + +ansi-styles@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.0.0.tgz#cb102df1c56f5123eab8b67cd7b98027a0279178" + +any-observable@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.2.0.tgz#c67870058003579009083f54ac0abafb5c33d242" + +any-promise@1.3.0, any-promise@^1.0.0, any-promise@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + +anymatch@^1.3.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" + dependencies: + micromatch "^2.1.5" + normalize-path "^2.0.0" + +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +append-transform@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-1.0.0.tgz#046a52ae582a228bd72f58acfbe2967c678759ab" + dependencies: + default-require-extensions "^2.0.0" + +aproba@^1.0.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + +are-we-there-yet@~1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + dependencies: + sprintf-js "~1.0.2" + +argsarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/argsarray/-/argsarray-0.0.1.tgz#6e7207b4ecdb39b0af88303fa5ae22bda8df61cb" + +arr-diff@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + dependencies: + arr-flatten "^1.0.1" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + +arr-flatten@^1.0.1, arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + +array-differ@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031" + +array-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + +array-unique@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + +arrify@^1.0.0, arrify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + +asap@~2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + +asn1.js@^4.0.0: + version "4.10.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +asn1@~0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + +assert@^1.1.1, assert@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" + dependencies: + util "0.10.3" + +assertion-error@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + +ast-types@0.10.1: + version "0.10.1" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.10.1.tgz#f52fca9715579a14f841d67d7f8d25432ab6a3dd" + +ast-types@0.11.3: + version "0.11.3" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.11.3.tgz#c20757fe72ee71278ea0ff3d87e5c2ca30d9edf8" + +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" + +async-each@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + +async-eventemitter@^0.2.2: + version "0.2.4" + resolved "https://registry.yarnpkg.com/async-eventemitter/-/async-eventemitter-0.2.4.tgz#f5e7c8ca7d3e46aab9ec40a292baf686a0bafaca" + dependencies: + async "^2.4.0" + +async-eventemitter@ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c: + version "0.2.3" + resolved "https://codeload.github.com/ahultgren/async-eventemitter/tar.gz/fa06e39e56786ba541c180061dbf2c0a5bbf951c" + dependencies: + async "^2.4.0" + +async-limiter@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" + +async@1.x, async@^1.4.0, async@^1.4.2, async@^1.5.0, async@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + +async@^2.0.1, async@^2.1.2, async@^2.4.0, async@^2.5.0, async@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.0.tgz#61a29abb6fcc026fea77e56d1c6ec53a795951f4" + dependencies: + lodash "^4.14.0" + +async@^2.1.4: + version "2.6.1" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" + dependencies: + lodash "^4.17.10" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + +atob@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.1.tgz#ae2d5a729477f289d60dd7f96a6314a22dd6c22a" + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + +aws4@^1.6.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.7.0.tgz#d4d0e9b9dbfca77bf08eeb0a8a471550fe39e289" + +babel-cli@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-cli/-/babel-cli-6.26.0.tgz#502ab54874d7db88ad00b887a06383ce03d002f1" + dependencies: + babel-core "^6.26.0" + babel-polyfill "^6.26.0" + babel-register "^6.26.0" + babel-runtime "^6.26.0" + commander "^2.11.0" + convert-source-map "^1.5.0" + fs-readdir-recursive "^1.0.0" + glob "^7.1.2" + lodash "^4.17.4" + output-file-sync "^1.1.2" + path-is-absolute "^1.0.1" + slash "^1.0.0" + source-map "^0.5.6" + v8flags "^2.1.1" + optionalDependencies: + chokidar "^1.6.1" + +babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + dependencies: + chalk "^1.1.3" + esutils "^2.0.2" + js-tokens "^3.0.2" + +babel-core@^6.0.0, babel-core@^6.0.14, babel-core@^6.23.1, babel-core@^6.26.0: + version "6.26.3" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207" + dependencies: + babel-code-frame "^6.26.0" + babel-generator "^6.26.0" + babel-helpers "^6.24.1" + babel-messages "^6.23.0" + babel-register "^6.26.0" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + convert-source-map "^1.5.1" + debug "^2.6.9" + json5 "^0.5.1" + lodash "^4.17.4" + minimatch "^3.0.4" + path-is-absolute "^1.0.1" + private "^0.1.8" + slash "^1.0.0" + source-map "^0.5.7" + +babel-eslint@^8.2.3: + version "8.2.3" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-8.2.3.tgz#1a2e6681cc9bc4473c32899e59915e19cd6733cf" + dependencies: + "@babel/code-frame" "7.0.0-beta.44" + "@babel/traverse" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + babylon "7.0.0-beta.44" + eslint-scope "~3.7.1" + eslint-visitor-keys "^1.0.0" + +babel-generator@^6.18.0, babel-generator@^6.26.0: + version "6.26.1" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" + dependencies: + babel-messages "^6.23.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + detect-indent "^4.0.0" + jsesc "^1.3.0" + lodash "^4.17.4" + source-map "^0.5.7" + trim-right "^1.0.1" + +babel-helper-bindify-decorators@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.24.1.tgz#14c19e5f142d7b47f19a52431e52b1ccbc40a330" + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" + dependencies: + babel-helper-explode-assignable-expression "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-call-delegate@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-define-map@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-helper-explode-assignable-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-explode-class@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz#7dc2a3910dee007056e1e31d640ced3d54eaa9eb" + dependencies: + babel-helper-bindify-decorators "^6.24.1" + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-function-name@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" + dependencies: + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-get-function-arity@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-hoist-variables@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-optimise-call-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-regex@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" + dependencies: + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-helper-remap-async-to-generator@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-replace-supers@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" + dependencies: + babel-helper-optimise-call-expression "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helpers@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-jest@^23.0.1: + version "23.0.1" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-23.0.1.tgz#bbad3bf523fb202da05ed0a6540b48c84eed13a6" + dependencies: + babel-plugin-istanbul "^4.1.6" + babel-preset-jest "^23.0.1" + +babel-loader@^6.3.2: + version "6.4.1" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-6.4.1.tgz#0b34112d5b0748a8dcdbf51acf6f9bd42d50b8ca" + dependencies: + find-cache-dir "^0.1.1" + loader-utils "^0.2.16" + mkdirp "^0.5.1" + object-assign "^4.0.1" + +babel-messages@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-add-module-exports@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/babel-plugin-add-module-exports/-/babel-plugin-add-module-exports-0.2.1.tgz#9ae9a1f4a8dc67f0cdec4f4aeda1e43a5ff65e25" + +babel-plugin-check-es2015-constants@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-istanbul@^4.1.6: + version "4.1.6" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz#36c59b2192efce81c5b378321b74175add1c9a45" + dependencies: + babel-plugin-syntax-object-rest-spread "^6.13.0" + find-up "^2.1.0" + istanbul-lib-instrument "^1.10.1" + test-exclude "^4.2.1" + +babel-plugin-jest-hoist@^23.0.1: + version "23.0.1" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-23.0.1.tgz#eaa11c964563aea9c21becef2bdf7853f7f3c148" + +babel-plugin-syntax-async-functions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" + +babel-plugin-syntax-async-generators@^6.5.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz#6bc963ebb16eccbae6b92b596eb7f35c342a8b9a" + +babel-plugin-syntax-class-constructor-call@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-constructor-call/-/babel-plugin-syntax-class-constructor-call-6.18.0.tgz#9cb9d39fe43c8600bec8146456ddcbd4e1a76416" + +babel-plugin-syntax-class-properties@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" + +babel-plugin-syntax-decorators@^6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz#312563b4dbde3cc806cee3e416cceeaddd11ac0b" + +babel-plugin-syntax-dynamic-import@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da" + +babel-plugin-syntax-exponentiation-operator@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" + +babel-plugin-syntax-export-extensions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz#70a1484f0f9089a4e84ad44bac353c95b9b12721" + +babel-plugin-syntax-flow@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d" + +babel-plugin-syntax-object-rest-spread@^6.13.0, babel-plugin-syntax-object-rest-spread@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" + +babel-plugin-syntax-trailing-function-commas@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" + +babel-plugin-transform-async-generator-functions@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz#f058900145fd3e9907a6ddf28da59f215258a5db" + dependencies: + babel-helper-remap-async-to-generator "^6.24.1" + babel-plugin-syntax-async-generators "^6.5.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-async-to-generator@^6.22.0, babel-plugin-transform-async-to-generator@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" + dependencies: + babel-helper-remap-async-to-generator "^6.24.1" + babel-plugin-syntax-async-functions "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-class-constructor-call@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-constructor-call/-/babel-plugin-transform-class-constructor-call-6.24.1.tgz#80dc285505ac067dcb8d6c65e2f6f11ab7765ef9" + dependencies: + babel-plugin-syntax-class-constructor-call "^6.18.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-class-properties@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac" + dependencies: + babel-helper-function-name "^6.24.1" + babel-plugin-syntax-class-properties "^6.8.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-decorators@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.24.1.tgz#788013d8f8c6b5222bdf7b344390dfd77569e24d" + dependencies: + babel-helper-explode-class "^6.24.1" + babel-plugin-syntax-decorators "^6.13.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-arrow-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoping@^6.23.0, babel-plugin-transform-es2015-block-scoping@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" + dependencies: + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-plugin-transform-es2015-classes@^6.23.0, babel-plugin-transform-es2015-classes@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" + dependencies: + babel-helper-define-map "^6.24.1" + babel-helper-function-name "^6.24.1" + babel-helper-optimise-call-expression "^6.24.1" + babel-helper-replace-supers "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-computed-properties@^6.22.0, babel-plugin-transform-es2015-computed-properties@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-destructuring@^6.22.0, babel-plugin-transform-es2015-destructuring@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-duplicate-keys@^6.22.0, babel-plugin-transform-es2015-duplicate-keys@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-for-of@^6.22.0, babel-plugin-transform-es2015-for-of@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-function-name@^6.22.0, babel-plugin-transform-es2015-function-name@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" + dependencies: + babel-plugin-transform-es2015-modules-commonjs "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1: + version "6.26.2" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz#58a793863a9e7ca870bdc5a881117ffac27db6f3" + dependencies: + babel-plugin-transform-strict-mode "^6.24.1" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-types "^6.26.0" + +babel-plugin-transform-es2015-modules-systemjs@^6.23.0, babel-plugin-transform-es2015-modules-systemjs@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-modules-umd@^6.23.0, babel-plugin-transform-es2015-modules-umd@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" + dependencies: + babel-plugin-transform-es2015-modules-amd "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-object-super@^6.22.0, babel-plugin-transform-es2015-object-super@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" + dependencies: + babel-helper-replace-supers "^6.24.1" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-parameters@^6.23.0, babel-plugin-transform-es2015-parameters@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" + dependencies: + babel-helper-call-delegate "^6.24.1" + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-shorthand-properties@^6.22.0, babel-plugin-transform-es2015-shorthand-properties@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-spread@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-sticky-regex@^6.22.0, babel-plugin-transform-es2015-sticky-regex@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-template-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-typeof-symbol@^6.22.0, babel-plugin-transform-es2015-typeof-symbol@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-unicode-regex@^6.22.0, babel-plugin-transform-es2015-unicode-regex@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + regexpu-core "^2.0.0" + +babel-plugin-transform-exponentiation-operator@^6.22.0, babel-plugin-transform-exponentiation-operator@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" + dependencies: + babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" + babel-plugin-syntax-exponentiation-operator "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-export-extensions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-export-extensions/-/babel-plugin-transform-export-extensions-6.22.0.tgz#53738b47e75e8218589eea946cbbd39109bbe653" + dependencies: + babel-plugin-syntax-export-extensions "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-flow-strip-types@^6.8.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz#84cb672935d43714fdc32bce84568d87441cf7cf" + dependencies: + babel-plugin-syntax-flow "^6.18.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-object-rest-spread@^6.22.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz#0f36692d50fef6b7e2d4b3ac1478137a963b7b06" + dependencies: + babel-plugin-syntax-object-rest-spread "^6.8.0" + babel-runtime "^6.26.0" + +babel-plugin-transform-regenerator@^6.22.0, babel-plugin-transform-regenerator@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" + dependencies: + regenerator-transform "^0.10.0" + +babel-plugin-transform-runtime@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-runtime/-/babel-plugin-transform-runtime-6.23.0.tgz#88490d446502ea9b8e7efb0fe09ec4d99479b1ee" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-strict-mode@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-polyfill@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" + dependencies: + babel-runtime "^6.26.0" + core-js "^2.5.0" + regenerator-runtime "^0.10.5" + +babel-preset-env@^1.3.2: + version "1.6.1" + resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.6.1.tgz#a18b564cc9b9afdf4aae57ae3c1b0d99188e6f48" + dependencies: + babel-plugin-check-es2015-constants "^6.22.0" + babel-plugin-syntax-trailing-function-commas "^6.22.0" + babel-plugin-transform-async-to-generator "^6.22.0" + babel-plugin-transform-es2015-arrow-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoping "^6.23.0" + babel-plugin-transform-es2015-classes "^6.23.0" + babel-plugin-transform-es2015-computed-properties "^6.22.0" + babel-plugin-transform-es2015-destructuring "^6.23.0" + babel-plugin-transform-es2015-duplicate-keys "^6.22.0" + babel-plugin-transform-es2015-for-of "^6.23.0" + babel-plugin-transform-es2015-function-name "^6.22.0" + babel-plugin-transform-es2015-literals "^6.22.0" + babel-plugin-transform-es2015-modules-amd "^6.22.0" + babel-plugin-transform-es2015-modules-commonjs "^6.23.0" + babel-plugin-transform-es2015-modules-systemjs "^6.23.0" + babel-plugin-transform-es2015-modules-umd "^6.23.0" + babel-plugin-transform-es2015-object-super "^6.22.0" + babel-plugin-transform-es2015-parameters "^6.23.0" + babel-plugin-transform-es2015-shorthand-properties "^6.22.0" + babel-plugin-transform-es2015-spread "^6.22.0" + babel-plugin-transform-es2015-sticky-regex "^6.22.0" + babel-plugin-transform-es2015-template-literals "^6.22.0" + babel-plugin-transform-es2015-typeof-symbol "^6.23.0" + babel-plugin-transform-es2015-unicode-regex "^6.22.0" + babel-plugin-transform-exponentiation-operator "^6.22.0" + babel-plugin-transform-regenerator "^6.22.0" + browserslist "^2.1.2" + invariant "^2.2.2" + semver "^5.3.0" + +babel-preset-es2015@^6.22.0, babel-preset-es2015@^6.24.1, babel-preset-es2015@^6.9.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz#d44050d6bc2c9feea702aaf38d727a0210538939" + dependencies: + 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.22.0" + babel-plugin-transform-es2015-duplicate-keys "^6.24.1" + babel-plugin-transform-es2015-for-of "^6.22.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.22.0" + babel-plugin-transform-es2015-unicode-regex "^6.24.1" + babel-plugin-transform-regenerator "^6.24.1" + +babel-preset-jest@^23.0.1: + version "23.0.1" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-23.0.1.tgz#631cc545c6cf021943013bcaf22f45d87fe62198" + dependencies: + babel-plugin-jest-hoist "^23.0.1" + babel-plugin-syntax-object-rest-spread "^6.13.0" + +babel-preset-stage-1@^6.5.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-stage-1/-/babel-preset-stage-1-6.24.1.tgz#7692cd7dcd6849907e6ae4a0a85589cfb9e2bfb0" + dependencies: + 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@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz#d9e2960fb3d71187f0e64eec62bc07767219bdc1" + dependencies: + babel-plugin-syntax-dynamic-import "^6.18.0" + babel-plugin-transform-class-properties "^6.24.1" + babel-plugin-transform-decorators "^6.24.1" + babel-preset-stage-3 "^6.24.1" + +babel-preset-stage-3@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz#836ada0a9e7a7fa37cb138fb9326f87934a48395" + dependencies: + babel-plugin-syntax-trailing-function-commas "^6.22.0" + babel-plugin-transform-async-generator-functions "^6.24.1" + babel-plugin-transform-async-to-generator "^6.24.1" + babel-plugin-transform-exponentiation-operator "^6.24.1" + babel-plugin-transform-object-rest-spread "^6.22.0" + +babel-register@^6.26.0, babel-register@^6.9.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" + dependencies: + babel-core "^6.26.0" + babel-runtime "^6.26.0" + core-js "^2.5.0" + home-or-tmp "^2.0.0" + lodash "^4.17.4" + mkdirp "^0.5.1" + source-map-support "^0.4.15" + +babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + +babel-template@^6.16.0, babel-template@^6.24.1, babel-template@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" + dependencies: + babel-runtime "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + lodash "^4.17.4" + +babel-traverse@^6.18.0, babel-traverse@^6.24.1, babel-traverse@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" + dependencies: + babel-code-frame "^6.26.0" + babel-messages "^6.23.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + debug "^2.6.8" + globals "^9.18.0" + invariant "^2.2.2" + lodash "^4.17.4" + +babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" + dependencies: + babel-runtime "^6.26.0" + esutils "^2.0.2" + lodash "^4.17.4" + to-fast-properties "^1.0.3" + +babelify@^7.3.0: + version "7.3.0" + resolved "https://registry.yarnpkg.com/babelify/-/babelify-7.3.0.tgz#aa56aede7067fd7bd549666ee16dc285087e88e5" + dependencies: + babel-core "^6.0.14" + object-assign "^4.0.0" + +babylon@7.0.0-beta.44: + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.44.tgz#89159e15e6e30c5096e22d738d8c0af8a0e8ca1d" + +babylon@^6.17.3, babylon@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" + +babylon@^7.0.0-beta.30: + version "7.0.0-beta.46" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.46.tgz#b6ddaba81bbb130313932757ff9c195d527088b6" + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + +base-x@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-1.1.0.tgz#42d3d717474f9ea02207f6d1aa1f426913eeb7ac" + +base64-js@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-0.0.8.tgz#1101e9544f4a76b1bc3b26d452ca96d7a35e7978" + +base64-js@^1.0.2: + version "1.3.0" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +bcrypt-pbkdf@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" + dependencies: + tweetnacl "^0.14.3" + +big.js@^3.1.3: + version "3.2.0" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" + +"bignumber.js@git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2": + version "2.0.7" + resolved "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2" + +binary-extensions@^1.0.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" + +binaryextensions@2: + version "2.1.1" + resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.1.1.tgz#3209a51ca4a4ad541a3b8d3d6a6d5b83a2485935" + +bindings@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.3.0.tgz#b346f6ecf6a95f5a815c5839fc7cdb22502f1ed7" + +bip39@~2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/bip39/-/bip39-2.4.0.tgz#a0b8adbf163f53495f00f05d9ede7c25369ccf13" + dependencies: + create-hash "^1.1.0" + pbkdf2 "^3.0.9" + randombytes "^2.0.1" + safe-buffer "^5.0.1" + unorm "^1.3.3" + +bip66@^1.1.3: + version "1.1.5" + resolved "https://registry.yarnpkg.com/bip66/-/bip66-1.1.5.tgz#01fa8748785ca70955d5011217d1b3139969ca22" + dependencies: + safe-buffer "^5.0.1" + +bl@^1.0.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c" + dependencies: + readable-stream "^2.3.5" + safe-buffer "^5.1.1" + +bl@~0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/bl/-/bl-0.8.2.tgz#c9b6bca08d1bc2ea00fc8afb4f1a5fd1e1c66e4e" + dependencies: + readable-stream "~1.0.26" + +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + dependencies: + inherits "~2.0.0" + +bluebird@^2.9.34: + version "2.11.0" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" + +bluebird@^3.5.0: + version "3.5.1" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" + +bn.js@4.11.6: + version "4.11.6" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.10.0, bn.js@^4.11.0, bn.js@^4.11.3, bn.js@^4.11.6, bn.js@^4.11.8, bn.js@^4.4.0, bn.js@^4.8.0: + version "4.11.8" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" + +body-parser@1.18.2, body-parser@^1.16.0: + version "1.18.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.2.tgz#87678a19d84b47d859b83199bd59bce222b10454" + dependencies: + bytes "3.0.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.1" + http-errors "~1.6.2" + iconv-lite "0.4.19" + on-finished "~2.3.0" + qs "6.5.1" + raw-body "2.3.2" + type-is "~1.6.15" + +boom@4.x.x: + version "4.3.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-4.3.1.tgz#4f8a3005cb4a7e3889f749030fd25b96e01d2e31" + dependencies: + hoek "4.x.x" + +boom@5.x.x: + version "5.2.0" + resolved "https://registry.yarnpkg.com/boom/-/boom-5.2.0.tgz#5dd9da6ee3a5f302077436290cb717d3f4a54e02" + dependencies: + hoek "4.x.x" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^1.8.2: + version "1.8.5" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + dependencies: + expand-range "^1.8.1" + preserve "^0.2.0" + repeat-element "^1.1.2" + +braces@^2.3.0, braces@^2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +brorand@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + +browser-process-hrtime@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-0.1.2.tgz#425d68a58d3447f02a04aa894187fce8af8b7b8e" + +browser-resolve@^1.11.2: + version "1.11.2" + resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.2.tgz#8ff09b0a2c421718a1051c260b32e48f442938ce" + dependencies: + resolve "1.1.7" + +browser-stdout@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.0.tgz#f351d32969d32fa5d7a5567154263d928ae3bd1f" + +browser-stdout@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + +browserify-aes@^1.0.0, browserify-aes@^1.0.4, browserify-aes@^1.0.6: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.1.tgz#3343124db6d7ad53e26a8826318712bdc8450f9c" + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + +browserify-rsa@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" + dependencies: + bn.js "^4.1.0" + randombytes "^2.0.1" + +browserify-sha3@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/browserify-sha3/-/browserify-sha3-0.0.1.tgz#3ff34a3006ef15c0fb3567e541b91a2340123d11" + dependencies: + js-sha3 "^0.3.1" + +browserify-sign@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" + dependencies: + bn.js "^4.1.1" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.2" + elliptic "^6.0.0" + inherits "^2.0.1" + parse-asn1 "^5.0.0" + +browserify-zlib@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + dependencies: + pako "~1.0.5" + +browserslist@^2.1.2: + version "2.11.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.11.3.tgz#fe36167aed1bbcde4827ebfe71347a2cc70b99b2" + dependencies: + caniuse-lite "^1.0.30000792" + electron-to-chromium "^1.3.30" + +bs58@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/bs58/-/bs58-2.0.1.tgz#55908d58f1982aba2008fa1bed8f91998a29bf8d" + +bs58@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/bs58/-/bs58-3.1.0.tgz#d4c26388bf4804cac714141b1945aa47e5eb248e" + dependencies: + base-x "^1.1.0" + +bs58check@^1.0.8: + version "1.3.4" + resolved "https://registry.yarnpkg.com/bs58check/-/bs58check-1.3.4.tgz#c52540073749117714fa042c3047eb8f9151cbf8" + dependencies: + bs58 "^3.1.0" + create-hash "^1.1.0" + +bser@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" + dependencies: + node-int64 "^0.4.0" + +buffer-alloc-unsafe@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-0.1.1.tgz#ffe1f67551dd055737de253337bfe853dfab1a6a" + +buffer-alloc@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.1.0.tgz#05514d33bf1656d3540c684f65b1202e90eca303" + dependencies: + buffer-alloc-unsafe "^0.1.0" + buffer-fill "^0.1.0" + +buffer-crc32@~0.2.3: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + +buffer-fill@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-0.1.1.tgz#76d825c4d6e50e06b7a31eb520c04d08cc235071" + +buffer-from@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-0.1.2.tgz#15f4b9bcef012044df31142c14333caf6e0260d0" + +buffer-from@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.0.0.tgz#4cb8832d23612589b0406e9e2956c17f06fdf531" + +buffer-to-arraybuffer@^0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz#6064a40fa76eb43c723aba9ef8f6e1216d10511a" + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + +buffer@^3.0.1: + version "3.6.0" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-3.6.0.tgz#a72c936f77b96bf52f5f7e7b467180628551defb" + dependencies: + base64-js "0.0.8" + ieee754 "^1.1.4" + isarray "^1.0.0" + +buffer@^4.3.0: + version "4.9.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + +buffer@^5.0.5: + version "5.1.0" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.1.0.tgz#c913e43678c7cb7c8bd16afbcddb6c5505e8f9fe" + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + +builtin-modules@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + +bytewise-core@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/bytewise-core/-/bytewise-core-1.2.3.tgz#3fb410c7e91558eb1ab22a82834577aa6bd61d42" + dependencies: + typewise-core "^1.2" + +bytewise@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/bytewise/-/bytewise-1.1.0.tgz#1d13cbff717ae7158094aa881b35d081b387253e" + dependencies: + bytewise-core "^1.2.2" + typewise "^1.0.3" + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +cacheable-request@^2.1.1: + version "2.1.4" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-2.1.4.tgz#0d808801b6342ad33c91df9d0b44dc09b91e5c3d" + dependencies: + clone-response "1.0.2" + get-stream "3.0.0" + http-cache-semantics "3.8.1" + keyv "3.0.0" + lowercase-keys "1.0.0" + normalize-url "2.0.1" + responselike "1.0.2" + +cachedown@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/cachedown/-/cachedown-1.0.0.tgz#d43f036e4510696b31246d7db31ebf0f7ac32d15" + dependencies: + abstract-leveldown "^2.4.1" + lru-cache "^3.2.0" + +call-me-maybe@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" + +caller-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" + dependencies: + callsites "^0.2.0" + +callsites@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" + +callsites@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" + +camelcase@^1.0.2: + version "1.2.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" + +camelcase@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" + +camelcase@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" + +caniuse-lite@^1.0.30000792: + version "1.0.30000833" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000833.tgz#98e84fcdb4399c6fa0b0fd41490d3217ac7802b4" + +capture-exit@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f" + dependencies: + rsvp "^3.3.3" + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + +center-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" + dependencies: + align-text "^0.1.3" + lazy-cache "^1.0.3" + +chai@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/chai/-/chai-3.5.0.tgz#4d02637b067fe958bdbfdd3a40ec56fef7373247" + dependencies: + assertion-error "^1.0.1" + deep-eql "^0.1.3" + type-detect "^1.0.0" + +chai@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.1.2.tgz#0f64584ba642f0f2ace2806279f4f06ca23ad73c" + dependencies: + assertion-error "^1.0.1" + check-error "^1.0.1" + deep-eql "^3.0.0" + get-func-name "^2.0.0" + pathval "^1.0.0" + type-detect "^4.0.0" + +chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.2: + version "2.4.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.4.0.tgz#5199a3ddcd0c1efe23bc08c1b027b06176e0c64f" + dependencies: + ansi-styles "~1.0.0" + has-color "~0.1.0" + strip-ansi "~0.1.0" + +chardet@^0.4.0: + version "0.4.2" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" + +charenc@~0.0.1: + version "0.0.2" + resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" + +check-error@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" + +checkpoint-store@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/checkpoint-store/-/checkpoint-store-1.1.0.tgz#04e4cb516b91433893581e6d4601a78e9552ea06" + dependencies: + functional-red-black-tree "^1.0.1" + +chokidar@^1.6.0, chokidar@^1.6.1: + version "1.7.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" + dependencies: + anymatch "^1.3.0" + async-each "^1.0.0" + glob-parent "^2.0.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^2.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + optionalDependencies: + fsevents "^1.0.0" + +chokidar@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.3.tgz#dcbd4f6cbb2a55b4799ba8a840ac527e5f4b1176" + dependencies: + anymatch "^2.0.0" + async-each "^1.0.0" + braces "^2.3.0" + glob-parent "^3.1.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + normalize-path "^2.1.1" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + upath "^1.0.0" + optionalDependencies: + fsevents "^1.1.2" + +chownr@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" + +ci-info@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.3.tgz#710193264bb05c77b8c90d02f5aaf22216a667b2" + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +circular-json@^0.3.1: + version "0.3.3" + resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +cli-cursor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" + dependencies: + restore-cursor "^1.0.1" + +cli-cursor@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + dependencies: + restore-cursor "^2.0.0" + +cli-spinners@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-0.1.2.tgz#bb764d88e185fb9e1e6a2a1f19772318f605e31c" + +cli-table2@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/cli-table2/-/cli-table2-0.2.0.tgz#2d1ef7f218a0e786e214540562d4bd177fe32d97" + dependencies: + lodash "^3.10.1" + string-width "^1.0.1" + optionalDependencies: + colors "^1.1.2" + +cli-table@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" + dependencies: + colors "1.0.3" + +cli-truncate@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-0.2.1.tgz#9f15cfbb0705005369216c626ac7d05ab90dd574" + dependencies: + slice-ansi "0.0.4" + string-width "^1.0.1" + +cli-width@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" + +cliui@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" + dependencies: + center-align "^0.1.1" + right-align "^0.1.1" + wordwrap "0.0.2" + +cliui@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrap-ansi "^2.0.0" + +cliui@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" + dependencies: + string-width "^2.1.1" + strip-ansi "^4.0.0" + wrap-ansi "^2.0.0" + +clone-buffer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58" + +clone-response@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" + dependencies: + mimic-response "^1.0.0" + +clone-stats@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-0.0.1.tgz#b88f94a82cf38b8791d58046ea4029ad88ca99d1" + +clone-stats@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680" + +clone@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + +clone@^2.0.0, clone@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb" + +cloneable-readable@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/cloneable-readable/-/cloneable-readable-1.1.2.tgz#d591dee4a8f8bc15da43ce97dceeba13d43e2a65" + dependencies: + inherits "^2.0.1" + process-nextick-args "^2.0.0" + readable-stream "^2.3.5" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + +coinstring@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/coinstring/-/coinstring-2.3.0.tgz#cdb63363a961502404a25afb82c2e26d5ff627a4" + dependencies: + bs58 "^2.0.1" + create-hash "^1.1.1" + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.9.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed" + dependencies: + color-name "^1.1.1" + +color-name@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + +colors@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" + +colors@^1.1.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.2.3.tgz#1b152a9c4f6c9f74bc4bb96233ad0b7983b79744" + +combined-stream@1.0.6, combined-stream@~1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818" + dependencies: + delayed-stream "~1.0.0" + +commander@2.11.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" + +commander@2.15.1, commander@^2.11.0, commander@^2.8.1, commander@^2.9.0: + version "2.15.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" + +commander@2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" + dependencies: + graceful-readlink ">= 1.0.0" + +commander@~2.8.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" + dependencies: + graceful-readlink ">= 1.0.0" + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + +compare-versions@^3.1.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.3.0.tgz#af93ea705a96943f622ab309578b9b90586f39c3" + +component-emitter@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +concat-stream@^1.4.6, concat-stream@^1.4.7, concat-stream@^1.6.0: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +console-browserify@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" + dependencies: + date-now "^0.1.4" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + +constants-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + +contains-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" + +content-disposition@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + +convert-source-map@^1.4.0, convert-source-map@^1.5.0, convert-source-map@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + +cookie@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + +core-js@^2.4.0, core-js@^2.4.1, core-js@^2.5.0: + version "2.5.5" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.5.tgz#b14dde936c640c0579a6b50cabcc132dd6127e3b" + +core-util-is@1.0.2, core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +cors@^2.8.1: + version "2.8.4" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.4.tgz#2bd381f2eb201020105cd50ea59da63090694686" + dependencies: + object-assign "^4" + vary "^1" + +create-ecdh@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.1.tgz#44223dfed533193ba5ba54e0df5709b89acf1f82" + dependencies: + bn.js "^4.1.0" + elliptic "^6.0.0" + +create-hash@^1.1.0, create-hash@^1.1.1, create-hash@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +cross-spawn@^5.0.1, cross-spawn@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + +cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +crypt@~0.0.1: + version "0.0.2" + resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" + +cryptiles@3.x.x: + version "3.1.2" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-3.1.2.tgz#a89fbb220f5ce25ec56e8c4aa8a4fd7b5b0d29fe" + dependencies: + boom "5.x.x" + +crypto-browserify@3.12.0, crypto-browserify@^3.11.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + +crypto-js@^3.1.4: + version "3.1.8" + resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-3.1.8.tgz#715f070bf6014f2ae992a98b3929258b713f08d5" + +cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0": + version "0.3.2" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.2.tgz#b8036170c79f07a90ff2f16e22284027a243848b" + +"cssstyle@>= 0.3.1 < 0.4.0": + version "0.3.1" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-0.3.1.tgz#6da9b4cff1bc5d716e6e5fe8e04fcb1b50a49adf" + dependencies: + cssom "0.3.x" + +d64@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/d64/-/d64-1.0.0.tgz#4002a87e850cbfc9f9d9706b60fca613a3336e90" + +dargs@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/dargs/-/dargs-5.1.0.tgz#ec7ea50c78564cd36c9d5ec18f66329fade27829" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + dependencies: + assert-plus "^1.0.0" + +data-urls@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-1.0.0.tgz#24802de4e81c298ea8a9388bb0d8e461c774684f" + dependencies: + abab "^1.0.4" + whatwg-mimetype "^2.0.0" + whatwg-url "^6.4.0" + +date-fns@^1.27.2: + version "1.29.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.29.0.tgz#12e609cdcb935127311d04d33334e2960a2a54e6" + +date-now@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" + +dateformat@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" + +death@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/death/-/death-1.1.0.tgz#01aa9c401edd92750514470b8266390c66c67318" + +debug@2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.0.tgz#bc596bcabe7617f11d9fa15361eded5608b8499b" + dependencies: + ms "0.7.2" + +debug@2.6.8: + version "2.6.8" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" + dependencies: + ms "2.0.0" + +debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + dependencies: + ms "2.0.0" + +debug@3.1.0, debug@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + dependencies: + ms "2.0.0" + +decamelize@^1.0.0, decamelize@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + +decompress-response@^3.2.0, decompress-response@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + dependencies: + mimic-response "^1.0.0" + +decompress-tar@^4.0.0, decompress-tar@^4.1.0, decompress-tar@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/decompress-tar/-/decompress-tar-4.1.1.tgz#718cbd3fcb16209716e70a26b84e7ba4592e5af1" + dependencies: + file-type "^5.2.0" + is-stream "^1.1.0" + tar-stream "^1.5.2" + +decompress-tarbz2@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz#3082a5b880ea4043816349f378b56c516be1a39b" + dependencies: + decompress-tar "^4.1.0" + file-type "^6.1.0" + is-stream "^1.1.0" + seek-bzip "^1.0.5" + unbzip2-stream "^1.0.9" + +decompress-targz@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/decompress-targz/-/decompress-targz-4.1.1.tgz#c09bc35c4d11f3de09f2d2da53e9de23e7ce1eee" + dependencies: + decompress-tar "^4.1.1" + file-type "^5.2.0" + is-stream "^1.1.0" + +decompress-unzip@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/decompress-unzip/-/decompress-unzip-4.0.1.tgz#deaaccdfd14aeaf85578f733ae8210f9b4848f69" + dependencies: + file-type "^3.8.0" + get-stream "^2.2.0" + pify "^2.3.0" + yauzl "^2.4.2" + +decompress@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/decompress/-/decompress-4.2.0.tgz#7aedd85427e5a92dacfe55674a7c505e96d01f9d" + dependencies: + decompress-tar "^4.0.0" + decompress-tarbz2 "^4.0.0" + decompress-targz "^4.0.0" + decompress-unzip "^4.0.1" + graceful-fs "^4.1.10" + make-dir "^1.0.0" + pify "^2.3.0" + strip-dirs "^2.0.0" + +deep-eql@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2" + dependencies: + type-detect "0.1.1" + +deep-eql@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" + dependencies: + type-detect "^4.0.0" + +deep-equal@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" + +deep-extend@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.5.1.tgz#b894a9dd90d3023fbf1c55a394fb858eb2066f1f" + +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + +default-require-extensions@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-2.0.0.tgz#f5f8fbb18a7d6d50b21f641f649ebb522cfe24f7" + dependencies: + strip-bom "^3.0.0" + +deferred-leveldown@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-0.2.0.tgz#2cef1f111e1c57870d8bbb8af2650e587cd2f5b4" + dependencies: + abstract-leveldown "~0.12.1" + +deferred-leveldown@~1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-1.2.2.tgz#3acd2e0b75d1669924bc0a4b642851131173e1eb" + dependencies: + abstract-leveldown "~2.6.0" + +define-properties@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" + dependencies: + foreach "^2.0.5" + object-keys "^1.0.8" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +defined@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" + +del@^2.0.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" + dependencies: + globby "^5.0.0" + is-path-cwd "^1.0.0" + is-path-in-cwd "^1.0.0" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + rimraf "^2.2.8" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + +depd@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" + +depd@~1.1.1, depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + +des.js@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + +detect-conflict@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/detect-conflict/-/detect-conflict-1.0.1.tgz#088657a66a961c05019db7c4230883b1c6b4176e" + +detect-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + dependencies: + repeating "^2.0.0" + +detect-libc@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + +detect-newline@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" + +diff@3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9" + +diff@3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.3.1.tgz#aa8567a6eed03c531fc89d3f711cd0e5259dec75" + +diff@3.5.0, diff@^3.2.0, diff@^3.3.1, diff@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" + +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +dir-glob@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.0.0.tgz#0b205d2b6aef98238ca286598a8204d29d0a0034" + dependencies: + arrify "^1.0.1" + path-type "^3.0.0" + +doctrine@1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" + dependencies: + esutils "^2.0.2" + isarray "^1.0.0" + +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + dependencies: + esutils "^2.0.2" + +dom-walk@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018" + +domain-browser@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" + +domexception@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" + dependencies: + webidl-conversions "^4.0.2" + +drbg.js@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/drbg.js/-/drbg.js-1.0.1.tgz#3e36b6c42b37043823cdbc332d58f31e2445480b" + dependencies: + browserify-aes "^1.0.6" + create-hash "^1.1.2" + create-hmac "^1.1.4" + +duplexer3@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + +ecc-jsbn@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" + dependencies: + jsbn "~0.1.0" + +editions@^1.3.3: + version "1.3.4" + resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.4.tgz#3662cb592347c3168eb8e498a0ff73271d67f50b" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + +ejs@^2.5.9: + version "2.5.9" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.9.tgz#7ba254582a560d267437109a68354112475b0ce5" + +electron-to-chromium@^1.3.30: + version "1.3.45" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.45.tgz#458ac1b1c5c760ce8811a16d2bfbd97ec30bafb8" + +elegant-spinner@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e" + +elliptic@6.3.3: + version "6.3.3" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.3.3.tgz#5482d9646d54bcb89fd7d994fc9e2e9568876e3f" + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + inherits "^2.0.1" + +elliptic@^6.0.0, elliptic@^6.2.3, elliptic@^6.4.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df" + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + hmac-drbg "^1.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.0" + +emojis-list@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + +encoding@^0.1.11: + version "0.1.12" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + dependencies: + iconv-lite "~0.4.13" + +end-of-stream@^1.0.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" + dependencies: + once "^1.4.0" + +enhanced-resolve@^3.3.0: + version "3.4.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz#0421e339fd71419b3da13d129b3979040230476e" + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.4.0" + object-assign "^4.0.1" + tapable "^0.2.7" + +enhanced-resolve@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.0.0.tgz#e34a6eaa790f62fccd71d93959f56b2b432db10a" + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.4.0" + tapable "^1.0.0" + +envinfo@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-4.4.2.tgz#472c49f3a8b9bca73962641ce7cb692bf623cd1c" + +errno@^0.1.3, errno@~0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" + dependencies: + prr "~1.0.1" + +error-ex@^1.2.0, error-ex@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" + dependencies: + is-arrayish "^0.2.1" + +error@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02" + dependencies: + string-template "~0.2.1" + xtend "~4.0.0" + +es-abstract@^1.5.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.11.0.tgz#cce87d518f0496893b1a30cd8461835535480681" + dependencies: + es-to-primitive "^1.1.1" + function-bind "^1.1.1" + has "^1.0.1" + is-callable "^1.1.3" + is-regex "^1.0.4" + +es-abstract@^1.5.1: + version "1.12.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165" + dependencies: + es-to-primitive "^1.1.1" + function-bind "^1.1.1" + has "^1.0.1" + is-callable "^1.1.3" + is-regex "^1.0.4" + +es-to-primitive@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" + dependencies: + is-callable "^1.1.1" + is-date-object "^1.0.1" + is-symbol "^1.0.1" + +es6-object-assign@^1.0.3: + version "1.1.0" + resolved "https://registry.yarnpkg.com/es6-object-assign/-/es6-object-assign-1.1.0.tgz#c2c3582656247c39ea107cb1e6652b6f9f24523c" + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + +escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +escodegen@1.8.x: + version "1.8.1" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018" + dependencies: + esprima "^2.7.1" + estraverse "^1.9.1" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.2.0" + +escodegen@^1.9.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.10.0.tgz#f647395de22519fbd0d928ffcf1d17e0dec2603e" + dependencies: + esprima "^3.1.3" + estraverse "^4.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + +eslint-config-airbnb-base@^12.1.0: + version "12.1.0" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-12.1.0.tgz#386441e54a12ccd957b0a92564a4bafebd747944" + dependencies: + eslint-restricted-globals "^0.1.1" + +eslint-config-prettier@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-2.9.0.tgz#5ecd65174d486c22dff389fe036febf502d468a3" + dependencies: + get-stdin "^5.0.1" + +eslint-import-resolver-jest@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-jest/-/eslint-import-resolver-jest-2.1.1.tgz#78c1934e3b5b77283326f036e089cc3b9fae6346" + dependencies: + find-root "^1.0.0" + micromatch "^3.1.6" + resolve "^1.5.0" + +eslint-import-resolver-node@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz#58f15fb839b8d0576ca980413476aab2472db66a" + dependencies: + debug "^2.6.9" + resolve "^1.5.0" + +eslint-module-utils@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.2.0.tgz#b270362cd88b1a48ad308976ce7fa54e98411746" + dependencies: + debug "^2.6.8" + pkg-dir "^1.0.0" + +eslint-plugin-flowtype@^2.46.3: + version "2.46.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.46.3.tgz#7e84131d87ef18b496b1810448593374860b4e8e" + dependencies: + lodash "^4.15.0" + +eslint-plugin-import@^2.11.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.11.0.tgz#15aeea37a67499d848e8e981806d4627b5503816" + dependencies: + contains-path "^0.1.0" + debug "^2.6.8" + doctrine "1.5.0" + eslint-import-resolver-node "^0.3.1" + eslint-module-utils "^2.2.0" + has "^1.0.1" + lodash "^4.17.4" + minimatch "^3.0.3" + read-pkg-up "^2.0.0" + resolve "^1.6.0" + +eslint-plugin-prettier@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-2.6.0.tgz#33e4e228bdb06142d03c560ce04ec23f6c767dd7" + dependencies: + fast-diff "^1.1.1" + jest-docblock "^21.0.0" + +eslint-restricted-globals@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz#35f0d5cbc64c2e3ed62e93b4b1a7af05ba7ed4d7" + +eslint-scope@^3.7.1, eslint-scope@~3.7.1: + version "3.7.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-visitor-keys@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" + +eslint@^4.19.1: + version "4.19.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.19.1.tgz#32d1d653e1d90408854bfb296f076ec7e186a300" + dependencies: + ajv "^5.3.0" + babel-code-frame "^6.22.0" + chalk "^2.1.0" + concat-stream "^1.6.0" + cross-spawn "^5.1.0" + debug "^3.1.0" + doctrine "^2.1.0" + eslint-scope "^3.7.1" + eslint-visitor-keys "^1.0.0" + espree "^3.5.4" + esquery "^1.0.0" + esutils "^2.0.2" + file-entry-cache "^2.0.0" + functional-red-black-tree "^1.0.1" + glob "^7.1.2" + globals "^11.0.1" + ignore "^3.3.3" + imurmurhash "^0.1.4" + inquirer "^3.0.6" + is-resolvable "^1.0.0" + js-yaml "^3.9.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.3.0" + lodash "^4.17.4" + minimatch "^3.0.2" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.2" + path-is-inside "^1.0.2" + pluralize "^7.0.0" + progress "^2.0.0" + regexpp "^1.0.1" + require-uncached "^1.0.3" + semver "^5.3.0" + strip-ansi "^4.0.0" + strip-json-comments "~2.0.1" + table "4.0.2" + text-table "~0.2.0" + +espree@^3.5.4: + version "3.5.4" + resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7" + dependencies: + acorn "^5.5.0" + acorn-jsx "^3.0.0" + +esprima@2.7.x, esprima@^2.7.1: + version "2.7.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" + +esprima@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" + +esprima@^4.0.0, esprima@~4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" + +esquery@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" + dependencies: + estraverse "^4.0.0" + +esrecurse@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" + dependencies: + estraverse "^4.1.0" + +estraverse@^1.9.1: + version "1.9.3" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44" + +estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + +esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + +eth-block-tracker@^2.2.2: + version "2.3.1" + resolved "https://registry.yarnpkg.com/eth-block-tracker/-/eth-block-tracker-2.3.1.tgz#ab6d177e5b50128fa06d7ae9e0489c7484bac95e" + dependencies: + async-eventemitter ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c + eth-query "^2.1.0" + ethereumjs-tx "^1.3.3" + ethereumjs-util "^5.1.3" + ethjs-util "^0.1.3" + json-rpc-engine "^3.6.0" + pify "^2.3.0" + tape "^4.6.3" + +eth-gas-reporter@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/eth-gas-reporter/-/eth-gas-reporter-0.1.2.tgz#504b4f655c0f9f45d6d429a384d16c3cd77b5de9" + dependencies: + abi-decoder "^1.0.8" + cli-table2 "^0.2.0" + colors "^1.1.2" + lodash "^4.17.4" + mocha "^3.5.3" + req-cwd "^2.0.0" + request "^2.83.0" + request-promise-native "^1.0.5" + shelljs "^0.7.8" + sync-request "^6.0.0" + +eth-lib@0.1.27, eth-lib@^0.1.26: + version "0.1.27" + resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.1.27.tgz#f0b0fd144f865d2d6bf8257a40004f2e75ca1dd6" + dependencies: + bn.js "^4.11.6" + elliptic "^6.4.0" + keccakjs "^0.2.1" + nano-json-stream-parser "^0.1.2" + servify "^0.1.12" + ws "^3.0.0" + xhr-request-promise "^0.1.2" + +eth-lib@0.2.7: + version "0.2.7" + resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.2.7.tgz#2f93f17b1e23aec3759cd4a3fe20c1286a3fc1ca" + dependencies: + bn.js "^4.11.6" + elliptic "^6.4.0" + xhr-request-promise "^0.1.2" + +eth-query@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/eth-query/-/eth-query-2.1.2.tgz#d6741d9000106b51510c72db92d6365456a6da5e" + dependencies: + json-rpc-random-id "^1.0.0" + xtend "^4.0.1" + +eth-sig-util@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/eth-sig-util/-/eth-sig-util-1.4.2.tgz#8d958202c7edbaae839707fba6f09ff327606210" + dependencies: + ethereumjs-abi "git+https://github.com/ethereumjs/ethereumjs-abi.git" + ethereumjs-util "^5.1.1" + +ethereum-common@0.0.16: + version "0.0.16" + resolved "https://registry.yarnpkg.com/ethereum-common/-/ethereum-common-0.0.16.tgz#9a1e169ead34ab75e089f50ca512bfd0fbd12655" + +ethereum-common@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/ethereum-common/-/ethereum-common-0.2.0.tgz#13bf966131cce1eeade62a1b434249bb4cb120ca" + +ethereum-common@^0.0.18: + version "0.0.18" + resolved "https://registry.yarnpkg.com/ethereum-common/-/ethereum-common-0.0.18.tgz#2fdc3576f232903358976eb39da783213ff9523f" + +"ethereumjs-abi@git+https://github.com/ethereumjs/ethereumjs-abi.git": + version "0.6.5" + resolved "git+https://github.com/ethereumjs/ethereumjs-abi.git#4ea2fdfed09e8f99117d9362d17c6b01b64a2bcf" + dependencies: + bn.js "^4.10.0" + ethereumjs-util "^5.0.0" + +ethereumjs-account@^2.0.3, ethereumjs-account@~2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/ethereumjs-account/-/ethereumjs-account-2.0.4.tgz#f8c30231bcb707f4514d8a052c1f9da103624d47" + dependencies: + ethereumjs-util "^4.0.1" + rlp "^2.0.0" + +ethereumjs-block@^1.2.2, ethereumjs-block@~1.7.0: + version "1.7.1" + resolved "https://registry.yarnpkg.com/ethereumjs-block/-/ethereumjs-block-1.7.1.tgz#78b88e6cc56de29a6b4884ee75379b6860333c3f" + dependencies: + async "^2.0.1" + ethereum-common "0.2.0" + ethereumjs-tx "^1.2.2" + ethereumjs-util "^5.0.0" + merkle-patricia-tree "^2.1.2" + +ethereumjs-block@~1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/ethereumjs-block/-/ethereumjs-block-1.2.2.tgz#2ec7534a59021b8ec9b83c30e49690c6ebaedda1" + dependencies: + async "^1.5.2" + ethereum-common "0.0.16" + ethereumjs-tx "^1.0.0" + ethereumjs-util "^4.0.1" + merkle-patricia-tree "^2.1.2" + +ethereumjs-testrpc-sc@6.1.2: + version "6.1.2" + resolved "https://registry.yarnpkg.com/ethereumjs-testrpc-sc/-/ethereumjs-testrpc-sc-6.1.2.tgz#bd1d8306abb2d51481f3f01538fa71fb7fd44a4d" + dependencies: + source-map-support "^0.5.3" + webpack-cli "^2.0.9" + +ethereumjs-tx@^1.0.0, ethereumjs-tx@^1.2.0, ethereumjs-tx@^1.2.2, ethereumjs-tx@^1.3.0, ethereumjs-tx@^1.3.3: + version "1.3.4" + resolved "https://registry.yarnpkg.com/ethereumjs-tx/-/ethereumjs-tx-1.3.4.tgz#c2304912f6c07af03237ad8675ac036e290dad48" + dependencies: + ethereum-common "^0.0.18" + ethereumjs-util "^5.0.0" + +ethereumjs-util@^4.0.1, ethereumjs-util@^4.4.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-4.5.0.tgz#3e9428b317eebda3d7260d854fddda954b1f1bc6" + dependencies: + bn.js "^4.8.0" + create-hash "^1.1.2" + keccakjs "^0.2.0" + rlp "^2.0.0" + secp256k1 "^3.0.1" + +ethereumjs-util@^5.0.0, ethereumjs-util@^5.1.1, ethereumjs-util@^5.1.3, ethereumjs-util@^5.1.5, ethereumjs-util@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz#3e0c0d1741471acf1036052d048623dee54ad642" + dependencies: + bn.js "^4.11.0" + create-hash "^1.1.2" + ethjs-util "^0.1.3" + keccak "^1.0.2" + rlp "^2.0.0" + safe-buffer "^5.1.1" + secp256k1 "^3.0.1" + +ethereumjs-vm@2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/ethereumjs-vm/-/ethereumjs-vm-2.3.3.tgz#05719139e0c4a59e829022964a6048b17d2d84b0" + dependencies: + async "^2.1.2" + async-eventemitter "^0.2.2" + ethereum-common "0.2.0" + ethereumjs-account "^2.0.3" + ethereumjs-block "~1.7.0" + ethereumjs-util "^5.1.3" + fake-merkle-patricia-tree "^1.0.1" + functional-red-black-tree "^1.0.1" + merkle-patricia-tree "^2.1.2" + rustbn.js "~0.1.1" + safe-buffer "^5.1.1" + +ethereumjs-vm@^2.0.2: + version "2.3.5" + resolved "https://registry.yarnpkg.com/ethereumjs-vm/-/ethereumjs-vm-2.3.5.tgz#e69306737b8a7ea80c633ceb9b7dd561897007de" + dependencies: + async "^2.1.2" + async-eventemitter "^0.2.2" + ethereum-common "0.2.0" + ethereumjs-account "^2.0.3" + ethereumjs-block "~1.7.0" + ethereumjs-util "^5.1.3" + fake-merkle-patricia-tree "^1.0.1" + functional-red-black-tree "^1.0.1" + merkle-patricia-tree "^2.1.2" + rustbn.js "~0.1.1" + safe-buffer "^5.1.1" + +ethereumjs-wallet@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/ethereumjs-wallet/-/ethereumjs-wallet-0.6.0.tgz#82763b1697ee7a796be7155da9dfb49b2f98cfdb" + dependencies: + aes-js "^0.2.3" + bs58check "^1.0.8" + ethereumjs-util "^4.4.0" + hdkey "^0.7.0" + scrypt.js "^0.2.0" + utf8 "^2.1.1" + uuid "^2.0.1" + +ethers@^3.0.15: + version "3.0.15" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-3.0.15.tgz#7cdea4e23025681f69f575bf481b227315e0e7ab" + dependencies: + aes-js "3.0.0" + bn.js "^4.4.0" + elliptic "6.3.3" + hash.js "^1.0.0" + inherits "2.0.1" + js-sha3 "0.5.7" + scrypt-js "2.0.3" + setimmediate "1.0.4" + uuid "2.0.1" + xmlhttprequest "1.8.0" + +ethjs-unit@0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" + dependencies: + bn.js "4.11.6" + number-to-bn "1.7.0" + +ethjs-util@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/ethjs-util/-/ethjs-util-0.1.4.tgz#1c8b6879257444ef4d3f3fbbac2ded12cd997d93" + dependencies: + is-hex-prefixed "1.0.0" + strip-hex-prefix "1.0.0" + +eventemitter3@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.1.1.tgz#47786bdaa087caf7b1b75e73abc5c7d540158cd0" + +events@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +exec-sh@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.1.tgz#163b98a6e89e6b65b47c2a28d215bc1f63989c38" + dependencies: + merge "^1.1.3" + +execa@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +exit-hook@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + +expand-brackets@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + dependencies: + is-posix-bracket "^0.1.0" + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + dependencies: + fill-range "^2.1.0" + +expand-tilde@^2.0.0, expand-tilde@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" + dependencies: + homedir-polyfill "^1.0.1" + +expect@^23.1.0: + version "23.1.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-23.1.0.tgz#bfdfd57a2a20170d875999ee9787cc71f01c205f" + dependencies: + ansi-styles "^3.2.0" + jest-diff "^23.0.1" + jest-get-type "^22.1.0" + jest-matcher-utils "^23.0.1" + jest-message-util "^23.1.0" + jest-regex-util "^23.0.0" + +express@^4.14.0, express@^4.16.3: + version "4.16.3" + resolved "https://registry.yarnpkg.com/express/-/express-4.16.3.tgz#6af8a502350db3246ecc4becf6b5a34d22f7ed53" + dependencies: + accepts "~1.3.5" + array-flatten "1.1.1" + body-parser "1.18.2" + content-disposition "0.5.2" + content-type "~1.0.4" + cookie "0.3.1" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.1.1" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.2" + path-to-regexp "0.1.7" + proxy-addr "~2.0.3" + qs "6.5.1" + range-parser "~1.2.0" + safe-buffer "5.1.1" + send "0.16.2" + serve-static "1.13.2" + setprototypeof "1.1.0" + statuses "~1.4.0" + type-is "~1.6.16" + utils-merge "1.0.1" + vary "~1.1.2" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend@~3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" + +external-editor@^2.0.4, external-editor@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" + dependencies: + chardet "^0.4.0" + iconv-lite "^0.4.17" + tmp "^0.0.33" + +extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + dependencies: + is-extglob "^1.0.0" + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + +fake-merkle-patricia-tree@^1.0.1, fake-merkle-patricia-tree@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/fake-merkle-patricia-tree/-/fake-merkle-patricia-tree-1.0.1.tgz#4b8c3acfb520afadf9860b1f14cd8ce3402cddd3" + dependencies: + checkpoint-store "^1.1.0" + +fast-deep-equal@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" + +fast-diff@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.1.2.tgz#4b62c42b8e03de3f848460b639079920695d0154" + +fast-glob@^2.0.2: + version "2.2.1" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.1.tgz#686c2345be88f3741e174add0be6f2e5b6078889" + dependencies: + "@mrmlnc/readdir-enhanced" "^2.2.1" + glob-parent "^3.1.0" + is-glob "^4.0.0" + merge2 "^1.2.1" + micromatch "^3.1.10" + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + +fast-levenshtein@~2.0.4: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + +fb-watchman@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58" + dependencies: + bser "^2.0.0" + +fd-slicer@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" + dependencies: + pend "~1.2.0" + +fetch-ponyfill@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/fetch-ponyfill/-/fetch-ponyfill-4.1.0.tgz#ae3ce5f732c645eab87e4ae8793414709b239893" + dependencies: + node-fetch "~1.7.1" + +figures@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" + dependencies: + escape-string-regexp "^1.0.5" + object-assign "^4.1.0" + +figures@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + dependencies: + escape-string-regexp "^1.0.5" + +file-entry-cache@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" + dependencies: + flat-cache "^1.2.1" + object-assign "^4.0.1" + +file-type@^3.8.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9" + +file-type@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-5.2.0.tgz#2ddbea7c73ffe36368dfae49dc338c058c2b8ad6" + +file-type@^6.1.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-6.2.0.tgz#e50cd75d356ffed4e306dc4f5bcf52a79903a919" + +filename-regex@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" + +fileset@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/fileset/-/fileset-2.0.3.tgz#8e7548a96d3cc2327ee5e674168723a333bba2a0" + dependencies: + glob "^7.0.3" + minimatch "^3.0.3" + +fill-range@^2.1.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^1.1.3" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +finalhandler@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.2" + statuses "~1.4.0" + unpipe "~1.0.0" + +find-cache-dir@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-0.1.1.tgz#c8defae57c8a52a8a784f9e31c57c742e993a0b9" + dependencies: + commondir "^1.0.1" + mkdirp "^0.5.1" + pkg-dir "^1.0.0" + +find-root@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" + +find-up@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + dependencies: + path-exists "^2.0.0" + pinkie-promise "^2.0.0" + +find-up@^2.0.0, find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + dependencies: + locate-path "^2.0.0" + +first-chunk-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-2.0.0.tgz#1bdecdb8e083c0664b91945581577a43a9f31d70" + dependencies: + readable-stream "^2.0.2" + +flat-cache@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.0.tgz#d3030b32b38154f4e3b7e9c709f490f7ef97c481" + dependencies: + circular-json "^0.3.1" + del "^2.0.2" + graceful-fs "^4.1.2" + write "^0.2.1" + +flow-parser@^0.*: + version "0.71.0" + resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.71.0.tgz#da2479b83f9207905b4b17ab0c4e6d17bd505250" + +for-each@^0.3.2, for-each@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.2.tgz#2c40450b9348e97f281322593ba96704b9abd4d4" + dependencies: + is-function "~1.0.0" + +for-in@^1.0.1, for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + +for-own@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" + dependencies: + for-in "^1.0.1" + +foreach@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + +form-data@^2.2.0, form-data@~2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099" + dependencies: + asynckit "^0.4.0" + combined-stream "1.0.6" + mime-types "^2.1.12" + +forwarded@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + dependencies: + map-cache "^0.2.2" + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + +from2@^2.1.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.0" + +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + +fs-extra@^0.30.0: + version "0.30.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + klaw "^1.0.0" + path-is-absolute "^1.0.0" + rimraf "^2.2.8" + +fs-extra@^2.0.0, fs-extra@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-2.1.2.tgz#046c70163cef9aad46b0e4a7fa467fb22d71de35" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + +fs-minipass@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" + dependencies: + minipass "^2.2.1" + +fs-promise@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/fs-promise/-/fs-promise-2.0.3.tgz#f64e4f854bcf689aa8bddcba268916db3db46854" + dependencies: + any-promise "^1.3.0" + fs-extra "^2.0.0" + mz "^2.6.0" + thenify-all "^1.6.0" + +fs-readdir-recursive@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +fsevents@^1.0.0, fsevents@^1.1.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.3.tgz#08292982e7059f6674c93d8b829c1e8604979ac0" + dependencies: + nan "^2.9.2" + node-pre-gyp "^0.9.0" + +fsevents@^1.2.3: + version "1.2.4" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" + dependencies: + nan "^2.9.2" + node-pre-gyp "^0.10.0" + +fstream@^1.0.2, fstream@^1.0.8: + version "1.0.11" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +function-bind@^1.0.2, function-bind@^1.1.1, function-bind@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + +ganache-cli@6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/ganache-cli/-/ganache-cli-6.1.0.tgz#486c846497204b644166b5f0f74c9b41d02bdc25" + dependencies: + source-map-support "^0.5.3" + webpack-cli "^2.0.9" + +ganache-core@^2.0.2, ganache-core@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ganache-core/-/ganache-core-2.1.0.tgz#afe4ac8d5a2b5ed3622dd82d530acced78d5fb94" + dependencies: + abstract-leveldown "^3.0.0" + async "^2.5.0" + bip39 "~2.4.0" + bn.js "4.11.6" + cachedown "^1.0.0" + chai "^3.5.0" + clone "^2.1.1" + ethereumjs-account "~2.0.4" + ethereumjs-block "~1.2.2" + ethereumjs-tx "^1.3.0" + ethereumjs-util "^5.1.5" + ethereumjs-vm "2.3.3" + ethereumjs-wallet "~0.6.0" + fake-merkle-patricia-tree "~1.0.1" + heap "~0.2.6" + js-scrypt "^0.2.0" + level-sublevel "^6.6.1" + levelup "^1.1.0" + localstorage-down "^0.6.7" + lodash "^4.17.5" + merkle-patricia-tree "^2.2.0" + mocha "~3.3.0" + pify "^3.0.0" + prepend-file "^1.3.1" + seedrandom "~2.4.2" + shebang-loader "0.0.1" + solc "0.4.18" + temp "^0.8.3" + tmp "0.0.31" + web3 "^1.0.0-beta.30" + web3-provider-engine "^13.6.5" + websocket "^1.0.24" + yargs "^7.0.2" + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +generic-pool@~2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-2.0.4.tgz#f9718deda82fa125ed5c43e341c9a215a766d9a3" + +get-caller-file@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" + +get-func-name@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" + +get-port@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/get-port/-/get-port-3.2.0.tgz#dd7ce7de187c06c8bf353796ac71e099f0980ebc" + +get-stdin@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398" + +get-stream@3.0.0, get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + +get-stream@^2.2.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-2.3.1.tgz#5f38f93f346009666ee0150a054167f91bdd95de" + dependencies: + object-assign "^4.0.1" + pinkie-promise "^2.0.0" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + dependencies: + assert-plus "^1.0.0" + +gh-got@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/gh-got/-/gh-got-6.0.0.tgz#d74353004c6ec466647520a10bd46f7299d268d0" + dependencies: + got "^7.0.0" + is-plain-obj "^1.1.0" + +github-username@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/github-username/-/github-username-4.1.0.tgz#cbe280041883206da4212ae9e4b5f169c30bf417" + dependencies: + gh-got "^6.0.0" + +glob-all@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-all/-/glob-all-3.1.0.tgz#8913ddfb5ee1ac7812656241b03d5217c64b02ab" + dependencies: + glob "^7.0.5" + yargs "~1.2.6" + +glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + +glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + dependencies: + is-glob "^2.0.0" + +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob-to-regexp@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" + +glob@7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.2" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@7.1.2, glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@~7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^5.0.15: + version "5.0.15" + resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global-modules@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" + dependencies: + global-prefix "^1.0.1" + is-windows "^1.0.1" + resolve-dir "^1.0.0" + +global-prefix@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" + dependencies: + expand-tilde "^2.0.2" + homedir-polyfill "^1.0.1" + ini "^1.3.4" + is-windows "^1.0.1" + which "^1.2.14" + +global@~4.3.0: + version "4.3.2" + resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f" + dependencies: + min-document "^2.19.0" + process "~0.5.1" + +globals@^11.0.1, globals@^11.1.0: + version "11.5.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.5.0.tgz#6bc840de6771173b191f13d3a9c94d441ee92642" + +globals@^9.18.0: + version "9.18.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" + +globby@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" + dependencies: + array-union "^1.0.1" + arrify "^1.0.0" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +globby@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" + dependencies: + array-union "^1.0.1" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +globby@^8.0.0: + version "8.0.1" + resolved "https://registry.yarnpkg.com/globby/-/globby-8.0.1.tgz#b5ad48b8aa80b35b814fc1281ecc851f1d2b5b50" + dependencies: + array-union "^1.0.1" + dir-glob "^2.0.0" + fast-glob "^2.0.2" + glob "^7.1.2" + ignore "^3.3.5" + pify "^3.0.0" + slash "^1.0.0" + +got@7.1.0, got@^7.0.0, got@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/got/-/got-7.1.0.tgz#05450fd84094e6bbea56f451a43a9c289166385a" + dependencies: + decompress-response "^3.2.0" + duplexer3 "^0.1.4" + get-stream "^3.0.0" + is-plain-obj "^1.1.0" + is-retry-allowed "^1.0.0" + is-stream "^1.0.0" + isurl "^1.0.0-alpha5" + lowercase-keys "^1.0.0" + p-cancelable "^0.3.0" + p-timeout "^1.1.1" + safe-buffer "^5.0.1" + timed-out "^4.0.0" + url-parse-lax "^1.0.0" + url-to-options "^1.0.1" + +got@^8.2.0: + version "8.3.1" + resolved "https://registry.yarnpkg.com/got/-/got-8.3.1.tgz#093324403d4d955f5a16a7a8d39955d055ae10ed" + dependencies: + "@sindresorhus/is" "^0.7.0" + cacheable-request "^2.1.1" + decompress-response "^3.3.0" + duplexer3 "^0.1.4" + get-stream "^3.0.0" + into-stream "^3.1.0" + is-retry-allowed "^1.1.0" + isurl "^1.0.0-alpha5" + lowercase-keys "^1.0.0" + mimic-response "^1.0.0" + p-cancelable "^0.4.0" + p-timeout "^2.0.1" + pify "^3.0.0" + safe-buffer "^5.1.1" + timed-out "^4.0.1" + url-parse-lax "^3.0.0" + url-to-options "^1.0.1" + +graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.4, graceful-fs@^4.1.6, graceful-fs@^4.1.9: + version "4.1.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + +"graceful-readlink@>= 1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + +grouped-queue@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/grouped-queue/-/grouped-queue-0.3.3.tgz#c167d2a5319c5a0e0964ef6a25b7c2df8996c85c" + dependencies: + lodash "^4.17.2" + +growl@1.10.3: + version "1.10.3" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.3.tgz#1926ba90cf3edfe2adb4927f5880bc22c66c790f" + +growl@1.10.5: + version "1.10.5" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" + +growl@1.9.2: + version "1.9.2" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f" + +growly@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" + +handlebars@^4.0.1, handlebars@^4.0.3: + version "4.0.11" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc" + dependencies: + async "^1.4.0" + optimist "^0.6.1" + source-map "^0.4.4" + optionalDependencies: + uglify-js "^2.6" + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + +har-validator@~5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" + dependencies: + ajv "^5.1.0" + har-schema "^2.0.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + dependencies: + ansi-regex "^2.0.0" + +has-color@~0.1.0: + version "0.1.7" + resolved "https://registry.yarnpkg.com/has-color/-/has-color-0.1.7.tgz#67144a5260c34fc3cca677d041daf52fe7b78b2f" + +has-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" + +has-flag@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + +has-localstorage@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-localstorage/-/has-localstorage-1.0.1.tgz#fe62406c4767fbd6d784dac6905928108b82971b" + +has-symbol-support-x@^1.4.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" + +has-to-string-tag-x@^1.2.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" + dependencies: + has-symbol-support-x "^1.4.1" + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +has@^1.0.1, has@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" + dependencies: + function-bind "^1.0.2" + +hash-base@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.3.tgz#340dedbe6290187151c1ea1d777a3448935df846" + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.0" + +hawk@~6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-6.0.2.tgz#af4d914eb065f9b5ce4d9d11c1cb2126eecc3038" + dependencies: + boom "4.x.x" + cryptiles "3.x.x" + hoek "4.x.x" + sntp "2.x.x" + +hdkey@^0.7.0: + version "0.7.1" + resolved "https://registry.yarnpkg.com/hdkey/-/hdkey-0.7.1.tgz#caee4be81aa77921e909b8d228dd0f29acaee632" + dependencies: + coinstring "^2.0.0" + secp256k1 "^3.0.1" + +he@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" + +heap@~0.2.6: + version "0.2.6" + resolved "https://registry.yarnpkg.com/heap/-/heap-0.2.6.tgz#087e1f10b046932fc8594dd9e6d378afc9d1e5ac" + +hmac-drbg@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +hoek@4.x.x: + version "4.2.1" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.1.tgz#9634502aa12c445dd5a7c5734b572bb8738aacbb" + +home-or-tmp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.1" + +homedir-polyfill@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" + dependencies: + parse-passwd "^1.0.0" + +hosted-git-info@^2.1.4: + version "2.6.0" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.6.0.tgz#23235b29ab230c576aab0d4f13fc046b0b038222" + +html-encoding-sniffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8" + dependencies: + whatwg-encoding "^1.0.1" + +http-basic@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/http-basic/-/http-basic-7.0.0.tgz#82f0a506be942732ec8deebee80e746ef5736dba" + dependencies: + "@types/concat-stream" "^1.6.0" + "@types/node" "^9.4.1" + caseless "~0.12.0" + concat-stream "^1.4.6" + http-response-object "^3.0.1" + parse-cache-control "^1.0.1" + +http-cache-semantics@3.8.1: + version "3.8.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" + +http-errors@1.6.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" + dependencies: + depd "1.1.1" + inherits "2.0.3" + setprototypeof "1.0.3" + statuses ">= 1.3.1 < 2" + +http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-https@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/http-https/-/http-https-1.0.0.tgz#2f908dd5f1db4068c058cd6e6d4ce392c913389b" + +http-response-object@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/http-response-object/-/http-response-object-3.0.1.tgz#90174d44c27b5e797cf6efe51a043bc889ae64bf" + dependencies: + "@types/node" "^9.3.0" + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + +humble-localstorage@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/humble-localstorage/-/humble-localstorage-1.4.2.tgz#d05ab0d526c4edbddbf7c6a60df6ff5805283469" + dependencies: + has-localstorage "^1.0.1" + localstorage-memory "^1.0.1" + +iconv-lite@0.4.19: + version "0.4.19" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" + +iconv-lite@^0.4.17, iconv-lite@^0.4.4, iconv-lite@~0.4.13: + version "0.4.21" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.21.tgz#c47f8733d02171189ebc4a400f3218d348094798" + dependencies: + safer-buffer "^2.1.0" + +ieee754@^1.1.4: + version "1.1.11" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.11.tgz#c16384ffe00f5b7835824e67b6f2bd44a5229455" + +ignore-walk@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" + dependencies: + minimatch "^3.0.4" + +ignore@^3.3.3, ignore@^3.3.5: + version "3.3.8" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.8.tgz#3f8e9c35d38708a3a7e0e9abb6c73e7ee7707b2b" + +immediate@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.2.3.tgz#d140fa8f614659bd6541233097ddaac25cdd991c" + +import-local@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-1.0.0.tgz#5e4ffdc03f4fe6c009c6729beb29631c2f8227bc" + dependencies: + pkg-dir "^2.0.0" + resolve-cwd "^2.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + +indent-string@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" + dependencies: + repeating "^2.0.0" + +indent-string@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289" + +indexof@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + +ini@^1.3.4, ini@~1.3.0: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + +inquirer@^3.0.6, inquirer@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.0" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^2.0.4" + figures "^2.0.0" + lodash "^4.3.0" + mute-stream "0.0.7" + run-async "^2.2.0" + rx-lite "^4.0.8" + rx-lite-aggregates "^4.0.8" + string-width "^2.1.0" + strip-ansi "^4.0.0" + through "^2.3.6" + +inquirer@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-5.2.0.tgz#db350c2b73daca77ff1243962e9f22f099685726" + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.0" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^2.1.0" + figures "^2.0.0" + lodash "^4.3.0" + mute-stream "0.0.7" + run-async "^2.2.0" + rxjs "^5.5.2" + string-width "^2.1.0" + strip-ansi "^4.0.0" + through "^2.3.6" + +interpret@^1.0.0, interpret@^1.0.4: + version "1.1.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614" + +into-stream@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-3.1.0.tgz#96fb0a936c12babd6ff1752a17d05616abd094c6" + dependencies: + from2 "^2.1.1" + p-is-promise "^1.1.0" + +invariant@^2.2.0, invariant@^2.2.2: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + dependencies: + loose-envify "^1.0.0" + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + +ipaddr.js@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.6.0.tgz#e3fa357b773da619f26e95f049d055c72796f86b" + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + dependencies: + kind-of "^6.0.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.1.5, is-buffer@~1.1.1: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + +is-builtin-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + dependencies: + builtin-modules "^1.0.0" + +is-callable@^1.1.1, is-callable@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.3.tgz#86eb75392805ddc33af71c92a0eedf74ee7604b2" + +is-ci@^1.0.10: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.1.0.tgz#247e4162e7860cebbdaf30b774d6b0ac7dcfe7a5" + dependencies: + ci-info "^1.0.0" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + dependencies: + kind-of "^6.0.0" + +is-date-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-dotfile@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" + +is-equal-shallow@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + dependencies: + is-primitive "^2.0.0" + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + +is-extglob@^2.1.0, is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + +is-finite@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + dependencies: + number-is-nan "^1.0.0" + +is-fn@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fn/-/is-fn-1.0.0.tgz#9543d5de7bcf5b08a22ec8a20bae6e286d510d8c" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + +is-function@^1.0.1, is-function@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5" + +is-generator-fn@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-1.0.0.tgz#969d49e1bb3329f6bb7f09089be26578b2ddd46a" + +is-glob@^2.0.0, is-glob@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + dependencies: + is-extglob "^1.0.0" + +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + dependencies: + is-extglob "^2.1.0" + +is-glob@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0" + dependencies: + is-extglob "^2.1.1" + +is-hex-prefixed@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz#7d8d37e6ad77e5d127148913c573e082d777f554" + +is-natural-number@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-natural-number/-/is-natural-number-4.0.1.tgz#ab9d76e1db4ced51e35de0c72ebecf09f734cde8" + +is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + dependencies: + kind-of "^3.0.2" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + dependencies: + kind-of "^3.0.2" + +is-number@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" + +is-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" + +is-observable@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/is-observable/-/is-observable-0.2.0.tgz#b361311d83c6e5d726cabf5e250b0237106f5ae2" + dependencies: + symbol-observable "^0.2.2" + +is-odd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-odd/-/is-odd-2.0.0.tgz#7646624671fd7ea558ccd9a2795182f2958f1b24" + dependencies: + is-number "^4.0.0" + +is-path-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + +is-path-in-cwd@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz#5ac48b345ef675339bd6c7a48a912110b241cf52" + dependencies: + is-path-inside "^1.0.0" + +is-path-inside@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" + dependencies: + path-is-inside "^1.0.1" + +is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + +is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + dependencies: + isobject "^3.0.1" + +is-posix-bracket@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + +is-primitive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + +is-promise@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" + +is-regex@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" + dependencies: + has "^1.0.1" + +is-resolvable@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" + +is-retry-allowed@^1.0.0, is-retry-allowed@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" + +is-scoped@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-scoped/-/is-scoped-1.0.0.tgz#449ca98299e713038256289ecb2b540dc437cb30" + dependencies: + scoped-regex "^1.0.0" + +is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + +is-symbol@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" + +is-typedarray@^1.0.0, is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + +is-windows@^1.0.1, is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +isbinaryfile@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.2.tgz#4a3e974ec0cba9004d3fc6cde7209ea69368a621" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + +istanbul-api@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-1.3.1.tgz#4c3b05d18c0016d1022e079b98dc82c40f488954" + dependencies: + async "^2.1.4" + compare-versions "^3.1.0" + fileset "^2.0.2" + istanbul-lib-coverage "^1.2.0" + istanbul-lib-hook "^1.2.0" + istanbul-lib-instrument "^1.10.1" + istanbul-lib-report "^1.1.4" + istanbul-lib-source-maps "^1.2.4" + istanbul-reports "^1.3.0" + js-yaml "^3.7.0" + mkdirp "^0.5.1" + once "^1.4.0" + +istanbul-lib-coverage@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.0.tgz#f7d8f2e42b97e37fe796114cb0f9d68b5e3a4341" + +istanbul-lib-hook@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.2.1.tgz#f614ec45287b2a8fc4f07f5660af787575601805" + dependencies: + append-transform "^1.0.0" + +istanbul-lib-instrument@^1.10.1: + version "1.10.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.1.tgz#724b4b6caceba8692d3f1f9d0727e279c401af7b" + dependencies: + babel-generator "^6.18.0" + babel-template "^6.16.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + babylon "^6.18.0" + istanbul-lib-coverage "^1.2.0" + semver "^5.3.0" + +istanbul-lib-report@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.1.4.tgz#e886cdf505c4ebbd8e099e4396a90d0a28e2acb5" + dependencies: + istanbul-lib-coverage "^1.2.0" + mkdirp "^0.5.1" + path-parse "^1.0.5" + supports-color "^3.1.2" + +istanbul-lib-source-maps@^1.2.4: + version "1.2.5" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.5.tgz#ffe6be4e7ab86d3603e4290d54990b14506fc9b1" + dependencies: + debug "^3.1.0" + istanbul-lib-coverage "^1.2.0" + mkdirp "^0.5.1" + rimraf "^2.6.1" + source-map "^0.5.3" + +istanbul-reports@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.3.0.tgz#2f322e81e1d9520767597dca3c20a0cce89a3554" + dependencies: + handlebars "^4.0.3" + +istanbul@^0.4.5: + version "0.4.5" + resolved "https://registry.yarnpkg.com/istanbul/-/istanbul-0.4.5.tgz#65c7d73d4c4da84d4f3ac310b918fb0b8033733b" + dependencies: + abbrev "1.0.x" + async "1.x" + escodegen "1.8.x" + esprima "2.7.x" + glob "^5.0.15" + handlebars "^4.0.1" + js-yaml "3.x" + mkdirp "0.5.x" + nopt "3.x" + once "1.x" + resolve "1.1.x" + supports-color "^3.1.0" + which "^1.1.1" + wordwrap "^1.0.0" + +istextorbinary@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-2.2.1.tgz#a5231a08ef6dd22b268d0895084cf8d58b5bec53" + dependencies: + binaryextensions "2" + editions "^1.3.3" + textextensions "2" + +isurl@^1.0.0-alpha5: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" + dependencies: + has-to-string-tag-x "^1.2.0" + is-object "^1.0.1" + +jest-changed-files@^23.0.1: + version "23.0.1" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-23.0.1.tgz#f79572d0720844ea5df84c2a448e862c2254f60c" + dependencies: + throat "^4.0.0" + +jest-cli@^23.1.0: + version "23.1.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-23.1.0.tgz#eb8bdd4ce0d15250892e31ad9b69bc99d2a8f6bf" + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.1" + exit "^0.1.2" + glob "^7.1.2" + graceful-fs "^4.1.11" + import-local "^1.0.0" + is-ci "^1.0.10" + istanbul-api "^1.3.1" + istanbul-lib-coverage "^1.2.0" + istanbul-lib-instrument "^1.10.1" + istanbul-lib-source-maps "^1.2.4" + jest-changed-files "^23.0.1" + jest-config "^23.1.0" + jest-environment-jsdom "^23.1.0" + jest-get-type "^22.1.0" + jest-haste-map "^23.1.0" + jest-message-util "^23.1.0" + jest-regex-util "^23.0.0" + jest-resolve-dependencies "^23.0.1" + jest-runner "^23.1.0" + jest-runtime "^23.1.0" + jest-snapshot "^23.0.1" + jest-util "^23.1.0" + jest-validate "^23.0.1" + jest-watcher "^23.1.0" + jest-worker "^23.0.1" + micromatch "^2.3.11" + node-notifier "^5.2.1" + realpath-native "^1.0.0" + rimraf "^2.5.4" + slash "^1.0.0" + string-length "^2.0.0" + strip-ansi "^4.0.0" + which "^1.2.12" + yargs "^11.0.0" + +jest-config@^23.1.0: + version "23.1.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-23.1.0.tgz#708ca0f431d356ee424fb4895d3308006bdd8241" + dependencies: + babel-core "^6.0.0" + babel-jest "^23.0.1" + chalk "^2.0.1" + glob "^7.1.1" + jest-environment-jsdom "^23.1.0" + jest-environment-node "^23.1.0" + jest-get-type "^22.1.0" + jest-jasmine2 "^23.1.0" + jest-regex-util "^23.0.0" + jest-resolve "^23.1.0" + jest-util "^23.1.0" + jest-validate "^23.0.1" + pretty-format "^23.0.1" + +jest-diff@^23.0.1: + version "23.0.1" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-23.0.1.tgz#3d49137cee12c320a4b4d2b4a6fa6e82d491a16a" + dependencies: + chalk "^2.0.1" + diff "^3.2.0" + jest-get-type "^22.1.0" + pretty-format "^23.0.1" + +jest-docblock@^21.0.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-21.2.0.tgz#51529c3b30d5fd159da60c27ceedc195faf8d414" + +jest-docblock@^23.0.1: + version "23.0.1" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-23.0.1.tgz#deddd18333be5dc2415260a04ef3fce9276b5725" + dependencies: + detect-newline "^2.1.0" + +jest-each@^23.1.0: + version "23.1.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-23.1.0.tgz#16146b592c354867a5ae5e13cdf15c6c65b696c6" + dependencies: + chalk "^2.0.1" + pretty-format "^23.0.1" + +jest-environment-jsdom@^23.1.0: + version "23.1.0" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-23.1.0.tgz#85929914e23bed3577dac9755f4106d0697c479c" + dependencies: + jest-mock "^23.1.0" + jest-util "^23.1.0" + jsdom "^11.5.1" + +jest-environment-node@^23.1.0: + version "23.1.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-23.1.0.tgz#452c0bf949cfcbbacda1e1762eeed70bc784c7d5" + dependencies: + jest-mock "^23.1.0" + jest-util "^23.1.0" + +jest-get-type@^22.1.0: + version "22.4.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-22.4.3.tgz#e3a8504d8479342dd4420236b322869f18900ce4" + +jest-haste-map@^23.1.0: + version "23.1.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-23.1.0.tgz#18e6c7d5a8d27136f91b7d9852f85de0c7074c49" + dependencies: + fb-watchman "^2.0.0" + graceful-fs "^4.1.11" + jest-docblock "^23.0.1" + jest-serializer "^23.0.1" + jest-worker "^23.0.1" + micromatch "^2.3.11" + sane "^2.0.0" + +jest-jasmine2@^23.1.0: + version "23.1.0" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-23.1.0.tgz#4afab31729b654ddcd2b074add849396f13b30b8" + dependencies: + chalk "^2.0.1" + co "^4.6.0" + expect "^23.1.0" + is-generator-fn "^1.0.0" + jest-diff "^23.0.1" + jest-each "^23.1.0" + jest-matcher-utils "^23.0.1" + jest-message-util "^23.1.0" + jest-snapshot "^23.0.1" + jest-util "^23.1.0" + pretty-format "^23.0.1" + +jest-leak-detector@^23.0.1: + version "23.0.1" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-23.0.1.tgz#9dba07505ac3495c39d3ec09ac1e564599e861a0" + dependencies: + pretty-format "^23.0.1" + +jest-matcher-utils@^23.0.1: + version "23.0.1" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-23.0.1.tgz#0c6c0daedf9833c2a7f36236069efecb4c3f6e5f" + dependencies: + chalk "^2.0.1" + jest-get-type "^22.1.0" + pretty-format "^23.0.1" + +jest-message-util@^23.1.0: + version "23.1.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-23.1.0.tgz#9a809ba487ecac5ce511d4e698ee3b5ee2461ea9" + dependencies: + "@babel/code-frame" "^7.0.0-beta.35" + chalk "^2.0.1" + micromatch "^2.3.11" + slash "^1.0.0" + stack-utils "^1.0.1" + +jest-mock@^23.1.0: + version "23.1.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-23.1.0.tgz#a381c31b121ab1f60c462a2dadb7b86dcccac487" + +jest-regex-util@^23.0.0: + version "23.0.0" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-23.0.0.tgz#dd5c1fde0c46f4371314cf10f7a751a23f4e8f76" + +jest-resolve-dependencies@^23.0.1: + version "23.0.1" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-23.0.1.tgz#d01a10ddad9152c4cecdf5eac2b88571c4b6a64d" + dependencies: + jest-regex-util "^23.0.0" + jest-snapshot "^23.0.1" + +jest-resolve@^23.1.0: + version "23.1.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-23.1.0.tgz#b9e316eecebd6f00bc50a3960d1527bae65792d2" + dependencies: + browser-resolve "^1.11.2" + chalk "^2.0.1" + realpath-native "^1.0.0" + +jest-runner@^23.1.0: + version "23.1.0" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-23.1.0.tgz#fa20a933fff731a5432b3561e7f6426594fa29b5" + dependencies: + exit "^0.1.2" + graceful-fs "^4.1.11" + jest-config "^23.1.0" + jest-docblock "^23.0.1" + jest-haste-map "^23.1.0" + jest-jasmine2 "^23.1.0" + jest-leak-detector "^23.0.1" + jest-message-util "^23.1.0" + jest-runtime "^23.1.0" + jest-util "^23.1.0" + jest-worker "^23.0.1" + source-map-support "^0.5.6" + throat "^4.0.0" + +jest-runtime@^23.1.0: + version "23.1.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-23.1.0.tgz#b4ae0e87259ecacfd4a884b639db07cf4dd620af" + dependencies: + babel-core "^6.0.0" + babel-plugin-istanbul "^4.1.6" + chalk "^2.0.1" + convert-source-map "^1.4.0" + exit "^0.1.2" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.1.11" + jest-config "^23.1.0" + jest-haste-map "^23.1.0" + jest-message-util "^23.1.0" + jest-regex-util "^23.0.0" + jest-resolve "^23.1.0" + jest-snapshot "^23.0.1" + jest-util "^23.1.0" + jest-validate "^23.0.1" + micromatch "^2.3.11" + realpath-native "^1.0.0" + slash "^1.0.0" + strip-bom "3.0.0" + write-file-atomic "^2.1.0" + yargs "^11.0.0" + +jest-serializer@^23.0.1: + version "23.0.1" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-23.0.1.tgz#a3776aeb311e90fe83fab9e533e85102bd164165" + +jest-snapshot@^23.0.1: + version "23.0.1" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-23.0.1.tgz#6674fa19b9eb69a99cabecd415bddc42d6af3e7e" + dependencies: + chalk "^2.0.1" + jest-diff "^23.0.1" + jest-matcher-utils "^23.0.1" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + pretty-format "^23.0.1" + +jest-util@^23.1.0: + version "23.1.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-23.1.0.tgz#c0251baf34644c6dd2fea78a962f4263ac55772d" + dependencies: + callsites "^2.0.0" + chalk "^2.0.1" + graceful-fs "^4.1.11" + is-ci "^1.0.10" + jest-message-util "^23.1.0" + mkdirp "^0.5.1" + slash "^1.0.0" + source-map "^0.6.0" + +jest-validate@^23.0.1: + version "23.0.1" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-23.0.1.tgz#cd9f01a89d26bb885f12a8667715e9c865a5754f" + dependencies: + chalk "^2.0.1" + jest-get-type "^22.1.0" + leven "^2.1.0" + pretty-format "^23.0.1" + +jest-watcher@^23.1.0: + version "23.1.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-23.1.0.tgz#a8d5842e38d9fb4afff823df6abb42a58ae6cdbd" + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.1" + string-length "^2.0.0" + +jest-worker@^23.0.1: + version "23.0.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-23.0.1.tgz#9e649dd963ff4046026f91c4017f039a6aa4a7bc" + dependencies: + merge-stream "^1.0.1" + +jest@^23.1.0: + version "23.1.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-23.1.0.tgz#bbb7f893100a11a742dd8bd0d047a54b0968ad1a" + dependencies: + import-local "^1.0.0" + jest-cli "^23.1.0" + +js-scrypt@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/js-scrypt/-/js-scrypt-0.2.0.tgz#7a62b701b4616e70ad0cde544627aabb99d7fe39" + dependencies: + generic-pool "~2.0.4" + +js-sha3@0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7" + +js-sha3@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.3.1.tgz#86122802142f0828502a0d1dee1d95e253bb0243" + +js-string-escape@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" + +js-tokens@^3.0.0, js-tokens@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + +js-yaml@3.x, js-yaml@^3.9.1: + version "3.11.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.11.0.tgz#597c1a8bd57152f26d622ce4117851a51f5ebaef" + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@^3.7.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + +jscodeshift@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/jscodeshift/-/jscodeshift-0.4.1.tgz#da91a1c2eccfa03a3387a21d39948e251ced444a" + dependencies: + async "^1.5.0" + babel-plugin-transform-flow-strip-types "^6.8.0" + babel-preset-es2015 "^6.9.0" + babel-preset-stage-1 "^6.5.0" + babel-register "^6.9.0" + babylon "^6.17.3" + colors "^1.1.2" + flow-parser "^0.*" + lodash "^4.13.1" + micromatch "^2.3.7" + node-dir "0.1.8" + nomnom "^1.8.1" + recast "^0.12.5" + temp "^0.8.1" + write-file-atomic "^1.2.0" + +jscodeshift@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jscodeshift/-/jscodeshift-0.5.0.tgz#bdb7b6cc20dd62c16aa728c3fa2d2fe66ca7c748" + dependencies: + babel-plugin-transform-flow-strip-types "^6.8.0" + babel-preset-es2015 "^6.9.0" + babel-preset-stage-1 "^6.5.0" + babel-register "^6.9.0" + babylon "^7.0.0-beta.30" + colors "^1.1.2" + flow-parser "^0.*" + lodash "^4.13.1" + micromatch "^2.3.7" + neo-async "^2.5.0" + node-dir "0.1.8" + nomnom "^1.8.1" + recast "^0.14.1" + temp "^0.8.1" + write-file-atomic "^1.2.0" + +jsdom@^11.5.1: + version "11.11.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.11.0.tgz#df486efad41aee96c59ad7a190e2449c7eb1110e" + dependencies: + abab "^1.0.4" + acorn "^5.3.0" + acorn-globals "^4.1.0" + array-equal "^1.0.0" + cssom ">= 0.3.2 < 0.4.0" + cssstyle ">= 0.3.1 < 0.4.0" + data-urls "^1.0.0" + domexception "^1.0.0" + escodegen "^1.9.0" + html-encoding-sniffer "^1.0.2" + left-pad "^1.2.0" + nwsapi "^2.0.0" + parse5 "4.0.0" + pn "^1.1.0" + request "^2.83.0" + request-promise-native "^1.0.5" + sax "^1.2.4" + symbol-tree "^3.2.2" + tough-cookie "^2.3.3" + w3c-hr-time "^1.0.1" + webidl-conversions "^4.0.2" + whatwg-encoding "^1.0.3" + whatwg-mimetype "^2.1.0" + whatwg-url "^6.4.1" + ws "^4.0.0" + xml-name-validator "^3.0.0" + +jsesc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + +jsesc@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.1.tgz#e421a2a8e20d6b0819df28908f782526b96dd1fe" + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + +json-buffer@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" + +json-loader@^0.5.4: + version "0.5.7" + resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.7.tgz#dca14a70235ff82f0ac9a3abeb60d337a365185d" + +json-parse-better-errors@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + +json-rpc-engine@^3.6.0: + version "3.6.1" + resolved "https://registry.yarnpkg.com/json-rpc-engine/-/json-rpc-engine-3.6.1.tgz#f53084726dc6dedeead0e2c457eeb997135f1e25" + dependencies: + async "^2.0.1" + babel-preset-env "^1.3.2" + babelify "^7.3.0" + json-rpc-error "^2.0.0" + promise-to-callback "^1.0.0" + +json-rpc-error@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/json-rpc-error/-/json-rpc-error-2.0.0.tgz#a7af9c202838b5e905c7250e547f1aff77258a02" + dependencies: + inherits "^2.0.1" + +json-rpc-random-id@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-rpc-random-id/-/json-rpc-random-id-1.0.1.tgz#ba49d96aded1444dbb8da3d203748acbbcdec8c8" + +json-schema-traverse@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + +json-stable-stringify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + dependencies: + jsonify "~0.0.0" + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + +json3@3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" + +json5@^0.5.0, json5@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + +jsonfile@^2.1.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" + optionalDependencies: + graceful-fs "^4.1.6" + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + optionalDependencies: + graceful-fs "^4.1.6" + +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +keccak@^1.0.2: + version "1.4.0" + resolved "https://registry.yarnpkg.com/keccak/-/keccak-1.4.0.tgz#572f8a6dbee8e7b3aa421550f9e6408ca2186f80" + dependencies: + bindings "^1.2.1" + inherits "^2.0.3" + nan "^2.2.1" + safe-buffer "^5.1.0" + +keccakjs@^0.2.0, keccakjs@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/keccakjs/-/keccakjs-0.2.1.tgz#1d633af907ef305bbf9f2fa616d56c44561dfa4d" + dependencies: + browserify-sha3 "^0.0.1" + sha3 "^1.1.0" + +keyv@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.0.0.tgz#44923ba39e68b12a7cec7df6c3268c031f2ef373" + dependencies: + json-buffer "3.0.0" + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + +klaw@^1.0.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" + optionalDependencies: + graceful-fs "^4.1.9" + +lazy-cache@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" + +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + dependencies: + invert-kv "^1.0.0" + +left-pad@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e" + +level-codec@~7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/level-codec/-/level-codec-7.0.1.tgz#341f22f907ce0f16763f24bddd681e395a0fb8a7" + +level-errors@^1.0.3: + version "1.1.2" + resolved "https://registry.yarnpkg.com/level-errors/-/level-errors-1.1.2.tgz#4399c2f3d3ab87d0625f7e3676e2d807deff404d" + dependencies: + errno "~0.1.1" + +level-errors@~1.0.3: + version "1.0.5" + resolved "https://registry.yarnpkg.com/level-errors/-/level-errors-1.0.5.tgz#83dbfb12f0b8a2516bdc9a31c4876038e227b859" + dependencies: + errno "~0.1.1" + +level-iterator-stream@~1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/level-iterator-stream/-/level-iterator-stream-1.3.1.tgz#e43b78b1a8143e6fa97a4f485eb8ea530352f2ed" + dependencies: + inherits "^2.0.1" + level-errors "^1.0.3" + readable-stream "^1.0.33" + xtend "^4.0.0" + +level-post@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/level-post/-/level-post-1.0.7.tgz#19ccca9441a7cc527879a0635000f06d5e8f27d0" + dependencies: + ltgt "^2.1.2" + +level-sublevel@^6.6.1: + version "6.6.1" + resolved "https://registry.yarnpkg.com/level-sublevel/-/level-sublevel-6.6.1.tgz#f9a77f7521ab70a8f8e92ed56f21a3c7886a4485" + dependencies: + bytewise "~1.1.0" + levelup "~0.19.0" + ltgt "~2.1.1" + pull-level "^2.0.3" + pull-stream "^3.4.5" + typewiselite "~1.0.0" + xtend "~4.0.0" + +level-ws@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/level-ws/-/level-ws-0.0.0.tgz#372e512177924a00424b0b43aef2bb42496d228b" + dependencies: + readable-stream "~1.0.15" + xtend "~2.1.1" + +levelup@^1.1.0, levelup@^1.2.1: + version "1.3.9" + resolved "https://registry.yarnpkg.com/levelup/-/levelup-1.3.9.tgz#2dbcae845b2bb2b6bea84df334c475533bbd82ab" + dependencies: + deferred-leveldown "~1.2.1" + level-codec "~7.0.0" + level-errors "~1.0.3" + level-iterator-stream "~1.3.0" + prr "~1.0.1" + semver "~5.4.1" + xtend "~4.0.0" + +levelup@~0.19.0: + version "0.19.1" + resolved "https://registry.yarnpkg.com/levelup/-/levelup-0.19.1.tgz#f3a6a7205272c4b5f35e412ff004a03a0aedf50b" + dependencies: + bl "~0.8.1" + deferred-leveldown "~0.2.0" + errno "~0.1.1" + prr "~0.0.0" + readable-stream "~1.0.26" + semver "~5.1.0" + xtend "~3.0.0" + +leven@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580" + +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +listr-silent-renderer@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz#924b5a3757153770bf1a8e3fbf74b8bbf3f9242e" + +listr-update-renderer@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/listr-update-renderer/-/listr-update-renderer-0.4.0.tgz#344d980da2ca2e8b145ba305908f32ae3f4cc8a7" + dependencies: + chalk "^1.1.3" + cli-truncate "^0.2.1" + elegant-spinner "^1.0.1" + figures "^1.7.0" + indent-string "^3.0.0" + log-symbols "^1.0.2" + log-update "^1.0.2" + strip-ansi "^3.0.1" + +listr-verbose-renderer@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/listr-verbose-renderer/-/listr-verbose-renderer-0.4.1.tgz#8206f4cf6d52ddc5827e5fd14989e0e965933a35" + dependencies: + chalk "^1.1.3" + cli-cursor "^1.0.2" + date-fns "^1.27.2" + figures "^1.7.0" + +listr@^0.13.0: + version "0.13.0" + resolved "https://registry.yarnpkg.com/listr/-/listr-0.13.0.tgz#20bb0ba30bae660ee84cc0503df4be3d5623887d" + dependencies: + chalk "^1.1.3" + cli-truncate "^0.2.1" + figures "^1.7.0" + indent-string "^2.1.0" + is-observable "^0.2.0" + is-promise "^2.1.0" + is-stream "^1.1.0" + listr-silent-renderer "^1.1.1" + listr-update-renderer "^0.4.0" + listr-verbose-renderer "^0.4.0" + log-symbols "^1.0.2" + log-update "^1.0.2" + ora "^0.2.3" + p-map "^1.1.1" + rxjs "^5.4.2" + stream-to-observable "^0.2.0" + strip-ansi "^3.0.1" + +load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + +load-json-file@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + strip-bom "^3.0.0" + +load-json-file@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" + dependencies: + graceful-fs "^4.1.2" + parse-json "^4.0.0" + pify "^3.0.0" + strip-bom "^3.0.0" + +loader-runner@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2" + +loader-utils@^0.2.16: + version "0.2.17" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348" + dependencies: + big.js "^3.1.3" + emojis-list "^2.0.0" + json5 "^0.5.0" + object-assign "^4.0.1" + +loader-utils@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd" + dependencies: + big.js "^3.1.3" + emojis-list "^2.0.0" + json5 "^0.5.0" + +localstorage-down@^0.6.7: + version "0.6.7" + resolved "https://registry.yarnpkg.com/localstorage-down/-/localstorage-down-0.6.7.tgz#d0799a93b31e6c5fa5188ec06242eb1cce9d6d15" + dependencies: + abstract-leveldown "0.12.3" + argsarray "0.0.1" + buffer-from "^0.1.1" + d64 "^1.0.0" + humble-localstorage "^1.4.2" + inherits "^2.0.1" + tiny-queue "0.2.0" + +localstorage-memory@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/localstorage-memory/-/localstorage-memory-1.0.2.tgz#cd4a8f210e55dd519c929f4b4cc82829b58f9a51" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +lodash._baseassign@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" + dependencies: + lodash._basecopy "^3.0.0" + lodash.keys "^3.0.0" + +lodash._basecopy@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" + +lodash._basecreate@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz#1bc661614daa7fc311b7d03bf16806a0213cf821" + +lodash._getnative@^3.0.0: + version "3.9.1" + resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" + +lodash._isiterateecall@^3.0.0: + version "3.0.9" + resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" + +lodash.assign@^4.0.3, lodash.assign@^4.0.6: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" + +lodash.create@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lodash.create/-/lodash.create-3.1.1.tgz#d7f2849f0dbda7e04682bb8cd72ab022461debe7" + dependencies: + lodash._baseassign "^3.0.0" + lodash._basecreate "^3.0.0" + lodash._isiterateecall "^3.0.0" + +lodash.isarguments@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + +lodash.isarray@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" + +lodash.keys@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" + dependencies: + lodash._getnative "^3.0.0" + lodash.isarguments "^3.0.0" + lodash.isarray "^3.0.0" + +lodash.sortby@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" + +lodash@^3.10.1: + version "3.10.1" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" + +lodash@^4.13.1, lodash@^4.14.0, lodash@^4.14.2, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.3.0: + version "4.17.10" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" + +log-symbols@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18" + dependencies: + chalk "^1.0.0" + +log-symbols@^2.1.0, log-symbols@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" + dependencies: + chalk "^2.0.1" + +log-update@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/log-update/-/log-update-1.0.2.tgz#19929f64c4093d2d2e7075a1dad8af59c296b8d1" + dependencies: + ansi-escapes "^1.0.0" + cli-cursor "^1.0.2" + +longest@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" + +looper@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/looper/-/looper-2.0.0.tgz#66cd0c774af3d4fedac53794f742db56da8f09ec" + +looper@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/looper/-/looper-3.0.0.tgz#2efa54c3b1cbaba9b94aee2e5914b0be57fbb749" + +loose-envify@^1.0.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" + dependencies: + js-tokens "^3.0.0" + +lowercase-keys@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" + +lowercase-keys@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + +lru-cache@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-3.2.0.tgz#71789b3b7f5399bec8565dda38aa30d2a097efee" + dependencies: + pseudomap "^1.0.1" + +lru-cache@^4.0.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.2.tgz#45234b2e6e2f2b33da125624c4664929a0224c3f" + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +ltgt@^2.1.2, ltgt@~2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.2.1.tgz#f35ca91c493f7b73da0e07495304f17b31f87ee5" + +ltgt@~2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.1.3.tgz#10851a06d9964b971178441c23c9e52698eece34" + +make-dir@^1.0.0, make-dir@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.2.0.tgz#6d6a49eead4aae296c53bbf3a1a008bd6c89469b" + dependencies: + pify "^3.0.0" + +makeerror@1.0.x: + version "1.0.11" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + dependencies: + tmpl "1.0.x" + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + dependencies: + object-visit "^1.0.0" + +md5.js@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.4.tgz#e9bdbde94a20a5ac18b04340fc5764d5b09d901d" + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +md5@^2.1.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/md5/-/md5-2.2.1.tgz#53ab38d5fe3c8891ba465329ea23fac0540126f9" + dependencies: + charenc "~0.0.1" + crypt "~0.0.1" + is-buffer "~1.1.1" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + +mem-fs-editor@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/mem-fs-editor/-/mem-fs-editor-4.0.1.tgz#27e6b59df91b37248e9be2145b1bea84695103ed" + dependencies: + commondir "^1.0.1" + deep-extend "^0.5.1" + ejs "^2.5.9" + glob "^7.0.3" + globby "^8.0.0" + isbinaryfile "^3.0.2" + mkdirp "^0.5.0" + multimatch "^2.0.0" + rimraf "^2.2.8" + through2 "^2.0.0" + vinyl "^2.0.1" + +mem-fs@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/mem-fs/-/mem-fs-1.1.3.tgz#b8ae8d2e3fcb6f5d3f9165c12d4551a065d989cc" + dependencies: + through2 "^2.0.0" + vinyl "^1.1.0" + vinyl-file "^2.0.0" + +mem@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" + dependencies: + mimic-fn "^1.0.0" + +memdown@^1.0.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/memdown/-/memdown-1.4.1.tgz#b4e4e192174664ffbae41361aa500f3119efe215" + dependencies: + abstract-leveldown "~2.7.1" + functional-red-black-tree "^1.0.1" + immediate "^3.2.3" + inherits "~2.0.1" + ltgt "~2.2.0" + safe-buffer "~5.1.1" + +memory-fs@^0.4.0, memory-fs@~0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +memorystream@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + +merge-stream@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1" + dependencies: + readable-stream "^2.0.1" + +merge2@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.1.tgz#271d2516ff52d4af7f7b710b8bf3e16e183fef66" + +merge@^1.1.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" + +merkle-patricia-tree@^2.1.2, merkle-patricia-tree@^2.2.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/merkle-patricia-tree/-/merkle-patricia-tree-2.3.1.tgz#7d4e7263a9c85c1679187cad4a6d71f48d524c71" + dependencies: + async "^1.4.2" + ethereumjs-util "^5.0.0" + level-ws "0.0.0" + levelup "^1.2.1" + memdown "^1.0.0" + readable-stream "^2.0.0" + rlp "^2.0.0" + semaphore ">=1.0.1" + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + +micromatch@^2.1.5, micromatch@^2.3.11, micromatch@^2.3.7: + version "2.3.11" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + dependencies: + arr-diff "^2.0.0" + array-unique "^0.2.1" + braces "^1.8.2" + expand-brackets "^0.1.4" + extglob "^0.3.1" + filename-regex "^2.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.1" + kind-of "^3.0.2" + normalize-path "^2.0.1" + object.omit "^2.0.0" + parse-glob "^3.0.4" + regex-cache "^0.4.2" + +micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.6, micromatch@^3.1.8: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +mime-db@~1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" + +mime-types@^2.1.12, mime-types@^2.1.16, mime-types@~2.1.17, mime-types@~2.1.18: + version "2.1.18" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" + dependencies: + mime-db "~1.33.0" + +mime@1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" + +mimic-fn@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + +mimic-response@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.0.tgz#df3d3652a73fded6b9b0b24146e6fd052353458e" + +min-document@^2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" + dependencies: + dom-walk "^0.1.0" + +minimalistic-assert@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + +minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + +"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + +minimist@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.1.0.tgz#99df657a52574c21c9057497df742790b2b4c0de" + +minimist@^1.1.1, minimist@^1.2.0, minimist@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +minimist@~0.0.1: + version "0.0.10" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" + +minipass@^2.2.1, minipass@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.2.4.tgz#03c824d84551ec38a8d1bb5bc350a5a30a354a40" + dependencies: + safe-buffer "^5.1.1" + yallist "^3.0.0" + +minizlib@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb" + dependencies: + minipass "^2.2.1" + +mixin-deep@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp-promise@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz#e9b8f68e552c68a9c1713b84883f7a1dd039b8a1" + dependencies: + mkdirp "*" + +mkdirp@*, mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + +mocha-circleci-reporter@^0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/mocha-circleci-reporter/-/mocha-circleci-reporter-0.0.3.tgz#5303d722cdb0390c2e03632517055c06146df6a0" + dependencies: + mocha "^5.1.1" + mocha-junit-reporter "^1.17.0" + +mocha-junit-reporter@^1.17.0: + version "1.17.0" + resolved "https://registry.yarnpkg.com/mocha-junit-reporter/-/mocha-junit-reporter-1.17.0.tgz#2e5149ed40fc5d2e3ca71e42db5ab1fec9c6d85c" + dependencies: + debug "^2.2.0" + md5 "^2.1.0" + mkdirp "~0.5.1" + strip-ansi "^4.0.0" + xml "^1.0.0" + +mocha@^3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-3.5.3.tgz#1e0480fe36d2da5858d1eb6acc38418b26eaa20d" + dependencies: + browser-stdout "1.3.0" + commander "2.9.0" + debug "2.6.8" + diff "3.2.0" + escape-string-regexp "1.0.5" + glob "7.1.1" + growl "1.9.2" + he "1.1.1" + json3 "3.3.2" + lodash.create "3.1.1" + mkdirp "0.5.1" + supports-color "3.1.2" + +mocha@^4.0.1, mocha@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-4.1.0.tgz#7d86cfbcf35cb829e2754c32e17355ec05338794" + dependencies: + browser-stdout "1.3.0" + commander "2.11.0" + debug "3.1.0" + diff "3.3.1" + escape-string-regexp "1.0.5" + glob "7.1.2" + growl "1.10.3" + he "1.1.1" + mkdirp "0.5.1" + supports-color "4.4.0" + +mocha@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.1.1.tgz#b774c75609dac05eb48f4d9ba1d827b97fde8a7b" + dependencies: + browser-stdout "1.3.1" + commander "2.11.0" + debug "3.1.0" + diff "3.5.0" + escape-string-regexp "1.0.5" + glob "7.1.2" + growl "1.10.3" + he "1.1.1" + minimatch "3.0.4" + mkdirp "0.5.1" + supports-color "4.4.0" + +mocha@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.2.0.tgz#6d8ae508f59167f940f2b5b3c4a612ae50c90ae6" + dependencies: + browser-stdout "1.3.1" + commander "2.15.1" + debug "3.1.0" + diff "3.5.0" + escape-string-regexp "1.0.5" + glob "7.1.2" + growl "1.10.5" + he "1.1.1" + minimatch "3.0.4" + mkdirp "0.5.1" + supports-color "5.4.0" + +mocha@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-3.3.0.tgz#d29b7428d3f52c82e2e65df1ecb7064e1aabbfb5" + dependencies: + browser-stdout "1.3.0" + commander "2.9.0" + debug "2.6.0" + diff "3.2.0" + escape-string-regexp "1.0.5" + glob "7.1.1" + growl "1.9.2" + json3 "3.3.2" + lodash.create "3.1.1" + mkdirp "0.5.1" + supports-color "3.1.2" + +mock-fs@^4.1.0: + version "4.4.2" + resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.4.2.tgz#09dec5313f97095a450be6aa2ad8ab6738d63d6b" + +mout@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/mout/-/mout-0.11.1.tgz#ba3611df5f0e5b1ffbfd01166b8f02d1f5fa2b99" + +ms@0.7.2: + version "0.7.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + +multimatch@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-2.1.0.tgz#9c7906a22fb4c02919e2f5f75161b4cdbd4b2a2b" + dependencies: + array-differ "^1.0.0" + array-union "^1.0.1" + arrify "^1.0.0" + minimatch "^3.0.0" + +mute-stream@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + +mz@^2.6.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + +nan@2.10.0, nan@^2.0.8, nan@^2.2.1, nan@^2.3.3, nan@^2.9.2: + version "2.10.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" + +nano-json-stream-parser@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz#0cc8f6d0e2b622b479c40d499c46d64b755c6f5f" + +nanomatch@^1.2.9: + version "1.2.9" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.9.tgz#879f7150cb2dab7a471259066c104eee6e0fa7c2" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-odd "^2.0.0" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + +needle@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.1.tgz#b5e325bd3aae8c2678902fa296f729455d1d3a7d" + dependencies: + debug "^2.1.2" + iconv-lite "^0.4.4" + sax "^1.2.4" + +negotiator@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + +neo-async@^2.5.0: + version "2.5.1" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.5.1.tgz#acb909e327b1e87ec9ef15f41b8a269512ad41ee" + +nice-try@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4" + +node-dir@0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.8.tgz#55fb8deb699070707fb67f91a460f0448294c77d" + +node-fetch@~1.7.1: + version "1.7.3" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" + dependencies: + encoding "^0.1.11" + is-stream "^1.0.1" + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + +node-libs-browser@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df" + dependencies: + assert "^1.1.1" + browserify-zlib "^0.2.0" + buffer "^4.3.0" + console-browserify "^1.1.0" + constants-browserify "^1.0.0" + crypto-browserify "^3.11.0" + domain-browser "^1.1.1" + events "^1.0.0" + https-browserify "^1.0.0" + os-browserify "^0.3.0" + path-browserify "0.0.0" + process "^0.11.10" + punycode "^1.2.4" + querystring-es3 "^0.2.0" + readable-stream "^2.3.3" + stream-browserify "^2.0.1" + stream-http "^2.7.2" + string_decoder "^1.0.0" + timers-browserify "^2.0.4" + tty-browserify "0.0.0" + url "^0.11.0" + util "^0.10.3" + vm-browserify "0.0.4" + +node-notifier@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.2.1.tgz#fa313dd08f5517db0e2502e5758d664ac69f9dea" + dependencies: + growly "^1.3.0" + semver "^5.4.1" + shellwords "^0.1.1" + which "^1.3.0" + +node-pre-gyp@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.0.tgz#6e4ef5bb5c5203c6552448828c852c40111aac46" + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.0" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.1.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4" + +node-pre-gyp@^0.9.0: + version "0.9.1" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.9.1.tgz#f11c07516dd92f87199dbc7e1838eab7cd56c9e0" + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.0" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.1.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4" + +nomnom@^1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/nomnom/-/nomnom-1.8.1.tgz#2151f722472ba79e50a76fc125bb8c8f2e4dc2a7" + dependencies: + chalk "~0.4.0" + underscore "~1.6.0" + +nopt@3.x: + version "3.0.6" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + dependencies: + abbrev "1" + +nopt@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + dependencies: + abbrev "1" + osenv "^0.1.4" + +normalize-package-data@^2.3.2: + version "2.4.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" + dependencies: + hosted-git-info "^2.1.4" + is-builtin-module "^1.0.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.0.0, normalize-path@^2.0.1, normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + dependencies: + remove-trailing-separator "^1.0.1" + +normalize-url@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-2.0.1.tgz#835a9da1551fa26f70e92329069a23aa6574d7e6" + dependencies: + prepend-http "^2.0.0" + query-string "^5.0.1" + sort-keys "^2.0.0" + +npm-bundled@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.3.tgz#7e71703d973af3370a9591bafe3a63aca0be2308" + +npm-packlist@^1.1.6: + version "1.1.10" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.10.tgz#1039db9e985727e464df066f4cf0ab6ef85c398a" + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + dependencies: + path-key "^2.0.0" + +npmlog@^4.0.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + +number-to-bn@1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/number-to-bn/-/number-to-bn-1.7.0.tgz#bb3623592f7e5f9e0030b1977bd41a0c53fe1ea0" + dependencies: + bn.js "4.11.6" + strip-hex-prefix "1.0.0" + +nwsapi@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.0.3.tgz#3f4010d6c943f34018d3dfb5f2fbc0de90476959" + +oauth-sign@~0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + +object-assign@^4, object-assign@^4.0.0, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-inspect@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.5.0.tgz#9d876c11e40f485c79215670281b767488f9bfe3" + +object-keys@^1.0.8: + version "1.0.11" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" + +object-keys@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336" + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + dependencies: + isobject "^3.0.0" + +object.getownpropertydescriptors@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.5.1" + +object.omit@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + dependencies: + for-own "^0.1.4" + is-extendable "^0.1.1" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + dependencies: + isobject "^3.0.1" + +oboe@2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/oboe/-/oboe-2.1.3.tgz#2b4865dbd46be81225713f4e9bfe4bcf4f680a4f" + dependencies: + http-https "^1.0.0" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + dependencies: + ee-first "1.1.1" + +once@1.x, once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +onetime@^1.0.0: + version "1.1.0" + resolved "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" + +onetime@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + dependencies: + mimic-fn "^1.0.0" + +optimist@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + dependencies: + minimist "~0.0.1" + wordwrap "~0.0.2" + +optionator@^0.8.1, optionator@^0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.4" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + wordwrap "~1.0.0" + +ora@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/ora/-/ora-0.2.3.tgz#37527d220adcd53c39b73571d754156d5db657a4" + dependencies: + chalk "^1.1.1" + cli-cursor "^1.0.2" + cli-spinners "^0.1.2" + object-assign "^4.0.1" + +original-require@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/original-require/-/original-require-1.0.1.tgz#0f130471584cd33511c5ec38c8d59213f9ac5e20" + +os-browserify@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +os-locale@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + dependencies: + lcid "^1.0.0" + +os-locale@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" + dependencies: + execa "^0.7.0" + lcid "^1.0.0" + mem "^1.1.0" + +os-shim@^0.1.2: + version "0.1.3" + resolved "https://registry.yarnpkg.com/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" + +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + +osenv@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +output-file-sync@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76" + dependencies: + graceful-fs "^4.1.4" + mkdirp "^0.5.1" + object-assign "^4.1.0" + +p-cancelable@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa" + +p-cancelable@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.4.1.tgz#35f363d67d52081c8d9585e37bcceb7e0bbcb2a0" + +p-each-series@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-1.0.0.tgz#930f3d12dd1f50e7434457a22cd6f04ac6ad7f71" + dependencies: + p-reduce "^1.0.0" + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + +p-is-promise@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" + +p-lazy@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-lazy/-/p-lazy-1.0.0.tgz#ec53c802f2ee3ac28f166cc82d0b2b02de27a835" + +p-limit@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.2.0.tgz#0e92b6bedcb59f022c13d0f1949dc82d15909f1c" + dependencies: + p-try "^1.0.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + dependencies: + p-limit "^1.1.0" + +p-map@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b" + +p-reduce@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-1.0.0.tgz#18c2b0dd936a4690a529f8231f58a0fdb6a47dfa" + +p-timeout@^1.1.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-1.2.1.tgz#5eb3b353b7fce99f101a1038880bb054ebbea386" + dependencies: + p-finally "^1.0.0" + +p-timeout@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038" + dependencies: + p-finally "^1.0.0" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + +pako@~1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258" + +parse-asn1@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.1.tgz#f6bf293818332bd0dab54efb16087724745e6ca8" + dependencies: + asn1.js "^4.0.0" + browserify-aes "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + +parse-cache-control@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parse-cache-control/-/parse-cache-control-1.0.1.tgz#8eeab3e54fa56920fe16ba38f77fa21aacc2d74e" + +parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + +parse-headers@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.1.tgz#6ae83a7aa25a9d9b700acc28698cd1f1ed7e9536" + dependencies: + for-each "^0.3.2" + trim "0.0.1" + +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + dependencies: + error-ex "^1.2.0" + +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + +parse-passwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" + +parse5@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" + +parseurl@~1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + +path-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" + +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + +path-exists@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + dependencies: + pinkie-promise "^2.0.0" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + +path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +path-is-inside@^1.0.1, path-is-inside@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + +path-parse@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + +path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + dependencies: + graceful-fs "^4.1.2" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +path-type@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" + dependencies: + pify "^2.0.0" + +path-type@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" + dependencies: + pify "^3.0.0" + +pathval@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" + +pbkdf2@^3.0.3, pbkdf2@^3.0.9: + version "3.0.16" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.16.tgz#7404208ec6b01b62d85bf83853a8064f8d9c2a5c" + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +pegjs@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/pegjs/-/pegjs-0.10.0.tgz#cf8bafae6eddff4b5a7efb185269eaaf4610ddbd" + +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + +pify@^2.0.0, pify@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + +pkg-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" + dependencies: + find-up "^1.0.0" + +pkg-dir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" + dependencies: + find-up "^2.1.0" + +pluralize@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" + +pn@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + +pre-commit@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/pre-commit/-/pre-commit-1.2.2.tgz#dbcee0ee9de7235e57f79c56d7ce94641a69eec6" + dependencies: + cross-spawn "^5.0.1" + spawn-sync "^1.0.15" + which "1.2.x" + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + +prepend-file@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/prepend-file/-/prepend-file-1.3.1.tgz#83b16e0b4ac1901fce88dbd945a22f4cc81df579" + dependencies: + tmp "0.0.31" + +prepend-http@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + +prepend-http@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" + +preserve@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + +prettier@^1.12.1, prettier@^1.5.3: + version "1.12.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.12.1.tgz#c1ad20e803e7749faf905a409d2367e06bbe7325" + +pretty-bytes@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-4.0.2.tgz#b2bf82e7350d65c6c33aa95aaa5a4f6327f61cd9" + +pretty-format@^23.0.1: + version "23.0.1" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-23.0.1.tgz#d61d065268e4c759083bccbca27a01ad7c7601f4" + dependencies: + ansi-regex "^3.0.0" + ansi-styles "^3.2.0" + +private@^0.1.6, private@^0.1.8, private@~0.1.5: + version "0.1.8" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" + +process-nextick-args@^2.0.0, process-nextick-args@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + +process@~0.5.1: + version "0.5.2" + resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" + +progress@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" + +promise-to-callback@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/promise-to-callback/-/promise-to-callback-1.0.0.tgz#5d2a749010bfb67d963598fcd3960746a68feef7" + dependencies: + is-fn "^1.0.0" + set-immediate-shim "^1.0.1" + +promise@^8.0.0: + version "8.0.1" + resolved "https://registry.yarnpkg.com/promise/-/promise-8.0.1.tgz#e45d68b00a17647b6da711bf85ed6ed47208f450" + dependencies: + asap "~2.0.3" + +proxy-addr@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.3.tgz#355f262505a621646b3130a728eb647e22055341" + dependencies: + forwarded "~0.1.2" + ipaddr.js "1.6.0" + +prr@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a" + +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + +pseudomap@^1.0.1, pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + +psl@^1.1.24: + version "1.1.28" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.28.tgz#4fb6ceb08a1e2214d4fd4de0ca22dae13740bc7b" + +public-encrypt@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.2.tgz#46eb9107206bf73489f8b85b69d91334c6610994" + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + +pull-cat@^1.1.9: + version "1.1.11" + resolved "https://registry.yarnpkg.com/pull-cat/-/pull-cat-1.1.11.tgz#b642dd1255da376a706b6db4fa962f5fdb74c31b" + +pull-level@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pull-level/-/pull-level-2.0.4.tgz#4822e61757c10bdcc7cf4a03af04c92734c9afac" + dependencies: + level-post "^1.0.7" + pull-cat "^1.1.9" + pull-live "^1.0.1" + pull-pushable "^2.0.0" + pull-stream "^3.4.0" + pull-window "^2.1.4" + stream-to-pull-stream "^1.7.1" + +pull-live@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/pull-live/-/pull-live-1.0.1.tgz#a4ecee01e330155e9124bbbcf4761f21b38f51f5" + dependencies: + pull-cat "^1.1.9" + pull-stream "^3.4.0" + +pull-pushable@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/pull-pushable/-/pull-pushable-2.2.0.tgz#5f2f3aed47ad86919f01b12a2e99d6f1bd776581" + +pull-stream@^3.2.3, pull-stream@^3.4.0, pull-stream@^3.4.5: + version "3.6.7" + resolved "https://registry.yarnpkg.com/pull-stream/-/pull-stream-3.6.7.tgz#fe4ae4f7cc3a9ee3ac82cd5be32729f2f0d5f02b" + +pull-window@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/pull-window/-/pull-window-2.1.4.tgz#fc3b86feebd1920c7ae297691e23f705f88552f0" + dependencies: + looper "^2.0.0" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + +punycode@^1.2.4, punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + +qs@6.5.1, qs@^6.4.0, qs@~6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" + +query-string@^5.0.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" + dependencies: + decode-uri-component "^0.2.0" + object-assign "^4.1.0" + strict-uri-encode "^1.0.0" + +querystring-es3@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + +randomatic@^1.1.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80" + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +randomhex@0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/randomhex/-/randomhex-0.1.5.tgz#baceef982329091400f2a2912c6cd02f1094f585" + +range-parser@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + +raw-body@2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89" + dependencies: + bytes "3.0.0" + http-errors "1.6.2" + iconv-lite "0.4.19" + unpipe "1.0.0" + +rc@^1.1.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.7.tgz#8a10ca30d588d00464360372b890d06dacd02297" + dependencies: + deep-extend "^0.5.1" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +read-chunk@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/read-chunk/-/read-chunk-2.1.0.tgz#6a04c0928005ed9d42e1a6ac5600e19cbc7ff655" + dependencies: + pify "^3.0.0" + safe-buffer "^5.1.1" + +read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + dependencies: + find-up "^1.0.0" + read-pkg "^1.0.0" + +read-pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" + dependencies: + find-up "^2.0.0" + read-pkg "^2.0.0" + +read-pkg-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" + dependencies: + find-up "^2.0.0" + read-pkg "^3.0.0" + +read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + dependencies: + load-json-file "^1.0.0" + normalize-package-data "^2.3.2" + path-type "^1.0.0" + +read-pkg@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" + dependencies: + load-json-file "^2.0.0" + normalize-package-data "^2.3.2" + path-type "^2.0.0" + +read-pkg@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" + dependencies: + load-json-file "^4.0.0" + normalize-package-data "^2.3.2" + path-type "^3.0.0" + +readable-stream@^1.0.33: + version "1.1.14" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.3, readable-stream@^2.3.5: + version "2.3.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@~1.0.15, readable-stream@~1.0.26: + version "1.0.34" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readdirp@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" + dependencies: + graceful-fs "^4.1.2" + minimatch "^3.0.2" + readable-stream "^2.0.2" + set-immediate-shim "^1.0.1" + +realpath-native@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-1.0.0.tgz#7885721a83b43bd5327609f0ddecb2482305fdf0" + dependencies: + util.promisify "^1.0.0" + +recast@^0.12.5: + version "0.12.9" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.12.9.tgz#e8e52bdb9691af462ccbd7c15d5a5113647a15f1" + dependencies: + ast-types "0.10.1" + core-js "^2.4.1" + esprima "~4.0.0" + private "~0.1.5" + source-map "~0.6.1" + +recast@^0.14.1: + version "0.14.7" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.14.7.tgz#4f1497c2b5826d42a66e8e3c9d80c512983ff61d" + dependencies: + ast-types "0.11.3" + esprima "~4.0.0" + private "~0.1.5" + source-map "~0.6.1" + +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + dependencies: + resolve "^1.1.6" + +regenerate@^1.2.1: + version "1.3.3" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.3.tgz#0c336d3980553d755c39b586ae3b20aa49c82b7f" + +regenerator-runtime@^0.10.5: + version "0.10.5" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" + +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + +regenerator-transform@^0.10.0: + version "0.10.1" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" + dependencies: + babel-runtime "^6.18.0" + babel-types "^6.19.0" + private "^0.1.6" + +regex-cache@^0.4.2: + version "0.4.4" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" + dependencies: + is-equal-shallow "^0.1.3" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +regexpp@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab" + +regexpu-core@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + +regjsgen@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + +regjsparser@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + dependencies: + jsesc "~0.5.0" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + +repeat-element@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + +repeat-string@^1.5.2, repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + dependencies: + is-finite "^1.0.0" + +replace-ext@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924" + +replace-ext@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb" + +req-cwd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/req-cwd/-/req-cwd-1.0.1.tgz#0d73aeae9266e697a78f7976019677e76acf0fff" + dependencies: + req-from "^1.0.1" + +req-cwd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/req-cwd/-/req-cwd-2.0.0.tgz#d4082b4d44598036640fb73ddea01ed53db49ebc" + dependencies: + req-from "^2.0.0" + +req-from@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/req-from/-/req-from-1.0.1.tgz#bf81da5147947d32d13b947dc12a58ad4587350e" + dependencies: + resolve-from "^2.0.0" + +req-from@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/req-from/-/req-from-2.0.0.tgz#d74188e47f93796f4aa71df6ee35ae689f3e0e70" + dependencies: + resolve-from "^3.0.0" + +request-promise-core@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.1.tgz#3eee00b2c5aa83239cfb04c5700da36f81cd08b6" + dependencies: + lodash "^4.13.1" + +request-promise-native@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.5.tgz#5281770f68e0c9719e5163fd3fab482215f4fda5" + dependencies: + request-promise-core "1.1.1" + stealthy-require "^1.1.0" + tough-cookie ">=2.3.3" + +request@^2.67.0, request@^2.79.0, request@^2.83.0: + version "2.85.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.85.0.tgz#5a03615a47c61420b3eb99b7dba204f83603e1fa" + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.6.0" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.1" + forever-agent "~0.6.1" + form-data "~2.3.1" + har-validator "~5.0.3" + hawk "~6.0.2" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.17" + oauth-sign "~0.8.2" + performance-now "^2.1.0" + qs "~6.5.1" + safe-buffer "^5.1.1" + stringstream "~0.0.5" + tough-cookie "~2.3.3" + tunnel-agent "^0.6.0" + uuid "^3.1.0" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + +require-from-string@^1.1.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-1.2.1.tgz#529c9ccef27380adfec9a2f965b649bbee636418" + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + +require-uncached@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" + dependencies: + caller-path "^0.1.0" + resolve-from "^1.0.0" + +resolve-cwd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" + dependencies: + resolve-from "^3.0.0" + +resolve-dir@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" + dependencies: + expand-tilde "^2.0.0" + global-modules "^1.0.0" + +resolve-from@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" + +resolve-from@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" + +resolve-from@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + +resolve@1.1.7, resolve@1.1.x: + version "1.1.7" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" + +resolve@^1.1.6, resolve@^1.5.0, resolve@^1.6.0: + version "1.7.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.7.1.tgz#aadd656374fd298aee895bc026b8297418677fd3" + dependencies: + path-parse "^1.0.5" + +resolve@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" + dependencies: + path-parse "^1.0.5" + +responselike@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" + dependencies: + lowercase-keys "^1.0.0" + +restore-cursor@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" + dependencies: + exit-hook "^1.0.0" + onetime "^1.0.0" + +restore-cursor@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + dependencies: + onetime "^2.0.0" + signal-exit "^3.0.2" + +resumer@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/resumer/-/resumer-0.0.0.tgz#f1e8f461e4064ba39e82af3cdc2a8c893d076759" + dependencies: + through "~2.3.4" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + +right-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" + dependencies: + align-text "^0.1.1" + +rimraf@2, rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" + dependencies: + glob "^7.0.5" + +rimraf@~2.2.6: + version "2.2.8" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +rlp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/rlp/-/rlp-2.0.0.tgz#9db384ff4b89a8f61563d92395d8625b18f3afb0" + +rsvp@^3.3.3: + version "3.6.2" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" + +run-async@^2.0.0, run-async@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" + dependencies: + is-promise "^2.1.0" + +rustbn.js@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/rustbn.js/-/rustbn.js-0.1.2.tgz#979fa0f9562216dd667c9d2cd179ae5d13830eff" + +rx-lite-aggregates@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" + dependencies: + rx-lite "*" + +rx-lite@*, rx-lite@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" + +rxjs@^5.4.2, rxjs@^5.5.2: + version "5.5.10" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.10.tgz#fde02d7a614f6c8683d0d1957827f492e09db045" + dependencies: + symbol-observable "1.0.1" + +safe-buffer@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" + +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + dependencies: + ret "~0.1.10" + +safer-buffer@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + +sane@^2.0.0: + version "2.5.2" + resolved "https://registry.yarnpkg.com/sane/-/sane-2.5.2.tgz#b4dc1861c21b427e929507a3e751e2a2cb8ab3fa" + dependencies: + anymatch "^2.0.0" + capture-exit "^1.2.0" + exec-sh "^0.2.0" + fb-watchman "^2.0.0" + micromatch "^3.1.4" + minimist "^1.1.1" + walker "~1.0.5" + watch "~0.18.0" + optionalDependencies: + fsevents "^1.2.3" + +sax@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + +scoped-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/scoped-regex/-/scoped-regex-1.0.0.tgz#a346bb1acd4207ae70bd7c0c7ca9e566b6baddb8" + +scrypt-js@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-2.0.3.tgz#bb0040be03043da9a012a2cea9fc9f852cfc87d4" + +scrypt.js@0.2.0, scrypt.js@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/scrypt.js/-/scrypt.js-0.2.0.tgz#af8d1465b71e9990110bedfc593b9479e03a8ada" + dependencies: + scrypt "^6.0.2" + scryptsy "^1.2.1" + +scrypt@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/scrypt/-/scrypt-6.0.3.tgz#04e014a5682b53fa50c2d5cce167d719c06d870d" + dependencies: + nan "^2.0.8" + +scryptsy@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/scryptsy/-/scryptsy-1.2.1.tgz#a3225fa4b2524f802700761e2855bdf3b2d92163" + dependencies: + pbkdf2 "^3.0.3" + +secp256k1@^3.0.1: + version "3.5.0" + resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-3.5.0.tgz#677d3b8a8e04e1a5fa381a1ae437c54207b738d0" + dependencies: + bindings "^1.2.1" + bip66 "^1.1.3" + bn.js "^4.11.3" + create-hash "^1.1.2" + drbg.js "^1.0.1" + elliptic "^6.2.3" + nan "^2.2.1" + safe-buffer "^5.1.0" + +seedrandom@~2.4.2: + version "2.4.3" + resolved "https://registry.yarnpkg.com/seedrandom/-/seedrandom-2.4.3.tgz#2438504dad33917314bff18ac4d794f16d6aaecc" + +seek-bzip@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/seek-bzip/-/seek-bzip-1.0.5.tgz#cfe917cb3d274bcffac792758af53173eb1fabdc" + dependencies: + commander "~2.8.1" + +semaphore@>=1.0.1, semaphore@^1.0.3: + version "1.1.0" + resolved "https://registry.yarnpkg.com/semaphore/-/semaphore-1.1.0.tgz#aaad8b86b20fe8e9b32b16dc2ee682a8cd26a8aa" + +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" + +semver@~5.1.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.1.1.tgz#a3292a373e6f3e0798da0b20641b9a9c5bc47e19" + +semver@~5.4.1: + version "5.4.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" + +send@0.16.2: + version "0.16.2" + resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.6.2" + mime "1.4.1" + ms "2.0.0" + on-finished "~2.3.0" + range-parser "~1.2.0" + statuses "~1.4.0" + +serve-static@1.13.2: + version "1.13.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.2" + send "0.16.2" + +servify@^0.1.12: + version "0.1.12" + resolved "https://registry.yarnpkg.com/servify/-/servify-0.1.12.tgz#142ab7bee1f1d033b66d0707086085b17c06db95" + dependencies: + body-parser "^1.16.0" + cors "^2.8.1" + express "^4.14.0" + request "^2.79.0" + xhr "^2.3.3" + +set-blocking@^2.0.0, set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +set-immediate-shim@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + +set-value@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.1" + to-object-path "^0.3.0" + +set-value@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setimmediate@1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.4.tgz#20e81de622d4a02588ce0c8da8973cbcf1d3138f" + +setimmediate@^1.0.4, setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + +setprototypeof@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +sha3@^1.1.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/sha3/-/sha3-1.2.2.tgz#a66c5098de4c25bc88336ec8b4817d005bca7ba9" + dependencies: + nan "2.10.0" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + dependencies: + shebang-regex "^1.0.0" + +shebang-loader@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/shebang-loader/-/shebang-loader-0.0.1.tgz#a4000495d44cceefbec63435e7b1698569fa52ec" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + +shelljs@^0.7.4, shelljs@^0.7.8: + version "0.7.8" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.8.tgz#decbcf874b0d1e5fb72e14b164a9683048e9acb3" + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" + +shelljs@^0.8.0: + version "0.8.1" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.1.tgz#729e038c413a2254c4078b95ed46e0397154a9f1" + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" + +shelljs@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.2.tgz#345b7df7763f4c2340d584abb532c5f752ca9e35" + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" + +shellwords@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" + +shortid@^2.2.8: + version "2.2.8" + resolved "https://registry.yarnpkg.com/shortid/-/shortid-2.2.8.tgz#033b117d6a2e975804f6f0969dbe7d3d0b355131" + +shx@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/shx/-/shx-0.3.0.tgz#f978c7a2c18cbf26ecdc1c44c22cc0238ff7c444" + dependencies: + es6-object-assign "^1.0.3" + minimist "^1.2.0" + shelljs "^0.8.1" + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + +simple-concat@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.0.tgz#7344cbb8b6e26fb27d66b2fc86f9f6d5997521c6" + +simple-get@^2.7.0: + version "2.8.1" + resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-2.8.1.tgz#0e22e91d4575d87620620bc91308d57a77f44b5d" + dependencies: + decompress-response "^3.3.0" + once "^1.3.1" + simple-concat "^1.0.0" + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + +slice-ansi@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" + +slice-ansi@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" + dependencies: + is-fullwidth-code-point "^2.0.0" + +slide@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +sntp@2.x.x: + version "2.1.0" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-2.1.0.tgz#2c6cec14fedc2222739caf9b5c3d85d1cc5a2cc8" + dependencies: + hoek "4.x.x" + +sol-digger@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/sol-digger/-/sol-digger-0.0.2.tgz#406c4a9d31e269e7f88eb1c2ea101318e5e09025" + +sol-explore@1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/sol-explore/-/sol-explore-1.6.1.tgz#b59f073c69fe332560d5a10c32ba8ca7f2986cfb" + +sol-explore@^1.6.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/sol-explore/-/sol-explore-1.6.2.tgz#43ae8c419fd3ac056a05f8a9d1fb1022cd41ecc2" + +solc@0.4.18: + version "0.4.18" + resolved "https://registry.yarnpkg.com/solc/-/solc-0.4.18.tgz#83ac6d871dd16a9710e67dbb76dad7f614100702" + dependencies: + fs-extra "^0.30.0" + memorystream "^0.3.1" + require-from-string "^1.1.0" + semver "^5.3.0" + yargs "^4.7.1" + +solc@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/solc/-/solc-0.4.24.tgz#354f14b269b38cbaa82a47d1ff151723502b954e" + dependencies: + fs-extra "^0.30.0" + memorystream "^0.3.1" + require-from-string "^1.1.0" + semver "^5.3.0" + yargs "^4.7.1" + +solc@^0.4.2: + version "0.4.23" + resolved "https://registry.yarnpkg.com/solc/-/solc-0.4.23.tgz#54a0ff4015827b32fddb62c0a418b5247310a58e" + dependencies: + fs-extra "^0.30.0" + memorystream "^0.3.1" + require-from-string "^1.1.0" + semver "^5.3.0" + yargs "^4.7.1" + +solidity-coverage@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/solidity-coverage/-/solidity-coverage-0.5.4.tgz#f61d8de310fc17102ffd8bac38d660b7017c10c3" + dependencies: + death "^1.1.0" + ethereumjs-testrpc-sc "6.1.2" + istanbul "^0.4.5" + keccakjs "^0.2.1" + req-cwd "^1.0.1" + shelljs "^0.7.4" + sol-explore "^1.6.2" + solidity-parser-sc "0.4.10" + tree-kill "^1.2.0" + web3 "^0.18.4" + +solidity-parser-antlr@^0.2.11: + version "0.2.11" + resolved "https://registry.yarnpkg.com/solidity-parser-antlr/-/solidity-parser-antlr-0.2.11.tgz#b3e4d0aca0d15796e9b59da53a49137aab51c298" + +solidity-parser-sc@0.4.10: + version "0.4.10" + resolved "https://registry.yarnpkg.com/solidity-parser-sc/-/solidity-parser-sc-0.4.10.tgz#5a594cd5e0d6ce1a72add781a7770663bab65d3d" + dependencies: + mocha "^4.1.0" + pegjs "^0.10.0" + yargs "^4.6.0" + +solium-plugin-security@0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/solium-plugin-security/-/solium-plugin-security-0.1.1.tgz#2a87bcf8f8c3abf7d198e292e4ac080284e3f3f6" + +solium@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/solium/-/solium-1.1.7.tgz#332e499be0dbcac663af886de82ff1ed7e3d51af" + dependencies: + ajv "^5.2.2" + chokidar "^1.6.0" + colors "^1.1.2" + commander "^2.9.0" + js-string-escape "^1.0.1" + lodash "^4.14.2" + sol-digger "0.0.2" + sol-explore "1.6.1" + solium-plugin-security "0.1.1" + solparse "2.2.5" + text-table "^0.2.0" + +solparse@2.2.5: + version "2.2.5" + resolved "https://registry.yarnpkg.com/solparse/-/solparse-2.2.5.tgz#72709c867cd6bfc50ec2325f4b81d2b3ea365d99" + dependencies: + mocha "^4.0.1" + pegjs "^0.10.0" + yargs "^10.0.3" + +sort-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" + dependencies: + is-plain-obj "^1.0.0" + +source-list-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.0.tgz#aaa47403f7b245a92fbc97ea08f250d6087ed085" + +source-map-resolve@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.1.tgz#7ad0f593f2281598e854df80f19aae4b92d7a11a" + dependencies: + atob "^2.0.0" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-support@^0.4.15: + version "0.4.18" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" + dependencies: + source-map "^0.5.6" + +source-map-support@^0.5.3: + version "0.5.5" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.5.tgz#0d4af9e00493e855402e8ec36ebed2d266fceb90" + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-support@^0.5.6: + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.6.tgz#4435cee46b1aab62b8e8610ce60f788091c51c13" + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + +source-map@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + dependencies: + amdefine ">=0.0.4" + +source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.1: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + +source-map@^0.6.0, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + +source-map@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d" + dependencies: + amdefine ">=0.0.4" + +spawn-sync@^1.0.15: + version "1.0.15" + resolved "https://registry.yarnpkg.com/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476" + dependencies: + concat-stream "^1.4.7" + os-shim "^0.1.2" + +spdx-correct@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.0.0.tgz#05a5b4d7153a195bc92c3c425b69f3b2a9524c82" + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz#2c7ae61056c714a5b9b9b2b2af7d311ef5c78fe9" + +spdx-expression-parse@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz#7a7cd28470cc6d3a1cfe6d66886f6bc430d3ac87" + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + dependencies: + extend-shallow "^3.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + +sshpk@^1.7.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.14.1.tgz#130f5975eddad963f1d56f92b9ac6c51fa9f83eb" + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + dashdash "^1.12.0" + getpass "^0.1.1" + optionalDependencies: + bcrypt-pbkdf "^1.0.0" + ecc-jsbn "~0.1.1" + jsbn "~0.1.0" + tweetnacl "~0.14.0" + +stack-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.1.tgz#d4f33ab54e8e38778b0ca5cfd3b3afb12db68620" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +"statuses@>= 1.3.1 < 2", "statuses@>= 1.4.0 < 2": + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + +statuses@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" + +stealthy-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" + +stream-browserify@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" + dependencies: + inherits "~2.0.1" + readable-stream "^2.0.2" + +stream-http@^2.7.2: + version "2.8.1" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.1.tgz#d0441be1a457a73a733a8a7b53570bebd9ef66a4" + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.1" + readable-stream "^2.3.3" + to-arraybuffer "^1.0.0" + xtend "^4.0.0" + +stream-to-observable@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/stream-to-observable/-/stream-to-observable-0.2.0.tgz#59d6ea393d87c2c0ddac10aa0d561bc6ba6f0e10" + dependencies: + any-observable "^0.2.0" + +stream-to-pull-stream@^1.7.1: + version "1.7.2" + resolved "https://registry.yarnpkg.com/stream-to-pull-stream/-/stream-to-pull-stream-1.7.2.tgz#757609ae1cebd33c7432d4afbe31ff78650b9dde" + dependencies: + looper "^3.0.0" + pull-stream "^3.2.3" + +strict-uri-encode@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + +string-length@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-2.0.0.tgz#d40dbb686a3ace960c1cffca562bf2c45f8363ed" + dependencies: + astral-regex "^1.0.0" + strip-ansi "^4.0.0" + +string-template@~0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" + +string-width@^1.0.1, string-width@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string.prototype.trim@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz#d04de2c89e137f4d7d206f086b5ed2fae6be8cea" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.5.0" + function-bind "^1.0.2" + +string_decoder@^1.0.0, string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + dependencies: + safe-buffer "~5.1.0" + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + +stringstream@~0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + dependencies: + ansi-regex "^3.0.0" + +strip-ansi@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.1.1.tgz#39e8a98d044d150660abe4a6808acf70bb7bc991" + +strip-bom-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom-stream/-/strip-bom-stream-2.0.0.tgz#f87db5ef2613f6968aa545abfe1ec728b6a829ca" + dependencies: + first-chunk-stream "^2.0.0" + strip-bom "^2.0.0" + +strip-bom@3.0.0, strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + dependencies: + is-utf8 "^0.2.0" + +strip-dirs@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/strip-dirs/-/strip-dirs-2.1.0.tgz#4987736264fc344cf20f6c34aca9d13d1d4ed6c5" + dependencies: + is-natural-number "^4.0.1" + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + +strip-hex-prefix@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz#0c5f155fef1151373377de9dbb588da05500e36f" + dependencies: + is-hex-prefixed "1.0.0" + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + +supports-color@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.1.2.tgz#72a262894d9d408b956ca05ff37b2ed8a6e2a2d5" + dependencies: + has-flag "^1.0.0" + +supports-color@4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.4.0.tgz#883f7ddabc165142b2a61427f3352ded195d1a3e" + dependencies: + has-flag "^2.0.0" + +supports-color@5.4.0, supports-color@^5.3.0: + version "5.4.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" + dependencies: + has-flag "^3.0.0" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + +supports-color@^3.1.0, supports-color@^3.1.2: + version "3.2.3" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" + dependencies: + has-flag "^1.0.0" + +swarm-js@0.1.37: + version "0.1.37" + resolved "https://registry.yarnpkg.com/swarm-js/-/swarm-js-0.1.37.tgz#27d485317a340bbeec40292af783cc10acfa4663" + dependencies: + bluebird "^3.5.0" + buffer "^5.0.5" + decompress "^4.0.0" + eth-lib "^0.1.26" + fs-extra "^2.1.2" + fs-promise "^2.0.0" + got "^7.1.0" + mime-types "^2.1.16" + mkdirp-promise "^5.0.1" + mock-fs "^4.1.0" + setimmediate "^1.0.5" + tar.gz "^1.0.5" + xhr-request-promise "^0.1.2" + +symbol-observable@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4" + +symbol-observable@^0.2.2: + version "0.2.4" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-0.2.4.tgz#95a83db26186d6af7e7a18dbd9760a2f86d08f40" + +symbol-tree@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6" + +sync-request@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/sync-request/-/sync-request-6.0.0.tgz#db867eccc4ed31bbcb9fa3732393a3413da582ed" + dependencies: + http-response-object "^3.0.1" + sync-rpc "^1.2.1" + then-request "^6.0.0" + +sync-rpc@^1.2.1: + version "1.3.3" + resolved "https://registry.yarnpkg.com/sync-rpc/-/sync-rpc-1.3.3.tgz#f72ec6da8aa6f1a7d4a69003711f528e275993f4" + dependencies: + get-port "^3.1.0" + +table@4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36" + dependencies: + ajv "^5.2.3" + ajv-keywords "^2.1.0" + chalk "^2.1.0" + lodash "^4.17.4" + slice-ansi "1.0.0" + string-width "^2.1.1" + +tapable@^0.2.7, tapable@~0.2.5: + version "0.2.8" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.8.tgz#99372a5c999bf2df160afc0d74bed4f47948cd22" + +tapable@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.0.0.tgz#cbb639d9002eed9c6b5975eb20598d7936f1f9f2" + +tape@^4.4.0, tape@^4.6.3: + version "4.9.0" + resolved "https://registry.yarnpkg.com/tape/-/tape-4.9.0.tgz#855c08360395133709d34d3fbf9ef341eb73ca6a" + dependencies: + deep-equal "~1.0.1" + defined "~1.0.0" + for-each "~0.3.2" + function-bind "~1.1.1" + glob "~7.1.2" + has "~1.0.1" + inherits "~2.0.3" + minimist "~1.2.0" + object-inspect "~1.5.0" + resolve "~1.5.0" + resumer "~0.0.0" + string.prototype.trim "~1.1.2" + through "~2.3.8" + +tar-stream@^1.5.2: + version "1.6.0" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.0.tgz#a50efaa7b17760b82c27b3cae4a301a8254a5715" + dependencies: + bl "^1.0.0" + buffer-alloc "^1.1.0" + end-of-stream "^1.0.0" + fs-constants "^1.0.0" + readable-stream "^2.0.0" + to-buffer "^1.1.0" + xtend "^4.0.0" + +tar.gz@^1.0.5: + version "1.0.7" + resolved "https://registry.yarnpkg.com/tar.gz/-/tar.gz-1.0.7.tgz#577ef2c595faaa73452ef0415fed41113212257b" + dependencies: + bluebird "^2.9.34" + commander "^2.8.1" + fstream "^1.0.8" + mout "^0.11.0" + tar "^2.1.1" + +tar@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + dependencies: + block-stream "*" + fstream "^1.0.2" + inherits "2" + +tar@^4: + version "4.4.2" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.2.tgz#60685211ba46b38847b1ae7ee1a24d744a2cd462" + dependencies: + chownr "^1.0.1" + fs-minipass "^1.2.5" + minipass "^2.2.4" + minizlib "^1.1.0" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.2" + +temp@^0.8.1, temp@^0.8.3: + version "0.8.3" + resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" + dependencies: + os-tmpdir "^1.0.0" + rimraf "~2.2.6" + +test-exclude@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-4.2.1.tgz#dfa222f03480bca69207ca728b37d74b45f724fa" + dependencies: + arrify "^1.0.1" + micromatch "^3.1.8" + object-assign "^4.1.0" + read-pkg-up "^1.0.1" + require-main-filename "^1.0.1" + +text-table@^0.2.0, text-table@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + +textextensions@2: + version "2.2.0" + resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-2.2.0.tgz#38ac676151285b658654581987a0ce1a4490d286" + +then-request@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/then-request/-/then-request-6.0.0.tgz#2cab198e48f2d8e79c8c1ed260198368a4a0bcba" + dependencies: + "@types/concat-stream" "^1.6.0" + "@types/form-data" "0.0.33" + "@types/node" "^8.0.0" + "@types/qs" "^6.2.31" + caseless "~0.12.0" + concat-stream "^1.6.0" + form-data "^2.2.0" + http-basic "^7.0.0" + http-response-object "^3.0.1" + promise "^8.0.0" + qs "^6.4.0" + +thenify-all@^1.0.0, thenify-all@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.3.0" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.0.tgz#e69e38a1babe969b0108207978b9f62b88604839" + dependencies: + any-promise "^1.0.0" + +throat@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a" + +through2@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" + dependencies: + readable-stream "^2.1.5" + xtend "~4.0.1" + +through@^2.3.6, through@~2.3.4, through@~2.3.8: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + +timed-out@^4.0.0, timed-out@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" + +timers-browserify@^2.0.4: + version "2.0.10" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.10.tgz#1d28e3d2aadf1d5a5996c4e9f95601cd053480ae" + dependencies: + setimmediate "^1.0.4" + +tiny-queue@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/tiny-queue/-/tiny-queue-0.2.0.tgz#c49fcb5c87555be1b4a5df7eb87101d5b78bc9dc" + +tmp@0.0.31: + version "0.0.31" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.31.tgz#8f38ab9438e17315e5dbd8b3657e8bfb277ae4a7" + dependencies: + os-tmpdir "~1.0.1" + +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + dependencies: + os-tmpdir "~1.0.2" + +tmpl@1.0.x: + version "1.0.4" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" + +to-arraybuffer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" + +to-buffer@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" + +to-fast-properties@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +tough-cookie@>=2.3.3, tough-cookie@~2.3.3: + version "2.3.4" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655" + dependencies: + punycode "^1.4.1" + +tough-cookie@^2.3.3: + version "2.4.2" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.2.tgz#aa9133154518b494efab98a58247bfc38818c00c" + dependencies: + psl "^1.1.24" + punycode "^1.4.1" + +tr46@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" + dependencies: + punycode "^2.1.0" + +tree-kill@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.0.tgz#5846786237b4239014f05db156b643212d4c6f36" + +trim-right@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + +trim@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/trim/-/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd" + +truffle@^4.1.11: + version "4.1.11" + resolved "https://registry.yarnpkg.com/truffle/-/truffle-4.1.11.tgz#a4df812ebf4a564892900c4a1dac1131104a0799" + dependencies: + mocha "^4.1.0" + original-require "^1.0.1" + solc "0.4.24" + +tty-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + dependencies: + prelude-ls "~1.1.2" + +type-detect@0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822" + +type-detect@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" + +type-detect@^4.0.0: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + +type-is@~1.6.15, type-is@~1.6.16: + version "1.6.16" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" + dependencies: + media-typer "0.3.0" + mime-types "~2.1.18" + +typedarray-to-buffer@^3.1.2: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + dependencies: + is-typedarray "^1.0.0" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + +typewise-core@^1.2, typewise-core@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/typewise-core/-/typewise-core-1.2.0.tgz#97eb91805c7f55d2f941748fa50d315d991ef195" + +typewise@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/typewise/-/typewise-1.0.3.tgz#1067936540af97937cc5dcf9922486e9fa284651" + dependencies: + typewise-core "^1.2.0" + +typewiselite@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/typewiselite/-/typewiselite-1.0.0.tgz#c8882fa1bb1092c06005a97f34ef5c8508e3664e" + +uglify-js@^2.6, uglify-js@^2.8.27: + version "2.8.29" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" + dependencies: + source-map "~0.5.1" + yargs "~3.10.0" + optionalDependencies: + uglify-to-browserify "~1.0.0" + +uglify-to-browserify@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" + +ultron@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" + +unbzip2-stream@^1.0.9: + version "1.2.5" + resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.2.5.tgz#73a033a567bbbde59654b193c44d48a7e4f43c47" + dependencies: + buffer "^3.0.1" + through "^2.3.6" + +underscore@1.8.3: + version "1.8.3" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" + +underscore@~1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.6.0.tgz#8b38b10cacdef63337b8b24e4ff86d45aea529a8" + +union-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^0.4.3" + +unorm@^1.3.3: + version "1.4.1" + resolved "https://registry.yarnpkg.com/unorm/-/unorm-1.4.1.tgz#364200d5f13646ca8bcd44490271335614792300" + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +untildify@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/untildify/-/untildify-3.0.2.tgz#7f1f302055b3fea0f3e81dc78eb36766cb65e3f1" + +upath@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.0.5.tgz#02cab9ecebe95bbec6d5fc2566325725ab6d1a73" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + +url-parse-lax@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" + dependencies: + prepend-http "^1.0.1" + +url-parse-lax@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" + dependencies: + prepend-http "^2.0.0" + +url-set-query@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/url-set-query/-/url-set-query-1.0.0.tgz#016e8cfd7c20ee05cafe7795e892bd0702faa339" + +url-to-options@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" + +url@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +use@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.0.tgz#14716bf03fdfefd03040aef58d8b4b85f3a7c544" + dependencies: + kind-of "^6.0.2" + +user-home@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" + +utf8@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/utf8/-/utf8-2.1.1.tgz#2e01db02f7d8d0944f77104f1609eb0c304cf768" + +utf8@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/utf8/-/utf8-2.1.2.tgz#1fa0d9270e9be850d9b05027f63519bf46457d96" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +util.promisify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" + dependencies: + define-properties "^1.1.2" + object.getownpropertydescriptors "^2.0.3" + +util@0.10.3, util@^0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + dependencies: + inherits "2.0.1" + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + +uuid@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.1.tgz#c2a30dedb3e535d72ccf82e343941a50ba8533ac" + +uuid@^2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" + +uuid@^3.1.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" + +v8-compile-cache@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-1.1.2.tgz#8d32e4f16974654657e676e0e467a348e89b0dc4" + +v8flags@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.1.1.tgz#aab1a1fa30d45f88dd321148875ac02c0b55e5b4" + dependencies: + user-home "^1.1.1" + +validate-npm-package-license@^3.0.1: + version "3.0.3" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz#81643bcbef1bdfecd4623793dc4648948ba98338" + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +vary@^1, vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +vinyl-file@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/vinyl-file/-/vinyl-file-2.0.0.tgz#a7ebf5ffbefda1b7d18d140fcb07b223efb6751a" + dependencies: + graceful-fs "^4.1.2" + pify "^2.3.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + strip-bom-stream "^2.0.0" + vinyl "^1.1.0" + +vinyl@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-1.2.0.tgz#5c88036cf565e5df05558bfc911f8656df218884" + dependencies: + clone "^1.0.0" + clone-stats "^0.0.1" + replace-ext "0.0.1" + +vinyl@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.1.0.tgz#021f9c2cf951d6b939943c89eb5ee5add4fd924c" + dependencies: + clone "^2.1.1" + clone-buffer "^1.0.0" + clone-stats "^1.0.0" + cloneable-readable "^1.0.0" + remove-trailing-separator "^1.0.1" + replace-ext "^1.0.0" + +vm-browserify@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" + dependencies: + indexof "0.0.1" + +w3c-hr-time@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz#82ac2bff63d950ea9e3189a58a65625fedf19045" + dependencies: + browser-process-hrtime "^0.1.2" + +walker@~1.0.5: + version "1.0.7" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + dependencies: + makeerror "1.0.x" + +watch@~0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/watch/-/watch-0.18.0.tgz#28095476c6df7c90c963138990c0a5423eb4b986" + dependencies: + exec-sh "^0.2.0" + minimist "^1.2.0" + +watchpack@^1.3.1: + version "1.6.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00" + dependencies: + chokidar "^2.0.2" + graceful-fs "^4.1.2" + neo-async "^2.5.0" + +web3-bzz@1.0.0-beta.34: + version "1.0.0-beta.34" + resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.0.0-beta.34.tgz#068d37777ab65e5c60f8ec8b9a50cfe45277929c" + dependencies: + got "7.1.0" + swarm-js "0.1.37" + underscore "1.8.3" + +web3-core-helpers@1.0.0-beta.34: + version "1.0.0-beta.34" + resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.0.0-beta.34.tgz#b168da00d3e19e156bc15ae203203dd4dfee2d03" + dependencies: + underscore "1.8.3" + web3-eth-iban "1.0.0-beta.34" + web3-utils "1.0.0-beta.34" + +web3-core-method@1.0.0-beta.34: + version "1.0.0-beta.34" + resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.0.0-beta.34.tgz#ec163c8a2c490fa02a7ec15559fa7307fc7cc6dd" + dependencies: + underscore "1.8.3" + web3-core-helpers "1.0.0-beta.34" + web3-core-promievent "1.0.0-beta.34" + web3-core-subscriptions "1.0.0-beta.34" + web3-utils "1.0.0-beta.34" + +web3-core-promievent@1.0.0-beta.34: + version "1.0.0-beta.34" + resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.0.0-beta.34.tgz#a4f4fa6784bb293e82c60960ae5b56a94cd03edc" + dependencies: + any-promise "1.3.0" + eventemitter3 "1.1.1" + +web3-core-requestmanager@1.0.0-beta.34: + version "1.0.0-beta.34" + resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.0.0-beta.34.tgz#01f8f6cf2ae6b6f0b70c38bae1ef741b5bab215c" + dependencies: + underscore "1.8.3" + web3-core-helpers "1.0.0-beta.34" + web3-providers-http "1.0.0-beta.34" + web3-providers-ipc "1.0.0-beta.34" + web3-providers-ws "1.0.0-beta.34" + +web3-core-subscriptions@1.0.0-beta.34: + version "1.0.0-beta.34" + resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.0.0-beta.34.tgz#9fed144033f221c3cf21060302ffdaf5ef2de2de" + dependencies: + eventemitter3 "1.1.1" + underscore "1.8.3" + web3-core-helpers "1.0.0-beta.34" + +web3-core@1.0.0-beta.34: + version "1.0.0-beta.34" + resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.0.0-beta.34.tgz#121be8555e9fb00d2c5d05ddd3381d0c9e46987e" + dependencies: + web3-core-helpers "1.0.0-beta.34" + web3-core-method "1.0.0-beta.34" + web3-core-requestmanager "1.0.0-beta.34" + web3-utils "1.0.0-beta.34" + +web3-eth-abi@1.0.0-beta.34: + version "1.0.0-beta.34" + resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.0.0-beta.34.tgz#034533e3aa2f7e59ff31793eaea685c0ed5af67a" + dependencies: + bn.js "4.11.6" + underscore "1.8.3" + web3-core-helpers "1.0.0-beta.34" + web3-utils "1.0.0-beta.34" + +web3-eth-accounts@1.0.0-beta.34: + version "1.0.0-beta.34" + resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.0.0-beta.34.tgz#e09142eeecc797ac3459b75e9b23946d3695f333" + dependencies: + any-promise "1.3.0" + crypto-browserify "3.12.0" + eth-lib "0.2.7" + scrypt.js "0.2.0" + underscore "1.8.3" + uuid "2.0.1" + web3-core "1.0.0-beta.34" + web3-core-helpers "1.0.0-beta.34" + web3-core-method "1.0.0-beta.34" + web3-utils "1.0.0-beta.34" + +web3-eth-contract@1.0.0-beta.34: + version "1.0.0-beta.34" + resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.0.0-beta.34.tgz#9dbb38fae7643a808427a20180470ec7415c91e6" + dependencies: + underscore "1.8.3" + web3-core "1.0.0-beta.34" + web3-core-helpers "1.0.0-beta.34" + web3-core-method "1.0.0-beta.34" + web3-core-promievent "1.0.0-beta.34" + web3-core-subscriptions "1.0.0-beta.34" + web3-eth-abi "1.0.0-beta.34" + web3-utils "1.0.0-beta.34" + +web3-eth-iban@1.0.0-beta.34: + version "1.0.0-beta.34" + resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.0.0-beta.34.tgz#9af458605867ccf74ea979aaf326b38ba6a5ba0c" + dependencies: + bn.js "4.11.6" + web3-utils "1.0.0-beta.34" + +web3-eth-personal@1.0.0-beta.34: + version "1.0.0-beta.34" + resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.0.0-beta.34.tgz#9afba167342ebde5420bcd5895c3f6c34388f205" + dependencies: + web3-core "1.0.0-beta.34" + web3-core-helpers "1.0.0-beta.34" + web3-core-method "1.0.0-beta.34" + web3-net "1.0.0-beta.34" + web3-utils "1.0.0-beta.34" + +web3-eth@1.0.0-beta.34: + version "1.0.0-beta.34" + resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.0.0-beta.34.tgz#74086000850c6fe6f535ef49837d6d4bb6113268" + dependencies: + underscore "1.8.3" + web3-core "1.0.0-beta.34" + web3-core-helpers "1.0.0-beta.34" + web3-core-method "1.0.0-beta.34" + web3-core-subscriptions "1.0.0-beta.34" + web3-eth-abi "1.0.0-beta.34" + web3-eth-accounts "1.0.0-beta.34" + web3-eth-contract "1.0.0-beta.34" + web3-eth-iban "1.0.0-beta.34" + web3-eth-personal "1.0.0-beta.34" + web3-net "1.0.0-beta.34" + web3-utils "1.0.0-beta.34" + +web3-net@1.0.0-beta.34: + version "1.0.0-beta.34" + resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.0.0-beta.34.tgz#427cea2f431881449c8e38d523290f173f9ff63d" + dependencies: + web3-core "1.0.0-beta.34" + web3-core-method "1.0.0-beta.34" + web3-utils "1.0.0-beta.34" + +web3-provider-engine@^13.6.5: + version "13.8.0" + resolved "https://registry.yarnpkg.com/web3-provider-engine/-/web3-provider-engine-13.8.0.tgz#4c7c1ad2af5f1fe10343b8a65495879a2f9c00df" + dependencies: + async "^2.5.0" + clone "^2.0.0" + eth-block-tracker "^2.2.2" + eth-sig-util "^1.4.2" + ethereumjs-block "^1.2.2" + ethereumjs-tx "^1.2.0" + ethereumjs-util "^5.1.1" + ethereumjs-vm "^2.0.2" + fetch-ponyfill "^4.0.0" + json-rpc-error "^2.0.0" + json-stable-stringify "^1.0.1" + promise-to-callback "^1.0.0" + readable-stream "^2.2.9" + request "^2.67.0" + semaphore "^1.0.3" + solc "^0.4.2" + tape "^4.4.0" + xhr "^2.2.0" + xtend "^4.0.1" + +web3-providers-http@1.0.0-beta.34: + version "1.0.0-beta.34" + resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.0.0-beta.34.tgz#e561b52bbb43766282007d40285bfe3550c27e7a" + dependencies: + web3-core-helpers "1.0.0-beta.34" + xhr2 "0.1.4" + +web3-providers-ipc@1.0.0-beta.34: + version "1.0.0-beta.34" + resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.0.0-beta.34.tgz#a1b77f1a306d73649a9c039052e40cb71328d00a" + dependencies: + oboe "2.1.3" + underscore "1.8.3" + web3-core-helpers "1.0.0-beta.34" + +web3-providers-ws@1.0.0-beta.34: + version "1.0.0-beta.34" + resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.0.0-beta.34.tgz#7de70f1b83f2de36476772156becfef6e3516eb3" + dependencies: + underscore "1.8.3" + web3-core-helpers "1.0.0-beta.34" + websocket "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible" + +web3-shh@1.0.0-beta.34: + version "1.0.0-beta.34" + resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.0.0-beta.34.tgz#975061d71eaec42ccee576f7bd8f70f03844afe0" + dependencies: + web3-core "1.0.0-beta.34" + web3-core-method "1.0.0-beta.34" + web3-core-subscriptions "1.0.0-beta.34" + web3-net "1.0.0-beta.34" + +web3-utils@1.0.0-beta.34, web3-utils@^1.0.0-beta.34: + version "1.0.0-beta.34" + resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.0.0-beta.34.tgz#9411fc39aaef39ca4e06169f762297d9ff020970" + dependencies: + bn.js "4.11.6" + eth-lib "0.1.27" + ethjs-unit "0.1.6" + number-to-bn "1.7.0" + randomhex "0.1.5" + underscore "1.8.3" + utf8 "2.1.1" + +web3@^0.18.4: + version "0.18.4" + resolved "https://registry.yarnpkg.com/web3/-/web3-0.18.4.tgz#81ec1784145491f2eaa8955b31c06049e07c5e7d" + dependencies: + bignumber.js "git+https://github.com/debris/bignumber.js.git#94d7146671b9719e00a09c29b01a691bc85048c2" + crypto-js "^3.1.4" + utf8 "^2.1.1" + xhr2 "*" + xmlhttprequest "*" + +web3@^1.0.0-beta.30: + version "1.0.0-beta.34" + resolved "https://registry.yarnpkg.com/web3/-/web3-1.0.0-beta.34.tgz#347e561b784098cb5563315f490479a1d91f2ab1" + dependencies: + web3-bzz "1.0.0-beta.34" + web3-core "1.0.0-beta.34" + web3-eth "1.0.0-beta.34" + web3-eth-personal "1.0.0-beta.34" + web3-net "1.0.0-beta.34" + web3-shh "1.0.0-beta.34" + web3-utils "1.0.0-beta.34" + +webidl-conversions@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" + +webpack-addons@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/webpack-addons/-/webpack-addons-1.1.5.tgz#2b178dfe873fb6e75e40a819fa5c26e4a9bc837a" + dependencies: + jscodeshift "^0.4.0" + +webpack-cli@^2.0.9: + version "2.1.2" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-2.1.2.tgz#9c9a4b90584f7b8acaf591238ef0667e04c817f6" + dependencies: + chalk "^2.3.2" + cross-spawn "^6.0.5" + diff "^3.5.0" + enhanced-resolve "^4.0.0" + envinfo "^4.4.2" + glob-all "^3.1.0" + global-modules "^1.0.0" + got "^8.2.0" + import-local "^1.0.0" + inquirer "^5.1.0" + interpret "^1.0.4" + jscodeshift "^0.5.0" + listr "^0.13.0" + loader-utils "^1.1.0" + lodash "^4.17.5" + log-symbols "^2.2.0" + mkdirp "^0.5.1" + p-each-series "^1.0.0" + p-lazy "^1.0.0" + prettier "^1.5.3" + supports-color "^5.3.0" + v8-compile-cache "^1.1.2" + webpack-addons "^1.1.5" + yargs "^11.1.0" + yeoman-environment "^2.0.0" + yeoman-generator "^2.0.4" + +webpack-sources@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54" + dependencies: + source-list-map "^2.0.0" + source-map "~0.6.1" + +webpack@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-2.7.0.tgz#b2a1226804373ffd3d03ea9c6bd525067034f6b1" + dependencies: + acorn "^5.0.0" + acorn-dynamic-import "^2.0.0" + ajv "^4.7.0" + ajv-keywords "^1.1.1" + async "^2.1.2" + enhanced-resolve "^3.3.0" + interpret "^1.0.0" + json-loader "^0.5.4" + json5 "^0.5.1" + loader-runner "^2.3.0" + loader-utils "^0.2.16" + memory-fs "~0.4.1" + mkdirp "~0.5.0" + node-libs-browser "^2.0.0" + source-map "^0.5.3" + supports-color "^3.1.0" + tapable "~0.2.5" + uglify-js "^2.8.27" + watchpack "^1.3.1" + webpack-sources "^1.0.1" + yargs "^6.0.0" + +websocket@^1.0.24: + version "1.0.26" + resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.26.tgz#a03a01299849c35268c83044aa919c6374be8194" + dependencies: + debug "^2.2.0" + nan "^2.3.3" + typedarray-to-buffer "^3.1.2" + yaeti "^0.0.6" + +"websocket@git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible": + version "1.0.24" + resolved "git://github.com/frozeman/WebSocket-Node.git#7004c39c42ac98875ab61126e5b4a925430f592c" + dependencies: + debug "^2.2.0" + nan "^2.3.3" + typedarray-to-buffer "^3.1.2" + yaeti "^0.0.6" + +whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.3.tgz#57c235bc8657e914d24e1a397d3c82daee0a6ba3" + dependencies: + iconv-lite "0.4.19" + +whatwg-mimetype@^2.0.0, whatwg-mimetype@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.1.0.tgz#f0f21d76cbba72362eb609dbed2a30cd17fcc7d4" + +whatwg-url@^6.4.0, whatwg-url@^6.4.1: + version "6.5.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.5.0.tgz#f2df02bff176fd65070df74ad5ccbb5a199965a8" + dependencies: + lodash.sortby "^4.7.0" + tr46 "^1.0.1" + webidl-conversions "^4.0.2" + +which-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + +which@1.2.x: + version "1.2.14" + resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5" + dependencies: + isexe "^2.0.0" + +which@^1.1.1, which@^1.2.14, which@^1.2.9: + version "1.3.0" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" + dependencies: + isexe "^2.0.0" + +which@^1.2.12, which@^1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" + dependencies: + string-width "^1.0.2" + +window-size@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" + +window-size@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" + +wordwrap@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" + +wordwrap@^1.0.0, wordwrap@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + +wordwrap@~0.0.2: + version "0.0.3" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +write-file-atomic@^1.2.0: + version "1.3.4" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.4.tgz#f807a4f0b1d9e913ae7a48112e6cc3af1991b45f" + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + slide "^1.1.5" + +write-file-atomic@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.3.0.tgz#1ff61575c2e2a4e8e510d6fa4e243cce183999ab" + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + signal-exit "^3.0.2" + +write@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" + dependencies: + mkdirp "^0.5.1" + +ws@^3.0.0: + version "3.3.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" + dependencies: + async-limiter "~1.0.0" + safe-buffer "~5.1.0" + ultron "~1.1.0" + +ws@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-4.1.0.tgz#a979b5d7d4da68bf54efe0408967c324869a7289" + dependencies: + async-limiter "~1.0.0" + safe-buffer "~5.1.0" + +xhr-request-promise@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/xhr-request-promise/-/xhr-request-promise-0.1.2.tgz#343c44d1ee7726b8648069682d0f840c83b4261d" + dependencies: + xhr-request "^1.0.1" + +xhr-request@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/xhr-request/-/xhr-request-1.1.0.tgz#f4a7c1868b9f198723444d82dcae317643f2e2ed" + dependencies: + buffer-to-arraybuffer "^0.0.5" + object-assign "^4.1.1" + query-string "^5.0.1" + simple-get "^2.7.0" + timed-out "^4.0.1" + url-set-query "^1.0.0" + xhr "^2.0.4" + +xhr2@*, xhr2@0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/xhr2/-/xhr2-0.1.4.tgz#7f87658847716db5026323812f818cadab387a5f" + +xhr@^2.0.4, xhr@^2.2.0, xhr@^2.3.3: + version "2.4.1" + resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.4.1.tgz#ba982cced205ae5eec387169ac9dc77ca4853d38" + dependencies: + global "~4.3.0" + is-function "^1.0.1" + parse-headers "^2.0.0" + xtend "^4.0.0" + +xml-name-validator@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" + +xml@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" + +xmlhttprequest@*, xmlhttprequest@1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc" + +xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.0, xtend@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + +xtend@~2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-2.1.2.tgz#6efecc2a4dad8e6962c4901b337ce7ba87b5d28b" + dependencies: + object-keys "~0.4.0" + +xtend@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-3.0.0.tgz#5cce7407baf642cba7becda568111c493f59665a" + +y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + +yaeti@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577" + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + +yallist@^3.0.0, yallist@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9" + +yargs-parser@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-2.4.1.tgz#85568de3cf150ff49fa51825f03a8c880ddcc5c4" + dependencies: + camelcase "^3.0.0" + lodash.assign "^4.0.6" + +yargs-parser@^4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c" + dependencies: + camelcase "^3.0.0" + +yargs-parser@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a" + dependencies: + camelcase "^3.0.0" + +yargs-parser@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-8.1.0.tgz#f1376a33b6629a5d063782944da732631e966950" + dependencies: + camelcase "^4.1.0" + +yargs-parser@^9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-9.0.2.tgz#9ccf6a43460fe4ed40a9bb68f48d43b8a68cc077" + dependencies: + camelcase "^4.1.0" + +yargs@^10.0.3: + version "10.1.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-10.1.2.tgz#454d074c2b16a51a43e2fb7807e4f9de69ccb5c5" + dependencies: + cliui "^4.0.0" + decamelize "^1.1.1" + find-up "^2.1.0" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^8.1.0" + +yargs@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.0.0.tgz#c052931006c5eee74610e5fc0354bedfd08a201b" + dependencies: + cliui "^4.0.0" + decamelize "^1.1.1" + find-up "^2.1.0" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^9.0.2" + +yargs@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.1.0.tgz#90b869934ed6e871115ea2ff58b03f4724ed2d77" + dependencies: + cliui "^4.0.0" + decamelize "^1.1.1" + find-up "^2.1.0" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^9.0.2" + +yargs@^4.6.0, yargs@^4.7.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-4.8.1.tgz#c0c42924ca4aaa6b0e6da1739dfb216439f9ddc0" + dependencies: + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + lodash.assign "^4.0.3" + 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.1" + which-module "^1.0.0" + window-size "^0.2.0" + y18n "^3.2.1" + yargs-parser "^2.4.1" + +yargs@^6.0.0: + version "6.6.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208" + dependencies: + camelcase "^3.0.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + 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.0" + +yargs@^7.0.2: + version "7.1.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8" + dependencies: + camelcase "^3.0.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + 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 "^5.0.0" + +yargs@~1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-1.2.6.tgz#9c7b4a82fd5d595b2bf17ab6dcc43135432fe34b" + dependencies: + minimist "^0.1.0" + +yargs@~3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" + dependencies: + camelcase "^1.0.2" + cliui "^2.1.0" + decamelize "^1.0.0" + window-size "0.1.0" + +yauzl@^2.4.2: + version "2.9.1" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.9.1.tgz#a81981ea70a57946133883f029c5821a89359a7f" + dependencies: + buffer-crc32 "~0.2.3" + fd-slicer "~1.0.1" + +yeoman-environment@^2.0.0, yeoman-environment@^2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/yeoman-environment/-/yeoman-environment-2.0.6.tgz#ae1b21d826b363f3d637f88a7fc9ea7414cb5377" + dependencies: + chalk "^2.1.0" + debug "^3.1.0" + diff "^3.3.1" + escape-string-regexp "^1.0.2" + globby "^6.1.0" + grouped-queue "^0.3.3" + inquirer "^3.3.0" + is-scoped "^1.0.0" + lodash "^4.17.4" + log-symbols "^2.1.0" + mem-fs "^1.1.0" + text-table "^0.2.0" + untildify "^3.0.2" + +yeoman-generator@^2.0.4: + version "2.0.5" + resolved "https://registry.yarnpkg.com/yeoman-generator/-/yeoman-generator-2.0.5.tgz#57b0b3474701293cc9ec965288f3400b00887c81" + dependencies: + async "^2.6.0" + chalk "^2.3.0" + cli-table "^0.3.1" + cross-spawn "^6.0.5" + dargs "^5.1.0" + dateformat "^3.0.3" + debug "^3.1.0" + detect-conflict "^1.0.0" + error "^7.0.2" + find-up "^2.1.0" + github-username "^4.0.0" + istextorbinary "^2.2.1" + lodash "^4.17.10" + make-dir "^1.1.0" + mem-fs-editor "^4.0.0" + minimist "^1.2.0" + pretty-bytes "^4.0.2" + read-chunk "^2.1.0" + read-pkg-up "^3.0.0" + rimraf "^2.6.2" + run-async "^2.0.0" + shelljs "^0.8.0" + text-table "^0.2.0" + through2 "^2.0.0" + yeoman-environment "^2.0.5" diff --git a/src/lib/materialize/LICENSE b/src/lib/materialize/LICENSE new file mode 100644 index 0000000..fcff17e --- /dev/null +++ b/src/lib/materialize/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014-2018 Materialize + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/lib/materialize/README.md b/src/lib/materialize/README.md new file mode 100644 index 0000000..796d6cb --- /dev/null +++ b/src/lib/materialize/README.md @@ -0,0 +1,90 @@ +

+ + + + +

MaterializeCSS

+ +

+ Materialize, a CSS Framework based on material design. +
+ -- Browse the docs -- +
+
+ + Travis CI badge + + + npm version badge + + + CDNJS version badge + + + dependencies Status badge + + + devDependency Status badge + + + Gitter badge + +

+ +## Table of Contents +- [Quickstart](#quickstart) +- [Documentation](#documentation) +- [Supported Browsers](#supported-browsers) +- [Changelog](#changelog) +- [Testing](#testing) +- [Contributing](#contributing) +- [Copyright and license](#copyright-and-license) + +## Quickstart: +Read the [getting started guide](http://materializecss.com/getting-started.html) for more information on how to use materialize. + +- [Download the latest release](https://github.com/Dogfalo/materialize/releases/latest) of materialize directly from GitHub. +- Clone the repo: `git clone https://github.com/Dogfalo/materialize.git` +- Include the files via [cdnjs](https://cdnjs.com/libraries/materialize). More [here](http://materializecss.com/getting-started.html). +- Install with [npm](https://www.npmjs.com): `npm install materialize-css` +- Install with [Bower](https://bower.io): `bower install materialize` ([DEPRECATED](https://bower.io/blog/2017/how-to-migrate-away-from-bower/)) +- Install with [Atmosphere](https://atmospherejs.com): `meteor add materialize:materialize` + +## Documentation +The documentation can be found at . To run the documentation locally on your machine, you need [Node.js](https://nodejs.org/en/) installed on your computer. + +### Running documentation locally +Run these commands to set up the documentation: + +```bash +git clone https://github.com/Dogfalo/materialize +cd materialize +npm install +``` + +Then run `grunt monitor` to compile the documentation. When it finishes, open a new browser window and navigate to `localhost:8000`. We use [BrowserSync](https://www.browsersync.io/) to display the documentation. + +### Documentation for previous releases +Previous releases and their documentation are available for [download](https://github.com/Dogfalo/materialize/releases). + +## Supported Browsers: +Materialize is compatible with: + +- Chrome 35+ +- Firefox 31+ +- Safari 9+ +- Opera +- Edge +- IE 11+ + +## Changelog +For changelogs, check out [the Releases section of materialize](https://github.com/Dogfalo/materialize/releases) or the [CHANGELOG.md](CHANGELOG.md). + +## Testing +We use Jasmine as our testing framework and we're trying to write a robust test suite for our components. If you want to help, [here's a starting guide on how to write tests in Jasmine](CONTRIBUTING.md#jasmine-testing-guide). + +## Contributing +Check out the [CONTRIBUTING document](CONTRIBUTING.md) in the root of the repository to learn how you can contribute. You can also browse the [help-wanted](https://github.com/Dogfalo/materialize/labels/help-wanted) tag in our issue tracker to find things to do. + +## Copyright and license +Code copyright 2017 Materialize. Code released under the MIT license. diff --git a/src/lib/materialize/css/materialize.css b/src/lib/materialize/css/materialize.css new file mode 100644 index 0000000..e8c513b --- /dev/null +++ b/src/lib/materialize/css/materialize.css @@ -0,0 +1,9039 @@ +/*! + * Materialize v1.0.0-beta (http://materializecss.com) + * Copyright 2014-2017 Materialize + * MIT License (https://raw.githubusercontent.com/Dogfalo/materialize/master/LICENSE) + */ +.materialize-red { + background-color: #e51c23 !important; +} + +.materialize-red-text { + color: #e51c23 !important; +} + +.materialize-red.lighten-5 { + background-color: #fdeaeb !important; +} + +.materialize-red-text.text-lighten-5 { + color: #fdeaeb !important; +} + +.materialize-red.lighten-4 { + background-color: #f8c1c3 !important; +} + +.materialize-red-text.text-lighten-4 { + color: #f8c1c3 !important; +} + +.materialize-red.lighten-3 { + background-color: #f3989b !important; +} + +.materialize-red-text.text-lighten-3 { + color: #f3989b !important; +} + +.materialize-red.lighten-2 { + background-color: #ee6e73 !important; +} + +.materialize-red-text.text-lighten-2 { + color: #ee6e73 !important; +} + +.materialize-red.lighten-1 { + background-color: #ea454b !important; +} + +.materialize-red-text.text-lighten-1 { + color: #ea454b !important; +} + +.materialize-red.darken-1 { + background-color: #d0181e !important; +} + +.materialize-red-text.text-darken-1 { + color: #d0181e !important; +} + +.materialize-red.darken-2 { + background-color: #b9151b !important; +} + +.materialize-red-text.text-darken-2 { + color: #b9151b !important; +} + +.materialize-red.darken-3 { + background-color: #a21318 !important; +} + +.materialize-red-text.text-darken-3 { + color: #a21318 !important; +} + +.materialize-red.darken-4 { + background-color: #8b1014 !important; +} + +.materialize-red-text.text-darken-4 { + color: #8b1014 !important; +} + +.red { + background-color: #F44336 !important; +} + +.red-text { + color: #F44336 !important; +} + +.red.lighten-5 { + background-color: #FFEBEE !important; +} + +.red-text.text-lighten-5 { + color: #FFEBEE !important; +} + +.red.lighten-4 { + background-color: #FFCDD2 !important; +} + +.red-text.text-lighten-4 { + color: #FFCDD2 !important; +} + +.red.lighten-3 { + background-color: #EF9A9A !important; +} + +.red-text.text-lighten-3 { + color: #EF9A9A !important; +} + +.red.lighten-2 { + background-color: #E57373 !important; +} + +.red-text.text-lighten-2 { + color: #E57373 !important; +} + +.red.lighten-1 { + background-color: #EF5350 !important; +} + +.red-text.text-lighten-1 { + color: #EF5350 !important; +} + +.red.darken-1 { + background-color: #E53935 !important; +} + +.red-text.text-darken-1 { + color: #E53935 !important; +} + +.red.darken-2 { + background-color: #D32F2F !important; +} + +.red-text.text-darken-2 { + color: #D32F2F !important; +} + +.red.darken-3 { + background-color: #C62828 !important; +} + +.red-text.text-darken-3 { + color: #C62828 !important; +} + +.red.darken-4 { + background-color: #B71C1C !important; +} + +.red-text.text-darken-4 { + color: #B71C1C !important; +} + +.red.accent-1 { + background-color: #FF8A80 !important; +} + +.red-text.text-accent-1 { + color: #FF8A80 !important; +} + +.red.accent-2 { + background-color: #FF5252 !important; +} + +.red-text.text-accent-2 { + color: #FF5252 !important; +} + +.red.accent-3 { + background-color: #FF1744 !important; +} + +.red-text.text-accent-3 { + color: #FF1744 !important; +} + +.red.accent-4 { + background-color: #D50000 !important; +} + +.red-text.text-accent-4 { + color: #D50000 !important; +} + +.pink { + background-color: #e91e63 !important; +} + +.pink-text { + color: #e91e63 !important; +} + +.pink.lighten-5 { + background-color: #fce4ec !important; +} + +.pink-text.text-lighten-5 { + color: #fce4ec !important; +} + +.pink.lighten-4 { + background-color: #f8bbd0 !important; +} + +.pink-text.text-lighten-4 { + color: #f8bbd0 !important; +} + +.pink.lighten-3 { + background-color: #f48fb1 !important; +} + +.pink-text.text-lighten-3 { + color: #f48fb1 !important; +} + +.pink.lighten-2 { + background-color: #f06292 !important; +} + +.pink-text.text-lighten-2 { + color: #f06292 !important; +} + +.pink.lighten-1 { + background-color: #ec407a !important; +} + +.pink-text.text-lighten-1 { + color: #ec407a !important; +} + +.pink.darken-1 { + background-color: #d81b60 !important; +} + +.pink-text.text-darken-1 { + color: #d81b60 !important; +} + +.pink.darken-2 { + background-color: #c2185b !important; +} + +.pink-text.text-darken-2 { + color: #c2185b !important; +} + +.pink.darken-3 { + background-color: #ad1457 !important; +} + +.pink-text.text-darken-3 { + color: #ad1457 !important; +} + +.pink.darken-4 { + background-color: #880e4f !important; +} + +.pink-text.text-darken-4 { + color: #880e4f !important; +} + +.pink.accent-1 { + background-color: #ff80ab !important; +} + +.pink-text.text-accent-1 { + color: #ff80ab !important; +} + +.pink.accent-2 { + background-color: #ff4081 !important; +} + +.pink-text.text-accent-2 { + color: #ff4081 !important; +} + +.pink.accent-3 { + background-color: #f50057 !important; +} + +.pink-text.text-accent-3 { + color: #f50057 !important; +} + +.pink.accent-4 { + background-color: #c51162 !important; +} + +.pink-text.text-accent-4 { + color: #c51162 !important; +} + +.purple { + background-color: #9c27b0 !important; +} + +.purple-text { + color: #9c27b0 !important; +} + +.purple.lighten-5 { + background-color: #f3e5f5 !important; +} + +.purple-text.text-lighten-5 { + color: #f3e5f5 !important; +} + +.purple.lighten-4 { + background-color: #e1bee7 !important; +} + +.purple-text.text-lighten-4 { + color: #e1bee7 !important; +} + +.purple.lighten-3 { + background-color: #ce93d8 !important; +} + +.purple-text.text-lighten-3 { + color: #ce93d8 !important; +} + +.purple.lighten-2 { + background-color: #ba68c8 !important; +} + +.purple-text.text-lighten-2 { + color: #ba68c8 !important; +} + +.purple.lighten-1 { + background-color: #ab47bc !important; +} + +.purple-text.text-lighten-1 { + color: #ab47bc !important; +} + +.purple.darken-1 { + background-color: #8e24aa !important; +} + +.purple-text.text-darken-1 { + color: #8e24aa !important; +} + +.purple.darken-2 { + background-color: #7b1fa2 !important; +} + +.purple-text.text-darken-2 { + color: #7b1fa2 !important; +} + +.purple.darken-3 { + background-color: #6a1b9a !important; +} + +.purple-text.text-darken-3 { + color: #6a1b9a !important; +} + +.purple.darken-4 { + background-color: #4a148c !important; +} + +.purple-text.text-darken-4 { + color: #4a148c !important; +} + +.purple.accent-1 { + background-color: #ea80fc !important; +} + +.purple-text.text-accent-1 { + color: #ea80fc !important; +} + +.purple.accent-2 { + background-color: #e040fb !important; +} + +.purple-text.text-accent-2 { + color: #e040fb !important; +} + +.purple.accent-3 { + background-color: #d500f9 !important; +} + +.purple-text.text-accent-3 { + color: #d500f9 !important; +} + +.purple.accent-4 { + background-color: #aa00ff !important; +} + +.purple-text.text-accent-4 { + color: #aa00ff !important; +} + +.deep-purple { + background-color: #673ab7 !important; +} + +.deep-purple-text { + color: #673ab7 !important; +} + +.deep-purple.lighten-5 { + background-color: #ede7f6 !important; +} + +.deep-purple-text.text-lighten-5 { + color: #ede7f6 !important; +} + +.deep-purple.lighten-4 { + background-color: #d1c4e9 !important; +} + +.deep-purple-text.text-lighten-4 { + color: #d1c4e9 !important; +} + +.deep-purple.lighten-3 { + background-color: #b39ddb !important; +} + +.deep-purple-text.text-lighten-3 { + color: #b39ddb !important; +} + +.deep-purple.lighten-2 { + background-color: #9575cd !important; +} + +.deep-purple-text.text-lighten-2 { + color: #9575cd !important; +} + +.deep-purple.lighten-1 { + background-color: #7e57c2 !important; +} + +.deep-purple-text.text-lighten-1 { + color: #7e57c2 !important; +} + +.deep-purple.darken-1 { + background-color: #5e35b1 !important; +} + +.deep-purple-text.text-darken-1 { + color: #5e35b1 !important; +} + +.deep-purple.darken-2 { + background-color: #512da8 !important; +} + +.deep-purple-text.text-darken-2 { + color: #512da8 !important; +} + +.deep-purple.darken-3 { + background-color: #4527a0 !important; +} + +.deep-purple-text.text-darken-3 { + color: #4527a0 !important; +} + +.deep-purple.darken-4 { + background-color: #311b92 !important; +} + +.deep-purple-text.text-darken-4 { + color: #311b92 !important; +} + +.deep-purple.accent-1 { + background-color: #b388ff !important; +} + +.deep-purple-text.text-accent-1 { + color: #b388ff !important; +} + +.deep-purple.accent-2 { + background-color: #7c4dff !important; +} + +.deep-purple-text.text-accent-2 { + color: #7c4dff !important; +} + +.deep-purple.accent-3 { + background-color: #651fff !important; +} + +.deep-purple-text.text-accent-3 { + color: #651fff !important; +} + +.deep-purple.accent-4 { + background-color: #6200ea !important; +} + +.deep-purple-text.text-accent-4 { + color: #6200ea !important; +} + +.indigo { + background-color: #3f51b5 !important; +} + +.indigo-text { + color: #3f51b5 !important; +} + +.indigo.lighten-5 { + background-color: #e8eaf6 !important; +} + +.indigo-text.text-lighten-5 { + color: #e8eaf6 !important; +} + +.indigo.lighten-4 { + background-color: #c5cae9 !important; +} + +.indigo-text.text-lighten-4 { + color: #c5cae9 !important; +} + +.indigo.lighten-3 { + background-color: #9fa8da !important; +} + +.indigo-text.text-lighten-3 { + color: #9fa8da !important; +} + +.indigo.lighten-2 { + background-color: #7986cb !important; +} + +.indigo-text.text-lighten-2 { + color: #7986cb !important; +} + +.indigo.lighten-1 { + background-color: #5c6bc0 !important; +} + +.indigo-text.text-lighten-1 { + color: #5c6bc0 !important; +} + +.indigo.darken-1 { + background-color: #3949ab !important; +} + +.indigo-text.text-darken-1 { + color: #3949ab !important; +} + +.indigo.darken-2 { + background-color: #303f9f !important; +} + +.indigo-text.text-darken-2 { + color: #303f9f !important; +} + +.indigo.darken-3 { + background-color: #283593 !important; +} + +.indigo-text.text-darken-3 { + color: #283593 !important; +} + +.indigo.darken-4 { + background-color: #1a237e !important; +} + +.indigo-text.text-darken-4 { + color: #1a237e !important; +} + +.indigo.accent-1 { + background-color: #8c9eff !important; +} + +.indigo-text.text-accent-1 { + color: #8c9eff !important; +} + +.indigo.accent-2 { + background-color: #536dfe !important; +} + +.indigo-text.text-accent-2 { + color: #536dfe !important; +} + +.indigo.accent-3 { + background-color: #3d5afe !important; +} + +.indigo-text.text-accent-3 { + color: #3d5afe !important; +} + +.indigo.accent-4 { + background-color: #304ffe !important; +} + +.indigo-text.text-accent-4 { + color: #304ffe !important; +} + +.blue { + background-color: #2196F3 !important; +} + +.blue-text { + color: #2196F3 !important; +} + +.blue.lighten-5 { + background-color: #E3F2FD !important; +} + +.blue-text.text-lighten-5 { + color: #E3F2FD !important; +} + +.blue.lighten-4 { + background-color: #BBDEFB !important; +} + +.blue-text.text-lighten-4 { + color: #BBDEFB !important; +} + +.blue.lighten-3 { + background-color: #90CAF9 !important; +} + +.blue-text.text-lighten-3 { + color: #90CAF9 !important; +} + +.blue.lighten-2 { + background-color: #64B5F6 !important; +} + +.blue-text.text-lighten-2 { + color: #64B5F6 !important; +} + +.blue.lighten-1 { + background-color: #42A5F5 !important; +} + +.blue-text.text-lighten-1 { + color: #42A5F5 !important; +} + +.blue.darken-1 { + background-color: #1E88E5 !important; +} + +.blue-text.text-darken-1 { + color: #1E88E5 !important; +} + +.blue.darken-2 { + background-color: #1976D2 !important; +} + +.blue-text.text-darken-2 { + color: #1976D2 !important; +} + +.blue.darken-3 { + background-color: #1565C0 !important; +} + +.blue-text.text-darken-3 { + color: #1565C0 !important; +} + +.blue.darken-4 { + background-color: #0D47A1 !important; +} + +.blue-text.text-darken-4 { + color: #0D47A1 !important; +} + +.blue.accent-1 { + background-color: #82B1FF !important; +} + +.blue-text.text-accent-1 { + color: #82B1FF !important; +} + +.blue.accent-2 { + background-color: #448AFF !important; +} + +.blue-text.text-accent-2 { + color: #448AFF !important; +} + +.blue.accent-3 { + background-color: #2979FF !important; +} + +.blue-text.text-accent-3 { + color: #2979FF !important; +} + +.blue.accent-4 { + background-color: #2962FF !important; +} + +.blue-text.text-accent-4 { + color: #2962FF !important; +} + +.light-blue { + background-color: #03a9f4 !important; +} + +.light-blue-text { + color: #03a9f4 !important; +} + +.light-blue.lighten-5 { + background-color: #e1f5fe !important; +} + +.light-blue-text.text-lighten-5 { + color: #e1f5fe !important; +} + +.light-blue.lighten-4 { + background-color: #b3e5fc !important; +} + +.light-blue-text.text-lighten-4 { + color: #b3e5fc !important; +} + +.light-blue.lighten-3 { + background-color: #81d4fa !important; +} + +.light-blue-text.text-lighten-3 { + color: #81d4fa !important; +} + +.light-blue.lighten-2 { + background-color: #4fc3f7 !important; +} + +.light-blue-text.text-lighten-2 { + color: #4fc3f7 !important; +} + +.light-blue.lighten-1 { + background-color: #29b6f6 !important; +} + +.light-blue-text.text-lighten-1 { + color: #29b6f6 !important; +} + +.light-blue.darken-1 { + background-color: #039be5 !important; +} + +.light-blue-text.text-darken-1 { + color: #039be5 !important; +} + +.light-blue.darken-2 { + background-color: #0288d1 !important; +} + +.light-blue-text.text-darken-2 { + color: #0288d1 !important; +} + +.light-blue.darken-3 { + background-color: #0277bd !important; +} + +.light-blue-text.text-darken-3 { + color: #0277bd !important; +} + +.light-blue.darken-4 { + background-color: #01579b !important; +} + +.light-blue-text.text-darken-4 { + color: #01579b !important; +} + +.light-blue.accent-1 { + background-color: #80d8ff !important; +} + +.light-blue-text.text-accent-1 { + color: #80d8ff !important; +} + +.light-blue.accent-2 { + background-color: #40c4ff !important; +} + +.light-blue-text.text-accent-2 { + color: #40c4ff !important; +} + +.light-blue.accent-3 { + background-color: #00b0ff !important; +} + +.light-blue-text.text-accent-3 { + color: #00b0ff !important; +} + +.light-blue.accent-4 { + background-color: #0091ea !important; +} + +.light-blue-text.text-accent-4 { + color: #0091ea !important; +} + +.cyan { + background-color: #00bcd4 !important; +} + +.cyan-text { + color: #00bcd4 !important; +} + +.cyan.lighten-5 { + background-color: #e0f7fa !important; +} + +.cyan-text.text-lighten-5 { + color: #e0f7fa !important; +} + +.cyan.lighten-4 { + background-color: #b2ebf2 !important; +} + +.cyan-text.text-lighten-4 { + color: #b2ebf2 !important; +} + +.cyan.lighten-3 { + background-color: #80deea !important; +} + +.cyan-text.text-lighten-3 { + color: #80deea !important; +} + +.cyan.lighten-2 { + background-color: #4dd0e1 !important; +} + +.cyan-text.text-lighten-2 { + color: #4dd0e1 !important; +} + +.cyan.lighten-1 { + background-color: #26c6da !important; +} + +.cyan-text.text-lighten-1 { + color: #26c6da !important; +} + +.cyan.darken-1 { + background-color: #00acc1 !important; +} + +.cyan-text.text-darken-1 { + color: #00acc1 !important; +} + +.cyan.darken-2 { + background-color: #0097a7 !important; +} + +.cyan-text.text-darken-2 { + color: #0097a7 !important; +} + +.cyan.darken-3 { + background-color: #00838f !important; +} + +.cyan-text.text-darken-3 { + color: #00838f !important; +} + +.cyan.darken-4 { + background-color: #006064 !important; +} + +.cyan-text.text-darken-4 { + color: #006064 !important; +} + +.cyan.accent-1 { + background-color: #84ffff !important; +} + +.cyan-text.text-accent-1 { + color: #84ffff !important; +} + +.cyan.accent-2 { + background-color: #18ffff !important; +} + +.cyan-text.text-accent-2 { + color: #18ffff !important; +} + +.cyan.accent-3 { + background-color: #00e5ff !important; +} + +.cyan-text.text-accent-3 { + color: #00e5ff !important; +} + +.cyan.accent-4 { + background-color: #00b8d4 !important; +} + +.cyan-text.text-accent-4 { + color: #00b8d4 !important; +} + +.teal { + background-color: #009688 !important; +} + +.teal-text { + color: #009688 !important; +} + +.teal.lighten-5 { + background-color: #e0f2f1 !important; +} + +.teal-text.text-lighten-5 { + color: #e0f2f1 !important; +} + +.teal.lighten-4 { + background-color: #b2dfdb !important; +} + +.teal-text.text-lighten-4 { + color: #b2dfdb !important; +} + +.teal.lighten-3 { + background-color: #80cbc4 !important; +} + +.teal-text.text-lighten-3 { + color: #80cbc4 !important; +} + +.teal.lighten-2 { + background-color: #4db6ac !important; +} + +.teal-text.text-lighten-2 { + color: #4db6ac !important; +} + +.teal.lighten-1 { + background-color: #26a69a !important; +} + +.teal-text.text-lighten-1 { + color: #26a69a !important; +} + +.teal.darken-1 { + background-color: #00897b !important; +} + +.teal-text.text-darken-1 { + color: #00897b !important; +} + +.teal.darken-2 { + background-color: #00796b !important; +} + +.teal-text.text-darken-2 { + color: #00796b !important; +} + +.teal.darken-3 { + background-color: #00695c !important; +} + +.teal-text.text-darken-3 { + color: #00695c !important; +} + +.teal.darken-4 { + background-color: #004d40 !important; +} + +.teal-text.text-darken-4 { + color: #004d40 !important; +} + +.teal.accent-1 { + background-color: #a7ffeb !important; +} + +.teal-text.text-accent-1 { + color: #a7ffeb !important; +} + +.teal.accent-2 { + background-color: #64ffda !important; +} + +.teal-text.text-accent-2 { + color: #64ffda !important; +} + +.teal.accent-3 { + background-color: #1de9b6 !important; +} + +.teal-text.text-accent-3 { + color: #1de9b6 !important; +} + +.teal.accent-4 { + background-color: #00bfa5 !important; +} + +.teal-text.text-accent-4 { + color: #00bfa5 !important; +} + +.green { + background-color: #4CAF50 !important; +} + +.green-text { + color: #4CAF50 !important; +} + +.green.lighten-5 { + background-color: #E8F5E9 !important; +} + +.green-text.text-lighten-5 { + color: #E8F5E9 !important; +} + +.green.lighten-4 { + background-color: #C8E6C9 !important; +} + +.green-text.text-lighten-4 { + color: #C8E6C9 !important; +} + +.green.lighten-3 { + background-color: #A5D6A7 !important; +} + +.green-text.text-lighten-3 { + color: #A5D6A7 !important; +} + +.green.lighten-2 { + background-color: #81C784 !important; +} + +.green-text.text-lighten-2 { + color: #81C784 !important; +} + +.green.lighten-1 { + background-color: #66BB6A !important; +} + +.green-text.text-lighten-1 { + color: #66BB6A !important; +} + +.green.darken-1 { + background-color: #43A047 !important; +} + +.green-text.text-darken-1 { + color: #43A047 !important; +} + +.green.darken-2 { + background-color: #388E3C !important; +} + +.green-text.text-darken-2 { + color: #388E3C !important; +} + +.green.darken-3 { + background-color: #2E7D32 !important; +} + +.green-text.text-darken-3 { + color: #2E7D32 !important; +} + +.green.darken-4 { + background-color: #1B5E20 !important; +} + +.green-text.text-darken-4 { + color: #1B5E20 !important; +} + +.green.accent-1 { + background-color: #B9F6CA !important; +} + +.green-text.text-accent-1 { + color: #B9F6CA !important; +} + +.green.accent-2 { + background-color: #69F0AE !important; +} + +.green-text.text-accent-2 { + color: #69F0AE !important; +} + +.green.accent-3 { + background-color: #00E676 !important; +} + +.green-text.text-accent-3 { + color: #00E676 !important; +} + +.green.accent-4 { + background-color: #00C853 !important; +} + +.green-text.text-accent-4 { + color: #00C853 !important; +} + +.light-green { + background-color: #8bc34a !important; +} + +.light-green-text { + color: #8bc34a !important; +} + +.light-green.lighten-5 { + background-color: #f1f8e9 !important; +} + +.light-green-text.text-lighten-5 { + color: #f1f8e9 !important; +} + +.light-green.lighten-4 { + background-color: #dcedc8 !important; +} + +.light-green-text.text-lighten-4 { + color: #dcedc8 !important; +} + +.light-green.lighten-3 { + background-color: #c5e1a5 !important; +} + +.light-green-text.text-lighten-3 { + color: #c5e1a5 !important; +} + +.light-green.lighten-2 { + background-color: #aed581 !important; +} + +.light-green-text.text-lighten-2 { + color: #aed581 !important; +} + +.light-green.lighten-1 { + background-color: #9ccc65 !important; +} + +.light-green-text.text-lighten-1 { + color: #9ccc65 !important; +} + +.light-green.darken-1 { + background-color: #7cb342 !important; +} + +.light-green-text.text-darken-1 { + color: #7cb342 !important; +} + +.light-green.darken-2 { + background-color: #689f38 !important; +} + +.light-green-text.text-darken-2 { + color: #689f38 !important; +} + +.light-green.darken-3 { + background-color: #558b2f !important; +} + +.light-green-text.text-darken-3 { + color: #558b2f !important; +} + +.light-green.darken-4 { + background-color: #33691e !important; +} + +.light-green-text.text-darken-4 { + color: #33691e !important; +} + +.light-green.accent-1 { + background-color: #ccff90 !important; +} + +.light-green-text.text-accent-1 { + color: #ccff90 !important; +} + +.light-green.accent-2 { + background-color: #b2ff59 !important; +} + +.light-green-text.text-accent-2 { + color: #b2ff59 !important; +} + +.light-green.accent-3 { + background-color: #76ff03 !important; +} + +.light-green-text.text-accent-3 { + color: #76ff03 !important; +} + +.light-green.accent-4 { + background-color: #64dd17 !important; +} + +.light-green-text.text-accent-4 { + color: #64dd17 !important; +} + +.lime { + background-color: #cddc39 !important; +} + +.lime-text { + color: #cddc39 !important; +} + +.lime.lighten-5 { + background-color: #f9fbe7 !important; +} + +.lime-text.text-lighten-5 { + color: #f9fbe7 !important; +} + +.lime.lighten-4 { + background-color: #f0f4c3 !important; +} + +.lime-text.text-lighten-4 { + color: #f0f4c3 !important; +} + +.lime.lighten-3 { + background-color: #e6ee9c !important; +} + +.lime-text.text-lighten-3 { + color: #e6ee9c !important; +} + +.lime.lighten-2 { + background-color: #dce775 !important; +} + +.lime-text.text-lighten-2 { + color: #dce775 !important; +} + +.lime.lighten-1 { + background-color: #d4e157 !important; +} + +.lime-text.text-lighten-1 { + color: #d4e157 !important; +} + +.lime.darken-1 { + background-color: #c0ca33 !important; +} + +.lime-text.text-darken-1 { + color: #c0ca33 !important; +} + +.lime.darken-2 { + background-color: #afb42b !important; +} + +.lime-text.text-darken-2 { + color: #afb42b !important; +} + +.lime.darken-3 { + background-color: #9e9d24 !important; +} + +.lime-text.text-darken-3 { + color: #9e9d24 !important; +} + +.lime.darken-4 { + background-color: #827717 !important; +} + +.lime-text.text-darken-4 { + color: #827717 !important; +} + +.lime.accent-1 { + background-color: #f4ff81 !important; +} + +.lime-text.text-accent-1 { + color: #f4ff81 !important; +} + +.lime.accent-2 { + background-color: #eeff41 !important; +} + +.lime-text.text-accent-2 { + color: #eeff41 !important; +} + +.lime.accent-3 { + background-color: #c6ff00 !important; +} + +.lime-text.text-accent-3 { + color: #c6ff00 !important; +} + +.lime.accent-4 { + background-color: #aeea00 !important; +} + +.lime-text.text-accent-4 { + color: #aeea00 !important; +} + +.yellow { + background-color: #ffeb3b !important; +} + +.yellow-text { + color: #ffeb3b !important; +} + +.yellow.lighten-5 { + background-color: #fffde7 !important; +} + +.yellow-text.text-lighten-5 { + color: #fffde7 !important; +} + +.yellow.lighten-4 { + background-color: #fff9c4 !important; +} + +.yellow-text.text-lighten-4 { + color: #fff9c4 !important; +} + +.yellow.lighten-3 { + background-color: #fff59d !important; +} + +.yellow-text.text-lighten-3 { + color: #fff59d !important; +} + +.yellow.lighten-2 { + background-color: #fff176 !important; +} + +.yellow-text.text-lighten-2 { + color: #fff176 !important; +} + +.yellow.lighten-1 { + background-color: #ffee58 !important; +} + +.yellow-text.text-lighten-1 { + color: #ffee58 !important; +} + +.yellow.darken-1 { + background-color: #fdd835 !important; +} + +.yellow-text.text-darken-1 { + color: #fdd835 !important; +} + +.yellow.darken-2 { + background-color: #fbc02d !important; +} + +.yellow-text.text-darken-2 { + color: #fbc02d !important; +} + +.yellow.darken-3 { + background-color: #f9a825 !important; +} + +.yellow-text.text-darken-3 { + color: #f9a825 !important; +} + +.yellow.darken-4 { + background-color: #f57f17 !important; +} + +.yellow-text.text-darken-4 { + color: #f57f17 !important; +} + +.yellow.accent-1 { + background-color: #ffff8d !important; +} + +.yellow-text.text-accent-1 { + color: #ffff8d !important; +} + +.yellow.accent-2 { + background-color: #ffff00 !important; +} + +.yellow-text.text-accent-2 { + color: #ffff00 !important; +} + +.yellow.accent-3 { + background-color: #ffea00 !important; +} + +.yellow-text.text-accent-3 { + color: #ffea00 !important; +} + +.yellow.accent-4 { + background-color: #ffd600 !important; +} + +.yellow-text.text-accent-4 { + color: #ffd600 !important; +} + +.amber { + background-color: #ffc107 !important; +} + +.amber-text { + color: #ffc107 !important; +} + +.amber.lighten-5 { + background-color: #fff8e1 !important; +} + +.amber-text.text-lighten-5 { + color: #fff8e1 !important; +} + +.amber.lighten-4 { + background-color: #ffecb3 !important; +} + +.amber-text.text-lighten-4 { + color: #ffecb3 !important; +} + +.amber.lighten-3 { + background-color: #ffe082 !important; +} + +.amber-text.text-lighten-3 { + color: #ffe082 !important; +} + +.amber.lighten-2 { + background-color: #ffd54f !important; +} + +.amber-text.text-lighten-2 { + color: #ffd54f !important; +} + +.amber.lighten-1 { + background-color: #ffca28 !important; +} + +.amber-text.text-lighten-1 { + color: #ffca28 !important; +} + +.amber.darken-1 { + background-color: #ffb300 !important; +} + +.amber-text.text-darken-1 { + color: #ffb300 !important; +} + +.amber.darken-2 { + background-color: #ffa000 !important; +} + +.amber-text.text-darken-2 { + color: #ffa000 !important; +} + +.amber.darken-3 { + background-color: #ff8f00 !important; +} + +.amber-text.text-darken-3 { + color: #ff8f00 !important; +} + +.amber.darken-4 { + background-color: #ff6f00 !important; +} + +.amber-text.text-darken-4 { + color: #ff6f00 !important; +} + +.amber.accent-1 { + background-color: #ffe57f !important; +} + +.amber-text.text-accent-1 { + color: #ffe57f !important; +} + +.amber.accent-2 { + background-color: #ffd740 !important; +} + +.amber-text.text-accent-2 { + color: #ffd740 !important; +} + +.amber.accent-3 { + background-color: #ffc400 !important; +} + +.amber-text.text-accent-3 { + color: #ffc400 !important; +} + +.amber.accent-4 { + background-color: #ffab00 !important; +} + +.amber-text.text-accent-4 { + color: #ffab00 !important; +} + +.orange { + background-color: #ff9800 !important; +} + +.orange-text { + color: #ff9800 !important; +} + +.orange.lighten-5 { + background-color: #fff3e0 !important; +} + +.orange-text.text-lighten-5 { + color: #fff3e0 !important; +} + +.orange.lighten-4 { + background-color: #ffe0b2 !important; +} + +.orange-text.text-lighten-4 { + color: #ffe0b2 !important; +} + +.orange.lighten-3 { + background-color: #ffcc80 !important; +} + +.orange-text.text-lighten-3 { + color: #ffcc80 !important; +} + +.orange.lighten-2 { + background-color: #ffb74d !important; +} + +.orange-text.text-lighten-2 { + color: #ffb74d !important; +} + +.orange.lighten-1 { + background-color: #ffa726 !important; +} + +.orange-text.text-lighten-1 { + color: #ffa726 !important; +} + +.orange.darken-1 { + background-color: #fb8c00 !important; +} + +.orange-text.text-darken-1 { + color: #fb8c00 !important; +} + +.orange.darken-2 { + background-color: #f57c00 !important; +} + +.orange-text.text-darken-2 { + color: #f57c00 !important; +} + +.orange.darken-3 { + background-color: #ef6c00 !important; +} + +.orange-text.text-darken-3 { + color: #ef6c00 !important; +} + +.orange.darken-4 { + background-color: #e65100 !important; +} + +.orange-text.text-darken-4 { + color: #e65100 !important; +} + +.orange.accent-1 { + background-color: #ffd180 !important; +} + +.orange-text.text-accent-1 { + color: #ffd180 !important; +} + +.orange.accent-2 { + background-color: #ffab40 !important; +} + +.orange-text.text-accent-2 { + color: #ffab40 !important; +} + +.orange.accent-3 { + background-color: #ff9100 !important; +} + +.orange-text.text-accent-3 { + color: #ff9100 !important; +} + +.orange.accent-4 { + background-color: #ff6d00 !important; +} + +.orange-text.text-accent-4 { + color: #ff6d00 !important; +} + +.deep-orange { + background-color: #ff5722 !important; +} + +.deep-orange-text { + color: #ff5722 !important; +} + +.deep-orange.lighten-5 { + background-color: #fbe9e7 !important; +} + +.deep-orange-text.text-lighten-5 { + color: #fbe9e7 !important; +} + +.deep-orange.lighten-4 { + background-color: #ffccbc !important; +} + +.deep-orange-text.text-lighten-4 { + color: #ffccbc !important; +} + +.deep-orange.lighten-3 { + background-color: #ffab91 !important; +} + +.deep-orange-text.text-lighten-3 { + color: #ffab91 !important; +} + +.deep-orange.lighten-2 { + background-color: #ff8a65 !important; +} + +.deep-orange-text.text-lighten-2 { + color: #ff8a65 !important; +} + +.deep-orange.lighten-1 { + background-color: #ff7043 !important; +} + +.deep-orange-text.text-lighten-1 { + color: #ff7043 !important; +} + +.deep-orange.darken-1 { + background-color: #f4511e !important; +} + +.deep-orange-text.text-darken-1 { + color: #f4511e !important; +} + +.deep-orange.darken-2 { + background-color: #e64a19 !important; +} + +.deep-orange-text.text-darken-2 { + color: #e64a19 !important; +} + +.deep-orange.darken-3 { + background-color: #d84315 !important; +} + +.deep-orange-text.text-darken-3 { + color: #d84315 !important; +} + +.deep-orange.darken-4 { + background-color: #bf360c !important; +} + +.deep-orange-text.text-darken-4 { + color: #bf360c !important; +} + +.deep-orange.accent-1 { + background-color: #ff9e80 !important; +} + +.deep-orange-text.text-accent-1 { + color: #ff9e80 !important; +} + +.deep-orange.accent-2 { + background-color: #ff6e40 !important; +} + +.deep-orange-text.text-accent-2 { + color: #ff6e40 !important; +} + +.deep-orange.accent-3 { + background-color: #ff3d00 !important; +} + +.deep-orange-text.text-accent-3 { + color: #ff3d00 !important; +} + +.deep-orange.accent-4 { + background-color: #dd2c00 !important; +} + +.deep-orange-text.text-accent-4 { + color: #dd2c00 !important; +} + +.brown { + background-color: #795548 !important; +} + +.brown-text { + color: #795548 !important; +} + +.brown.lighten-5 { + background-color: #efebe9 !important; +} + +.brown-text.text-lighten-5 { + color: #efebe9 !important; +} + +.brown.lighten-4 { + background-color: #d7ccc8 !important; +} + +.brown-text.text-lighten-4 { + color: #d7ccc8 !important; +} + +.brown.lighten-3 { + background-color: #bcaaa4 !important; +} + +.brown-text.text-lighten-3 { + color: #bcaaa4 !important; +} + +.brown.lighten-2 { + background-color: #a1887f !important; +} + +.brown-text.text-lighten-2 { + color: #a1887f !important; +} + +.brown.lighten-1 { + background-color: #8d6e63 !important; +} + +.brown-text.text-lighten-1 { + color: #8d6e63 !important; +} + +.brown.darken-1 { + background-color: #6d4c41 !important; +} + +.brown-text.text-darken-1 { + color: #6d4c41 !important; +} + +.brown.darken-2 { + background-color: #5d4037 !important; +} + +.brown-text.text-darken-2 { + color: #5d4037 !important; +} + +.brown.darken-3 { + background-color: #4e342e !important; +} + +.brown-text.text-darken-3 { + color: #4e342e !important; +} + +.brown.darken-4 { + background-color: #3e2723 !important; +} + +.brown-text.text-darken-4 { + color: #3e2723 !important; +} + +.blue-grey { + background-color: #607d8b !important; +} + +.blue-grey-text { + color: #607d8b !important; +} + +.blue-grey.lighten-5 { + background-color: #eceff1 !important; +} + +.blue-grey-text.text-lighten-5 { + color: #eceff1 !important; +} + +.blue-grey.lighten-4 { + background-color: #cfd8dc !important; +} + +.blue-grey-text.text-lighten-4 { + color: #cfd8dc !important; +} + +.blue-grey.lighten-3 { + background-color: #b0bec5 !important; +} + +.blue-grey-text.text-lighten-3 { + color: #b0bec5 !important; +} + +.blue-grey.lighten-2 { + background-color: #90a4ae !important; +} + +.blue-grey-text.text-lighten-2 { + color: #90a4ae !important; +} + +.blue-grey.lighten-1 { + background-color: #78909c !important; +} + +.blue-grey-text.text-lighten-1 { + color: #78909c !important; +} + +.blue-grey.darken-1 { + background-color: #546e7a !important; +} + +.blue-grey-text.text-darken-1 { + color: #546e7a !important; +} + +.blue-grey.darken-2 { + background-color: #455a64 !important; +} + +.blue-grey-text.text-darken-2 { + color: #455a64 !important; +} + +.blue-grey.darken-3 { + background-color: #37474f !important; +} + +.blue-grey-text.text-darken-3 { + color: #37474f !important; +} + +.blue-grey.darken-4 { + background-color: #263238 !important; +} + +.blue-grey-text.text-darken-4 { + color: #263238 !important; +} + +.grey { + background-color: #9e9e9e !important; +} + +.grey-text { + color: #9e9e9e !important; +} + +.grey.lighten-5 { + background-color: #fafafa !important; +} + +.grey-text.text-lighten-5 { + color: #fafafa !important; +} + +.grey.lighten-4 { + background-color: #f5f5f5 !important; +} + +.grey-text.text-lighten-4 { + color: #f5f5f5 !important; +} + +.grey.lighten-3 { + background-color: #eeeeee !important; +} + +.grey-text.text-lighten-3 { + color: #eeeeee !important; +} + +.grey.lighten-2 { + background-color: #e0e0e0 !important; +} + +.grey-text.text-lighten-2 { + color: #e0e0e0 !important; +} + +.grey.lighten-1 { + background-color: #bdbdbd !important; +} + +.grey-text.text-lighten-1 { + color: #bdbdbd !important; +} + +.grey.darken-1 { + background-color: #757575 !important; +} + +.grey-text.text-darken-1 { + color: #757575 !important; +} + +.grey.darken-2 { + background-color: #616161 !important; +} + +.grey-text.text-darken-2 { + color: #616161 !important; +} + +.grey.darken-3 { + background-color: #424242 !important; +} + +.grey-text.text-darken-3 { + color: #424242 !important; +} + +.grey.darken-4 { + background-color: #212121 !important; +} + +.grey-text.text-darken-4 { + color: #212121 !important; +} + +.black { + background-color: #000000 !important; +} + +.black-text { + color: #000000 !important; +} + +.white { + background-color: #FFFFFF !important; +} + +.white-text { + color: #FFFFFF !important; +} + +.transparent { + background-color: transparent !important; +} + +.transparent-text { + color: transparent !important; +} + +/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */ +/* Document + ========================================================================== */ +/** + * 1. Correct the line height in all browsers. + * 2. Prevent adjustments of font size after orientation changes in + * IE on Windows Phone and in iOS. + */ +html { + line-height: 1.15; + /* 1 */ + -ms-text-size-adjust: 100%; + /* 2 */ + -webkit-text-size-adjust: 100%; + /* 2 */ +} + +/* Sections + ========================================================================== */ +/** + * Remove the margin in all browsers (opinionated). + */ +body { + margin: 0; +} + +/** + * Add the correct display in IE 9-. + */ +article, +aside, +footer, +header, +nav, +section { + display: block; +} + +/** + * Correct the font size and margin on `h1` elements within `section` and + * `article` contexts in Chrome, Firefox, and Safari. + */ +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/* Grouping content + ========================================================================== */ +/** + * Add the correct display in IE 9-. + * 1. Add the correct display in IE. + */ +figcaption, +figure, +main { + /* 1 */ + display: block; +} + +/** + * Add the correct margin in IE 8. + */ +figure { + margin: 1em 40px; +} + +/** + * 1. Add the correct box sizing in Firefox. + * 2. Show the overflow in Edge and IE. + */ +hr { + -webkit-box-sizing: content-box; + box-sizing: content-box; + /* 1 */ + height: 0; + /* 1 */ + overflow: visible; + /* 2 */ +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ +pre { + font-family: monospace, monospace; + /* 1 */ + font-size: 1em; + /* 2 */ +} + +/* Text-level semantics + ========================================================================== */ +/** + * 1. Remove the gray background on active links in IE 10. + * 2. Remove gaps in links underline in iOS 8+ and Safari 8+. + */ +a { + background-color: transparent; + /* 1 */ + -webkit-text-decoration-skip: objects; + /* 2 */ +} + +/** + * 1. Remove the bottom border in Chrome 57- and Firefox 39-. + * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. + */ +abbr[title] { + border-bottom: none; + /* 1 */ + text-decoration: underline; + /* 2 */ + -webkit-text-decoration: underline dotted; + -moz-text-decoration: underline dotted; + text-decoration: underline dotted; + /* 2 */ +} + +/** + * Prevent the duplicate application of `bolder` by the next rule in Safari 6. + */ +b, +strong { + font-weight: inherit; +} + +/** + * Add the correct font weight in Chrome, Edge, and Safari. + */ +b, +strong { + font-weight: bolder; +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ +code, +kbd, +samp { + font-family: monospace, monospace; + /* 1 */ + font-size: 1em; + /* 2 */ +} + +/** + * Add the correct font style in Android 4.3-. + */ +dfn { + font-style: italic; +} + +/** + * Add the correct background and color in IE 9-. + */ +mark { + background-color: #ff0; + color: #000; +} + +/** + * Add the correct font size in all browsers. + */ +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` elements from affecting the line height in + * all browsers. + */ +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* Embedded content + ========================================================================== */ +/** + * Add the correct display in IE 9-. + */ +audio, +video { + display: inline-block; +} + +/** + * Add the correct display in iOS 4-7. + */ +audio:not([controls]) { + display: none; + height: 0; +} + +/** + * Remove the border on images inside links in IE 10-. + */ +img { + border-style: none; +} + +/** + * Hide the overflow in IE. + */ +svg:not(:root) { + overflow: hidden; +} + +/* Forms + ========================================================================== */ +/** + * 1. Change the font styles in all browsers (opinionated). + * 2. Remove the margin in Firefox and Safari. + */ +button, +input, +optgroup, +select, +textarea { + font-family: sans-serif; + /* 1 */ + font-size: 100%; + /* 1 */ + line-height: 1.15; + /* 1 */ + margin: 0; + /* 2 */ +} + +/** + * Show the overflow in IE. + * 1. Show the overflow in Edge. + */ +button, +input { + /* 1 */ + overflow: visible; +} + +/** + * Remove the inheritance of text transform in Edge, Firefox, and IE. + * 1. Remove the inheritance of text transform in Firefox. + */ +button, +select { + /* 1 */ + text-transform: none; +} + +/** + * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` + * controls in Android 4. + * 2. Correct the inability to style clickable types in iOS and Safari. + */ +button, +html [type="button"], +[type="reset"], +[type="submit"] { + -webkit-appearance: button; + /* 2 */ +} + +/** + * Remove the inner border and padding in Firefox. + */ +button::-moz-focus-inner, +[type="button"]::-moz-focus-inner, +[type="reset"]::-moz-focus-inner, +[type="submit"]::-moz-focus-inner { + border-style: none; + padding: 0; +} + +/** + * Restore the focus styles unset by the previous rule. + */ +button:-moz-focusring, +[type="button"]:-moz-focusring, +[type="reset"]:-moz-focusring, +[type="submit"]:-moz-focusring { + outline: 1px dotted ButtonText; +} + +/** + * Correct the padding in Firefox. + */ +fieldset { + padding: 0.35em 0.75em 0.625em; +} + +/** + * 1. Correct the text wrapping in Edge and IE. + * 2. Correct the color inheritance from `fieldset` elements in IE. + * 3. Remove the padding so developers are not caught out when they zero out + * `fieldset` elements in all browsers. + */ +legend { + -webkit-box-sizing: border-box; + box-sizing: border-box; + /* 1 */ + color: inherit; + /* 2 */ + display: table; + /* 1 */ + max-width: 100%; + /* 1 */ + padding: 0; + /* 3 */ + white-space: normal; + /* 1 */ +} + +/** + * 1. Add the correct display in IE 9-. + * 2. Add the correct vertical alignment in Chrome, Firefox, and Opera. + */ +progress { + display: inline-block; + /* 1 */ + vertical-align: baseline; + /* 2 */ +} + +/** + * Remove the default vertical scrollbar in IE. + */ +textarea { + overflow: auto; +} + +/** + * 1. Add the correct box sizing in IE 10-. + * 2. Remove the padding in IE 10-. + */ +[type="checkbox"], +[type="radio"] { + -webkit-box-sizing: border-box; + box-sizing: border-box; + /* 1 */ + padding: 0; + /* 2 */ +} + +/** + * Correct the cursor style of increment and decrement buttons in Chrome. + */ +[type="number"]::-webkit-inner-spin-button, +[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Correct the odd appearance in Chrome and Safari. + * 2. Correct the outline style in Safari. + */ +[type="search"] { + -webkit-appearance: textfield; + /* 1 */ + outline-offset: -2px; + /* 2 */ +} + +/** + * Remove the inner padding and cancel buttons in Chrome and Safari on macOS. + */ +[type="search"]::-webkit-search-cancel-button, +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * 1. Correct the inability to style clickable types in iOS and Safari. + * 2. Change font properties to `inherit` in Safari. + */ +::-webkit-file-upload-button { + -webkit-appearance: button; + /* 1 */ + font: inherit; + /* 2 */ +} + +/* Interactive + ========================================================================== */ +/* + * Add the correct display in IE 9-. + * 1. Add the correct display in Edge, IE, and Firefox. + */ +details, +menu { + display: block; +} + +/* + * Add the correct display in all browsers. + */ +summary { + display: list-item; +} + +/* Scripting + ========================================================================== */ +/** + * Add the correct display in IE 9-. + */ +canvas { + display: inline-block; +} + +/** + * Add the correct display in IE. + */ +template { + display: none; +} + +/* Hidden + ========================================================================== */ +/** + * Add the correct display in IE 10-. + */ +[hidden] { + display: none; +} + +html { + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +*, *:before, *:after { + -webkit-box-sizing: inherit; + box-sizing: inherit; +} + +button, +input, +optgroup, +select, +textarea { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; +} + +ul:not(.browser-default) { + padding-left: 0; + list-style-type: none; +} + +ul:not(.browser-default) > li { + list-style-type: none; +} + +a { + color: #039be5; + text-decoration: none; + -webkit-tap-highlight-color: transparent; +} + +.valign-wrapper { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -webkit-align-items: center; + -ms-flex-align: center; + align-items: center; +} + +.clearfix { + clear: both; +} + +.z-depth-0 { + -webkit-box-shadow: none !important; + box-shadow: none !important; +} + +/* 2dp elevation modified*/ +.z-depth-1, nav, .card-panel, .card, .toast, .btn, .btn-large, .btn-small, .btn-floating, .dropdown-content, .collapsible, .sidenav { + -webkit-box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.12), 0 1px 5px 0 rgba(0, 0, 0, 0.2); + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.12), 0 1px 5px 0 rgba(0, 0, 0, 0.2); +} + +.z-depth-1-half, .btn:hover, .btn-large:hover, .btn-small:hover, .btn-floating:hover { + -webkit-box-shadow: 0 3px 3px 0 rgba(0, 0, 0, 0.14), 0 1px 7px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -1px rgba(0, 0, 0, 0.2); + box-shadow: 0 3px 3px 0 rgba(0, 0, 0, 0.14), 0 1px 7px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -1px rgba(0, 0, 0, 0.2); +} + +/* 6dp elevation modified*/ +.z-depth-2 { + -webkit-box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12), 0 2px 4px -1px rgba(0, 0, 0, 0.3); + box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12), 0 2px 4px -1px rgba(0, 0, 0, 0.3); +} + +/* 12dp elevation modified*/ +.z-depth-3 { + -webkit-box-shadow: 0 8px 17px 2px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12), 0 5px 5px -3px rgba(0, 0, 0, 0.2); + box-shadow: 0 8px 17px 2px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12), 0 5px 5px -3px rgba(0, 0, 0, 0.2); +} + +/* 16dp elevation */ +.z-depth-4 { + -webkit-box-shadow: 0 16px 24px 2px rgba(0, 0, 0, 0.14), 0 6px 30px 5px rgba(0, 0, 0, 0.12), 0 8px 10px -7px rgba(0, 0, 0, 0.2); + box-shadow: 0 16px 24px 2px rgba(0, 0, 0, 0.14), 0 6px 30px 5px rgba(0, 0, 0, 0.12), 0 8px 10px -7px rgba(0, 0, 0, 0.2); +} + +/* 24dp elevation */ +.z-depth-5, .modal { + -webkit-box-shadow: 0 24px 38px 3px rgba(0, 0, 0, 0.14), 0 9px 46px 8px rgba(0, 0, 0, 0.12), 0 11px 15px -7px rgba(0, 0, 0, 0.2); + box-shadow: 0 24px 38px 3px rgba(0, 0, 0, 0.14), 0 9px 46px 8px rgba(0, 0, 0, 0.12), 0 11px 15px -7px rgba(0, 0, 0, 0.2); +} + +.hoverable { + -webkit-transition: -webkit-box-shadow .25s; + transition: -webkit-box-shadow .25s; + transition: box-shadow .25s; + transition: box-shadow .25s, -webkit-box-shadow .25s; +} + +.hoverable:hover { + -webkit-box-shadow: 0 8px 17px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); + box-shadow: 0 8px 17px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); +} + +.divider { + height: 1px; + overflow: hidden; + background-color: #e0e0e0; +} + +blockquote { + margin: 20px 0; + padding-left: 1.5rem; + border-left: 5px solid #ee6e73; +} + +i { + line-height: inherit; +} + +i.left { + float: left; + margin-right: 15px; +} + +i.right { + float: right; + margin-left: 15px; +} + +i.tiny { + font-size: 1rem; +} + +i.small { + font-size: 2rem; +} + +i.medium { + font-size: 4rem; +} + +i.large { + font-size: 6rem; +} + +img.responsive-img, +video.responsive-video { + max-width: 100%; + height: auto; +} + +.pagination li { + display: inline-block; + border-radius: 2px; + text-align: center; + vertical-align: top; + height: 30px; +} + +.pagination li a { + color: #444; + display: inline-block; + font-size: 1.2rem; + padding: 0 10px; + line-height: 30px; +} + +.pagination li.active a { + color: #fff; +} + +.pagination li.active { + background-color: #ee6e73; +} + +.pagination li.disabled a { + cursor: default; + color: #999; +} + +.pagination li i { + font-size: 2rem; +} + +.pagination li.pages ul li { + display: inline-block; + float: none; +} + +@media only screen and (max-width: 992px) { + .pagination { + width: 100%; + } + .pagination li.prev, + .pagination li.next { + width: 10%; + } + .pagination li.pages { + width: 80%; + overflow: hidden; + white-space: nowrap; + } +} + +.breadcrumb { + font-size: 18px; + color: rgba(255, 255, 255, 0.7); +} + +.breadcrumb i, +.breadcrumb [class^="mdi-"], .breadcrumb [class*="mdi-"], +.breadcrumb i.material-icons { + display: inline-block; + float: left; + font-size: 24px; +} + +.breadcrumb:before { + content: '\E5CC'; + color: rgba(255, 255, 255, 0.7); + vertical-align: top; + display: inline-block; + font-family: 'Material Icons'; + font-weight: normal; + font-style: normal; + font-size: 25px; + margin: 0 10px 0 8px; + -webkit-font-smoothing: antialiased; +} + +.breadcrumb:first-child:before { + display: none; +} + +.breadcrumb:last-child { + color: #fff; +} + +.parallax-container { + position: relative; + overflow: hidden; + height: 500px; +} + +.parallax-container .parallax { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: -1; +} + +.parallax-container .parallax img { + opacity: 0; + position: absolute; + left: 50%; + bottom: 0; + min-width: 100%; + min-height: 100%; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + -webkit-transform: translateX(-50%); + transform: translateX(-50%); +} + +.pin-top, .pin-bottom { + position: relative; +} + +.pinned { + position: fixed !important; +} + +/********************* + Transition Classes +**********************/ +ul.staggered-list li { + opacity: 0; +} + +.fade-in { + opacity: 0; + -webkit-transform-origin: 0 50%; + transform-origin: 0 50%; +} + +/********************* + Media Query Classes +**********************/ +@media only screen and (max-width: 600px) { + .hide-on-small-only, .hide-on-small-and-down { + display: none !important; + } +} + +@media only screen and (max-width: 992px) { + .hide-on-med-and-down { + display: none !important; + } +} + +@media only screen and (min-width: 601px) { + .hide-on-med-and-up { + display: none !important; + } +} + +@media only screen and (min-width: 600px) and (max-width: 992px) { + .hide-on-med-only { + display: none !important; + } +} + +@media only screen and (min-width: 993px) { + .hide-on-large-only { + display: none !important; + } +} + +@media only screen and (min-width: 1201px) { + .hide-on-extra-large-only { + display: none !important; + } +} + +@media only screen and (min-width: 1201px) { + .show-on-extra-large { + display: block !important; + } +} + +@media only screen and (min-width: 993px) { + .show-on-large { + display: block !important; + } +} + +@media only screen and (min-width: 600px) and (max-width: 992px) { + .show-on-medium { + display: block !important; + } +} + +@media only screen and (max-width: 600px) { + .show-on-small { + display: block !important; + } +} + +@media only screen and (min-width: 601px) { + .show-on-medium-and-up { + display: block !important; + } +} + +@media only screen and (max-width: 992px) { + .show-on-medium-and-down { + display: block !important; + } +} + +@media only screen and (max-width: 600px) { + .center-on-small-only { + text-align: center; + } +} + +.page-footer { + padding-top: 20px; + color: #fff; + background-color: #ee6e73; +} + +.page-footer .footer-copyright { + overflow: hidden; + min-height: 50px; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -webkit-align-items: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + -ms-flex-pack: justify; + justify-content: space-between; + padding: 10px 0px; + color: rgba(255, 255, 255, 0.8); + background-color: rgba(51, 51, 51, 0.08); +} + +table, th, td { + border: none; +} + +table { + width: 100%; + display: table; + border-collapse: collapse; + border-spacing: 0; +} + +table.striped tr { + border-bottom: none; +} + +table.striped > tbody > tr:nth-child(odd) { + background-color: rgba(242, 242, 242, 0.5); +} + +table.striped > tbody > tr > td { + border-radius: 0; +} + +table.highlight > tbody > tr { + -webkit-transition: background-color .25s ease; + transition: background-color .25s ease; +} + +table.highlight > tbody > tr:hover { + background-color: rgba(242, 242, 242, 0.5); +} + +table.centered thead tr th, table.centered tbody tr td { + text-align: center; +} + +tr { + border-bottom: 1px solid rgba(0, 0, 0, 0.12); +} + +td, th { + padding: 15px 5px; + display: table-cell; + text-align: left; + vertical-align: middle; + border-radius: 2px; +} + +@media only screen and (max-width: 992px) { + table.responsive-table { + width: 100%; + border-collapse: collapse; + border-spacing: 0; + display: block; + position: relative; + /* sort out borders */ + } + table.responsive-table td:empty:before { + content: '\00a0'; + } + table.responsive-table th, + table.responsive-table td { + margin: 0; + vertical-align: top; + } + table.responsive-table th { + text-align: left; + } + table.responsive-table thead { + display: block; + float: left; + } + table.responsive-table thead tr { + display: block; + padding: 0 10px 0 0; + } + table.responsive-table thead tr th::before { + content: "\00a0"; + } + table.responsive-table tbody { + display: block; + width: auto; + position: relative; + overflow-x: auto; + white-space: nowrap; + } + table.responsive-table tbody tr { + display: inline-block; + vertical-align: top; + } + table.responsive-table th { + display: block; + text-align: right; + } + table.responsive-table td { + display: block; + min-height: 1.25em; + text-align: left; + } + table.responsive-table tr { + border-bottom: none; + padding: 0 10px; + } + table.responsive-table thead { + border: 0; + border-right: 1px solid rgba(0, 0, 0, 0.12); + } +} + +.collection { + margin: 0.5rem 0 1rem 0; + border: 1px solid #e0e0e0; + border-radius: 2px; + overflow: hidden; + position: relative; +} + +.collection .collection-item { + background-color: #fff; + line-height: 1.5rem; + padding: 10px 20px; + margin: 0; + border-bottom: 1px solid #e0e0e0; +} + +.collection .collection-item.avatar { + min-height: 84px; + padding-left: 72px; + position: relative; +} + +.collection .collection-item.avatar:not(.circle-clipper) > .circle, +.collection .collection-item.avatar :not(.circle-clipper) > .circle { + position: absolute; + width: 42px; + height: 42px; + overflow: hidden; + left: 15px; + display: inline-block; + vertical-align: middle; +} + +.collection .collection-item.avatar i.circle { + font-size: 18px; + line-height: 42px; + color: #fff; + background-color: #999; + text-align: center; +} + +.collection .collection-item.avatar .title { + font-size: 16px; +} + +.collection .collection-item.avatar p { + margin: 0; +} + +.collection .collection-item.avatar .secondary-content { + position: absolute; + top: 16px; + right: 16px; +} + +.collection .collection-item:last-child { + border-bottom: none; +} + +.collection .collection-item.active { + background-color: #26a69a; + color: #eafaf9; +} + +.collection .collection-item.active .secondary-content { + color: #fff; +} + +.collection a.collection-item { + display: block; + -webkit-transition: .25s; + transition: .25s; + color: #26a69a; +} + +.collection a.collection-item:not(.active):hover { + background-color: #ddd; +} + +.collection.with-header .collection-header { + background-color: #fff; + border-bottom: 1px solid #e0e0e0; + padding: 10px 20px; +} + +.collection.with-header .collection-item { + padding-left: 30px; +} + +.collection.with-header .collection-item.avatar { + padding-left: 72px; +} + +.secondary-content { + float: right; + color: #26a69a; +} + +.collapsible .collection { + margin: 0; + border: none; +} + +.video-container { + position: relative; + padding-bottom: 56.25%; + height: 0; + overflow: hidden; +} + +.video-container iframe, .video-container object, .video-container embed { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} + +.progress { + position: relative; + height: 4px; + display: block; + width: 100%; + background-color: #acece6; + border-radius: 2px; + margin: 0.5rem 0 1rem 0; + overflow: hidden; +} + +.progress .determinate { + position: absolute; + top: 0; + left: 0; + bottom: 0; + background-color: #26a69a; + -webkit-transition: width .3s linear; + transition: width .3s linear; +} + +.progress .indeterminate { + background-color: #26a69a; +} + +.progress .indeterminate:before { + content: ''; + position: absolute; + background-color: inherit; + top: 0; + left: 0; + bottom: 0; + will-change: left, right; + -webkit-animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite; + animation: indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite; +} + +.progress .indeterminate:after { + content: ''; + position: absolute; + background-color: inherit; + top: 0; + left: 0; + bottom: 0; + will-change: left, right; + -webkit-animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite; + animation: indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite; + -webkit-animation-delay: 1.15s; + animation-delay: 1.15s; +} + +@-webkit-keyframes indeterminate { + 0% { + left: -35%; + right: 100%; + } + 60% { + left: 100%; + right: -90%; + } + 100% { + left: 100%; + right: -90%; + } +} + +@keyframes indeterminate { + 0% { + left: -35%; + right: 100%; + } + 60% { + left: 100%; + right: -90%; + } + 100% { + left: 100%; + right: -90%; + } +} + +@-webkit-keyframes indeterminate-short { + 0% { + left: -200%; + right: 100%; + } + 60% { + left: 107%; + right: -8%; + } + 100% { + left: 107%; + right: -8%; + } +} + +@keyframes indeterminate-short { + 0% { + left: -200%; + right: 100%; + } + 60% { + left: 107%; + right: -8%; + } + 100% { + left: 107%; + right: -8%; + } +} + +/******************* + Utility Classes +*******************/ +.hide { + display: none !important; +} + +.left-align { + text-align: left; +} + +.right-align { + text-align: right; +} + +.center, .center-align { + text-align: center; +} + +.left { + float: left !important; +} + +.right { + float: right !important; +} + +.no-select, input[type=range], +input[type=range] + .thumb { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.circle { + border-radius: 50%; +} + +.center-block { + display: block; + margin-left: auto; + margin-right: auto; +} + +.truncate { + display: block; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.no-padding { + padding: 0 !important; +} + +span.badge { + min-width: 3rem; + padding: 0 6px; + margin-left: 14px; + text-align: center; + font-size: 1rem; + line-height: 22px; + height: 22px; + color: #757575; + float: right; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +span.badge.new { + font-weight: 300; + font-size: 0.8rem; + color: #fff; + background-color: #26a69a; + border-radius: 2px; +} + +span.badge.new:after { + content: " new"; +} + +span.badge[data-badge-caption]::after { + content: " " attr(data-badge-caption); +} + +nav ul a span.badge { + display: inline-block; + float: none; + margin-left: 4px; + line-height: 22px; + height: 22px; + -webkit-font-smoothing: auto; +} + +.collection-item span.badge { + margin-top: calc(0.75rem - 11px); +} + +.collapsible span.badge { + margin-left: auto; +} + +.sidenav span.badge { + margin-top: calc(24px - 11px); +} + +table span.badge { + display: inline-block; + float: none; + margin-left: auto; +} + +/* This is needed for some mobile phones to display the Google Icon font properly */ +.material-icons { + text-rendering: optimizeLegibility; + -webkit-font-feature-settings: 'liga'; + -moz-font-feature-settings: 'liga'; + font-feature-settings: 'liga'; +} + +.container { + margin: 0 auto; + max-width: 1280px; + width: 90%; +} + +@media only screen and (min-width: 601px) { + .container { + width: 85%; + } +} + +@media only screen and (min-width: 993px) { + .container { + width: 70%; + } +} + +.col .row { + margin-left: -0.75rem; + margin-right: -0.75rem; +} + +.section { + padding-top: 1rem; + padding-bottom: 1rem; +} + +.section.no-pad { + padding: 0; +} + +.section.no-pad-bot { + padding-bottom: 0; +} + +.section.no-pad-top { + padding-top: 0; +} + +.row { + margin-left: auto; + margin-right: auto; + margin-bottom: 20px; +} + +.row:after { + content: ""; + display: table; + clear: both; +} + +.row .col { + float: left; + -webkit-box-sizing: border-box; + box-sizing: border-box; + padding: 0 0.75rem; + min-height: 1px; +} + +.row .col[class*="push-"], .row .col[class*="pull-"] { + position: relative; +} + +.row .col.s1 { + width: 8.3333333333%; + margin-left: auto; + left: auto; + right: auto; +} + +.row .col.s2 { + width: 16.6666666667%; + margin-left: auto; + left: auto; + right: auto; +} + +.row .col.s3 { + width: 25%; + margin-left: auto; + left: auto; + right: auto; +} + +.row .col.s4 { + width: 33.3333333333%; + margin-left: auto; + left: auto; + right: auto; +} + +.row .col.s5 { + width: 41.6666666667%; + margin-left: auto; + left: auto; + right: auto; +} + +.row .col.s6 { + width: 50%; + margin-left: auto; + left: auto; + right: auto; +} + +.row .col.s7 { + width: 58.3333333333%; + margin-left: auto; + left: auto; + right: auto; +} + +.row .col.s8 { + width: 66.6666666667%; + margin-left: auto; + left: auto; + right: auto; +} + +.row .col.s9 { + width: 75%; + margin-left: auto; + left: auto; + right: auto; +} + +.row .col.s10 { + width: 83.3333333333%; + margin-left: auto; + left: auto; + right: auto; +} + +.row .col.s11 { + width: 91.6666666667%; + margin-left: auto; + left: auto; + right: auto; +} + +.row .col.s12 { + width: 100%; + margin-left: auto; + left: auto; + right: auto; +} + +.row .col.offset-s1 { + margin-left: 8.3333333333%; +} + +.row .col.pull-s1 { + right: 8.3333333333%; +} + +.row .col.push-s1 { + left: 8.3333333333%; +} + +.row .col.offset-s2 { + margin-left: 16.6666666667%; +} + +.row .col.pull-s2 { + right: 16.6666666667%; +} + +.row .col.push-s2 { + left: 16.6666666667%; +} + +.row .col.offset-s3 { + margin-left: 25%; +} + +.row .col.pull-s3 { + right: 25%; +} + +.row .col.push-s3 { + left: 25%; +} + +.row .col.offset-s4 { + margin-left: 33.3333333333%; +} + +.row .col.pull-s4 { + right: 33.3333333333%; +} + +.row .col.push-s4 { + left: 33.3333333333%; +} + +.row .col.offset-s5 { + margin-left: 41.6666666667%; +} + +.row .col.pull-s5 { + right: 41.6666666667%; +} + +.row .col.push-s5 { + left: 41.6666666667%; +} + +.row .col.offset-s6 { + margin-left: 50%; +} + +.row .col.pull-s6 { + right: 50%; +} + +.row .col.push-s6 { + left: 50%; +} + +.row .col.offset-s7 { + margin-left: 58.3333333333%; +} + +.row .col.pull-s7 { + right: 58.3333333333%; +} + +.row .col.push-s7 { + left: 58.3333333333%; +} + +.row .col.offset-s8 { + margin-left: 66.6666666667%; +} + +.row .col.pull-s8 { + right: 66.6666666667%; +} + +.row .col.push-s8 { + left: 66.6666666667%; +} + +.row .col.offset-s9 { + margin-left: 75%; +} + +.row .col.pull-s9 { + right: 75%; +} + +.row .col.push-s9 { + left: 75%; +} + +.row .col.offset-s10 { + margin-left: 83.3333333333%; +} + +.row .col.pull-s10 { + right: 83.3333333333%; +} + +.row .col.push-s10 { + left: 83.3333333333%; +} + +.row .col.offset-s11 { + margin-left: 91.6666666667%; +} + +.row .col.pull-s11 { + right: 91.6666666667%; +} + +.row .col.push-s11 { + left: 91.6666666667%; +} + +.row .col.offset-s12 { + margin-left: 100%; +} + +.row .col.pull-s12 { + right: 100%; +} + +.row .col.push-s12 { + left: 100%; +} + +@media only screen and (min-width: 601px) { + .row .col.m1 { + width: 8.3333333333%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.m2 { + width: 16.6666666667%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.m3 { + width: 25%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.m4 { + width: 33.3333333333%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.m5 { + width: 41.6666666667%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.m6 { + width: 50%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.m7 { + width: 58.3333333333%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.m8 { + width: 66.6666666667%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.m9 { + width: 75%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.m10 { + width: 83.3333333333%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.m11 { + width: 91.6666666667%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.m12 { + width: 100%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.offset-m1 { + margin-left: 8.3333333333%; + } + .row .col.pull-m1 { + right: 8.3333333333%; + } + .row .col.push-m1 { + left: 8.3333333333%; + } + .row .col.offset-m2 { + margin-left: 16.6666666667%; + } + .row .col.pull-m2 { + right: 16.6666666667%; + } + .row .col.push-m2 { + left: 16.6666666667%; + } + .row .col.offset-m3 { + margin-left: 25%; + } + .row .col.pull-m3 { + right: 25%; + } + .row .col.push-m3 { + left: 25%; + } + .row .col.offset-m4 { + margin-left: 33.3333333333%; + } + .row .col.pull-m4 { + right: 33.3333333333%; + } + .row .col.push-m4 { + left: 33.3333333333%; + } + .row .col.offset-m5 { + margin-left: 41.6666666667%; + } + .row .col.pull-m5 { + right: 41.6666666667%; + } + .row .col.push-m5 { + left: 41.6666666667%; + } + .row .col.offset-m6 { + margin-left: 50%; + } + .row .col.pull-m6 { + right: 50%; + } + .row .col.push-m6 { + left: 50%; + } + .row .col.offset-m7 { + margin-left: 58.3333333333%; + } + .row .col.pull-m7 { + right: 58.3333333333%; + } + .row .col.push-m7 { + left: 58.3333333333%; + } + .row .col.offset-m8 { + margin-left: 66.6666666667%; + } + .row .col.pull-m8 { + right: 66.6666666667%; + } + .row .col.push-m8 { + left: 66.6666666667%; + } + .row .col.offset-m9 { + margin-left: 75%; + } + .row .col.pull-m9 { + right: 75%; + } + .row .col.push-m9 { + left: 75%; + } + .row .col.offset-m10 { + margin-left: 83.3333333333%; + } + .row .col.pull-m10 { + right: 83.3333333333%; + } + .row .col.push-m10 { + left: 83.3333333333%; + } + .row .col.offset-m11 { + margin-left: 91.6666666667%; + } + .row .col.pull-m11 { + right: 91.6666666667%; + } + .row .col.push-m11 { + left: 91.6666666667%; + } + .row .col.offset-m12 { + margin-left: 100%; + } + .row .col.pull-m12 { + right: 100%; + } + .row .col.push-m12 { + left: 100%; + } +} + +@media only screen and (min-width: 993px) { + .row .col.l1 { + width: 8.3333333333%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.l2 { + width: 16.6666666667%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.l3 { + width: 25%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.l4 { + width: 33.3333333333%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.l5 { + width: 41.6666666667%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.l6 { + width: 50%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.l7 { + width: 58.3333333333%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.l8 { + width: 66.6666666667%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.l9 { + width: 75%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.l10 { + width: 83.3333333333%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.l11 { + width: 91.6666666667%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.l12 { + width: 100%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.offset-l1 { + margin-left: 8.3333333333%; + } + .row .col.pull-l1 { + right: 8.3333333333%; + } + .row .col.push-l1 { + left: 8.3333333333%; + } + .row .col.offset-l2 { + margin-left: 16.6666666667%; + } + .row .col.pull-l2 { + right: 16.6666666667%; + } + .row .col.push-l2 { + left: 16.6666666667%; + } + .row .col.offset-l3 { + margin-left: 25%; + } + .row .col.pull-l3 { + right: 25%; + } + .row .col.push-l3 { + left: 25%; + } + .row .col.offset-l4 { + margin-left: 33.3333333333%; + } + .row .col.pull-l4 { + right: 33.3333333333%; + } + .row .col.push-l4 { + left: 33.3333333333%; + } + .row .col.offset-l5 { + margin-left: 41.6666666667%; + } + .row .col.pull-l5 { + right: 41.6666666667%; + } + .row .col.push-l5 { + left: 41.6666666667%; + } + .row .col.offset-l6 { + margin-left: 50%; + } + .row .col.pull-l6 { + right: 50%; + } + .row .col.push-l6 { + left: 50%; + } + .row .col.offset-l7 { + margin-left: 58.3333333333%; + } + .row .col.pull-l7 { + right: 58.3333333333%; + } + .row .col.push-l7 { + left: 58.3333333333%; + } + .row .col.offset-l8 { + margin-left: 66.6666666667%; + } + .row .col.pull-l8 { + right: 66.6666666667%; + } + .row .col.push-l8 { + left: 66.6666666667%; + } + .row .col.offset-l9 { + margin-left: 75%; + } + .row .col.pull-l9 { + right: 75%; + } + .row .col.push-l9 { + left: 75%; + } + .row .col.offset-l10 { + margin-left: 83.3333333333%; + } + .row .col.pull-l10 { + right: 83.3333333333%; + } + .row .col.push-l10 { + left: 83.3333333333%; + } + .row .col.offset-l11 { + margin-left: 91.6666666667%; + } + .row .col.pull-l11 { + right: 91.6666666667%; + } + .row .col.push-l11 { + left: 91.6666666667%; + } + .row .col.offset-l12 { + margin-left: 100%; + } + .row .col.pull-l12 { + right: 100%; + } + .row .col.push-l12 { + left: 100%; + } +} + +@media only screen and (min-width: 1201px) { + .row .col.xl1 { + width: 8.3333333333%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.xl2 { + width: 16.6666666667%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.xl3 { + width: 25%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.xl4 { + width: 33.3333333333%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.xl5 { + width: 41.6666666667%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.xl6 { + width: 50%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.xl7 { + width: 58.3333333333%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.xl8 { + width: 66.6666666667%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.xl9 { + width: 75%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.xl10 { + width: 83.3333333333%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.xl11 { + width: 91.6666666667%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.xl12 { + width: 100%; + margin-left: auto; + left: auto; + right: auto; + } + .row .col.offset-xl1 { + margin-left: 8.3333333333%; + } + .row .col.pull-xl1 { + right: 8.3333333333%; + } + .row .col.push-xl1 { + left: 8.3333333333%; + } + .row .col.offset-xl2 { + margin-left: 16.6666666667%; + } + .row .col.pull-xl2 { + right: 16.6666666667%; + } + .row .col.push-xl2 { + left: 16.6666666667%; + } + .row .col.offset-xl3 { + margin-left: 25%; + } + .row .col.pull-xl3 { + right: 25%; + } + .row .col.push-xl3 { + left: 25%; + } + .row .col.offset-xl4 { + margin-left: 33.3333333333%; + } + .row .col.pull-xl4 { + right: 33.3333333333%; + } + .row .col.push-xl4 { + left: 33.3333333333%; + } + .row .col.offset-xl5 { + margin-left: 41.6666666667%; + } + .row .col.pull-xl5 { + right: 41.6666666667%; + } + .row .col.push-xl5 { + left: 41.6666666667%; + } + .row .col.offset-xl6 { + margin-left: 50%; + } + .row .col.pull-xl6 { + right: 50%; + } + .row .col.push-xl6 { + left: 50%; + } + .row .col.offset-xl7 { + margin-left: 58.3333333333%; + } + .row .col.pull-xl7 { + right: 58.3333333333%; + } + .row .col.push-xl7 { + left: 58.3333333333%; + } + .row .col.offset-xl8 { + margin-left: 66.6666666667%; + } + .row .col.pull-xl8 { + right: 66.6666666667%; + } + .row .col.push-xl8 { + left: 66.6666666667%; + } + .row .col.offset-xl9 { + margin-left: 75%; + } + .row .col.pull-xl9 { + right: 75%; + } + .row .col.push-xl9 { + left: 75%; + } + .row .col.offset-xl10 { + margin-left: 83.3333333333%; + } + .row .col.pull-xl10 { + right: 83.3333333333%; + } + .row .col.push-xl10 { + left: 83.3333333333%; + } + .row .col.offset-xl11 { + margin-left: 91.6666666667%; + } + .row .col.pull-xl11 { + right: 91.6666666667%; + } + .row .col.push-xl11 { + left: 91.6666666667%; + } + .row .col.offset-xl12 { + margin-left: 100%; + } + .row .col.pull-xl12 { + right: 100%; + } + .row .col.push-xl12 { + left: 100%; + } +} + +nav { + color: #fff; + background-color: #ee6e73; + width: 100%; + height: 56px; + line-height: 56px; +} + +nav.nav-extended { + height: auto; +} + +nav.nav-extended .nav-wrapper { + min-height: 56px; + height: auto; +} + +nav.nav-extended .nav-content { + position: relative; + line-height: normal; +} + +nav a { + color: #fff; +} + +nav i, +nav [class^="mdi-"], nav [class*="mdi-"], +nav i.material-icons { + display: block; + font-size: 24px; + height: 56px; + line-height: 56px; +} + +nav .nav-wrapper { + position: relative; + height: 100%; +} + +@media only screen and (min-width: 993px) { + nav a.sidenav-trigger { + display: none; + } +} + +nav .sidenav-trigger { + float: left; + position: relative; + z-index: 1; + height: 56px; + margin: 0 18px; +} + +nav .sidenav-trigger i { + height: 56px; + line-height: 56px; +} + +nav .brand-logo { + position: absolute; + color: #fff; + display: inline-block; + font-size: 2.1rem; + padding: 0; +} + +nav .brand-logo.center { + left: 50%; + -webkit-transform: translateX(-50%); + transform: translateX(-50%); +} + +@media only screen and (max-width: 992px) { + nav .brand-logo { + left: 50%; + -webkit-transform: translateX(-50%); + transform: translateX(-50%); + } + nav .brand-logo.left, nav .brand-logo.right { + padding: 0; + -webkit-transform: none; + transform: none; + } + nav .brand-logo.left { + left: 0.5rem; + } + nav .brand-logo.right { + right: 0.5rem; + left: auto; + } +} + +nav .brand-logo.right { + right: 0.5rem; + padding: 0; +} + +nav .brand-logo i, +nav .brand-logo [class^="mdi-"], nav .brand-logo [class*="mdi-"], +nav .brand-logo i.material-icons { + float: left; + margin-right: 15px; +} + +nav .nav-title { + display: inline-block; + font-size: 32px; + padding: 28px 0; +} + +nav ul { + margin: 0; +} + +nav ul li { + -webkit-transition: background-color .3s; + transition: background-color .3s; + float: left; + padding: 0; +} + +nav ul li.active { + background-color: rgba(0, 0, 0, 0.1); +} + +nav ul a { + -webkit-transition: background-color .3s; + transition: background-color .3s; + font-size: 1rem; + color: #fff; + display: block; + padding: 0 15px; + cursor: pointer; +} + +nav ul a.btn, nav ul a.btn-large, nav ul a.btn-small, nav ul a.btn-large, nav ul a.btn-flat, nav ul a.btn-floating { + margin-top: -2px; + margin-left: 15px; + margin-right: 15px; +} + +nav ul a.btn > .material-icons, nav ul a.btn-large > .material-icons, nav ul a.btn-small > .material-icons, nav ul a.btn-large > .material-icons, nav ul a.btn-flat > .material-icons, nav ul a.btn-floating > .material-icons { + height: inherit; + line-height: inherit; +} + +nav ul a:hover { + background-color: rgba(0, 0, 0, 0.1); +} + +nav ul.left { + float: left; +} + +nav form { + height: 100%; +} + +nav .input-field { + margin: 0; + height: 100%; +} + +nav .input-field input { + height: 100%; + font-size: 1.2rem; + border: none; + padding-left: 2rem; +} + +nav .input-field input:focus, nav .input-field input[type=text]:valid, nav .input-field input[type=password]:valid, nav .input-field input[type=email]:valid, nav .input-field input[type=url]:valid, nav .input-field input[type=date]:valid { + border: none; + -webkit-box-shadow: none; + box-shadow: none; +} + +nav .input-field label { + top: 0; + left: 0; +} + +nav .input-field label i { + color: rgba(255, 255, 255, 0.7); + -webkit-transition: color .3s; + transition: color .3s; +} + +nav .input-field label.active i { + color: #fff; +} + +.navbar-fixed { + position: relative; + height: 56px; + z-index: 997; +} + +.navbar-fixed nav { + position: fixed; +} + +@media only screen and (min-width: 601px) { + nav.nav-extended .nav-wrapper { + min-height: 64px; + } + nav, nav .nav-wrapper i, nav a.sidenav-trigger, nav a.sidenav-trigger i { + height: 64px; + line-height: 64px; + } + .navbar-fixed { + height: 64px; + } +} + +a { + text-decoration: none; +} + +html { + line-height: 1.5; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; + font-weight: normal; + color: rgba(0, 0, 0, 0.87); +} + +@media only screen and (min-width: 0) { + html { + font-size: 14px; + } +} + +@media only screen and (min-width: 992px) { + html { + font-size: 14.5px; + } +} + +@media only screen and (min-width: 1200px) { + html { + font-size: 15px; + } +} + +h1, h2, h3, h4, h5, h6 { + font-weight: 400; + line-height: 1.3; +} + +h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { + font-weight: inherit; +} + +h1 { + font-size: 4.2rem; + line-height: 110%; + margin: 2.8rem 0 1.68rem 0; +} + +h2 { + font-size: 3.56rem; + line-height: 110%; + margin: 2.3733333333rem 0 1.424rem 0; +} + +h3 { + font-size: 2.92rem; + line-height: 110%; + margin: 1.9466666667rem 0 1.168rem 0; +} + +h4 { + font-size: 2.28rem; + line-height: 110%; + margin: 1.52rem 0 0.912rem 0; +} + +h5 { + font-size: 1.64rem; + line-height: 110%; + margin: 1.0933333333rem 0 0.656rem 0; +} + +h6 { + font-size: 1.15rem; + line-height: 110%; + margin: 0.7666666667rem 0 0.46rem 0; +} + +em { + font-style: italic; +} + +strong { + font-weight: 500; +} + +small { + font-size: 75%; +} + +.light { + font-weight: 300; +} + +.thin { + font-weight: 200; +} + +@media only screen and (min-width: 360px) { + .flow-text { + font-size: 1.2rem; + } +} + +@media only screen and (min-width: 390px) { + .flow-text { + font-size: 1.224rem; + } +} + +@media only screen and (min-width: 420px) { + .flow-text { + font-size: 1.248rem; + } +} + +@media only screen and (min-width: 450px) { + .flow-text { + font-size: 1.272rem; + } +} + +@media only screen and (min-width: 480px) { + .flow-text { + font-size: 1.296rem; + } +} + +@media only screen and (min-width: 510px) { + .flow-text { + font-size: 1.32rem; + } +} + +@media only screen and (min-width: 540px) { + .flow-text { + font-size: 1.344rem; + } +} + +@media only screen and (min-width: 570px) { + .flow-text { + font-size: 1.368rem; + } +} + +@media only screen and (min-width: 600px) { + .flow-text { + font-size: 1.392rem; + } +} + +@media only screen and (min-width: 630px) { + .flow-text { + font-size: 1.416rem; + } +} + +@media only screen and (min-width: 660px) { + .flow-text { + font-size: 1.44rem; + } +} + +@media only screen and (min-width: 690px) { + .flow-text { + font-size: 1.464rem; + } +} + +@media only screen and (min-width: 720px) { + .flow-text { + font-size: 1.488rem; + } +} + +@media only screen and (min-width: 750px) { + .flow-text { + font-size: 1.512rem; + } +} + +@media only screen and (min-width: 780px) { + .flow-text { + font-size: 1.536rem; + } +} + +@media only screen and (min-width: 810px) { + .flow-text { + font-size: 1.56rem; + } +} + +@media only screen and (min-width: 840px) { + .flow-text { + font-size: 1.584rem; + } +} + +@media only screen and (min-width: 870px) { + .flow-text { + font-size: 1.608rem; + } +} + +@media only screen and (min-width: 900px) { + .flow-text { + font-size: 1.632rem; + } +} + +@media only screen and (min-width: 930px) { + .flow-text { + font-size: 1.656rem; + } +} + +@media only screen and (min-width: 960px) { + .flow-text { + font-size: 1.68rem; + } +} + +@media only screen and (max-width: 360px) { + .flow-text { + font-size: 1.2rem; + } +} + +.scale-transition { + -webkit-transition: -webkit-transform 0.3s cubic-bezier(0.53, 0.01, 0.36, 1.63) !important; + transition: -webkit-transform 0.3s cubic-bezier(0.53, 0.01, 0.36, 1.63) !important; + transition: transform 0.3s cubic-bezier(0.53, 0.01, 0.36, 1.63) !important; + transition: transform 0.3s cubic-bezier(0.53, 0.01, 0.36, 1.63), -webkit-transform 0.3s cubic-bezier(0.53, 0.01, 0.36, 1.63) !important; +} + +.scale-transition.scale-out { + -webkit-transform: scale(0); + transform: scale(0); + -webkit-transition: -webkit-transform .2s !important; + transition: -webkit-transform .2s !important; + transition: transform .2s !important; + transition: transform .2s, -webkit-transform .2s !important; +} + +.scale-transition.scale-in { + -webkit-transform: scale(1); + transform: scale(1); +} + +.card-panel { + -webkit-transition: -webkit-box-shadow .25s; + transition: -webkit-box-shadow .25s; + transition: box-shadow .25s; + transition: box-shadow .25s, -webkit-box-shadow .25s; + padding: 24px; + margin: 0.5rem 0 1rem 0; + border-radius: 2px; + background-color: #fff; +} + +.card { + position: relative; + margin: 0.5rem 0 1rem 0; + background-color: #fff; + -webkit-transition: -webkit-box-shadow .25s; + transition: -webkit-box-shadow .25s; + transition: box-shadow .25s; + transition: box-shadow .25s, -webkit-box-shadow .25s; + border-radius: 2px; +} + +.card .card-title { + font-size: 24px; + font-weight: 300; +} + +.card .card-title.activator { + cursor: pointer; +} + +.card.small, .card.medium, .card.large { + position: relative; +} + +.card.small .card-image, .card.medium .card-image, .card.large .card-image { + max-height: 60%; + overflow: hidden; +} + +.card.small .card-image + .card-content, .card.medium .card-image + .card-content, .card.large .card-image + .card-content { + max-height: 40%; +} + +.card.small .card-content, .card.medium .card-content, .card.large .card-content { + max-height: 100%; + overflow: hidden; +} + +.card.small .card-action, .card.medium .card-action, .card.large .card-action { + position: absolute; + bottom: 0; + left: 0; + right: 0; +} + +.card.small { + height: 300px; +} + +.card.medium { + height: 400px; +} + +.card.large { + height: 500px; +} + +.card.horizontal { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; +} + +.card.horizontal.small .card-image, .card.horizontal.medium .card-image, .card.horizontal.large .card-image { + height: 100%; + max-height: none; + overflow: visible; +} + +.card.horizontal.small .card-image img, .card.horizontal.medium .card-image img, .card.horizontal.large .card-image img { + height: 100%; +} + +.card.horizontal .card-image { + max-width: 50%; +} + +.card.horizontal .card-image img { + border-radius: 2px 0 0 2px; + max-width: 100%; + width: auto; +} + +.card.horizontal .card-stacked { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + position: relative; +} + +.card.horizontal .card-stacked .card-content { + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + -ms-flex-positive: 1; + flex-grow: 1; +} + +.card.sticky-action .card-action { + z-index: 2; +} + +.card.sticky-action .card-reveal { + z-index: 1; + padding-bottom: 64px; +} + +.card .card-image { + position: relative; +} + +.card .card-image img { + display: block; + border-radius: 2px 2px 0 0; + position: relative; + left: 0; + right: 0; + top: 0; + bottom: 0; + width: 100%; +} + +.card .card-image .card-title { + color: #fff; + position: absolute; + bottom: 0; + left: 0; + max-width: 100%; + padding: 24px; +} + +.card .card-content { + padding: 24px; + border-radius: 0 0 2px 2px; +} + +.card .card-content p { + margin: 0; +} + +.card .card-content .card-title { + display: block; + line-height: 32px; + margin-bottom: 8px; +} + +.card .card-content .card-title i { + line-height: 32px; +} + +.card .card-action { + background-color: inherit; + border-top: 1px solid rgba(160, 160, 160, 0.2); + position: relative; + padding: 16px 24px; +} + +.card .card-action:last-child { + border-radius: 0 0 2px 2px; +} + +.card .card-action a:not(.btn):not(.btn-large):not(.btn-small):not(.btn-large):not(.btn-floating) { + color: #ffab40; + margin-right: 24px; + -webkit-transition: color .3s ease; + transition: color .3s ease; + text-transform: uppercase; +} + +.card .card-action a:not(.btn):not(.btn-large):not(.btn-small):not(.btn-large):not(.btn-floating):hover { + color: #ffd8a6; +} + +.card .card-reveal { + padding: 24px; + position: absolute; + background-color: #fff; + width: 100%; + overflow-y: auto; + left: 0; + top: 100%; + height: 100%; + z-index: 3; + display: none; +} + +.card .card-reveal .card-title { + cursor: pointer; + display: block; +} + +#toast-container { + display: block; + position: fixed; + z-index: 10000; +} + +@media only screen and (max-width: 600px) { + #toast-container { + min-width: 100%; + bottom: 0%; + } +} + +@media only screen and (min-width: 601px) and (max-width: 992px) { + #toast-container { + left: 5%; + bottom: 7%; + max-width: 90%; + } +} + +@media only screen and (min-width: 993px) { + #toast-container { + top: 10%; + right: 7%; + max-width: 86%; + } +} + +.toast { + border-radius: 2px; + top: 35px; + width: auto; + margin-top: 10px; + position: relative; + max-width: 100%; + height: auto; + min-height: 48px; + line-height: 1.5em; + word-break: break-all; + background-color: #323232; + padding: 10px 25px; + font-size: 1.1rem; + font-weight: 300; + color: #fff; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -webkit-align-items: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + -ms-flex-pack: justify; + justify-content: space-between; + cursor: default; +} + +.toast .toast-action { + color: #eeff41; + font-weight: 500; + margin-right: -25px; + margin-left: 3rem; +} + +.toast.rounded { + border-radius: 24px; +} + +@media only screen and (max-width: 600px) { + .toast { + width: 100%; + border-radius: 0; + } +} + +.tabs { + position: relative; + overflow-x: auto; + overflow-y: hidden; + height: 48px; + width: 100%; + background-color: #fff; + margin: 0 auto; + white-space: nowrap; +} + +.tabs.tabs-transparent { + background-color: transparent; +} + +.tabs.tabs-transparent .tab a, +.tabs.tabs-transparent .tab.disabled a, +.tabs.tabs-transparent .tab.disabled a:hover { + color: rgba(255, 255, 255, 0.7); +} + +.tabs.tabs-transparent .tab a:hover, +.tabs.tabs-transparent .tab a.active { + color: #fff; +} + +.tabs.tabs-transparent .indicator { + background-color: #fff; +} + +.tabs.tabs-fixed-width { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; +} + +.tabs.tabs-fixed-width .tab { + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + -ms-flex-positive: 1; + flex-grow: 1; +} + +.tabs .tab { + display: inline-block; + text-align: center; + line-height: 48px; + height: 48px; + padding: 0; + margin: 0; + text-transform: uppercase; +} + +.tabs .tab a { + color: rgba(238, 110, 115, 0.7); + display: block; + width: 100%; + height: 100%; + padding: 0 24px; + font-size: 14px; + text-overflow: ellipsis; + overflow: hidden; + -webkit-transition: color .28s ease, background-color .28s ease; + transition: color .28s ease, background-color .28s ease; +} + +.tabs .tab a:focus, .tabs .tab a:focus.active { + background-color: rgba(246, 178, 181, 0.2); + outline: none; +} + +.tabs .tab a:hover, .tabs .tab a.active { + background-color: transparent; + color: #ee6e73; +} + +.tabs .tab.disabled a, +.tabs .tab.disabled a:hover { + color: rgba(238, 110, 115, 0.4); + cursor: default; +} + +.tabs .indicator { + position: absolute; + bottom: 0; + height: 2px; + background-color: #f6b2b5; + will-change: left, right; +} + +@media only screen and (max-width: 992px) { + .tabs { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + } + .tabs .tab { + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + -ms-flex-positive: 1; + flex-grow: 1; + } + .tabs .tab a { + padding: 0 12px; + } +} + +.material-tooltip { + padding: 10px 8px; + font-size: 1rem; + z-index: 2000; + background-color: transparent; + border-radius: 2px; + color: #fff; + min-height: 36px; + line-height: 120%; + opacity: 0; + position: absolute; + text-align: center; + max-width: calc(100% - 4px); + overflow: hidden; + left: 0; + top: 0; + pointer-events: none; + visibility: hidden; + background-color: #323232; +} + +.backdrop { + position: absolute; + opacity: 0; + height: 7px; + width: 14px; + border-radius: 0 0 50% 50%; + background-color: #323232; + z-index: -1; + -webkit-transform-origin: 50% 0%; + transform-origin: 50% 0%; + visibility: hidden; +} + +.btn, .btn-large, .btn-small, +.btn-flat { + border: none; + border-radius: 2px; + display: inline-block; + height: 36px; + line-height: 36px; + padding: 0 16px; + text-transform: uppercase; + vertical-align: middle; + -webkit-tap-highlight-color: transparent; +} + +.btn.disabled, .disabled.btn-large, .disabled.btn-small, +.btn-floating.disabled, +.btn-large.disabled, +.btn-small.disabled, +.btn-flat.disabled, +.btn:disabled, +.btn-large:disabled, +.btn-small:disabled, +.btn-floating:disabled, +.btn-large:disabled, +.btn-small:disabled, +.btn-flat:disabled, +.btn[disabled], +[disabled].btn-large, +[disabled].btn-small, +.btn-floating[disabled], +.btn-large[disabled], +.btn-small[disabled], +.btn-flat[disabled] { + pointer-events: none; + background-color: #DFDFDF !important; + -webkit-box-shadow: none; + box-shadow: none; + color: #9F9F9F !important; + cursor: default; +} + +.btn.disabled:hover, .disabled.btn-large:hover, .disabled.btn-small:hover, +.btn-floating.disabled:hover, +.btn-large.disabled:hover, +.btn-small.disabled:hover, +.btn-flat.disabled:hover, +.btn:disabled:hover, +.btn-large:disabled:hover, +.btn-small:disabled:hover, +.btn-floating:disabled:hover, +.btn-large:disabled:hover, +.btn-small:disabled:hover, +.btn-flat:disabled:hover, +.btn[disabled]:hover, +[disabled].btn-large:hover, +[disabled].btn-small:hover, +.btn-floating[disabled]:hover, +.btn-large[disabled]:hover, +.btn-small[disabled]:hover, +.btn-flat[disabled]:hover { + background-color: #DFDFDF !important; + color: #9F9F9F !important; +} + +.btn, .btn-large, .btn-small, +.btn-floating, +.btn-large, +.btn-small, +.btn-flat { + font-size: 14px; + outline: 0; +} + +.btn i, .btn-large i, .btn-small i, +.btn-floating i, +.btn-large i, +.btn-small i, +.btn-flat i { + font-size: 1.3rem; + line-height: inherit; +} + +.btn:focus, .btn-large:focus, .btn-small:focus, +.btn-floating:focus { + background-color: #1d7d74; +} + +.btn, .btn-large, .btn-small { + text-decoration: none; + color: #fff; + background-color: #26a69a; + text-align: center; + letter-spacing: .5px; + -webkit-transition: background-color .2s ease-out; + transition: background-color .2s ease-out; + cursor: pointer; +} + +.btn:hover, .btn-large:hover, .btn-small:hover { + background-color: #2bbbad; +} + +.btn-floating { + display: inline-block; + color: #fff; + position: relative; + overflow: hidden; + z-index: 1; + width: 40px; + height: 40px; + line-height: 40px; + padding: 0; + background-color: #26a69a; + border-radius: 50%; + -webkit-transition: background-color .3s; + transition: background-color .3s; + cursor: pointer; + vertical-align: middle; +} + +.btn-floating:hover { + background-color: #26a69a; +} + +.btn-floating:before { + border-radius: 0; +} + +.btn-floating.btn-large { + width: 56px; + height: 56px; + padding: 0; +} + +.btn-floating.btn-large.halfway-fab { + bottom: -28px; +} + +.btn-floating.btn-large i { + line-height: 56px; +} + +.btn-floating.btn-small { + width: 32.4px; + height: 32.4px; +} + +.btn-floating.btn-small.halfway-fab { + bottom: -16.2px; +} + +.btn-floating.btn-small i { + line-height: 32.4px; +} + +.btn-floating.halfway-fab { + position: absolute; + right: 24px; + bottom: -20px; +} + +.btn-floating.halfway-fab.left { + right: auto; + left: 24px; +} + +.btn-floating i { + width: inherit; + display: inline-block; + text-align: center; + color: #fff; + font-size: 1.6rem; + line-height: 40px; +} + +button.btn-floating { + border: none; +} + +.fixed-action-btn { + position: fixed; + right: 23px; + bottom: 23px; + padding-top: 15px; + margin-bottom: 0; + z-index: 997; +} + +.fixed-action-btn.active ul { + visibility: visible; +} + +.fixed-action-btn.direction-left, .fixed-action-btn.direction-right { + padding: 0 0 0 15px; +} + +.fixed-action-btn.direction-left ul, .fixed-action-btn.direction-right ul { + text-align: right; + right: 64px; + top: 50%; + -webkit-transform: translateY(-50%); + transform: translateY(-50%); + height: 100%; + left: auto; + /*width 100% only goes to width of button container */ + width: 500px; +} + +.fixed-action-btn.direction-left ul li, .fixed-action-btn.direction-right ul li { + display: inline-block; + margin: 7.5px 15px 0 0; +} + +.fixed-action-btn.direction-right { + padding: 0 15px 0 0; +} + +.fixed-action-btn.direction-right ul { + text-align: left; + direction: rtl; + left: 64px; + right: auto; +} + +.fixed-action-btn.direction-right ul li { + margin: 7.5px 0 0 15px; +} + +.fixed-action-btn.direction-bottom { + padding: 0 0 15px 0; +} + +.fixed-action-btn.direction-bottom ul { + top: 64px; + bottom: auto; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: reverse; + -webkit-flex-direction: column-reverse; + -ms-flex-direction: column-reverse; + flex-direction: column-reverse; +} + +.fixed-action-btn.direction-bottom ul li { + margin: 15px 0 0 0; +} + +.fixed-action-btn.toolbar { + padding: 0; + height: 56px; +} + +.fixed-action-btn.toolbar.active > a i { + opacity: 0; +} + +.fixed-action-btn.toolbar ul { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + top: 0; + bottom: 0; + z-index: 1; +} + +.fixed-action-btn.toolbar ul li { + -webkit-box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + display: inline-block; + margin: 0; + height: 100%; + -webkit-transition: none; + transition: none; +} + +.fixed-action-btn.toolbar ul li a { + display: block; + overflow: hidden; + position: relative; + width: 100%; + height: 100%; + background-color: transparent; + -webkit-box-shadow: none; + box-shadow: none; + color: #fff; + line-height: 56px; + z-index: 1; +} + +.fixed-action-btn.toolbar ul li a i { + line-height: inherit; +} + +.fixed-action-btn ul { + left: 0; + right: 0; + text-align: center; + position: absolute; + bottom: 64px; + margin: 0; + visibility: hidden; +} + +.fixed-action-btn ul li { + margin-bottom: 15px; +} + +.fixed-action-btn ul a.btn-floating { + opacity: 0; +} + +.fixed-action-btn .fab-backdrop { + position: absolute; + top: 0; + left: 0; + z-index: -1; + width: 40px; + height: 40px; + background-color: #26a69a; + border-radius: 50%; + -webkit-transform: scale(0); + transform: scale(0); +} + +.btn-flat { + -webkit-box-shadow: none; + box-shadow: none; + background-color: transparent; + color: #343434; + cursor: pointer; + -webkit-transition: background-color .2s; + transition: background-color .2s; +} + +.btn-flat:focus, .btn-flat:hover { + -webkit-box-shadow: none; + box-shadow: none; +} + +.btn-flat:focus { + background-color: rgba(0, 0, 0, 0.1); +} + +.btn-flat.disabled { + background-color: transparent !important; + color: #b3b2b2 !important; + cursor: default; +} + +.btn-large { + height: 54px; + line-height: 54px; + font-size: 15px; + padding: 0 28px; +} + +.btn-large i { + font-size: 1.6rem; +} + +.btn-small { + height: 32.4px; + line-height: 32.4px; + font-size: 13px; +} + +.btn-small i { + font-size: 1.2rem; +} + +.btn-block { + display: block; +} + +.dropdown-content { + background-color: #fff; + margin: 0; + display: none; + min-width: 100px; + overflow-y: auto; + opacity: 0; + position: absolute; + left: 0; + top: 0; + z-index: 9999; + -webkit-transform-origin: 0 0; + transform-origin: 0 0; +} + +.dropdown-content:focus { + outline: 0; +} + +.dropdown-content li { + clear: both; + color: rgba(0, 0, 0, 0.87); + cursor: pointer; + min-height: 50px; + line-height: 1.5rem; + width: 100%; + text-align: left; +} + +.dropdown-content li:hover, .dropdown-content li.active { + background-color: #eee; +} + +.dropdown-content li:focus { + outline: none; + background-color: #dadada; +} + +.dropdown-content li.divider { + min-height: 0; + height: 1px; +} + +.dropdown-content li > a, .dropdown-content li > span { + font-size: 16px; + color: #26a69a; + display: block; + line-height: 22px; + padding: 14px 16px; +} + +.dropdown-content li > span > label { + top: 1px; + left: 0; + height: 18px; +} + +.dropdown-content li > a > i { + height: inherit; + line-height: inherit; + float: left; + margin: 0 24px 0 0; + width: 24px; +} + +.input-field.col .dropdown-content [type="checkbox"] + label { + top: 1px; + left: 0; + height: 18px; + -webkit-transform: none; + transform: none; +} + +/*! + * Waves v0.6.0 + * http://fian.my.id/Waves + * + * Copyright 2014 Alfiana E. Sibuea and other contributors + * Released under the MIT license + * https://github.com/fians/Waves/blob/master/LICENSE + */ +.waves-effect { + position: relative; + cursor: pointer; + display: inline-block; + overflow: hidden; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-tap-highlight-color: transparent; + vertical-align: middle; + z-index: 1; + -webkit-transition: .3s ease-out; + transition: .3s ease-out; +} + +.waves-effect .waves-ripple { + position: absolute; + border-radius: 50%; + width: 20px; + height: 20px; + margin-top: -10px; + margin-left: -10px; + opacity: 0; + background: rgba(0, 0, 0, 0.2); + -webkit-transition: all 0.7s ease-out; + transition: all 0.7s ease-out; + -webkit-transition-property: opacity, -webkit-transform; + transition-property: opacity, -webkit-transform; + transition-property: transform, opacity; + transition-property: transform, opacity, -webkit-transform; + -webkit-transform: scale(0); + transform: scale(0); + pointer-events: none; +} + +.waves-effect.waves-light .waves-ripple { + background-color: rgba(255, 255, 255, 0.45); +} + +.waves-effect.waves-red .waves-ripple { + background-color: rgba(244, 67, 54, 0.7); +} + +.waves-effect.waves-yellow .waves-ripple { + background-color: rgba(255, 235, 59, 0.7); +} + +.waves-effect.waves-orange .waves-ripple { + background-color: rgba(255, 152, 0, 0.7); +} + +.waves-effect.waves-purple .waves-ripple { + background-color: rgba(156, 39, 176, 0.7); +} + +.waves-effect.waves-green .waves-ripple { + background-color: rgba(76, 175, 80, 0.7); +} + +.waves-effect.waves-teal .waves-ripple { + background-color: rgba(0, 150, 136, 0.7); +} + +.waves-effect input[type="button"], .waves-effect input[type="reset"], .waves-effect input[type="submit"] { + border: 0; + font-style: normal; + font-size: inherit; + text-transform: inherit; + background: none; +} + +.waves-effect img { + position: relative; + z-index: -1; +} + +.waves-notransition { + -webkit-transition: none !important; + transition: none !important; +} + +.waves-circle { + -webkit-transform: translateZ(0); + transform: translateZ(0); + -webkit-mask-image: -webkit-radial-gradient(circle, white 100%, black 100%); +} + +.waves-input-wrapper { + border-radius: 0.2em; + vertical-align: bottom; +} + +.waves-input-wrapper .waves-button-input { + position: relative; + top: 0; + left: 0; + z-index: 1; +} + +.waves-circle { + text-align: center; + width: 2.5em; + height: 2.5em; + line-height: 2.5em; + border-radius: 50%; + -webkit-mask-image: none; +} + +.waves-block { + display: block; +} + +/* Firefox Bug: link not triggered */ +.waves-effect .waves-ripple { + z-index: -1; +} + +.modal { + display: none; + position: fixed; + left: 0; + right: 0; + background-color: #fafafa; + padding: 0; + max-height: 70%; + width: 55%; + margin: auto; + overflow-y: auto; + border-radius: 2px; + will-change: top, opacity; +} + +@media only screen and (max-width: 992px) { + .modal { + width: 80%; + } +} + +.modal h1, .modal h2, .modal h3, .modal h4 { + margin-top: 0; +} + +.modal .modal-content { + padding: 24px; +} + +.modal .modal-close { + cursor: pointer; +} + +.modal .modal-footer { + border-radius: 0 0 2px 2px; + background-color: #fafafa; + padding: 4px 6px; + height: 56px; + width: 100%; + text-align: right; +} + +.modal .modal-footer .btn, .modal .modal-footer .btn-large, .modal .modal-footer .btn-small, .modal .modal-footer .btn-flat { + margin: 6px 0; +} + +.modal-overlay { + position: fixed; + z-index: 999; + top: -25%; + left: 0; + bottom: 0; + right: 0; + height: 125%; + width: 100%; + background: #000; + display: none; + will-change: opacity; +} + +.modal.modal-fixed-footer { + padding: 0; + height: 70%; +} + +.modal.modal-fixed-footer .modal-content { + position: absolute; + height: calc(100% - 56px); + max-height: 100%; + width: 100%; + overflow-y: auto; +} + +.modal.modal-fixed-footer .modal-footer { + border-top: 1px solid rgba(0, 0, 0, 0.1); + position: absolute; + bottom: 0; +} + +.modal.bottom-sheet { + top: auto; + bottom: -100%; + margin: 0; + width: 100%; + max-height: 45%; + border-radius: 0; + will-change: bottom, opacity; +} + +.collapsible { + border-top: 1px solid #ddd; + border-right: 1px solid #ddd; + border-left: 1px solid #ddd; + margin: 0.5rem 0 1rem 0; +} + +.collapsible-header { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + cursor: pointer; + -webkit-tap-highlight-color: transparent; + line-height: 1.5; + padding: 1rem; + background-color: #fff; + border-bottom: 1px solid #ddd; +} + +.collapsible-header i { + width: 2rem; + font-size: 1.6rem; + display: inline-block; + text-align: center; + margin-right: 1rem; +} + +.collapsible-body { + display: none; + border-bottom: 1px solid #ddd; + -webkit-box-sizing: border-box; + box-sizing: border-box; + padding: 2rem; +} + +.sidenav .collapsible, +.sidenav.fixed .collapsible { + border: none; + -webkit-box-shadow: none; + box-shadow: none; +} + +.sidenav .collapsible li, +.sidenav.fixed .collapsible li { + padding: 0; +} + +.sidenav .collapsible-header, +.sidenav.fixed .collapsible-header { + background-color: transparent; + border: none; + line-height: inherit; + height: inherit; + padding: 0 16px; +} + +.sidenav .collapsible-header:hover, +.sidenav.fixed .collapsible-header:hover { + background-color: rgba(0, 0, 0, 0.05); +} + +.sidenav .collapsible-header i, +.sidenav.fixed .collapsible-header i { + line-height: inherit; +} + +.sidenav .collapsible-body, +.sidenav.fixed .collapsible-body { + border: 0; + background-color: #fff; +} + +.sidenav .collapsible-body li a, +.sidenav.fixed .collapsible-body li a { + padding: 0 23.5px 0 31px; +} + +.collapsible.popout { + border: none; + -webkit-box-shadow: none; + box-shadow: none; +} + +.collapsible.popout > li { + -webkit-box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12); + box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12); + margin: 0 24px; + -webkit-transition: margin 0.35s cubic-bezier(0.25, 0.46, 0.45, 0.94); + transition: margin 0.35s cubic-bezier(0.25, 0.46, 0.45, 0.94); +} + +.collapsible.popout > li.active { + -webkit-box-shadow: 0 5px 11px 0 rgba(0, 0, 0, 0.18), 0 4px 15px 0 rgba(0, 0, 0, 0.15); + box-shadow: 0 5px 11px 0 rgba(0, 0, 0, 0.18), 0 4px 15px 0 rgba(0, 0, 0, 0.15); + margin: 16px 0; +} + +.chip { + display: inline-block; + height: 32px; + font-size: 13px; + font-weight: 500; + color: rgba(0, 0, 0, 0.6); + line-height: 32px; + padding: 0 12px; + border-radius: 16px; + background-color: #e4e4e4; + margin-bottom: 5px; + margin-right: 5px; +} + +.chip:focus { + outline: none; + background-color: #26a69a; + color: #fff; +} + +.chip > img { + float: left; + margin: 0 8px 0 -12px; + height: 32px; + width: 32px; + border-radius: 50%; +} + +.chip .close { + cursor: pointer; + float: right; + font-size: 16px; + line-height: 32px; + padding-left: 8px; +} + +.chips { + border: none; + border-bottom: 1px solid #9e9e9e; + -webkit-box-shadow: none; + box-shadow: none; + margin: 0 0 8px 0; + min-height: 45px; + outline: none; + -webkit-transition: all .3s; + transition: all .3s; +} + +.chips.focus { + border-bottom: 1px solid #26a69a; + -webkit-box-shadow: 0 1px 0 0 #26a69a; + box-shadow: 0 1px 0 0 #26a69a; +} + +.chips:hover { + cursor: text; +} + +.chips .input { + background: none; + border: 0; + color: rgba(0, 0, 0, 0.6); + display: inline-block; + font-size: 16px; + height: 3rem; + line-height: 32px; + outline: 0; + margin: 0; + padding: 0 !important; + width: 120px !important; +} + +.chips .input:focus { + border: 0 !important; + -webkit-box-shadow: none !important; + box-shadow: none !important; +} + +.chips .autocomplete-content { + margin-top: 0; + margin-bottom: 0; +} + +.prefix ~ .chips { + margin-left: 3rem; + width: 92%; + width: calc(100% - 3rem); +} + +.chips:empty ~ label { + font-size: 0.8rem; + -webkit-transform: translateY(-140%); + transform: translateY(-140%); +} + +.materialboxed { + display: block; + cursor: -webkit-zoom-in; + cursor: zoom-in; + position: relative; + -webkit-transition: opacity .4s; + transition: opacity .4s; + -webkit-backface-visibility: hidden; +} + +.materialboxed:hover:not(.active) { + opacity: .8; +} + +.materialboxed.active { + cursor: -webkit-zoom-out; + cursor: zoom-out; +} + +#materialbox-overlay { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + background-color: #292929; + z-index: 1000; + will-change: opacity; +} + +.materialbox-caption { + position: fixed; + display: none; + color: #fff; + line-height: 50px; + bottom: 0; + left: 0; + width: 100%; + text-align: center; + padding: 0% 15%; + height: 50px; + z-index: 1000; + -webkit-font-smoothing: antialiased; +} + +select:focus { + outline: 1px solid #c9f3ef; +} + +button:focus { + outline: none; + background-color: #2ab7a9; +} + +label { + font-size: 0.8rem; + color: #9e9e9e; +} + +/* Text Inputs + Textarea + ========================================================================== */ +/* Style Placeholders */ +::-webkit-input-placeholder { + color: #d1d1d1; +} +::-moz-placeholder { + color: #d1d1d1; +} +:-ms-input-placeholder { + color: #d1d1d1; +} +::placeholder { + color: #d1d1d1; +} + +/* Text inputs */ +input:not([type]), +input[type=text]:not(.browser-default), +input[type=password]:not(.browser-default), +input[type=email]:not(.browser-default), +input[type=url]:not(.browser-default), +input[type=time]:not(.browser-default), +input[type=date]:not(.browser-default), +input[type=datetime]:not(.browser-default), +input[type=datetime-local]:not(.browser-default), +input[type=tel]:not(.browser-default), +input[type=number]:not(.browser-default), +input[type=search]:not(.browser-default), +textarea.materialize-textarea { + background-color: transparent; + border: none; + border-bottom: 1px solid #9e9e9e; + border-radius: 0; + outline: none; + height: 3rem; + width: 100%; + font-size: 16px; + margin: 0 0 8px 0; + padding: 0; + -webkit-box-shadow: none; + box-shadow: none; + -webkit-box-sizing: content-box; + box-sizing: content-box; + -webkit-transition: border .3s, -webkit-box-shadow .3s; + transition: border .3s, -webkit-box-shadow .3s; + transition: box-shadow .3s, border .3s; + transition: box-shadow .3s, border .3s, -webkit-box-shadow .3s; +} + +input:not([type]):disabled, input:not([type])[readonly="readonly"], +input[type=text]:not(.browser-default):disabled, +input[type=text]:not(.browser-default)[readonly="readonly"], +input[type=password]:not(.browser-default):disabled, +input[type=password]:not(.browser-default)[readonly="readonly"], +input[type=email]:not(.browser-default):disabled, +input[type=email]:not(.browser-default)[readonly="readonly"], +input[type=url]:not(.browser-default):disabled, +input[type=url]:not(.browser-default)[readonly="readonly"], +input[type=time]:not(.browser-default):disabled, +input[type=time]:not(.browser-default)[readonly="readonly"], +input[type=date]:not(.browser-default):disabled, +input[type=date]:not(.browser-default)[readonly="readonly"], +input[type=datetime]:not(.browser-default):disabled, +input[type=datetime]:not(.browser-default)[readonly="readonly"], +input[type=datetime-local]:not(.browser-default):disabled, +input[type=datetime-local]:not(.browser-default)[readonly="readonly"], +input[type=tel]:not(.browser-default):disabled, +input[type=tel]:not(.browser-default)[readonly="readonly"], +input[type=number]:not(.browser-default):disabled, +input[type=number]:not(.browser-default)[readonly="readonly"], +input[type=search]:not(.browser-default):disabled, +input[type=search]:not(.browser-default)[readonly="readonly"], +textarea.materialize-textarea:disabled, +textarea.materialize-textarea[readonly="readonly"] { + color: rgba(0, 0, 0, 0.42); + border-bottom: 1px dotted rgba(0, 0, 0, 0.42); +} + +input:not([type]):disabled + label, +input:not([type])[readonly="readonly"] + label, +input[type=text]:not(.browser-default):disabled + label, +input[type=text]:not(.browser-default)[readonly="readonly"] + label, +input[type=password]:not(.browser-default):disabled + label, +input[type=password]:not(.browser-default)[readonly="readonly"] + label, +input[type=email]:not(.browser-default):disabled + label, +input[type=email]:not(.browser-default)[readonly="readonly"] + label, +input[type=url]:not(.browser-default):disabled + label, +input[type=url]:not(.browser-default)[readonly="readonly"] + label, +input[type=time]:not(.browser-default):disabled + label, +input[type=time]:not(.browser-default)[readonly="readonly"] + label, +input[type=date]:not(.browser-default):disabled + label, +input[type=date]:not(.browser-default)[readonly="readonly"] + label, +input[type=datetime]:not(.browser-default):disabled + label, +input[type=datetime]:not(.browser-default)[readonly="readonly"] + label, +input[type=datetime-local]:not(.browser-default):disabled + label, +input[type=datetime-local]:not(.browser-default)[readonly="readonly"] + label, +input[type=tel]:not(.browser-default):disabled + label, +input[type=tel]:not(.browser-default)[readonly="readonly"] + label, +input[type=number]:not(.browser-default):disabled + label, +input[type=number]:not(.browser-default)[readonly="readonly"] + label, +input[type=search]:not(.browser-default):disabled + label, +input[type=search]:not(.browser-default)[readonly="readonly"] + label, +textarea.materialize-textarea:disabled + label, +textarea.materialize-textarea[readonly="readonly"] + label { + color: rgba(0, 0, 0, 0.42); +} + +input:not([type]):focus:not([readonly]), +input[type=text]:not(.browser-default):focus:not([readonly]), +input[type=password]:not(.browser-default):focus:not([readonly]), +input[type=email]:not(.browser-default):focus:not([readonly]), +input[type=url]:not(.browser-default):focus:not([readonly]), +input[type=time]:not(.browser-default):focus:not([readonly]), +input[type=date]:not(.browser-default):focus:not([readonly]), +input[type=datetime]:not(.browser-default):focus:not([readonly]), +input[type=datetime-local]:not(.browser-default):focus:not([readonly]), +input[type=tel]:not(.browser-default):focus:not([readonly]), +input[type=number]:not(.browser-default):focus:not([readonly]), +input[type=search]:not(.browser-default):focus:not([readonly]), +textarea.materialize-textarea:focus:not([readonly]) { + border-bottom: 1px solid #26a69a; + -webkit-box-shadow: 0 1px 0 0 #26a69a; + box-shadow: 0 1px 0 0 #26a69a; +} + +input:not([type]):focus:not([readonly]) + label, +input[type=text]:not(.browser-default):focus:not([readonly]) + label, +input[type=password]:not(.browser-default):focus:not([readonly]) + label, +input[type=email]:not(.browser-default):focus:not([readonly]) + label, +input[type=url]:not(.browser-default):focus:not([readonly]) + label, +input[type=time]:not(.browser-default):focus:not([readonly]) + label, +input[type=date]:not(.browser-default):focus:not([readonly]) + label, +input[type=datetime]:not(.browser-default):focus:not([readonly]) + label, +input[type=datetime-local]:not(.browser-default):focus:not([readonly]) + label, +input[type=tel]:not(.browser-default):focus:not([readonly]) + label, +input[type=number]:not(.browser-default):focus:not([readonly]) + label, +input[type=search]:not(.browser-default):focus:not([readonly]) + label, +textarea.materialize-textarea:focus:not([readonly]) + label { + color: #26a69a; +} + +input:not([type]):focus.valid ~ label, +input[type=text]:not(.browser-default):focus.valid ~ label, +input[type=password]:not(.browser-default):focus.valid ~ label, +input[type=email]:not(.browser-default):focus.valid ~ label, +input[type=url]:not(.browser-default):focus.valid ~ label, +input[type=time]:not(.browser-default):focus.valid ~ label, +input[type=date]:not(.browser-default):focus.valid ~ label, +input[type=datetime]:not(.browser-default):focus.valid ~ label, +input[type=datetime-local]:not(.browser-default):focus.valid ~ label, +input[type=tel]:not(.browser-default):focus.valid ~ label, +input[type=number]:not(.browser-default):focus.valid ~ label, +input[type=search]:not(.browser-default):focus.valid ~ label, +textarea.materialize-textarea:focus.valid ~ label { + color: #4CAF50; +} + +input:not([type]):focus.invalid ~ label, +input[type=text]:not(.browser-default):focus.invalid ~ label, +input[type=password]:not(.browser-default):focus.invalid ~ label, +input[type=email]:not(.browser-default):focus.invalid ~ label, +input[type=url]:not(.browser-default):focus.invalid ~ label, +input[type=time]:not(.browser-default):focus.invalid ~ label, +input[type=date]:not(.browser-default):focus.invalid ~ label, +input[type=datetime]:not(.browser-default):focus.invalid ~ label, +input[type=datetime-local]:not(.browser-default):focus.invalid ~ label, +input[type=tel]:not(.browser-default):focus.invalid ~ label, +input[type=number]:not(.browser-default):focus.invalid ~ label, +input[type=search]:not(.browser-default):focus.invalid ~ label, +textarea.materialize-textarea:focus.invalid ~ label { + color: #F44336; +} + +input:not([type]).validate + label, +input[type=text]:not(.browser-default).validate + label, +input[type=password]:not(.browser-default).validate + label, +input[type=email]:not(.browser-default).validate + label, +input[type=url]:not(.browser-default).validate + label, +input[type=time]:not(.browser-default).validate + label, +input[type=date]:not(.browser-default).validate + label, +input[type=datetime]:not(.browser-default).validate + label, +input[type=datetime-local]:not(.browser-default).validate + label, +input[type=tel]:not(.browser-default).validate + label, +input[type=number]:not(.browser-default).validate + label, +input[type=search]:not(.browser-default).validate + label, +textarea.materialize-textarea.validate + label { + width: 100%; +} + +/* Validation Sass Placeholders */ +input.valid:not([type]), input.valid:not([type]):focus, +input[type=text].valid:not(.browser-default), +input[type=text].valid:not(.browser-default):focus, +input[type=password].valid:not(.browser-default), +input[type=password].valid:not(.browser-default):focus, +input[type=email].valid:not(.browser-default), +input[type=email].valid:not(.browser-default):focus, +input[type=url].valid:not(.browser-default), +input[type=url].valid:not(.browser-default):focus, +input[type=time].valid:not(.browser-default), +input[type=time].valid:not(.browser-default):focus, +input[type=date].valid:not(.browser-default), +input[type=date].valid:not(.browser-default):focus, +input[type=datetime].valid:not(.browser-default), +input[type=datetime].valid:not(.browser-default):focus, +input[type=datetime-local].valid:not(.browser-default), +input[type=datetime-local].valid:not(.browser-default):focus, +input[type=tel].valid:not(.browser-default), +input[type=tel].valid:not(.browser-default):focus, +input[type=number].valid:not(.browser-default), +input[type=number].valid:not(.browser-default):focus, +input[type=search].valid:not(.browser-default), +input[type=search].valid:not(.browser-default):focus, +textarea.materialize-textarea.valid, +textarea.materialize-textarea.valid:focus, .select-wrapper.valid > input.select-dropdown { + border-bottom: 1px solid #4CAF50; + -webkit-box-shadow: 0 1px 0 0 #4CAF50; + box-shadow: 0 1px 0 0 #4CAF50; +} + +input.invalid:not([type]), input.invalid:not([type]):focus, +input[type=text].invalid:not(.browser-default), +input[type=text].invalid:not(.browser-default):focus, +input[type=password].invalid:not(.browser-default), +input[type=password].invalid:not(.browser-default):focus, +input[type=email].invalid:not(.browser-default), +input[type=email].invalid:not(.browser-default):focus, +input[type=url].invalid:not(.browser-default), +input[type=url].invalid:not(.browser-default):focus, +input[type=time].invalid:not(.browser-default), +input[type=time].invalid:not(.browser-default):focus, +input[type=date].invalid:not(.browser-default), +input[type=date].invalid:not(.browser-default):focus, +input[type=datetime].invalid:not(.browser-default), +input[type=datetime].invalid:not(.browser-default):focus, +input[type=datetime-local].invalid:not(.browser-default), +input[type=datetime-local].invalid:not(.browser-default):focus, +input[type=tel].invalid:not(.browser-default), +input[type=tel].invalid:not(.browser-default):focus, +input[type=number].invalid:not(.browser-default), +input[type=number].invalid:not(.browser-default):focus, +input[type=search].invalid:not(.browser-default), +input[type=search].invalid:not(.browser-default):focus, +textarea.materialize-textarea.invalid, +textarea.materialize-textarea.invalid:focus, .select-wrapper.invalid > input.select-dropdown, +.select-wrapper.invalid > input.select-dropdown:focus { + border-bottom: 1px solid #F44336; + -webkit-box-shadow: 0 1px 0 0 #F44336; + box-shadow: 0 1px 0 0 #F44336; +} + +input:not([type]).valid ~ .helper-text[data-success], +input:not([type]):focus.valid ~ .helper-text[data-success], +input:not([type]).invalid ~ .helper-text[data-error], +input:not([type]):focus.invalid ~ .helper-text[data-error], +input[type=text]:not(.browser-default).valid ~ .helper-text[data-success], +input[type=text]:not(.browser-default):focus.valid ~ .helper-text[data-success], +input[type=text]:not(.browser-default).invalid ~ .helper-text[data-error], +input[type=text]:not(.browser-default):focus.invalid ~ .helper-text[data-error], +input[type=password]:not(.browser-default).valid ~ .helper-text[data-success], +input[type=password]:not(.browser-default):focus.valid ~ .helper-text[data-success], +input[type=password]:not(.browser-default).invalid ~ .helper-text[data-error], +input[type=password]:not(.browser-default):focus.invalid ~ .helper-text[data-error], +input[type=email]:not(.browser-default).valid ~ .helper-text[data-success], +input[type=email]:not(.browser-default):focus.valid ~ .helper-text[data-success], +input[type=email]:not(.browser-default).invalid ~ .helper-text[data-error], +input[type=email]:not(.browser-default):focus.invalid ~ .helper-text[data-error], +input[type=url]:not(.browser-default).valid ~ .helper-text[data-success], +input[type=url]:not(.browser-default):focus.valid ~ .helper-text[data-success], +input[type=url]:not(.browser-default).invalid ~ .helper-text[data-error], +input[type=url]:not(.browser-default):focus.invalid ~ .helper-text[data-error], +input[type=time]:not(.browser-default).valid ~ .helper-text[data-success], +input[type=time]:not(.browser-default):focus.valid ~ .helper-text[data-success], +input[type=time]:not(.browser-default).invalid ~ .helper-text[data-error], +input[type=time]:not(.browser-default):focus.invalid ~ .helper-text[data-error], +input[type=date]:not(.browser-default).valid ~ .helper-text[data-success], +input[type=date]:not(.browser-default):focus.valid ~ .helper-text[data-success], +input[type=date]:not(.browser-default).invalid ~ .helper-text[data-error], +input[type=date]:not(.browser-default):focus.invalid ~ .helper-text[data-error], +input[type=datetime]:not(.browser-default).valid ~ .helper-text[data-success], +input[type=datetime]:not(.browser-default):focus.valid ~ .helper-text[data-success], +input[type=datetime]:not(.browser-default).invalid ~ .helper-text[data-error], +input[type=datetime]:not(.browser-default):focus.invalid ~ .helper-text[data-error], +input[type=datetime-local]:not(.browser-default).valid ~ .helper-text[data-success], +input[type=datetime-local]:not(.browser-default):focus.valid ~ .helper-text[data-success], +input[type=datetime-local]:not(.browser-default).invalid ~ .helper-text[data-error], +input[type=datetime-local]:not(.browser-default):focus.invalid ~ .helper-text[data-error], +input[type=tel]:not(.browser-default).valid ~ .helper-text[data-success], +input[type=tel]:not(.browser-default):focus.valid ~ .helper-text[data-success], +input[type=tel]:not(.browser-default).invalid ~ .helper-text[data-error], +input[type=tel]:not(.browser-default):focus.invalid ~ .helper-text[data-error], +input[type=number]:not(.browser-default).valid ~ .helper-text[data-success], +input[type=number]:not(.browser-default):focus.valid ~ .helper-text[data-success], +input[type=number]:not(.browser-default).invalid ~ .helper-text[data-error], +input[type=number]:not(.browser-default):focus.invalid ~ .helper-text[data-error], +input[type=search]:not(.browser-default).valid ~ .helper-text[data-success], +input[type=search]:not(.browser-default):focus.valid ~ .helper-text[data-success], +input[type=search]:not(.browser-default).invalid ~ .helper-text[data-error], +input[type=search]:not(.browser-default):focus.invalid ~ .helper-text[data-error], +textarea.materialize-textarea.valid ~ .helper-text[data-success], +textarea.materialize-textarea:focus.valid ~ .helper-text[data-success], +textarea.materialize-textarea.invalid ~ .helper-text[data-error], +textarea.materialize-textarea:focus.invalid ~ .helper-text[data-error], .select-wrapper.valid .helper-text[data-success], +.select-wrapper.invalid ~ .helper-text[data-error] { + color: transparent; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + pointer-events: none; +} + +input:not([type]).valid ~ .helper-text:after, +input:not([type]):focus.valid ~ .helper-text:after, +input[type=text]:not(.browser-default).valid ~ .helper-text:after, +input[type=text]:not(.browser-default):focus.valid ~ .helper-text:after, +input[type=password]:not(.browser-default).valid ~ .helper-text:after, +input[type=password]:not(.browser-default):focus.valid ~ .helper-text:after, +input[type=email]:not(.browser-default).valid ~ .helper-text:after, +input[type=email]:not(.browser-default):focus.valid ~ .helper-text:after, +input[type=url]:not(.browser-default).valid ~ .helper-text:after, +input[type=url]:not(.browser-default):focus.valid ~ .helper-text:after, +input[type=time]:not(.browser-default).valid ~ .helper-text:after, +input[type=time]:not(.browser-default):focus.valid ~ .helper-text:after, +input[type=date]:not(.browser-default).valid ~ .helper-text:after, +input[type=date]:not(.browser-default):focus.valid ~ .helper-text:after, +input[type=datetime]:not(.browser-default).valid ~ .helper-text:after, +input[type=datetime]:not(.browser-default):focus.valid ~ .helper-text:after, +input[type=datetime-local]:not(.browser-default).valid ~ .helper-text:after, +input[type=datetime-local]:not(.browser-default):focus.valid ~ .helper-text:after, +input[type=tel]:not(.browser-default).valid ~ .helper-text:after, +input[type=tel]:not(.browser-default):focus.valid ~ .helper-text:after, +input[type=number]:not(.browser-default).valid ~ .helper-text:after, +input[type=number]:not(.browser-default):focus.valid ~ .helper-text:after, +input[type=search]:not(.browser-default).valid ~ .helper-text:after, +input[type=search]:not(.browser-default):focus.valid ~ .helper-text:after, +textarea.materialize-textarea.valid ~ .helper-text:after, +textarea.materialize-textarea:focus.valid ~ .helper-text:after, .select-wrapper.valid ~ .helper-text:after { + content: attr(data-success); + color: #4CAF50; +} + +input:not([type]).invalid ~ .helper-text:after, +input:not([type]):focus.invalid ~ .helper-text:after, +input[type=text]:not(.browser-default).invalid ~ .helper-text:after, +input[type=text]:not(.browser-default):focus.invalid ~ .helper-text:after, +input[type=password]:not(.browser-default).invalid ~ .helper-text:after, +input[type=password]:not(.browser-default):focus.invalid ~ .helper-text:after, +input[type=email]:not(.browser-default).invalid ~ .helper-text:after, +input[type=email]:not(.browser-default):focus.invalid ~ .helper-text:after, +input[type=url]:not(.browser-default).invalid ~ .helper-text:after, +input[type=url]:not(.browser-default):focus.invalid ~ .helper-text:after, +input[type=time]:not(.browser-default).invalid ~ .helper-text:after, +input[type=time]:not(.browser-default):focus.invalid ~ .helper-text:after, +input[type=date]:not(.browser-default).invalid ~ .helper-text:after, +input[type=date]:not(.browser-default):focus.invalid ~ .helper-text:after, +input[type=datetime]:not(.browser-default).invalid ~ .helper-text:after, +input[type=datetime]:not(.browser-default):focus.invalid ~ .helper-text:after, +input[type=datetime-local]:not(.browser-default).invalid ~ .helper-text:after, +input[type=datetime-local]:not(.browser-default):focus.invalid ~ .helper-text:after, +input[type=tel]:not(.browser-default).invalid ~ .helper-text:after, +input[type=tel]:not(.browser-default):focus.invalid ~ .helper-text:after, +input[type=number]:not(.browser-default).invalid ~ .helper-text:after, +input[type=number]:not(.browser-default):focus.invalid ~ .helper-text:after, +input[type=search]:not(.browser-default).invalid ~ .helper-text:after, +input[type=search]:not(.browser-default):focus.invalid ~ .helper-text:after, +textarea.materialize-textarea.invalid ~ .helper-text:after, +textarea.materialize-textarea:focus.invalid ~ .helper-text:after, .select-wrapper.invalid ~ .helper-text:after { + content: attr(data-error); + color: #F44336; +} + +input:not([type]) + label:after, +input[type=text]:not(.browser-default) + label:after, +input[type=password]:not(.browser-default) + label:after, +input[type=email]:not(.browser-default) + label:after, +input[type=url]:not(.browser-default) + label:after, +input[type=time]:not(.browser-default) + label:after, +input[type=date]:not(.browser-default) + label:after, +input[type=datetime]:not(.browser-default) + label:after, +input[type=datetime-local]:not(.browser-default) + label:after, +input[type=tel]:not(.browser-default) + label:after, +input[type=number]:not(.browser-default) + label:after, +input[type=search]:not(.browser-default) + label:after, +textarea.materialize-textarea + label:after, .select-wrapper + label:after { + display: block; + content: ""; + position: absolute; + top: 100%; + left: 0; + opacity: 0; + -webkit-transition: .2s opacity ease-out, .2s color ease-out; + transition: .2s opacity ease-out, .2s color ease-out; +} + +.input-field { + position: relative; + margin-top: 1rem; + margin-bottom: 1rem; +} + +.input-field.inline { + display: inline-block; + vertical-align: middle; + margin-left: 5px; +} + +.input-field.inline input, +.input-field.inline .select-dropdown { + margin-bottom: 1rem; +} + +.input-field.col label { + left: 0.75rem; +} + +.input-field.col .prefix ~ label, +.input-field.col .prefix ~ .validate ~ label { + width: calc(100% - 3rem - 1.5rem); +} + +.input-field > label { + color: #9e9e9e; + position: absolute; + top: 0; + left: 0; + font-size: 1rem; + cursor: text; + -webkit-transition: color .2s ease-out, -webkit-transform .2s ease-out; + transition: color .2s ease-out, -webkit-transform .2s ease-out; + transition: transform .2s ease-out, color .2s ease-out; + transition: transform .2s ease-out, color .2s ease-out, -webkit-transform .2s ease-out; + -webkit-transform-origin: 0% 100%; + transform-origin: 0% 100%; + text-align: initial; + -webkit-transform: translateY(12px); + transform: translateY(12px); +} + +.input-field > label:not(.label-icon).active { + -webkit-transform: translateY(-14px) scale(0.8); + transform: translateY(-14px) scale(0.8); + -webkit-transform-origin: 0 0; + transform-origin: 0 0; +} + +.input-field > input[type=date]:not(.browser-default) + label, +.input-field > input[type=time]:not(.browser-default) + label { + -webkit-transform: translateY(-14px) scale(0.8); + transform: translateY(-14px) scale(0.8); + -webkit-transform-origin: 0 0; + transform-origin: 0 0; +} + +.input-field .helper-text { + position: relative; + min-height: 18px; + display: block; + font-size: 12px; + color: rgba(0, 0, 0, 0.54); +} + +.input-field .helper-text::after { + opacity: 1; + position: absolute; + top: 0; + left: 0; +} + +.input-field .prefix { + position: absolute; + width: 3rem; + font-size: 2rem; + -webkit-transition: color .2s; + transition: color .2s; + top: 0.5rem; +} + +.input-field .prefix.active { + color: #26a69a; +} + +.input-field .prefix ~ input, +.input-field .prefix ~ textarea, +.input-field .prefix ~ label, +.input-field .prefix ~ .validate ~ label, +.input-field .prefix ~ .helper-text, +.input-field .prefix ~ .autocomplete-content { + margin-left: 3rem; + width: 92%; + width: calc(100% - 3rem); +} + +.input-field .prefix ~ label { + margin-left: 3rem; +} + +@media only screen and (max-width: 992px) { + .input-field .prefix ~ input { + width: 86%; + width: calc(100% - 3rem); + } +} + +@media only screen and (max-width: 600px) { + .input-field .prefix ~ input { + width: 80%; + width: calc(100% - 3rem); + } +} + +/* Search Field */ +.input-field input[type=search] { + display: block; + line-height: inherit; + -webkit-transition: .3s background-color; + transition: .3s background-color; +} + +.nav-wrapper .input-field input[type=search] { + height: inherit; + padding-left: 4rem; + width: calc(100% - 4rem); + border: 0; + -webkit-box-shadow: none; + box-shadow: none; +} + +.input-field input[type=search]:focus:not(.browser-default) { + background-color: #fff; + border: 0; + -webkit-box-shadow: none; + box-shadow: none; + color: #444; +} + +.input-field input[type=search]:focus:not(.browser-default) + label i, +.input-field input[type=search]:focus:not(.browser-default) ~ .mdi-navigation-close, +.input-field input[type=search]:focus:not(.browser-default) ~ .material-icons { + color: #444; +} + +.input-field input[type=search] + .label-icon { + -webkit-transform: none; + transform: none; + left: 1rem; +} + +.input-field input[type=search] ~ .mdi-navigation-close, +.input-field input[type=search] ~ .material-icons { + position: absolute; + top: 0; + right: 1rem; + color: transparent; + cursor: pointer; + font-size: 2rem; + -webkit-transition: .3s color; + transition: .3s color; +} + +/* Textarea */ +textarea { + width: 100%; + height: 3rem; + background-color: transparent; +} + +textarea.materialize-textarea { + line-height: normal; + overflow-y: hidden; + /* prevents scroll bar flash */ + padding: .8rem 0 .8rem 0; + /* prevents text jump on Enter keypress */ + resize: none; + min-height: 3rem; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +.hiddendiv { + visibility: hidden; + white-space: pre-wrap; + word-wrap: break-word; + overflow-wrap: break-word; + /* future version of deprecated 'word-wrap' */ + padding-top: 1.2rem; + /* prevents text jump on Enter keypress */ + position: absolute; + top: 0; + z-index: -1; +} + +/* Autocomplete */ +.autocomplete-content li .highlight { + color: #444; +} + +.autocomplete-content li img { + height: 40px; + width: 40px; + margin: 5px 15px; +} + +/* Character Counter */ +.character-counter { + min-height: 18px; +} + +/* Radio Buttons + ========================================================================== */ +[type="radio"]:not(:checked), +[type="radio"]:checked { + position: absolute; + opacity: 0; + pointer-events: none; +} + +[type="radio"]:not(:checked) + span, +[type="radio"]:checked + span { + position: relative; + padding-left: 35px; + cursor: pointer; + display: inline-block; + height: 25px; + line-height: 25px; + font-size: 1rem; + -webkit-transition: .28s ease; + transition: .28s ease; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +[type="radio"] + span:before, +[type="radio"] + span:after { + content: ''; + position: absolute; + left: 0; + top: 0; + margin: 4px; + width: 16px; + height: 16px; + z-index: 0; + -webkit-transition: .28s ease; + transition: .28s ease; +} + +/* Unchecked styles */ +[type="radio"]:not(:checked) + span:before, +[type="radio"]:not(:checked) + span:after, +[type="radio"]:checked + span:before, +[type="radio"]:checked + span:after, +[type="radio"].with-gap:checked + span:before, +[type="radio"].with-gap:checked + span:after { + border-radius: 50%; +} + +[type="radio"]:not(:checked) + span:before, +[type="radio"]:not(:checked) + span:after { + border: 2px solid #5a5a5a; +} + +[type="radio"]:not(:checked) + span:after { + -webkit-transform: scale(0); + transform: scale(0); +} + +/* Checked styles */ +[type="radio"]:checked + span:before { + border: 2px solid transparent; +} + +[type="radio"]:checked + span:after, +[type="radio"].with-gap:checked + span:before, +[type="radio"].with-gap:checked + span:after { + border: 2px solid #26a69a; +} + +[type="radio"]:checked + span:after, +[type="radio"].with-gap:checked + span:after { + background-color: #26a69a; +} + +[type="radio"]:checked + span:after { + -webkit-transform: scale(1.02); + transform: scale(1.02); +} + +/* Radio With gap */ +[type="radio"].with-gap:checked + span:after { + -webkit-transform: scale(0.5); + transform: scale(0.5); +} + +/* Focused styles */ +[type="radio"].tabbed:focus + span:before { + -webkit-box-shadow: 0 0 0 10px rgba(0, 0, 0, 0.1); + box-shadow: 0 0 0 10px rgba(0, 0, 0, 0.1); +} + +/* Disabled Radio With gap */ +[type="radio"].with-gap:disabled:checked + span:before { + border: 2px solid rgba(0, 0, 0, 0.42); +} + +[type="radio"].with-gap:disabled:checked + span:after { + border: none; + background-color: rgba(0, 0, 0, 0.42); +} + +/* Disabled style */ +[type="radio"]:disabled:not(:checked) + span:before, +[type="radio"]:disabled:checked + span:before { + background-color: transparent; + border-color: rgba(0, 0, 0, 0.42); +} + +[type="radio"]:disabled + span { + color: rgba(0, 0, 0, 0.42); +} + +[type="radio"]:disabled:not(:checked) + span:before { + border-color: rgba(0, 0, 0, 0.42); +} + +[type="radio"]:disabled:checked + span:after { + background-color: rgba(0, 0, 0, 0.42); + border-color: #949494; +} + +/* Checkboxes + ========================================================================== */ +/* Remove default checkbox */ +[type="checkbox"]:not(:checked), +[type="checkbox"]:checked { + position: absolute; + opacity: 0; + pointer-events: none; +} + +[type="checkbox"] { + /* checkbox aspect */ +} + +[type="checkbox"] + span:not(.lever) { + position: relative; + padding-left: 35px; + cursor: pointer; + display: inline-block; + height: 25px; + line-height: 25px; + font-size: 1rem; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +[type="checkbox"] + span:not(.lever):before, +[type="checkbox"]:not(.filled-in) + span:not(.lever):after { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 18px; + height: 18px; + z-index: 0; + border: 2px solid #5a5a5a; + border-radius: 1px; + margin-top: 3px; + -webkit-transition: .2s; + transition: .2s; +} + +[type="checkbox"]:not(.filled-in) + span:not(.lever):after { + border: 0; + -webkit-transform: scale(0); + transform: scale(0); +} + +[type="checkbox"]:not(:checked):disabled + span:not(.lever):before { + border: none; + background-color: rgba(0, 0, 0, 0.42); +} + +[type="checkbox"].tabbed:focus + span:not(.lever):after { + -webkit-transform: scale(1); + transform: scale(1); + border: 0; + border-radius: 50%; + -webkit-box-shadow: 0 0 0 10px rgba(0, 0, 0, 0.1); + box-shadow: 0 0 0 10px rgba(0, 0, 0, 0.1); + background-color: rgba(0, 0, 0, 0.1); +} + +[type="checkbox"]:checked + span:not(.lever):before { + top: -4px; + left: -5px; + width: 12px; + height: 22px; + border-top: 2px solid transparent; + border-left: 2px solid transparent; + border-right: 2px solid #26a69a; + border-bottom: 2px solid #26a69a; + -webkit-transform: rotate(40deg); + transform: rotate(40deg); + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + -webkit-transform-origin: 100% 100%; + transform-origin: 100% 100%; +} + +[type="checkbox"]:checked:disabled + span:before { + border-right: 2px solid rgba(0, 0, 0, 0.42); + border-bottom: 2px solid rgba(0, 0, 0, 0.42); +} + +/* Indeterminate checkbox */ +[type="checkbox"]:indeterminate + span:not(.lever):before { + top: -11px; + left: -12px; + width: 10px; + height: 22px; + border-top: none; + border-left: none; + border-right: 2px solid #26a69a; + border-bottom: none; + -webkit-transform: rotate(90deg); + transform: rotate(90deg); + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + -webkit-transform-origin: 100% 100%; + transform-origin: 100% 100%; +} + +[type="checkbox"]:indeterminate:disabled + span:not(.lever):before { + border-right: 2px solid rgba(0, 0, 0, 0.42); + background-color: transparent; +} + +[type="checkbox"].filled-in + span:not(.lever):after { + border-radius: 2px; +} + +[type="checkbox"].filled-in + span:not(.lever):before, +[type="checkbox"].filled-in + span:not(.lever):after { + content: ''; + left: 0; + position: absolute; + /* .1s delay is for check animation */ + -webkit-transition: border .25s, background-color .25s, width .20s .1s, height .20s .1s, top .20s .1s, left .20s .1s; + transition: border .25s, background-color .25s, width .20s .1s, height .20s .1s, top .20s .1s, left .20s .1s; + z-index: 1; +} + +[type="checkbox"].filled-in:not(:checked) + span:not(.lever):before { + width: 0; + height: 0; + border: 3px solid transparent; + left: 6px; + top: 10px; + -webkit-transform: rotateZ(37deg); + transform: rotateZ(37deg); + -webkit-transform-origin: 100% 100%; + transform-origin: 100% 100%; +} + +[type="checkbox"].filled-in:not(:checked) + span:not(.lever):after { + height: 20px; + width: 20px; + background-color: transparent; + border: 2px solid #5a5a5a; + top: 0px; + z-index: 0; +} + +[type="checkbox"].filled-in:checked + span:not(.lever):before { + top: 0; + left: 1px; + width: 8px; + height: 13px; + border-top: 2px solid transparent; + border-left: 2px solid transparent; + border-right: 2px solid #fff; + border-bottom: 2px solid #fff; + -webkit-transform: rotateZ(37deg); + transform: rotateZ(37deg); + -webkit-transform-origin: 100% 100%; + transform-origin: 100% 100%; +} + +[type="checkbox"].filled-in:checked + span:not(.lever):after { + top: 0; + width: 20px; + height: 20px; + border: 2px solid #26a69a; + background-color: #26a69a; + z-index: 0; +} + +[type="checkbox"].filled-in.tabbed:focus + span:not(.lever):after { + border-radius: 2px; + border-color: #5a5a5a; + background-color: rgba(0, 0, 0, 0.1); +} + +[type="checkbox"].filled-in.tabbed:checked:focus + span:not(.lever):after { + border-radius: 2px; + background-color: #26a69a; + border-color: #26a69a; +} + +[type="checkbox"].filled-in:disabled:not(:checked) + span:not(.lever):before { + background-color: transparent; + border: 2px solid transparent; +} + +[type="checkbox"].filled-in:disabled:not(:checked) + span:not(.lever):after { + border-color: transparent; + background-color: #949494; +} + +[type="checkbox"].filled-in:disabled:checked + span:not(.lever):before { + background-color: transparent; +} + +[type="checkbox"].filled-in:disabled:checked + span:not(.lever):after { + background-color: #949494; + border-color: #949494; +} + +/* Switch + ========================================================================== */ +.switch, +.switch * { + -webkit-tap-highlight-color: transparent; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.switch label { + cursor: pointer; +} + +.switch label input[type=checkbox] { + opacity: 0; + width: 0; + height: 0; +} + +.switch label input[type=checkbox]:checked + .lever { + background-color: #84c7c1; +} + +.switch label input[type=checkbox]:checked + .lever:before, .switch label input[type=checkbox]:checked + .lever:after { + left: 18px; +} + +.switch label input[type=checkbox]:checked + .lever:after { + background-color: #26a69a; +} + +.switch label .lever { + content: ""; + display: inline-block; + position: relative; + width: 36px; + height: 14px; + background-color: rgba(0, 0, 0, 0.38); + border-radius: 15px; + margin-right: 10px; + -webkit-transition: background 0.3s ease; + transition: background 0.3s ease; + vertical-align: middle; + margin: 0 16px; +} + +.switch label .lever:before, .switch label .lever:after { + content: ""; + position: absolute; + display: inline-block; + width: 20px; + height: 20px; + border-radius: 50%; + left: 0; + top: -3px; + -webkit-transition: left 0.3s ease, background .3s ease, -webkit-box-shadow 0.1s ease, -webkit-transform .1s ease; + transition: left 0.3s ease, background .3s ease, -webkit-box-shadow 0.1s ease, -webkit-transform .1s ease; + transition: left 0.3s ease, background .3s ease, box-shadow 0.1s ease, transform .1s ease; + transition: left 0.3s ease, background .3s ease, box-shadow 0.1s ease, transform .1s ease, -webkit-box-shadow 0.1s ease, -webkit-transform .1s ease; +} + +.switch label .lever:before { + background-color: rgba(38, 166, 154, 0.15); +} + +.switch label .lever:after { + background-color: #F1F1F1; + -webkit-box-shadow: 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12); + box-shadow: 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12); +} + +input[type=checkbox]:checked:not(:disabled) ~ .lever:active::before, +input[type=checkbox]:checked:not(:disabled).tabbed:focus ~ .lever::before { + -webkit-transform: scale(2.4); + transform: scale(2.4); + background-color: rgba(38, 166, 154, 0.15); +} + +input[type=checkbox]:not(:disabled) ~ .lever:active:before, +input[type=checkbox]:not(:disabled).tabbed:focus ~ .lever::before { + -webkit-transform: scale(2.4); + transform: scale(2.4); + background-color: rgba(0, 0, 0, 0.08); +} + +.switch input[type=checkbox][disabled] + .lever { + cursor: default; + background-color: rgba(0, 0, 0, 0.12); +} + +.switch label input[type=checkbox][disabled] + .lever:after, +.switch label input[type=checkbox][disabled]:checked + .lever:after { + background-color: #949494; +} + +/* Select Field + ========================================================================== */ +select { + display: none; +} + +select.browser-default { + display: block; +} + +select { + background-color: rgba(255, 255, 255, 0.9); + width: 100%; + padding: 5px; + border: 1px solid #f2f2f2; + border-radius: 2px; + height: 3rem; +} + +.select-label { + position: absolute; +} + +.select-wrapper { + position: relative; +} + +.select-wrapper.valid + label, +.select-wrapper.invalid + label { + width: 100%; + pointer-events: none; +} + +.select-wrapper input.select-dropdown { + position: relative; + cursor: pointer; + background-color: transparent; + border: none; + border-bottom: 1px solid #9e9e9e; + outline: none; + height: 3rem; + line-height: 3rem; + width: 100%; + font-size: 16px; + margin: 0 0 8px 0; + padding: 0; + display: block; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + z-index: 1; +} + +.select-wrapper input.select-dropdown:focus { + border-bottom: 1px solid #26a69a; +} + +.select-wrapper .caret { + position: absolute; + right: 0; + top: 0; + bottom: 0; + margin: auto 0; + z-index: 0; + fill: rgba(0, 0, 0, 0.87); +} + +.select-wrapper + label { + position: absolute; + top: -26px; + font-size: 0.8rem; +} + +select:disabled { + color: rgba(0, 0, 0, 0.42); +} + +.select-wrapper.disabled + label { + color: rgba(0, 0, 0, 0.42); +} + +.select-wrapper.disabled .caret { + fill: rgba(0, 0, 0, 0.42); +} + +.select-wrapper input.select-dropdown:disabled { + color: rgba(0, 0, 0, 0.42); + cursor: default; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.select-wrapper i { + color: rgba(0, 0, 0, 0.3); +} + +.select-dropdown li.disabled, +.select-dropdown li.disabled > span, +.select-dropdown li.optgroup { + color: rgba(0, 0, 0, 0.3); + background-color: transparent; +} + +.select-dropdown.dropdown-content li:hover { + background-color: rgba(0, 0, 0, 0.08); +} + +.select-dropdown.dropdown-content li.selected { + background-color: rgba(0, 0, 0, 0.03); +} + +.select-dropdown.dropdown-content li:focus { + background-color: rgba(0, 0, 0, 0.08); +} + +.prefix ~ .select-wrapper { + margin-left: 3rem; + width: 92%; + width: calc(100% - 3rem); +} + +.prefix ~ label { + margin-left: 3rem; +} + +.select-dropdown li img { + height: 40px; + width: 40px; + margin: 5px 15px; + float: right; +} + +.select-dropdown li.optgroup { + border-top: 1px solid #eee; +} + +.select-dropdown li.optgroup.selected > span { + color: rgba(0, 0, 0, 0.7); +} + +.select-dropdown li.optgroup > span { + color: rgba(0, 0, 0, 0.4); +} + +.select-dropdown li.optgroup ~ li.optgroup-option { + padding-left: 1rem; +} + +/* File Input + ========================================================================== */ +.file-field { + position: relative; +} + +.file-field .file-path-wrapper { + overflow: hidden; + padding-left: 10px; +} + +.file-field input.file-path { + width: 100%; +} + +.file-field .btn, .file-field .btn-large, .file-field .btn-small { + float: left; + height: 3rem; + line-height: 3rem; +} + +.file-field span { + cursor: pointer; +} + +.file-field input[type=file] { + position: absolute; + top: 0; + right: 0; + left: 0; + bottom: 0; + width: 100%; + margin: 0; + padding: 0; + font-size: 20px; + cursor: pointer; + opacity: 0; + filter: alpha(opacity=0); +} + +.file-field input[type=file]::-webkit-file-upload-button { + display: none; +} + +/* Range + ========================================================================== */ +.range-field { + position: relative; +} + +input[type=range], +input[type=range] + .thumb { + cursor: pointer; +} + +input[type=range] { + position: relative; + background-color: transparent; + border: none; + outline: none; + width: 100%; + margin: 15px 0; + padding: 0; +} + +input[type=range]:focus { + outline: none; +} + +input[type=range] + .thumb { + position: absolute; + top: 10px; + left: 0; + border: none; + height: 0; + width: 0; + border-radius: 50%; + background-color: #26a69a; + margin-left: 7px; + -webkit-transform-origin: 50% 50%; + transform-origin: 50% 50%; + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); +} + +input[type=range] + .thumb .value { + display: block; + width: 30px; + text-align: center; + color: #26a69a; + font-size: 0; + -webkit-transform: rotate(45deg); + transform: rotate(45deg); +} + +input[type=range] + .thumb.active { + border-radius: 50% 50% 50% 0; +} + +input[type=range] + .thumb.active .value { + color: #fff; + margin-left: -1px; + margin-top: 8px; + font-size: 10px; +} + +input[type=range] { + -webkit-appearance: none; +} + +input[type=range]::-webkit-slider-runnable-track { + height: 3px; + background: #c2c0c2; + border: none; +} + +input[type=range]::-webkit-slider-thumb { + border: none; + height: 14px; + width: 14px; + border-radius: 50%; + background: #26a69a; + -webkit-transition: -webkit-box-shadow .3s; + transition: -webkit-box-shadow .3s; + transition: box-shadow .3s; + transition: box-shadow .3s, -webkit-box-shadow .3s; + -webkit-appearance: none; + background-color: #26a69a; + -webkit-transform-origin: 50% 50%; + transform-origin: 50% 50%; + margin: -5px 0 0 0; +} + +input[type=range].focused:focus:not(.active)::-webkit-slider-thumb { + -webkit-box-shadow: 0 0 0 10px rgba(38, 166, 154, 0.26); + box-shadow: 0 0 0 10px rgba(38, 166, 154, 0.26); +} + +input[type=range] { + /* fix for FF unable to apply focus style bug */ + border: 1px solid white; + /*required for proper track sizing in FF*/ +} + +input[type=range]::-moz-range-track { + height: 3px; + background: #c2c0c2; + border: none; +} + +input[type=range]::-moz-focus-inner { + border: 0; +} + +input[type=range]::-moz-range-thumb { + border: none; + height: 14px; + width: 14px; + border-radius: 50%; + background: #26a69a; + -webkit-transition: -webkit-box-shadow .3s; + transition: -webkit-box-shadow .3s; + transition: box-shadow .3s; + transition: box-shadow .3s, -webkit-box-shadow .3s; + margin-top: -5px; +} + +input[type=range]:-moz-focusring { + outline: 1px solid #fff; + outline-offset: -1px; +} + +input[type=range].focused:focus:not(.active)::-moz-range-thumb { + box-shadow: 0 0 0 10px rgba(38, 166, 154, 0.26); +} + +input[type=range]::-ms-track { + height: 3px; + background: transparent; + border-color: transparent; + border-width: 6px 0; + /*remove default tick marks*/ + color: transparent; +} + +input[type=range]::-ms-fill-lower { + background: #777; +} + +input[type=range]::-ms-fill-upper { + background: #ddd; +} + +input[type=range]::-ms-thumb { + border: none; + height: 14px; + width: 14px; + border-radius: 50%; + background: #26a69a; + -webkit-transition: -webkit-box-shadow .3s; + transition: -webkit-box-shadow .3s; + transition: box-shadow .3s; + transition: box-shadow .3s, -webkit-box-shadow .3s; +} + +input[type=range].focused:focus:not(.active)::-ms-thumb { + box-shadow: 0 0 0 10px rgba(38, 166, 154, 0.26); +} + +/*************** + Nav List +***************/ +.table-of-contents.fixed { + position: fixed; +} + +.table-of-contents li { + padding: 2px 0; +} + +.table-of-contents a { + display: inline-block; + font-weight: 300; + color: #757575; + padding-left: 16px; + height: 1.5rem; + line-height: 1.5rem; + letter-spacing: .4; + display: inline-block; +} + +.table-of-contents a:hover { + color: #a8a8a8; + padding-left: 15px; + border-left: 1px solid #ee6e73; +} + +.table-of-contents a.active { + font-weight: 500; + padding-left: 14px; + border-left: 2px solid #ee6e73; +} + +.sidenav { + position: fixed; + width: 300px; + left: 0; + top: 0; + margin: 0; + -webkit-transform: translateX(-100%); + transform: translateX(-100%); + height: 100%; + height: calc(100% + 60px); + height: -moz-calc(100%); + padding-bottom: 60px; + background-color: #fff; + z-index: 999; + overflow-y: auto; + will-change: transform; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + -webkit-transform: translateX(-105%); + transform: translateX(-105%); +} + +.sidenav.right-aligned { + right: 0; + -webkit-transform: translateX(105%); + transform: translateX(105%); + left: auto; + -webkit-transform: translateX(100%); + transform: translateX(100%); +} + +.sidenav .collapsible { + margin: 0; +} + +.sidenav li { + float: none; + line-height: 48px; +} + +.sidenav li.active { + background-color: rgba(0, 0, 0, 0.05); +} + +.sidenav li > a { + color: rgba(0, 0, 0, 0.87); + display: block; + font-size: 14px; + font-weight: 500; + height: 48px; + line-height: 48px; + padding: 0 32px; +} + +.sidenav li > a:hover { + background-color: rgba(0, 0, 0, 0.05); +} + +.sidenav li > a.btn, .sidenav li > a.btn-large, .sidenav li > a.btn-small, .sidenav li > a.btn-large, .sidenav li > a.btn-flat, .sidenav li > a.btn-floating { + margin: 10px 15px; +} + +.sidenav li > a.btn, .sidenav li > a.btn-large, .sidenav li > a.btn-small, .sidenav li > a.btn-large, .sidenav li > a.btn-floating { + color: #fff; +} + +.sidenav li > a.btn-flat { + color: #343434; +} + +.sidenav li > a.btn:hover, .sidenav li > a.btn-large:hover, .sidenav li > a.btn-small:hover, .sidenav li > a.btn-large:hover { + background-color: #2bbbad; +} + +.sidenav li > a.btn-floating:hover { + background-color: #26a69a; +} + +.sidenav li > a > i, +.sidenav li > a > [class^="mdi-"], .sidenav li > a li > a > [class*="mdi-"], +.sidenav li > a > i.material-icons { + float: left; + height: 48px; + line-height: 48px; + margin: 0 32px 0 0; + width: 24px; + color: rgba(0, 0, 0, 0.54); +} + +.sidenav .divider { + margin: 8px 0 0 0; +} + +.sidenav .subheader { + cursor: initial; + pointer-events: none; + color: rgba(0, 0, 0, 0.54); + font-size: 14px; + font-weight: 500; + line-height: 48px; +} + +.sidenav .subheader:hover { + background-color: transparent; +} + +.sidenav .user-view { + position: relative; + padding: 32px 32px 0; + margin-bottom: 8px; +} + +.sidenav .user-view > a { + height: auto; + padding: 0; +} + +.sidenav .user-view > a:hover { + background-color: transparent; +} + +.sidenav .user-view .background { + overflow: hidden; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: -1; +} + +.sidenav .user-view .circle, .sidenav .user-view .name, .sidenav .user-view .email { + display: block; +} + +.sidenav .user-view .circle { + height: 64px; + width: 64px; +} + +.sidenav .user-view .name, +.sidenav .user-view .email { + font-size: 14px; + line-height: 24px; +} + +.sidenav .user-view .name { + margin-top: 16px; + font-weight: 500; +} + +.sidenav .user-view .email { + padding-bottom: 16px; + font-weight: 400; +} + +.drag-target { + height: 100%; + width: 10px; + position: fixed; + top: 0; + z-index: 998; +} + +.drag-target.right-aligned { + right: 0; +} + +.sidenav.sidenav-fixed { + left: 0; + -webkit-transform: translateX(0); + transform: translateX(0); + position: fixed; +} + +.sidenav.sidenav-fixed.right-aligned { + right: 0; + left: auto; +} + +@media only screen and (max-width: 992px) { + .sidenav.sidenav-fixed { + -webkit-transform: translateX(-105%); + transform: translateX(-105%); + } + .sidenav.sidenav-fixed.right-aligned { + -webkit-transform: translateX(105%); + transform: translateX(105%); + } + .sidenav > a { + padding: 0 16px; + } + .sidenav .user-view { + padding: 16px 16px 0; + } +} + +.sidenav .collapsible-body > ul:not(.collapsible) > li.active, +.sidenav.sidenav-fixed .collapsible-body > ul:not(.collapsible) > li.active { + background-color: #ee6e73; +} + +.sidenav .collapsible-body > ul:not(.collapsible) > li.active a, +.sidenav.sidenav-fixed .collapsible-body > ul:not(.collapsible) > li.active a { + color: #fff; +} + +.sidenav .collapsible-body { + padding: 0; +} + +.sidenav-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + opacity: 0; + height: 120vh; + background-color: rgba(0, 0, 0, 0.5); + z-index: 997; + display: none; +} + +/* + @license + Copyright (c) 2014 The Polymer Project Authors. All rights reserved. + This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt + The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt + The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt + Code distributed by Google as part of the polymer project is also + subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt + */ +/**************************/ +/* STYLES FOR THE SPINNER */ +/**************************/ +/* + * Constants: + * STROKEWIDTH = 3px + * ARCSIZE = 270 degrees (amount of circle the arc takes up) + * ARCTIME = 1333ms (time it takes to expand and contract arc) + * ARCSTARTROT = 216 degrees (how much the start location of the arc + * should rotate each time, 216 gives us a + * 5 pointed star shape (it's 360/5 * 3). + * For a 7 pointed star, we might do + * 360/7 * 3 = 154.286) + * CONTAINERWIDTH = 28px + * SHRINK_TIME = 400ms + */ +.preloader-wrapper { + display: inline-block; + position: relative; + width: 50px; + height: 50px; +} + +.preloader-wrapper.small { + width: 36px; + height: 36px; +} + +.preloader-wrapper.big { + width: 64px; + height: 64px; +} + +.preloader-wrapper.active { + /* duration: 360 * ARCTIME / (ARCSTARTROT + (360-ARCSIZE)) */ + -webkit-animation: container-rotate 1568ms linear infinite; + animation: container-rotate 1568ms linear infinite; +} + +@-webkit-keyframes container-rotate { + to { + -webkit-transform: rotate(360deg); + } +} + +@keyframes container-rotate { + to { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +.spinner-layer { + position: absolute; + width: 100%; + height: 100%; + opacity: 0; + border-color: #26a69a; +} + +.spinner-blue, +.spinner-blue-only { + border-color: #4285f4; +} + +.spinner-red, +.spinner-red-only { + border-color: #db4437; +} + +.spinner-yellow, +.spinner-yellow-only { + border-color: #f4b400; +} + +.spinner-green, +.spinner-green-only { + border-color: #0f9d58; +} + +/** + * IMPORTANT NOTE ABOUT CSS ANIMATION PROPERTIES (keanulee): + * + * iOS Safari (tested on iOS 8.1) does not handle animation-delay very well - it doesn't + * guarantee that the animation will start _exactly_ after that value. So we avoid using + * animation-delay and instead set custom keyframes for each color (as redundant as it + * seems). + * + * We write out each animation in full (instead of separating animation-name, + * animation-duration, etc.) because under the polyfill, Safari does not recognize those + * specific properties properly, treats them as -webkit-animation, and overrides the + * other animation rules. See https://github.com/Polymer/platform/issues/53. + */ +.active .spinner-layer.spinner-blue { + /* durations: 4 * ARCTIME */ + -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, blue-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; + animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, blue-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; +} + +.active .spinner-layer.spinner-red { + /* durations: 4 * ARCTIME */ + -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, red-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; + animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, red-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; +} + +.active .spinner-layer.spinner-yellow { + /* durations: 4 * ARCTIME */ + -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, yellow-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; + animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, yellow-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; +} + +.active .spinner-layer.spinner-green { + /* durations: 4 * ARCTIME */ + -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, green-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; + animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both, green-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; +} + +.active .spinner-layer, +.active .spinner-layer.spinner-blue-only, +.active .spinner-layer.spinner-red-only, +.active .spinner-layer.spinner-yellow-only, +.active .spinner-layer.spinner-green-only { + /* durations: 4 * ARCTIME */ + opacity: 1; + -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; + animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; +} + +@-webkit-keyframes fill-unfill-rotate { + 12.5% { + -webkit-transform: rotate(135deg); + } + /* 0.5 * ARCSIZE */ + 25% { + -webkit-transform: rotate(270deg); + } + /* 1 * ARCSIZE */ + 37.5% { + -webkit-transform: rotate(405deg); + } + /* 1.5 * ARCSIZE */ + 50% { + -webkit-transform: rotate(540deg); + } + /* 2 * ARCSIZE */ + 62.5% { + -webkit-transform: rotate(675deg); + } + /* 2.5 * ARCSIZE */ + 75% { + -webkit-transform: rotate(810deg); + } + /* 3 * ARCSIZE */ + 87.5% { + -webkit-transform: rotate(945deg); + } + /* 3.5 * ARCSIZE */ + to { + -webkit-transform: rotate(1080deg); + } + /* 4 * ARCSIZE */ +} + +@keyframes fill-unfill-rotate { + 12.5% { + -webkit-transform: rotate(135deg); + transform: rotate(135deg); + } + /* 0.5 * ARCSIZE */ + 25% { + -webkit-transform: rotate(270deg); + transform: rotate(270deg); + } + /* 1 * ARCSIZE */ + 37.5% { + -webkit-transform: rotate(405deg); + transform: rotate(405deg); + } + /* 1.5 * ARCSIZE */ + 50% { + -webkit-transform: rotate(540deg); + transform: rotate(540deg); + } + /* 2 * ARCSIZE */ + 62.5% { + -webkit-transform: rotate(675deg); + transform: rotate(675deg); + } + /* 2.5 * ARCSIZE */ + 75% { + -webkit-transform: rotate(810deg); + transform: rotate(810deg); + } + /* 3 * ARCSIZE */ + 87.5% { + -webkit-transform: rotate(945deg); + transform: rotate(945deg); + } + /* 3.5 * ARCSIZE */ + to { + -webkit-transform: rotate(1080deg); + transform: rotate(1080deg); + } + /* 4 * ARCSIZE */ +} + +@-webkit-keyframes blue-fade-in-out { + from { + opacity: 1; + } + 25% { + opacity: 1; + } + 26% { + opacity: 0; + } + 89% { + opacity: 0; + } + 90% { + opacity: 1; + } + 100% { + opacity: 1; + } +} + +@keyframes blue-fade-in-out { + from { + opacity: 1; + } + 25% { + opacity: 1; + } + 26% { + opacity: 0; + } + 89% { + opacity: 0; + } + 90% { + opacity: 1; + } + 100% { + opacity: 1; + } +} + +@-webkit-keyframes red-fade-in-out { + from { + opacity: 0; + } + 15% { + opacity: 0; + } + 25% { + opacity: 1; + } + 50% { + opacity: 1; + } + 51% { + opacity: 0; + } +} + +@keyframes red-fade-in-out { + from { + opacity: 0; + } + 15% { + opacity: 0; + } + 25% { + opacity: 1; + } + 50% { + opacity: 1; + } + 51% { + opacity: 0; + } +} + +@-webkit-keyframes yellow-fade-in-out { + from { + opacity: 0; + } + 40% { + opacity: 0; + } + 50% { + opacity: 1; + } + 75% { + opacity: 1; + } + 76% { + opacity: 0; + } +} + +@keyframes yellow-fade-in-out { + from { + opacity: 0; + } + 40% { + opacity: 0; + } + 50% { + opacity: 1; + } + 75% { + opacity: 1; + } + 76% { + opacity: 0; + } +} + +@-webkit-keyframes green-fade-in-out { + from { + opacity: 0; + } + 65% { + opacity: 0; + } + 75% { + opacity: 1; + } + 90% { + opacity: 1; + } + 100% { + opacity: 0; + } +} + +@keyframes green-fade-in-out { + from { + opacity: 0; + } + 65% { + opacity: 0; + } + 75% { + opacity: 1; + } + 90% { + opacity: 1; + } + 100% { + opacity: 0; + } +} + +/** + * Patch the gap that appear between the two adjacent div.circle-clipper while the + * spinner is rotating (appears on Chrome 38, Safari 7.1, and IE 11). + */ +.gap-patch { + position: absolute; + top: 0; + left: 45%; + width: 10%; + height: 100%; + overflow: hidden; + border-color: inherit; +} + +.gap-patch .circle { + width: 1000%; + left: -450%; +} + +.circle-clipper { + display: inline-block; + position: relative; + width: 50%; + height: 100%; + overflow: hidden; + border-color: inherit; +} + +.circle-clipper .circle { + width: 200%; + height: 100%; + border-width: 3px; + /* STROKEWIDTH */ + border-style: solid; + border-color: inherit; + border-bottom-color: transparent !important; + border-radius: 50%; + -webkit-animation: none; + animation: none; + position: absolute; + top: 0; + right: 0; + bottom: 0; +} + +.circle-clipper.left .circle { + left: 0; + border-right-color: transparent !important; + -webkit-transform: rotate(129deg); + transform: rotate(129deg); +} + +.circle-clipper.right .circle { + left: -100%; + border-left-color: transparent !important; + -webkit-transform: rotate(-129deg); + transform: rotate(-129deg); +} + +.active .circle-clipper.left .circle { + /* duration: ARCTIME */ + -webkit-animation: left-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; + animation: left-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; +} + +.active .circle-clipper.right .circle { + /* duration: ARCTIME */ + -webkit-animation: right-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; + animation: right-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both; +} + +@-webkit-keyframes left-spin { + from { + -webkit-transform: rotate(130deg); + } + 50% { + -webkit-transform: rotate(-5deg); + } + to { + -webkit-transform: rotate(130deg); + } +} + +@keyframes left-spin { + from { + -webkit-transform: rotate(130deg); + transform: rotate(130deg); + } + 50% { + -webkit-transform: rotate(-5deg); + transform: rotate(-5deg); + } + to { + -webkit-transform: rotate(130deg); + transform: rotate(130deg); + } +} + +@-webkit-keyframes right-spin { + from { + -webkit-transform: rotate(-130deg); + } + 50% { + -webkit-transform: rotate(5deg); + } + to { + -webkit-transform: rotate(-130deg); + } +} + +@keyframes right-spin { + from { + -webkit-transform: rotate(-130deg); + transform: rotate(-130deg); + } + 50% { + -webkit-transform: rotate(5deg); + transform: rotate(5deg); + } + to { + -webkit-transform: rotate(-130deg); + transform: rotate(-130deg); + } +} + +#spinnerContainer.cooldown { + /* duration: SHRINK_TIME */ + -webkit-animation: container-rotate 1568ms linear infinite, fade-out 400ms cubic-bezier(0.4, 0, 0.2, 1); + animation: container-rotate 1568ms linear infinite, fade-out 400ms cubic-bezier(0.4, 0, 0.2, 1); +} + +@-webkit-keyframes fade-out { + from { + opacity: 1; + } + to { + opacity: 0; + } +} + +@keyframes fade-out { + from { + opacity: 1; + } + to { + opacity: 0; + } +} + +.slider { + position: relative; + height: 400px; + width: 100%; +} + +.slider.fullscreen { + height: 100%; + width: 100%; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; +} + +.slider.fullscreen ul.slides { + height: 100%; +} + +.slider.fullscreen ul.indicators { + z-index: 2; + bottom: 30px; +} + +.slider .slides { + background-color: #9e9e9e; + margin: 0; + height: 400px; +} + +.slider .slides li { + opacity: 0; + position: absolute; + top: 0; + left: 0; + z-index: 1; + width: 100%; + height: inherit; + overflow: hidden; +} + +.slider .slides li img { + height: 100%; + width: 100%; + background-size: cover; + background-position: center; +} + +.slider .slides li .caption { + color: #fff; + position: absolute; + top: 15%; + left: 15%; + width: 70%; + opacity: 0; +} + +.slider .slides li .caption p { + color: #e0e0e0; +} + +.slider .slides li.active { + z-index: 2; +} + +.slider .indicators { + position: absolute; + text-align: center; + left: 0; + right: 0; + bottom: 0; + margin: 0; +} + +.slider .indicators .indicator-item { + display: inline-block; + position: relative; + cursor: pointer; + height: 16px; + width: 16px; + margin: 0 12px; + background-color: #e0e0e0; + -webkit-transition: background-color .3s; + transition: background-color .3s; + border-radius: 50%; +} + +.slider .indicators .indicator-item.active { + background-color: #4CAF50; +} + +.carousel { + overflow: hidden; + position: relative; + width: 100%; + height: 400px; + -webkit-perspective: 500px; + perspective: 500px; + -webkit-transform-style: preserve-3d; + transform-style: preserve-3d; + -webkit-transform-origin: 0% 50%; + transform-origin: 0% 50%; +} + +.carousel.carousel-slider { + top: 0; + left: 0; +} + +.carousel.carousel-slider .carousel-fixed-item { + position: absolute; + left: 0; + right: 0; + bottom: 20px; + z-index: 1; +} + +.carousel.carousel-slider .carousel-fixed-item.with-indicators { + bottom: 68px; +} + +.carousel.carousel-slider .carousel-item { + width: 100%; + height: 100%; + min-height: 400px; + position: absolute; + top: 0; + left: 0; +} + +.carousel.carousel-slider .carousel-item h2 { + font-size: 24px; + font-weight: 500; + line-height: 32px; +} + +.carousel.carousel-slider .carousel-item p { + font-size: 15px; +} + +.carousel .carousel-item { + visibility: hidden; + width: 200px; + height: 200px; + position: absolute; + top: 0; + left: 0; +} + +.carousel .carousel-item > img { + width: 100%; +} + +.carousel .indicators { + position: absolute; + text-align: center; + left: 0; + right: 0; + bottom: 0; + margin: 0; +} + +.carousel .indicators .indicator-item { + display: inline-block; + position: relative; + cursor: pointer; + height: 8px; + width: 8px; + margin: 24px 4px; + background-color: rgba(255, 255, 255, 0.5); + -webkit-transition: background-color .3s; + transition: background-color .3s; + border-radius: 50%; +} + +.carousel .indicators .indicator-item.active { + background-color: #fff; +} + +.carousel.scrolling .carousel-item .materialboxed, +.carousel .carousel-item:not(.active) .materialboxed { + pointer-events: none; +} + +.tap-target-wrapper { + width: 800px; + height: 800px; + position: fixed; + z-index: 1000; + visibility: hidden; + -webkit-transition: visibility 0s .3s; + transition: visibility 0s .3s; +} + +.tap-target-wrapper.open { + visibility: visible; + -webkit-transition: visibility 0s; + transition: visibility 0s; +} + +.tap-target-wrapper.open .tap-target { + -webkit-transform: scale(1); + transform: scale(1); + opacity: .95; + -webkit-transition: opacity 0.3s cubic-bezier(0.42, 0, 0.58, 1), -webkit-transform 0.3s cubic-bezier(0.42, 0, 0.58, 1); + transition: opacity 0.3s cubic-bezier(0.42, 0, 0.58, 1), -webkit-transform 0.3s cubic-bezier(0.42, 0, 0.58, 1); + transition: transform 0.3s cubic-bezier(0.42, 0, 0.58, 1), opacity 0.3s cubic-bezier(0.42, 0, 0.58, 1); + transition: transform 0.3s cubic-bezier(0.42, 0, 0.58, 1), opacity 0.3s cubic-bezier(0.42, 0, 0.58, 1), -webkit-transform 0.3s cubic-bezier(0.42, 0, 0.58, 1); +} + +.tap-target-wrapper.open .tap-target-wave::before { + -webkit-transform: scale(1); + transform: scale(1); +} + +.tap-target-wrapper.open .tap-target-wave::after { + visibility: visible; + -webkit-animation: pulse-animation 1s cubic-bezier(0.24, 0, 0.38, 1) infinite; + animation: pulse-animation 1s cubic-bezier(0.24, 0, 0.38, 1) infinite; + -webkit-transition: opacity .3s, visibility 0s 1s, -webkit-transform .3s; + transition: opacity .3s, visibility 0s 1s, -webkit-transform .3s; + transition: opacity .3s, transform .3s, visibility 0s 1s; + transition: opacity .3s, transform .3s, visibility 0s 1s, -webkit-transform .3s; +} + +.tap-target { + position: absolute; + font-size: 1rem; + border-radius: 50%; + background-color: #ee6e73; + -webkit-box-shadow: 0 20px 20px 0 rgba(0, 0, 0, 0.14), 0 10px 50px 0 rgba(0, 0, 0, 0.12), 0 30px 10px -20px rgba(0, 0, 0, 0.2); + box-shadow: 0 20px 20px 0 rgba(0, 0, 0, 0.14), 0 10px 50px 0 rgba(0, 0, 0, 0.12), 0 30px 10px -20px rgba(0, 0, 0, 0.2); + width: 100%; + height: 100%; + opacity: 0; + -webkit-transform: scale(0); + transform: scale(0); + -webkit-transition: opacity 0.3s cubic-bezier(0.42, 0, 0.58, 1), -webkit-transform 0.3s cubic-bezier(0.42, 0, 0.58, 1); + transition: opacity 0.3s cubic-bezier(0.42, 0, 0.58, 1), -webkit-transform 0.3s cubic-bezier(0.42, 0, 0.58, 1); + transition: transform 0.3s cubic-bezier(0.42, 0, 0.58, 1), opacity 0.3s cubic-bezier(0.42, 0, 0.58, 1); + transition: transform 0.3s cubic-bezier(0.42, 0, 0.58, 1), opacity 0.3s cubic-bezier(0.42, 0, 0.58, 1), -webkit-transform 0.3s cubic-bezier(0.42, 0, 0.58, 1); +} + +.tap-target-content { + position: relative; + display: table-cell; +} + +.tap-target-wave { + position: absolute; + border-radius: 50%; + z-index: 10001; +} + +.tap-target-wave::before, .tap-target-wave::after { + content: ''; + display: block; + position: absolute; + width: 100%; + height: 100%; + border-radius: 50%; + background-color: #ffffff; +} + +.tap-target-wave::before { + -webkit-transform: scale(0); + transform: scale(0); + -webkit-transition: -webkit-transform .3s; + transition: -webkit-transform .3s; + transition: transform .3s; + transition: transform .3s, -webkit-transform .3s; +} + +.tap-target-wave::after { + visibility: hidden; + -webkit-transition: opacity .3s, visibility 0s, -webkit-transform .3s; + transition: opacity .3s, visibility 0s, -webkit-transform .3s; + transition: opacity .3s, transform .3s, visibility 0s; + transition: opacity .3s, transform .3s, visibility 0s, -webkit-transform .3s; + z-index: -1; +} + +.tap-target-origin { + top: 50%; + left: 50%; + -webkit-transform: translate(-50%, -50%); + transform: translate(-50%, -50%); + z-index: 10002; + position: absolute !important; +} + +.tap-target-origin:not(.btn):not(.btn-large):not(.btn-small), .tap-target-origin:not(.btn):not(.btn-large):not(.btn-small):hover { + background: none; +} + +@media only screen and (max-width: 600px) { + .tap-target, .tap-target-wrapper { + width: 600px; + height: 600px; + } +} + +.pulse { + overflow: visible; + position: relative; +} + +.pulse::before { + content: ''; + display: block; + position: absolute; + width: 100%; + height: 100%; + top: 0; + left: 0; + background-color: inherit; + border-radius: inherit; + -webkit-transition: opacity .3s, -webkit-transform .3s; + transition: opacity .3s, -webkit-transform .3s; + transition: opacity .3s, transform .3s; + transition: opacity .3s, transform .3s, -webkit-transform .3s; + -webkit-animation: pulse-animation 1s cubic-bezier(0.24, 0, 0.38, 1) infinite; + animation: pulse-animation 1s cubic-bezier(0.24, 0, 0.38, 1) infinite; + z-index: -1; +} + +@-webkit-keyframes pulse-animation { + 0% { + opacity: 1; + -webkit-transform: scale(1); + transform: scale(1); + } + 50% { + opacity: 0; + -webkit-transform: scale(1.5); + transform: scale(1.5); + } + 100% { + opacity: 0; + -webkit-transform: scale(1.5); + transform: scale(1.5); + } +} + +@keyframes pulse-animation { + 0% { + opacity: 1; + -webkit-transform: scale(1); + transform: scale(1); + } + 50% { + opacity: 0; + -webkit-transform: scale(1.5); + transform: scale(1.5); + } + 100% { + opacity: 0; + -webkit-transform: scale(1.5); + transform: scale(1.5); + } +} + +/* Modal */ +.datepicker-modal { + max-width: 325px; + min-width: 300px; + max-height: none; +} + +.datepicker-container.modal-content { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + padding: 0; +} + +.datepicker-controls { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + -ms-flex-pack: justify; + justify-content: space-between; + width: 280px; + margin: 0 auto; +} + +.datepicker-controls .selects-container { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; +} + +.datepicker-controls .select-wrapper input { + border-bottom: none; + text-align: center; + margin: 0; +} + +.datepicker-controls .select-wrapper input:focus { + border-bottom: none; +} + +.datepicker-controls .select-wrapper .caret { + display: none; +} + +.datepicker-controls .select-year input { + width: 50px; +} + +.datepicker-controls .select-month input { + width: 70px; +} + +.month-prev, .month-next { + margin-top: 4px; + cursor: pointer; + background-color: transparent; + border: none; +} + +/* Date Display */ +.datepicker-date-display { + -webkit-box-flex: 1; + -webkit-flex: 1 auto; + -ms-flex: 1 auto; + flex: 1 auto; + background-color: #26a69a; + color: #fff; + padding: 20px 22px; + font-weight: 500; +} + +.datepicker-date-display .year-text { + display: block; + font-size: 1.5rem; + line-height: 25px; + color: rgba(255, 255, 255, 0.7); +} + +.datepicker-date-display .date-text { + display: block; + font-size: 2.8rem; + line-height: 47px; + font-weight: 500; +} + +/* Calendar */ +.datepicker-calendar-container { + -webkit-box-flex: 2.5; + -webkit-flex: 2.5 auto; + -ms-flex: 2.5 auto; + flex: 2.5 auto; +} + +.datepicker-table { + width: 280px; + font-size: 1rem; + margin: 0 auto; +} + +.datepicker-table thead { + border-bottom: none; +} + +.datepicker-table th { + padding: 10px 5px; + text-align: center; +} + +.datepicker-table tr { + border: none; +} + +.datepicker-table abbr { + text-decoration: none; + color: #999; +} + +.datepicker-table td { + border-radius: 50%; + padding: 0; +} + +.datepicker-table td.is-today { + color: #26a69a; +} + +.datepicker-table td.is-selected { + background-color: #26a69a; + color: #fff; +} + +.datepicker-table td.is-outside-current-month, .datepicker-table td.is-disabled { + color: rgba(0, 0, 0, 0.3); + pointer-events: none; +} + +.datepicker-day-button { + background-color: transparent; + border: none; + line-height: 38px; + display: block; + width: 100%; + border-radius: 50%; + padding: 0 5px; + cursor: pointer; + color: inherit; +} + +.datepicker-day-button:focus { + background-color: rgba(43, 161, 150, 0.25); +} + +/* Footer */ +.datepicker-footer { + width: 280px; + margin: 0 auto; + padding-bottom: 5px; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + -ms-flex-pack: justify; + justify-content: space-between; +} + +.datepicker-cancel, +.datepicker-clear, +.datepicker-today, +.datepicker-done { + color: #26a69a; + padding: 0 1rem; +} + +.datepicker-clear { + color: #F44336; +} + +/* Media Queries */ +@media only screen and (min-width: 601px) { + .datepicker-modal { + max-width: 625px; + } + .datepicker-container.modal-content { + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + } + .datepicker-controls, + .datepicker-table, + .datepicker-footer { + width: 320px; + } + .datepicker-day-button { + line-height: 44px; + } +} + +/* Timepicker Containers */ +.timepicker-modal { + max-width: 325px; + max-height: none; +} + +.timepicker-container.modal-content { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + padding: 0; +} + +.text-primary { + color: white; +} + +/* Clock Digital Display */ +.timepicker-digital-display { + -webkit-box-flex: 1; + -webkit-flex: 1 auto; + -ms-flex: 1 auto; + flex: 1 auto; + background-color: #26a69a; + padding: 10px; + font-weight: 300; +} + +.timepicker-text-container { + font-size: 4rem; + font-weight: bold; + text-align: center; + color: rgba(255, 255, 255, 0.6); + font-weight: 400; + position: relative; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.timepicker-span-hours, +.timepicker-span-minutes, +.timepicker-span-am-pm div { + cursor: pointer; +} + +.timepicker-span-hours { + margin-right: 3px; +} + +.timepicker-span-minutes { + margin-left: 3px; +} + +.timepicker-display-am-pm { + font-size: 1.3rem; + position: absolute; + right: 1rem; + bottom: 1rem; + font-weight: 400; +} + +/* Analog Clock Display */ +.timepicker-analog-display { + -webkit-box-flex: 2.5; + -webkit-flex: 2.5 auto; + -ms-flex: 2.5 auto; + flex: 2.5 auto; +} + +.timepicker-plate { + background-color: #eee; + border-radius: 50%; + width: 270px; + height: 270px; + overflow: visible; + position: relative; + margin: auto; + margin-top: 25px; + margin-bottom: 5px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.timepicker-canvas, +.timepicker-dial { + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; +} + +.timepicker-minutes { + visibility: hidden; +} + +.timepicker-tick { + border-radius: 50%; + color: rgba(0, 0, 0, 0.87); + line-height: 40px; + text-align: center; + width: 40px; + height: 40px; + position: absolute; + cursor: pointer; + font-size: 15px; +} + +.timepicker-tick.active, +.timepicker-tick:hover { + background-color: rgba(38, 166, 154, 0.25); +} + +.timepicker-dial { + -webkit-transition: opacity 350ms, -webkit-transform 350ms; + transition: opacity 350ms, -webkit-transform 350ms; + transition: transform 350ms, opacity 350ms; + transition: transform 350ms, opacity 350ms, -webkit-transform 350ms; +} + +.timepicker-dial-out { + opacity: 0; +} + +.timepicker-dial-out.timepicker-hours { + -webkit-transform: scale(1.1, 1.1); + transform: scale(1.1, 1.1); +} + +.timepicker-dial-out.timepicker-minutes { + -webkit-transform: scale(0.8, 0.8); + transform: scale(0.8, 0.8); +} + +.timepicker-canvas { + -webkit-transition: opacity 175ms; + transition: opacity 175ms; +} + +.timepicker-canvas line { + stroke: #26a69a; + stroke-width: 4; + stroke-linecap: round; +} + +.timepicker-canvas-out { + opacity: 0.25; +} + +.timepicker-canvas-bearing { + stroke: none; + fill: #26a69a; +} + +.timepicker-canvas-bg { + stroke: none; + fill: #26a69a; +} + +/* Footer */ +.timepicker-footer { + margin: 0 auto; + padding: 5px 1rem; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + -ms-flex-pack: justify; + justify-content: space-between; +} + +.timepicker-clear { + color: #F44336; +} + +.timepicker-close { + color: #26a69a; +} + +.timepicker-clear, +.timepicker-close { + padding: 0 20px; +} + +/* Media Queries */ +@media only screen and (min-width: 601px) { + .timepicker-modal { + max-width: 600px; + } + .timepicker-container.modal-content { + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + } + .timepicker-text-container { + top: 32%; + } + .timepicker-display-am-pm { + position: relative; + right: auto; + bottom: auto; + text-align: center; + margin-top: 1.2rem; + } +} diff --git a/src/lib/materialize/css/materialize.min.css b/src/lib/materialize/css/materialize.min.css new file mode 100644 index 0000000..3f4fc7f --- /dev/null +++ b/src/lib/materialize/css/materialize.min.css @@ -0,0 +1,13 @@ +/*! + * Materialize v1.0.0-beta (http://materializecss.com) + * Copyright 2014-2017 Materialize + * MIT License (https://raw.githubusercontent.com/Dogfalo/materialize/master/LICENSE) + */ +.materialize-red{background-color:#e51c23 !important}.materialize-red-text{color:#e51c23 !important}.materialize-red.lighten-5{background-color:#fdeaeb !important}.materialize-red-text.text-lighten-5{color:#fdeaeb !important}.materialize-red.lighten-4{background-color:#f8c1c3 !important}.materialize-red-text.text-lighten-4{color:#f8c1c3 !important}.materialize-red.lighten-3{background-color:#f3989b !important}.materialize-red-text.text-lighten-3{color:#f3989b !important}.materialize-red.lighten-2{background-color:#ee6e73 !important}.materialize-red-text.text-lighten-2{color:#ee6e73 !important}.materialize-red.lighten-1{background-color:#ea454b !important}.materialize-red-text.text-lighten-1{color:#ea454b !important}.materialize-red.darken-1{background-color:#d0181e !important}.materialize-red-text.text-darken-1{color:#d0181e !important}.materialize-red.darken-2{background-color:#b9151b !important}.materialize-red-text.text-darken-2{color:#b9151b !important}.materialize-red.darken-3{background-color:#a21318 !important}.materialize-red-text.text-darken-3{color:#a21318 !important}.materialize-red.darken-4{background-color:#8b1014 !important}.materialize-red-text.text-darken-4{color:#8b1014 !important}.red{background-color:#F44336 !important}.red-text{color:#F44336 !important}.red.lighten-5{background-color:#FFEBEE !important}.red-text.text-lighten-5{color:#FFEBEE !important}.red.lighten-4{background-color:#FFCDD2 !important}.red-text.text-lighten-4{color:#FFCDD2 !important}.red.lighten-3{background-color:#EF9A9A !important}.red-text.text-lighten-3{color:#EF9A9A !important}.red.lighten-2{background-color:#E57373 !important}.red-text.text-lighten-2{color:#E57373 !important}.red.lighten-1{background-color:#EF5350 !important}.red-text.text-lighten-1{color:#EF5350 !important}.red.darken-1{background-color:#E53935 !important}.red-text.text-darken-1{color:#E53935 !important}.red.darken-2{background-color:#D32F2F !important}.red-text.text-darken-2{color:#D32F2F !important}.red.darken-3{background-color:#C62828 !important}.red-text.text-darken-3{color:#C62828 !important}.red.darken-4{background-color:#B71C1C !important}.red-text.text-darken-4{color:#B71C1C !important}.red.accent-1{background-color:#FF8A80 !important}.red-text.text-accent-1{color:#FF8A80 !important}.red.accent-2{background-color:#FF5252 !important}.red-text.text-accent-2{color:#FF5252 !important}.red.accent-3{background-color:#FF1744 !important}.red-text.text-accent-3{color:#FF1744 !important}.red.accent-4{background-color:#D50000 !important}.red-text.text-accent-4{color:#D50000 !important}.pink{background-color:#e91e63 !important}.pink-text{color:#e91e63 !important}.pink.lighten-5{background-color:#fce4ec !important}.pink-text.text-lighten-5{color:#fce4ec !important}.pink.lighten-4{background-color:#f8bbd0 !important}.pink-text.text-lighten-4{color:#f8bbd0 !important}.pink.lighten-3{background-color:#f48fb1 !important}.pink-text.text-lighten-3{color:#f48fb1 !important}.pink.lighten-2{background-color:#f06292 !important}.pink-text.text-lighten-2{color:#f06292 !important}.pink.lighten-1{background-color:#ec407a !important}.pink-text.text-lighten-1{color:#ec407a !important}.pink.darken-1{background-color:#d81b60 !important}.pink-text.text-darken-1{color:#d81b60 !important}.pink.darken-2{background-color:#c2185b !important}.pink-text.text-darken-2{color:#c2185b !important}.pink.darken-3{background-color:#ad1457 !important}.pink-text.text-darken-3{color:#ad1457 !important}.pink.darken-4{background-color:#880e4f !important}.pink-text.text-darken-4{color:#880e4f !important}.pink.accent-1{background-color:#ff80ab !important}.pink-text.text-accent-1{color:#ff80ab !important}.pink.accent-2{background-color:#ff4081 !important}.pink-text.text-accent-2{color:#ff4081 !important}.pink.accent-3{background-color:#f50057 !important}.pink-text.text-accent-3{color:#f50057 !important}.pink.accent-4{background-color:#c51162 !important}.pink-text.text-accent-4{color:#c51162 !important}.purple{background-color:#9c27b0 !important}.purple-text{color:#9c27b0 !important}.purple.lighten-5{background-color:#f3e5f5 !important}.purple-text.text-lighten-5{color:#f3e5f5 !important}.purple.lighten-4{background-color:#e1bee7 !important}.purple-text.text-lighten-4{color:#e1bee7 !important}.purple.lighten-3{background-color:#ce93d8 !important}.purple-text.text-lighten-3{color:#ce93d8 !important}.purple.lighten-2{background-color:#ba68c8 !important}.purple-text.text-lighten-2{color:#ba68c8 !important}.purple.lighten-1{background-color:#ab47bc !important}.purple-text.text-lighten-1{color:#ab47bc !important}.purple.darken-1{background-color:#8e24aa !important}.purple-text.text-darken-1{color:#8e24aa !important}.purple.darken-2{background-color:#7b1fa2 !important}.purple-text.text-darken-2{color:#7b1fa2 !important}.purple.darken-3{background-color:#6a1b9a !important}.purple-text.text-darken-3{color:#6a1b9a !important}.purple.darken-4{background-color:#4a148c !important}.purple-text.text-darken-4{color:#4a148c !important}.purple.accent-1{background-color:#ea80fc !important}.purple-text.text-accent-1{color:#ea80fc !important}.purple.accent-2{background-color:#e040fb !important}.purple-text.text-accent-2{color:#e040fb !important}.purple.accent-3{background-color:#d500f9 !important}.purple-text.text-accent-3{color:#d500f9 !important}.purple.accent-4{background-color:#a0f !important}.purple-text.text-accent-4{color:#a0f !important}.deep-purple{background-color:#673ab7 !important}.deep-purple-text{color:#673ab7 !important}.deep-purple.lighten-5{background-color:#ede7f6 !important}.deep-purple-text.text-lighten-5{color:#ede7f6 !important}.deep-purple.lighten-4{background-color:#d1c4e9 !important}.deep-purple-text.text-lighten-4{color:#d1c4e9 !important}.deep-purple.lighten-3{background-color:#b39ddb !important}.deep-purple-text.text-lighten-3{color:#b39ddb !important}.deep-purple.lighten-2{background-color:#9575cd !important}.deep-purple-text.text-lighten-2{color:#9575cd !important}.deep-purple.lighten-1{background-color:#7e57c2 !important}.deep-purple-text.text-lighten-1{color:#7e57c2 !important}.deep-purple.darken-1{background-color:#5e35b1 !important}.deep-purple-text.text-darken-1{color:#5e35b1 !important}.deep-purple.darken-2{background-color:#512da8 !important}.deep-purple-text.text-darken-2{color:#512da8 !important}.deep-purple.darken-3{background-color:#4527a0 !important}.deep-purple-text.text-darken-3{color:#4527a0 !important}.deep-purple.darken-4{background-color:#311b92 !important}.deep-purple-text.text-darken-4{color:#311b92 !important}.deep-purple.accent-1{background-color:#b388ff !important}.deep-purple-text.text-accent-1{color:#b388ff !important}.deep-purple.accent-2{background-color:#7c4dff !important}.deep-purple-text.text-accent-2{color:#7c4dff !important}.deep-purple.accent-3{background-color:#651fff !important}.deep-purple-text.text-accent-3{color:#651fff !important}.deep-purple.accent-4{background-color:#6200ea !important}.deep-purple-text.text-accent-4{color:#6200ea !important}.indigo{background-color:#3f51b5 !important}.indigo-text{color:#3f51b5 !important}.indigo.lighten-5{background-color:#e8eaf6 !important}.indigo-text.text-lighten-5{color:#e8eaf6 !important}.indigo.lighten-4{background-color:#c5cae9 !important}.indigo-text.text-lighten-4{color:#c5cae9 !important}.indigo.lighten-3{background-color:#9fa8da !important}.indigo-text.text-lighten-3{color:#9fa8da !important}.indigo.lighten-2{background-color:#7986cb !important}.indigo-text.text-lighten-2{color:#7986cb !important}.indigo.lighten-1{background-color:#5c6bc0 !important}.indigo-text.text-lighten-1{color:#5c6bc0 !important}.indigo.darken-1{background-color:#3949ab !important}.indigo-text.text-darken-1{color:#3949ab !important}.indigo.darken-2{background-color:#303f9f !important}.indigo-text.text-darken-2{color:#303f9f !important}.indigo.darken-3{background-color:#283593 !important}.indigo-text.text-darken-3{color:#283593 !important}.indigo.darken-4{background-color:#1a237e !important}.indigo-text.text-darken-4{color:#1a237e !important}.indigo.accent-1{background-color:#8c9eff !important}.indigo-text.text-accent-1{color:#8c9eff !important}.indigo.accent-2{background-color:#536dfe !important}.indigo-text.text-accent-2{color:#536dfe !important}.indigo.accent-3{background-color:#3d5afe !important}.indigo-text.text-accent-3{color:#3d5afe !important}.indigo.accent-4{background-color:#304ffe !important}.indigo-text.text-accent-4{color:#304ffe !important}.blue{background-color:#2196F3 !important}.blue-text{color:#2196F3 !important}.blue.lighten-5{background-color:#E3F2FD !important}.blue-text.text-lighten-5{color:#E3F2FD !important}.blue.lighten-4{background-color:#BBDEFB !important}.blue-text.text-lighten-4{color:#BBDEFB !important}.blue.lighten-3{background-color:#90CAF9 !important}.blue-text.text-lighten-3{color:#90CAF9 !important}.blue.lighten-2{background-color:#64B5F6 !important}.blue-text.text-lighten-2{color:#64B5F6 !important}.blue.lighten-1{background-color:#42A5F5 !important}.blue-text.text-lighten-1{color:#42A5F5 !important}.blue.darken-1{background-color:#1E88E5 !important}.blue-text.text-darken-1{color:#1E88E5 !important}.blue.darken-2{background-color:#1976D2 !important}.blue-text.text-darken-2{color:#1976D2 !important}.blue.darken-3{background-color:#1565C0 !important}.blue-text.text-darken-3{color:#1565C0 !important}.blue.darken-4{background-color:#0D47A1 !important}.blue-text.text-darken-4{color:#0D47A1 !important}.blue.accent-1{background-color:#82B1FF !important}.blue-text.text-accent-1{color:#82B1FF !important}.blue.accent-2{background-color:#448AFF !important}.blue-text.text-accent-2{color:#448AFF !important}.blue.accent-3{background-color:#2979FF !important}.blue-text.text-accent-3{color:#2979FF !important}.blue.accent-4{background-color:#2962FF !important}.blue-text.text-accent-4{color:#2962FF !important}.light-blue{background-color:#03a9f4 !important}.light-blue-text{color:#03a9f4 !important}.light-blue.lighten-5{background-color:#e1f5fe !important}.light-blue-text.text-lighten-5{color:#e1f5fe !important}.light-blue.lighten-4{background-color:#b3e5fc !important}.light-blue-text.text-lighten-4{color:#b3e5fc !important}.light-blue.lighten-3{background-color:#81d4fa !important}.light-blue-text.text-lighten-3{color:#81d4fa !important}.light-blue.lighten-2{background-color:#4fc3f7 !important}.light-blue-text.text-lighten-2{color:#4fc3f7 !important}.light-blue.lighten-1{background-color:#29b6f6 !important}.light-blue-text.text-lighten-1{color:#29b6f6 !important}.light-blue.darken-1{background-color:#039be5 !important}.light-blue-text.text-darken-1{color:#039be5 !important}.light-blue.darken-2{background-color:#0288d1 !important}.light-blue-text.text-darken-2{color:#0288d1 !important}.light-blue.darken-3{background-color:#0277bd !important}.light-blue-text.text-darken-3{color:#0277bd !important}.light-blue.darken-4{background-color:#01579b !important}.light-blue-text.text-darken-4{color:#01579b !important}.light-blue.accent-1{background-color:#80d8ff !important}.light-blue-text.text-accent-1{color:#80d8ff !important}.light-blue.accent-2{background-color:#40c4ff !important}.light-blue-text.text-accent-2{color:#40c4ff !important}.light-blue.accent-3{background-color:#00b0ff !important}.light-blue-text.text-accent-3{color:#00b0ff !important}.light-blue.accent-4{background-color:#0091ea !important}.light-blue-text.text-accent-4{color:#0091ea !important}.cyan{background-color:#00bcd4 !important}.cyan-text{color:#00bcd4 !important}.cyan.lighten-5{background-color:#e0f7fa !important}.cyan-text.text-lighten-5{color:#e0f7fa !important}.cyan.lighten-4{background-color:#b2ebf2 !important}.cyan-text.text-lighten-4{color:#b2ebf2 !important}.cyan.lighten-3{background-color:#80deea !important}.cyan-text.text-lighten-3{color:#80deea !important}.cyan.lighten-2{background-color:#4dd0e1 !important}.cyan-text.text-lighten-2{color:#4dd0e1 !important}.cyan.lighten-1{background-color:#26c6da !important}.cyan-text.text-lighten-1{color:#26c6da !important}.cyan.darken-1{background-color:#00acc1 !important}.cyan-text.text-darken-1{color:#00acc1 !important}.cyan.darken-2{background-color:#0097a7 !important}.cyan-text.text-darken-2{color:#0097a7 !important}.cyan.darken-3{background-color:#00838f !important}.cyan-text.text-darken-3{color:#00838f !important}.cyan.darken-4{background-color:#006064 !important}.cyan-text.text-darken-4{color:#006064 !important}.cyan.accent-1{background-color:#84ffff !important}.cyan-text.text-accent-1{color:#84ffff !important}.cyan.accent-2{background-color:#18ffff !important}.cyan-text.text-accent-2{color:#18ffff !important}.cyan.accent-3{background-color:#00e5ff !important}.cyan-text.text-accent-3{color:#00e5ff !important}.cyan.accent-4{background-color:#00b8d4 !important}.cyan-text.text-accent-4{color:#00b8d4 !important}.teal{background-color:#009688 !important}.teal-text{color:#009688 !important}.teal.lighten-5{background-color:#e0f2f1 !important}.teal-text.text-lighten-5{color:#e0f2f1 !important}.teal.lighten-4{background-color:#b2dfdb !important}.teal-text.text-lighten-4{color:#b2dfdb !important}.teal.lighten-3{background-color:#80cbc4 !important}.teal-text.text-lighten-3{color:#80cbc4 !important}.teal.lighten-2{background-color:#4db6ac !important}.teal-text.text-lighten-2{color:#4db6ac !important}.teal.lighten-1{background-color:#26a69a !important}.teal-text.text-lighten-1{color:#26a69a !important}.teal.darken-1{background-color:#00897b !important}.teal-text.text-darken-1{color:#00897b !important}.teal.darken-2{background-color:#00796b !important}.teal-text.text-darken-2{color:#00796b !important}.teal.darken-3{background-color:#00695c !important}.teal-text.text-darken-3{color:#00695c !important}.teal.darken-4{background-color:#004d40 !important}.teal-text.text-darken-4{color:#004d40 !important}.teal.accent-1{background-color:#a7ffeb !important}.teal-text.text-accent-1{color:#a7ffeb !important}.teal.accent-2{background-color:#64ffda !important}.teal-text.text-accent-2{color:#64ffda !important}.teal.accent-3{background-color:#1de9b6 !important}.teal-text.text-accent-3{color:#1de9b6 !important}.teal.accent-4{background-color:#00bfa5 !important}.teal-text.text-accent-4{color:#00bfa5 !important}.green{background-color:#4CAF50 !important}.green-text{color:#4CAF50 !important}.green.lighten-5{background-color:#E8F5E9 !important}.green-text.text-lighten-5{color:#E8F5E9 !important}.green.lighten-4{background-color:#C8E6C9 !important}.green-text.text-lighten-4{color:#C8E6C9 !important}.green.lighten-3{background-color:#A5D6A7 !important}.green-text.text-lighten-3{color:#A5D6A7 !important}.green.lighten-2{background-color:#81C784 !important}.green-text.text-lighten-2{color:#81C784 !important}.green.lighten-1{background-color:#66BB6A !important}.green-text.text-lighten-1{color:#66BB6A !important}.green.darken-1{background-color:#43A047 !important}.green-text.text-darken-1{color:#43A047 !important}.green.darken-2{background-color:#388E3C !important}.green-text.text-darken-2{color:#388E3C !important}.green.darken-3{background-color:#2E7D32 !important}.green-text.text-darken-3{color:#2E7D32 !important}.green.darken-4{background-color:#1B5E20 !important}.green-text.text-darken-4{color:#1B5E20 !important}.green.accent-1{background-color:#B9F6CA !important}.green-text.text-accent-1{color:#B9F6CA !important}.green.accent-2{background-color:#69F0AE !important}.green-text.text-accent-2{color:#69F0AE !important}.green.accent-3{background-color:#00E676 !important}.green-text.text-accent-3{color:#00E676 !important}.green.accent-4{background-color:#00C853 !important}.green-text.text-accent-4{color:#00C853 !important}.light-green{background-color:#8bc34a !important}.light-green-text{color:#8bc34a !important}.light-green.lighten-5{background-color:#f1f8e9 !important}.light-green-text.text-lighten-5{color:#f1f8e9 !important}.light-green.lighten-4{background-color:#dcedc8 !important}.light-green-text.text-lighten-4{color:#dcedc8 !important}.light-green.lighten-3{background-color:#c5e1a5 !important}.light-green-text.text-lighten-3{color:#c5e1a5 !important}.light-green.lighten-2{background-color:#aed581 !important}.light-green-text.text-lighten-2{color:#aed581 !important}.light-green.lighten-1{background-color:#9ccc65 !important}.light-green-text.text-lighten-1{color:#9ccc65 !important}.light-green.darken-1{background-color:#7cb342 !important}.light-green-text.text-darken-1{color:#7cb342 !important}.light-green.darken-2{background-color:#689f38 !important}.light-green-text.text-darken-2{color:#689f38 !important}.light-green.darken-3{background-color:#558b2f !important}.light-green-text.text-darken-3{color:#558b2f !important}.light-green.darken-4{background-color:#33691e !important}.light-green-text.text-darken-4{color:#33691e !important}.light-green.accent-1{background-color:#ccff90 !important}.light-green-text.text-accent-1{color:#ccff90 !important}.light-green.accent-2{background-color:#b2ff59 !important}.light-green-text.text-accent-2{color:#b2ff59 !important}.light-green.accent-3{background-color:#76ff03 !important}.light-green-text.text-accent-3{color:#76ff03 !important}.light-green.accent-4{background-color:#64dd17 !important}.light-green-text.text-accent-4{color:#64dd17 !important}.lime{background-color:#cddc39 !important}.lime-text{color:#cddc39 !important}.lime.lighten-5{background-color:#f9fbe7 !important}.lime-text.text-lighten-5{color:#f9fbe7 !important}.lime.lighten-4{background-color:#f0f4c3 !important}.lime-text.text-lighten-4{color:#f0f4c3 !important}.lime.lighten-3{background-color:#e6ee9c !important}.lime-text.text-lighten-3{color:#e6ee9c !important}.lime.lighten-2{background-color:#dce775 !important}.lime-text.text-lighten-2{color:#dce775 !important}.lime.lighten-1{background-color:#d4e157 !important}.lime-text.text-lighten-1{color:#d4e157 !important}.lime.darken-1{background-color:#c0ca33 !important}.lime-text.text-darken-1{color:#c0ca33 !important}.lime.darken-2{background-color:#afb42b !important}.lime-text.text-darken-2{color:#afb42b !important}.lime.darken-3{background-color:#9e9d24 !important}.lime-text.text-darken-3{color:#9e9d24 !important}.lime.darken-4{background-color:#827717 !important}.lime-text.text-darken-4{color:#827717 !important}.lime.accent-1{background-color:#f4ff81 !important}.lime-text.text-accent-1{color:#f4ff81 !important}.lime.accent-2{background-color:#eeff41 !important}.lime-text.text-accent-2{color:#eeff41 !important}.lime.accent-3{background-color:#c6ff00 !important}.lime-text.text-accent-3{color:#c6ff00 !important}.lime.accent-4{background-color:#aeea00 !important}.lime-text.text-accent-4{color:#aeea00 !important}.yellow{background-color:#ffeb3b !important}.yellow-text{color:#ffeb3b !important}.yellow.lighten-5{background-color:#fffde7 !important}.yellow-text.text-lighten-5{color:#fffde7 !important}.yellow.lighten-4{background-color:#fff9c4 !important}.yellow-text.text-lighten-4{color:#fff9c4 !important}.yellow.lighten-3{background-color:#fff59d !important}.yellow-text.text-lighten-3{color:#fff59d !important}.yellow.lighten-2{background-color:#fff176 !important}.yellow-text.text-lighten-2{color:#fff176 !important}.yellow.lighten-1{background-color:#ffee58 !important}.yellow-text.text-lighten-1{color:#ffee58 !important}.yellow.darken-1{background-color:#fdd835 !important}.yellow-text.text-darken-1{color:#fdd835 !important}.yellow.darken-2{background-color:#fbc02d !important}.yellow-text.text-darken-2{color:#fbc02d !important}.yellow.darken-3{background-color:#f9a825 !important}.yellow-text.text-darken-3{color:#f9a825 !important}.yellow.darken-4{background-color:#f57f17 !important}.yellow-text.text-darken-4{color:#f57f17 !important}.yellow.accent-1{background-color:#ffff8d !important}.yellow-text.text-accent-1{color:#ffff8d !important}.yellow.accent-2{background-color:#ff0 !important}.yellow-text.text-accent-2{color:#ff0 !important}.yellow.accent-3{background-color:#ffea00 !important}.yellow-text.text-accent-3{color:#ffea00 !important}.yellow.accent-4{background-color:#ffd600 !important}.yellow-text.text-accent-4{color:#ffd600 !important}.amber{background-color:#ffc107 !important}.amber-text{color:#ffc107 !important}.amber.lighten-5{background-color:#fff8e1 !important}.amber-text.text-lighten-5{color:#fff8e1 !important}.amber.lighten-4{background-color:#ffecb3 !important}.amber-text.text-lighten-4{color:#ffecb3 !important}.amber.lighten-3{background-color:#ffe082 !important}.amber-text.text-lighten-3{color:#ffe082 !important}.amber.lighten-2{background-color:#ffd54f !important}.amber-text.text-lighten-2{color:#ffd54f !important}.amber.lighten-1{background-color:#ffca28 !important}.amber-text.text-lighten-1{color:#ffca28 !important}.amber.darken-1{background-color:#ffb300 !important}.amber-text.text-darken-1{color:#ffb300 !important}.amber.darken-2{background-color:#ffa000 !important}.amber-text.text-darken-2{color:#ffa000 !important}.amber.darken-3{background-color:#ff8f00 !important}.amber-text.text-darken-3{color:#ff8f00 !important}.amber.darken-4{background-color:#ff6f00 !important}.amber-text.text-darken-4{color:#ff6f00 !important}.amber.accent-1{background-color:#ffe57f !important}.amber-text.text-accent-1{color:#ffe57f !important}.amber.accent-2{background-color:#ffd740 !important}.amber-text.text-accent-2{color:#ffd740 !important}.amber.accent-3{background-color:#ffc400 !important}.amber-text.text-accent-3{color:#ffc400 !important}.amber.accent-4{background-color:#ffab00 !important}.amber-text.text-accent-4{color:#ffab00 !important}.orange{background-color:#ff9800 !important}.orange-text{color:#ff9800 !important}.orange.lighten-5{background-color:#fff3e0 !important}.orange-text.text-lighten-5{color:#fff3e0 !important}.orange.lighten-4{background-color:#ffe0b2 !important}.orange-text.text-lighten-4{color:#ffe0b2 !important}.orange.lighten-3{background-color:#ffcc80 !important}.orange-text.text-lighten-3{color:#ffcc80 !important}.orange.lighten-2{background-color:#ffb74d !important}.orange-text.text-lighten-2{color:#ffb74d !important}.orange.lighten-1{background-color:#ffa726 !important}.orange-text.text-lighten-1{color:#ffa726 !important}.orange.darken-1{background-color:#fb8c00 !important}.orange-text.text-darken-1{color:#fb8c00 !important}.orange.darken-2{background-color:#f57c00 !important}.orange-text.text-darken-2{color:#f57c00 !important}.orange.darken-3{background-color:#ef6c00 !important}.orange-text.text-darken-3{color:#ef6c00 !important}.orange.darken-4{background-color:#e65100 !important}.orange-text.text-darken-4{color:#e65100 !important}.orange.accent-1{background-color:#ffd180 !important}.orange-text.text-accent-1{color:#ffd180 !important}.orange.accent-2{background-color:#ffab40 !important}.orange-text.text-accent-2{color:#ffab40 !important}.orange.accent-3{background-color:#ff9100 !important}.orange-text.text-accent-3{color:#ff9100 !important}.orange.accent-4{background-color:#ff6d00 !important}.orange-text.text-accent-4{color:#ff6d00 !important}.deep-orange{background-color:#ff5722 !important}.deep-orange-text{color:#ff5722 !important}.deep-orange.lighten-5{background-color:#fbe9e7 !important}.deep-orange-text.text-lighten-5{color:#fbe9e7 !important}.deep-orange.lighten-4{background-color:#ffccbc !important}.deep-orange-text.text-lighten-4{color:#ffccbc !important}.deep-orange.lighten-3{background-color:#ffab91 !important}.deep-orange-text.text-lighten-3{color:#ffab91 !important}.deep-orange.lighten-2{background-color:#ff8a65 !important}.deep-orange-text.text-lighten-2{color:#ff8a65 !important}.deep-orange.lighten-1{background-color:#ff7043 !important}.deep-orange-text.text-lighten-1{color:#ff7043 !important}.deep-orange.darken-1{background-color:#f4511e !important}.deep-orange-text.text-darken-1{color:#f4511e !important}.deep-orange.darken-2{background-color:#e64a19 !important}.deep-orange-text.text-darken-2{color:#e64a19 !important}.deep-orange.darken-3{background-color:#d84315 !important}.deep-orange-text.text-darken-3{color:#d84315 !important}.deep-orange.darken-4{background-color:#bf360c !important}.deep-orange-text.text-darken-4{color:#bf360c !important}.deep-orange.accent-1{background-color:#ff9e80 !important}.deep-orange-text.text-accent-1{color:#ff9e80 !important}.deep-orange.accent-2{background-color:#ff6e40 !important}.deep-orange-text.text-accent-2{color:#ff6e40 !important}.deep-orange.accent-3{background-color:#ff3d00 !important}.deep-orange-text.text-accent-3{color:#ff3d00 !important}.deep-orange.accent-4{background-color:#dd2c00 !important}.deep-orange-text.text-accent-4{color:#dd2c00 !important}.brown{background-color:#795548 !important}.brown-text{color:#795548 !important}.brown.lighten-5{background-color:#efebe9 !important}.brown-text.text-lighten-5{color:#efebe9 !important}.brown.lighten-4{background-color:#d7ccc8 !important}.brown-text.text-lighten-4{color:#d7ccc8 !important}.brown.lighten-3{background-color:#bcaaa4 !important}.brown-text.text-lighten-3{color:#bcaaa4 !important}.brown.lighten-2{background-color:#a1887f !important}.brown-text.text-lighten-2{color:#a1887f !important}.brown.lighten-1{background-color:#8d6e63 !important}.brown-text.text-lighten-1{color:#8d6e63 !important}.brown.darken-1{background-color:#6d4c41 !important}.brown-text.text-darken-1{color:#6d4c41 !important}.brown.darken-2{background-color:#5d4037 !important}.brown-text.text-darken-2{color:#5d4037 !important}.brown.darken-3{background-color:#4e342e !important}.brown-text.text-darken-3{color:#4e342e !important}.brown.darken-4{background-color:#3e2723 !important}.brown-text.text-darken-4{color:#3e2723 !important}.blue-grey{background-color:#607d8b !important}.blue-grey-text{color:#607d8b !important}.blue-grey.lighten-5{background-color:#eceff1 !important}.blue-grey-text.text-lighten-5{color:#eceff1 !important}.blue-grey.lighten-4{background-color:#cfd8dc !important}.blue-grey-text.text-lighten-4{color:#cfd8dc !important}.blue-grey.lighten-3{background-color:#b0bec5 !important}.blue-grey-text.text-lighten-3{color:#b0bec5 !important}.blue-grey.lighten-2{background-color:#90a4ae !important}.blue-grey-text.text-lighten-2{color:#90a4ae !important}.blue-grey.lighten-1{background-color:#78909c !important}.blue-grey-text.text-lighten-1{color:#78909c !important}.blue-grey.darken-1{background-color:#546e7a !important}.blue-grey-text.text-darken-1{color:#546e7a !important}.blue-grey.darken-2{background-color:#455a64 !important}.blue-grey-text.text-darken-2{color:#455a64 !important}.blue-grey.darken-3{background-color:#37474f !important}.blue-grey-text.text-darken-3{color:#37474f !important}.blue-grey.darken-4{background-color:#263238 !important}.blue-grey-text.text-darken-4{color:#263238 !important}.grey{background-color:#9e9e9e !important}.grey-text{color:#9e9e9e !important}.grey.lighten-5{background-color:#fafafa !important}.grey-text.text-lighten-5{color:#fafafa !important}.grey.lighten-4{background-color:#f5f5f5 !important}.grey-text.text-lighten-4{color:#f5f5f5 !important}.grey.lighten-3{background-color:#eee !important}.grey-text.text-lighten-3{color:#eee !important}.grey.lighten-2{background-color:#e0e0e0 !important}.grey-text.text-lighten-2{color:#e0e0e0 !important}.grey.lighten-1{background-color:#bdbdbd !important}.grey-text.text-lighten-1{color:#bdbdbd !important}.grey.darken-1{background-color:#757575 !important}.grey-text.text-darken-1{color:#757575 !important}.grey.darken-2{background-color:#616161 !important}.grey-text.text-darken-2{color:#616161 !important}.grey.darken-3{background-color:#424242 !important}.grey-text.text-darken-3{color:#424242 !important}.grey.darken-4{background-color:#212121 !important}.grey-text.text-darken-4{color:#212121 !important}.black{background-color:#000 !important}.black-text{color:#000 !important}.white{background-color:#fff !important}.white-text{color:#fff !important}.transparent{background-color:transparent !important}.transparent-text{color:transparent !important}/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:0.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace, monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;-moz-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:inherit}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace, monospace;font-size:1em}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}button,html [type="button"],[type="reset"],[type="submit"]{-webkit-appearance:button}button::-moz-focus-inner,[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner{border-style:none;padding:0}button:-moz-focusring,[type="button"]:-moz-focusring,[type="reset"]:-moz-focusring,[type="submit"]:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:0.35em 0.75em 0.625em}legend{-webkit-box-sizing:border-box;box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto}[type="checkbox"],[type="radio"]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}[type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button{height:auto}[type="search"]{-webkit-appearance:textfield;outline-offset:-2px}[type="search"]::-webkit-search-cancel-button,[type="search"]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details,menu{display:block}summary{display:list-item}canvas{display:inline-block}template{display:none}[hidden]{display:none}html{-webkit-box-sizing:border-box;box-sizing:border-box}*,*:before,*:after{-webkit-box-sizing:inherit;box-sizing:inherit}button,input,optgroup,select,textarea{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif}ul:not(.browser-default){padding-left:0;list-style-type:none}ul:not(.browser-default)>li{list-style-type:none}a{color:#039be5;text-decoration:none;-webkit-tap-highlight-color:transparent}.valign-wrapper{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center}.clearfix{clear:both}.z-depth-0{-webkit-box-shadow:none !important;box-shadow:none !important}.z-depth-1,nav,.card-panel,.card,.toast,.btn,.btn-large,.btn-small,.btn-floating,.dropdown-content,.collapsible,.sidenav{-webkit-box-shadow:0 2px 2px 0 rgba(0,0,0,0.14),0 3px 1px -2px rgba(0,0,0,0.12),0 1px 5px 0 rgba(0,0,0,0.2);box-shadow:0 2px 2px 0 rgba(0,0,0,0.14),0 3px 1px -2px rgba(0,0,0,0.12),0 1px 5px 0 rgba(0,0,0,0.2)}.z-depth-1-half,.btn:hover,.btn-large:hover,.btn-small:hover,.btn-floating:hover{-webkit-box-shadow:0 3px 3px 0 rgba(0,0,0,0.14),0 1px 7px 0 rgba(0,0,0,0.12),0 3px 1px -1px rgba(0,0,0,0.2);box-shadow:0 3px 3px 0 rgba(0,0,0,0.14),0 1px 7px 0 rgba(0,0,0,0.12),0 3px 1px -1px rgba(0,0,0,0.2)}.z-depth-2{-webkit-box-shadow:0 4px 5px 0 rgba(0,0,0,0.14),0 1px 10px 0 rgba(0,0,0,0.12),0 2px 4px -1px rgba(0,0,0,0.3);box-shadow:0 4px 5px 0 rgba(0,0,0,0.14),0 1px 10px 0 rgba(0,0,0,0.12),0 2px 4px -1px rgba(0,0,0,0.3)}.z-depth-3{-webkit-box-shadow:0 8px 17px 2px rgba(0,0,0,0.14),0 3px 14px 2px rgba(0,0,0,0.12),0 5px 5px -3px rgba(0,0,0,0.2);box-shadow:0 8px 17px 2px rgba(0,0,0,0.14),0 3px 14px 2px rgba(0,0,0,0.12),0 5px 5px -3px rgba(0,0,0,0.2)}.z-depth-4{-webkit-box-shadow:0 16px 24px 2px rgba(0,0,0,0.14),0 6px 30px 5px rgba(0,0,0,0.12),0 8px 10px -7px rgba(0,0,0,0.2);box-shadow:0 16px 24px 2px rgba(0,0,0,0.14),0 6px 30px 5px rgba(0,0,0,0.12),0 8px 10px -7px rgba(0,0,0,0.2)}.z-depth-5,.modal{-webkit-box-shadow:0 24px 38px 3px rgba(0,0,0,0.14),0 9px 46px 8px rgba(0,0,0,0.12),0 11px 15px -7px rgba(0,0,0,0.2);box-shadow:0 24px 38px 3px rgba(0,0,0,0.14),0 9px 46px 8px rgba(0,0,0,0.12),0 11px 15px -7px rgba(0,0,0,0.2)}.hoverable{-webkit-transition:-webkit-box-shadow .25s;transition:-webkit-box-shadow .25s;transition:box-shadow .25s;transition:box-shadow .25s, -webkit-box-shadow .25s}.hoverable:hover{-webkit-box-shadow:0 8px 17px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19);box-shadow:0 8px 17px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19)}.divider{height:1px;overflow:hidden;background-color:#e0e0e0}blockquote{margin:20px 0;padding-left:1.5rem;border-left:5px solid #ee6e73}i{line-height:inherit}i.left{float:left;margin-right:15px}i.right{float:right;margin-left:15px}i.tiny{font-size:1rem}i.small{font-size:2rem}i.medium{font-size:4rem}i.large{font-size:6rem}img.responsive-img,video.responsive-video{max-width:100%;height:auto}.pagination li{display:inline-block;border-radius:2px;text-align:center;vertical-align:top;height:30px}.pagination li a{color:#444;display:inline-block;font-size:1.2rem;padding:0 10px;line-height:30px}.pagination li.active a{color:#fff}.pagination li.active{background-color:#ee6e73}.pagination li.disabled a{cursor:default;color:#999}.pagination li i{font-size:2rem}.pagination li.pages ul li{display:inline-block;float:none}@media only screen and (max-width: 992px){.pagination{width:100%}.pagination li.prev,.pagination li.next{width:10%}.pagination li.pages{width:80%;overflow:hidden;white-space:nowrap}}.breadcrumb{font-size:18px;color:rgba(255,255,255,0.7)}.breadcrumb i,.breadcrumb [class^="mdi-"],.breadcrumb [class*="mdi-"],.breadcrumb i.material-icons{display:inline-block;float:left;font-size:24px}.breadcrumb:before{content:'\E5CC';color:rgba(255,255,255,0.7);vertical-align:top;display:inline-block;font-family:'Material Icons';font-weight:normal;font-style:normal;font-size:25px;margin:0 10px 0 8px;-webkit-font-smoothing:antialiased}.breadcrumb:first-child:before{display:none}.breadcrumb:last-child{color:#fff}.parallax-container{position:relative;overflow:hidden;height:500px}.parallax-container .parallax{position:absolute;top:0;left:0;right:0;bottom:0;z-index:-1}.parallax-container .parallax img{opacity:0;position:absolute;left:50%;bottom:0;min-width:100%;min-height:100%;-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0);-webkit-transform:translateX(-50%);transform:translateX(-50%)}.pin-top,.pin-bottom{position:relative}.pinned{position:fixed !important}ul.staggered-list li{opacity:0}.fade-in{opacity:0;-webkit-transform-origin:0 50%;transform-origin:0 50%}@media only screen and (max-width: 600px){.hide-on-small-only,.hide-on-small-and-down{display:none !important}}@media only screen and (max-width: 992px){.hide-on-med-and-down{display:none !important}}@media only screen and (min-width: 601px){.hide-on-med-and-up{display:none !important}}@media only screen and (min-width: 600px) and (max-width: 992px){.hide-on-med-only{display:none !important}}@media only screen and (min-width: 993px){.hide-on-large-only{display:none !important}}@media only screen and (min-width: 1201px){.hide-on-extra-large-only{display:none !important}}@media only screen and (min-width: 1201px){.show-on-extra-large{display:block !important}}@media only screen and (min-width: 993px){.show-on-large{display:block !important}}@media only screen and (min-width: 600px) and (max-width: 992px){.show-on-medium{display:block !important}}@media only screen and (max-width: 600px){.show-on-small{display:block !important}}@media only screen and (min-width: 601px){.show-on-medium-and-up{display:block !important}}@media only screen and (max-width: 992px){.show-on-medium-and-down{display:block !important}}@media only screen and (max-width: 600px){.center-on-small-only{text-align:center}}.page-footer{padding-top:20px;color:#fff;background-color:#ee6e73}.page-footer .footer-copyright{overflow:hidden;min-height:50px;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;padding:10px 0px;color:rgba(255,255,255,0.8);background-color:rgba(51,51,51,0.08)}table,th,td{border:none}table{width:100%;display:table;border-collapse:collapse;border-spacing:0}table.striped tr{border-bottom:none}table.striped>tbody>tr:nth-child(odd){background-color:rgba(242,242,242,0.5)}table.striped>tbody>tr>td{border-radius:0}table.highlight>tbody>tr{-webkit-transition:background-color .25s ease;transition:background-color .25s ease}table.highlight>tbody>tr:hover{background-color:rgba(242,242,242,0.5)}table.centered thead tr th,table.centered tbody tr td{text-align:center}tr{border-bottom:1px solid rgba(0,0,0,0.12)}td,th{padding:15px 5px;display:table-cell;text-align:left;vertical-align:middle;border-radius:2px}@media only screen and (max-width: 992px){table.responsive-table{width:100%;border-collapse:collapse;border-spacing:0;display:block;position:relative}table.responsive-table td:empty:before{content:'\00a0'}table.responsive-table th,table.responsive-table td{margin:0;vertical-align:top}table.responsive-table th{text-align:left}table.responsive-table thead{display:block;float:left}table.responsive-table thead tr{display:block;padding:0 10px 0 0}table.responsive-table thead tr th::before{content:"\00a0"}table.responsive-table tbody{display:block;width:auto;position:relative;overflow-x:auto;white-space:nowrap}table.responsive-table tbody tr{display:inline-block;vertical-align:top}table.responsive-table th{display:block;text-align:right}table.responsive-table td{display:block;min-height:1.25em;text-align:left}table.responsive-table tr{border-bottom:none;padding:0 10px}table.responsive-table thead{border:0;border-right:1px solid rgba(0,0,0,0.12)}}.collection{margin:.5rem 0 1rem 0;border:1px solid #e0e0e0;border-radius:2px;overflow:hidden;position:relative}.collection .collection-item{background-color:#fff;line-height:1.5rem;padding:10px 20px;margin:0;border-bottom:1px solid #e0e0e0}.collection .collection-item.avatar{min-height:84px;padding-left:72px;position:relative}.collection .collection-item.avatar:not(.circle-clipper)>.circle,.collection .collection-item.avatar :not(.circle-clipper)>.circle{position:absolute;width:42px;height:42px;overflow:hidden;left:15px;display:inline-block;vertical-align:middle}.collection .collection-item.avatar i.circle{font-size:18px;line-height:42px;color:#fff;background-color:#999;text-align:center}.collection .collection-item.avatar .title{font-size:16px}.collection .collection-item.avatar p{margin:0}.collection .collection-item.avatar .secondary-content{position:absolute;top:16px;right:16px}.collection .collection-item:last-child{border-bottom:none}.collection .collection-item.active{background-color:#26a69a;color:#eafaf9}.collection .collection-item.active .secondary-content{color:#fff}.collection a.collection-item{display:block;-webkit-transition:.25s;transition:.25s;color:#26a69a}.collection a.collection-item:not(.active):hover{background-color:#ddd}.collection.with-header .collection-header{background-color:#fff;border-bottom:1px solid #e0e0e0;padding:10px 20px}.collection.with-header .collection-item{padding-left:30px}.collection.with-header .collection-item.avatar{padding-left:72px}.secondary-content{float:right;color:#26a69a}.collapsible .collection{margin:0;border:none}.video-container{position:relative;padding-bottom:56.25%;height:0;overflow:hidden}.video-container iframe,.video-container object,.video-container embed{position:absolute;top:0;left:0;width:100%;height:100%}.progress{position:relative;height:4px;display:block;width:100%;background-color:#acece6;border-radius:2px;margin:.5rem 0 1rem 0;overflow:hidden}.progress .determinate{position:absolute;top:0;left:0;bottom:0;background-color:#26a69a;-webkit-transition:width .3s linear;transition:width .3s linear}.progress .indeterminate{background-color:#26a69a}.progress .indeterminate:before{content:'';position:absolute;background-color:inherit;top:0;left:0;bottom:0;will-change:left, right;-webkit-animation:indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;animation:indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite}.progress .indeterminate:after{content:'';position:absolute;background-color:inherit;top:0;left:0;bottom:0;will-change:left, right;-webkit-animation:indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;animation:indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;-webkit-animation-delay:1.15s;animation-delay:1.15s}@-webkit-keyframes indeterminate{0%{left:-35%;right:100%}60%{left:100%;right:-90%}100%{left:100%;right:-90%}}@keyframes indeterminate{0%{left:-35%;right:100%}60%{left:100%;right:-90%}100%{left:100%;right:-90%}}@-webkit-keyframes indeterminate-short{0%{left:-200%;right:100%}60%{left:107%;right:-8%}100%{left:107%;right:-8%}}@keyframes indeterminate-short{0%{left:-200%;right:100%}60%{left:107%;right:-8%}100%{left:107%;right:-8%}}.hide{display:none !important}.left-align{text-align:left}.right-align{text-align:right}.center,.center-align{text-align:center}.left{float:left !important}.right{float:right !important}.no-select,input[type=range],input[type=range]+.thumb{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.circle{border-radius:50%}.center-block{display:block;margin-left:auto;margin-right:auto}.truncate{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.no-padding{padding:0 !important}span.badge{min-width:3rem;padding:0 6px;margin-left:14px;text-align:center;font-size:1rem;line-height:22px;height:22px;color:#757575;float:right;-webkit-box-sizing:border-box;box-sizing:border-box}span.badge.new{font-weight:300;font-size:0.8rem;color:#fff;background-color:#26a69a;border-radius:2px}span.badge.new:after{content:" new"}span.badge[data-badge-caption]::after{content:" " attr(data-badge-caption)}nav ul a span.badge{display:inline-block;float:none;margin-left:4px;line-height:22px;height:22px;-webkit-font-smoothing:auto}.collection-item span.badge{margin-top:calc(.75rem - 11px)}.collapsible span.badge{margin-left:auto}.sidenav span.badge{margin-top:calc(24px - 11px)}table span.badge{display:inline-block;float:none;margin-left:auto}.material-icons{text-rendering:optimizeLegibility;-webkit-font-feature-settings:'liga';-moz-font-feature-settings:'liga';font-feature-settings:'liga'}.container{margin:0 auto;max-width:1280px;width:90%}@media only screen and (min-width: 601px){.container{width:85%}}@media only screen and (min-width: 993px){.container{width:70%}}.col .row{margin-left:-.75rem;margin-right:-.75rem}.section{padding-top:1rem;padding-bottom:1rem}.section.no-pad{padding:0}.section.no-pad-bot{padding-bottom:0}.section.no-pad-top{padding-top:0}.row{margin-left:auto;margin-right:auto;margin-bottom:20px}.row:after{content:"";display:table;clear:both}.row .col{float:left;-webkit-box-sizing:border-box;box-sizing:border-box;padding:0 .75rem;min-height:1px}.row .col[class*="push-"],.row .col[class*="pull-"]{position:relative}.row .col.s1{width:8.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.s2{width:16.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.s3{width:25%;margin-left:auto;left:auto;right:auto}.row .col.s4{width:33.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.s5{width:41.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.s6{width:50%;margin-left:auto;left:auto;right:auto}.row .col.s7{width:58.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.s8{width:66.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.s9{width:75%;margin-left:auto;left:auto;right:auto}.row .col.s10{width:83.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.s11{width:91.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.s12{width:100%;margin-left:auto;left:auto;right:auto}.row .col.offset-s1{margin-left:8.3333333333%}.row .col.pull-s1{right:8.3333333333%}.row .col.push-s1{left:8.3333333333%}.row .col.offset-s2{margin-left:16.6666666667%}.row .col.pull-s2{right:16.6666666667%}.row .col.push-s2{left:16.6666666667%}.row .col.offset-s3{margin-left:25%}.row .col.pull-s3{right:25%}.row .col.push-s3{left:25%}.row .col.offset-s4{margin-left:33.3333333333%}.row .col.pull-s4{right:33.3333333333%}.row .col.push-s4{left:33.3333333333%}.row .col.offset-s5{margin-left:41.6666666667%}.row .col.pull-s5{right:41.6666666667%}.row .col.push-s5{left:41.6666666667%}.row .col.offset-s6{margin-left:50%}.row .col.pull-s6{right:50%}.row .col.push-s6{left:50%}.row .col.offset-s7{margin-left:58.3333333333%}.row .col.pull-s7{right:58.3333333333%}.row .col.push-s7{left:58.3333333333%}.row .col.offset-s8{margin-left:66.6666666667%}.row .col.pull-s8{right:66.6666666667%}.row .col.push-s8{left:66.6666666667%}.row .col.offset-s9{margin-left:75%}.row .col.pull-s9{right:75%}.row .col.push-s9{left:75%}.row .col.offset-s10{margin-left:83.3333333333%}.row .col.pull-s10{right:83.3333333333%}.row .col.push-s10{left:83.3333333333%}.row .col.offset-s11{margin-left:91.6666666667%}.row .col.pull-s11{right:91.6666666667%}.row .col.push-s11{left:91.6666666667%}.row .col.offset-s12{margin-left:100%}.row .col.pull-s12{right:100%}.row .col.push-s12{left:100%}@media only screen and (min-width: 601px){.row .col.m1{width:8.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.m2{width:16.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.m3{width:25%;margin-left:auto;left:auto;right:auto}.row .col.m4{width:33.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.m5{width:41.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.m6{width:50%;margin-left:auto;left:auto;right:auto}.row .col.m7{width:58.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.m8{width:66.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.m9{width:75%;margin-left:auto;left:auto;right:auto}.row .col.m10{width:83.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.m11{width:91.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.m12{width:100%;margin-left:auto;left:auto;right:auto}.row .col.offset-m1{margin-left:8.3333333333%}.row .col.pull-m1{right:8.3333333333%}.row .col.push-m1{left:8.3333333333%}.row .col.offset-m2{margin-left:16.6666666667%}.row .col.pull-m2{right:16.6666666667%}.row .col.push-m2{left:16.6666666667%}.row .col.offset-m3{margin-left:25%}.row .col.pull-m3{right:25%}.row .col.push-m3{left:25%}.row .col.offset-m4{margin-left:33.3333333333%}.row .col.pull-m4{right:33.3333333333%}.row .col.push-m4{left:33.3333333333%}.row .col.offset-m5{margin-left:41.6666666667%}.row .col.pull-m5{right:41.6666666667%}.row .col.push-m5{left:41.6666666667%}.row .col.offset-m6{margin-left:50%}.row .col.pull-m6{right:50%}.row .col.push-m6{left:50%}.row .col.offset-m7{margin-left:58.3333333333%}.row .col.pull-m7{right:58.3333333333%}.row .col.push-m7{left:58.3333333333%}.row .col.offset-m8{margin-left:66.6666666667%}.row .col.pull-m8{right:66.6666666667%}.row .col.push-m8{left:66.6666666667%}.row .col.offset-m9{margin-left:75%}.row .col.pull-m9{right:75%}.row .col.push-m9{left:75%}.row .col.offset-m10{margin-left:83.3333333333%}.row .col.pull-m10{right:83.3333333333%}.row .col.push-m10{left:83.3333333333%}.row .col.offset-m11{margin-left:91.6666666667%}.row .col.pull-m11{right:91.6666666667%}.row .col.push-m11{left:91.6666666667%}.row .col.offset-m12{margin-left:100%}.row .col.pull-m12{right:100%}.row .col.push-m12{left:100%}}@media only screen and (min-width: 993px){.row .col.l1{width:8.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.l2{width:16.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.l3{width:25%;margin-left:auto;left:auto;right:auto}.row .col.l4{width:33.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.l5{width:41.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.l6{width:50%;margin-left:auto;left:auto;right:auto}.row .col.l7{width:58.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.l8{width:66.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.l9{width:75%;margin-left:auto;left:auto;right:auto}.row .col.l10{width:83.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.l11{width:91.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.l12{width:100%;margin-left:auto;left:auto;right:auto}.row .col.offset-l1{margin-left:8.3333333333%}.row .col.pull-l1{right:8.3333333333%}.row .col.push-l1{left:8.3333333333%}.row .col.offset-l2{margin-left:16.6666666667%}.row .col.pull-l2{right:16.6666666667%}.row .col.push-l2{left:16.6666666667%}.row .col.offset-l3{margin-left:25%}.row .col.pull-l3{right:25%}.row .col.push-l3{left:25%}.row .col.offset-l4{margin-left:33.3333333333%}.row .col.pull-l4{right:33.3333333333%}.row .col.push-l4{left:33.3333333333%}.row .col.offset-l5{margin-left:41.6666666667%}.row .col.pull-l5{right:41.6666666667%}.row .col.push-l5{left:41.6666666667%}.row .col.offset-l6{margin-left:50%}.row .col.pull-l6{right:50%}.row .col.push-l6{left:50%}.row .col.offset-l7{margin-left:58.3333333333%}.row .col.pull-l7{right:58.3333333333%}.row .col.push-l7{left:58.3333333333%}.row .col.offset-l8{margin-left:66.6666666667%}.row .col.pull-l8{right:66.6666666667%}.row .col.push-l8{left:66.6666666667%}.row .col.offset-l9{margin-left:75%}.row .col.pull-l9{right:75%}.row .col.push-l9{left:75%}.row .col.offset-l10{margin-left:83.3333333333%}.row .col.pull-l10{right:83.3333333333%}.row .col.push-l10{left:83.3333333333%}.row .col.offset-l11{margin-left:91.6666666667%}.row .col.pull-l11{right:91.6666666667%}.row .col.push-l11{left:91.6666666667%}.row .col.offset-l12{margin-left:100%}.row .col.pull-l12{right:100%}.row .col.push-l12{left:100%}}@media only screen and (min-width: 1201px){.row .col.xl1{width:8.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.xl2{width:16.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.xl3{width:25%;margin-left:auto;left:auto;right:auto}.row .col.xl4{width:33.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.xl5{width:41.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.xl6{width:50%;margin-left:auto;left:auto;right:auto}.row .col.xl7{width:58.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.xl8{width:66.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.xl9{width:75%;margin-left:auto;left:auto;right:auto}.row .col.xl10{width:83.3333333333%;margin-left:auto;left:auto;right:auto}.row .col.xl11{width:91.6666666667%;margin-left:auto;left:auto;right:auto}.row .col.xl12{width:100%;margin-left:auto;left:auto;right:auto}.row .col.offset-xl1{margin-left:8.3333333333%}.row .col.pull-xl1{right:8.3333333333%}.row .col.push-xl1{left:8.3333333333%}.row .col.offset-xl2{margin-left:16.6666666667%}.row .col.pull-xl2{right:16.6666666667%}.row .col.push-xl2{left:16.6666666667%}.row .col.offset-xl3{margin-left:25%}.row .col.pull-xl3{right:25%}.row .col.push-xl3{left:25%}.row .col.offset-xl4{margin-left:33.3333333333%}.row .col.pull-xl4{right:33.3333333333%}.row .col.push-xl4{left:33.3333333333%}.row .col.offset-xl5{margin-left:41.6666666667%}.row .col.pull-xl5{right:41.6666666667%}.row .col.push-xl5{left:41.6666666667%}.row .col.offset-xl6{margin-left:50%}.row .col.pull-xl6{right:50%}.row .col.push-xl6{left:50%}.row .col.offset-xl7{margin-left:58.3333333333%}.row .col.pull-xl7{right:58.3333333333%}.row .col.push-xl7{left:58.3333333333%}.row .col.offset-xl8{margin-left:66.6666666667%}.row .col.pull-xl8{right:66.6666666667%}.row .col.push-xl8{left:66.6666666667%}.row .col.offset-xl9{margin-left:75%}.row .col.pull-xl9{right:75%}.row .col.push-xl9{left:75%}.row .col.offset-xl10{margin-left:83.3333333333%}.row .col.pull-xl10{right:83.3333333333%}.row .col.push-xl10{left:83.3333333333%}.row .col.offset-xl11{margin-left:91.6666666667%}.row .col.pull-xl11{right:91.6666666667%}.row .col.push-xl11{left:91.6666666667%}.row .col.offset-xl12{margin-left:100%}.row .col.pull-xl12{right:100%}.row .col.push-xl12{left:100%}}nav{color:#fff;background-color:#ee6e73;width:100%;height:56px;line-height:56px}nav.nav-extended{height:auto}nav.nav-extended .nav-wrapper{min-height:56px;height:auto}nav.nav-extended .nav-content{position:relative;line-height:normal}nav a{color:#fff}nav i,nav [class^="mdi-"],nav [class*="mdi-"],nav i.material-icons{display:block;font-size:24px;height:56px;line-height:56px}nav .nav-wrapper{position:relative;height:100%}@media only screen and (min-width: 993px){nav a.sidenav-trigger{display:none}}nav .sidenav-trigger{float:left;position:relative;z-index:1;height:56px;margin:0 18px}nav .sidenav-trigger i{height:56px;line-height:56px}nav .brand-logo{position:absolute;color:#fff;display:inline-block;font-size:2.1rem;padding:0}nav .brand-logo.center{left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%)}@media only screen and (max-width: 992px){nav .brand-logo{left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%)}nav .brand-logo.left,nav .brand-logo.right{padding:0;-webkit-transform:none;transform:none}nav .brand-logo.left{left:0.5rem}nav .brand-logo.right{right:0.5rem;left:auto}}nav .brand-logo.right{right:0.5rem;padding:0}nav .brand-logo i,nav .brand-logo [class^="mdi-"],nav .brand-logo [class*="mdi-"],nav .brand-logo i.material-icons{float:left;margin-right:15px}nav .nav-title{display:inline-block;font-size:32px;padding:28px 0}nav ul{margin:0}nav ul li{-webkit-transition:background-color .3s;transition:background-color .3s;float:left;padding:0}nav ul li.active{background-color:rgba(0,0,0,0.1)}nav ul a{-webkit-transition:background-color .3s;transition:background-color .3s;font-size:1rem;color:#fff;display:block;padding:0 15px;cursor:pointer}nav ul a.btn,nav ul a.btn-large,nav ul a.btn-small,nav ul a.btn-large,nav ul a.btn-flat,nav ul a.btn-floating{margin-top:-2px;margin-left:15px;margin-right:15px}nav ul a.btn>.material-icons,nav ul a.btn-large>.material-icons,nav ul a.btn-small>.material-icons,nav ul a.btn-large>.material-icons,nav ul a.btn-flat>.material-icons,nav ul a.btn-floating>.material-icons{height:inherit;line-height:inherit}nav ul a:hover{background-color:rgba(0,0,0,0.1)}nav ul.left{float:left}nav form{height:100%}nav .input-field{margin:0;height:100%}nav .input-field input{height:100%;font-size:1.2rem;border:none;padding-left:2rem}nav .input-field input:focus,nav .input-field input[type=text]:valid,nav .input-field input[type=password]:valid,nav .input-field input[type=email]:valid,nav .input-field input[type=url]:valid,nav .input-field input[type=date]:valid{border:none;-webkit-box-shadow:none;box-shadow:none}nav .input-field label{top:0;left:0}nav .input-field label i{color:rgba(255,255,255,0.7);-webkit-transition:color .3s;transition:color .3s}nav .input-field label.active i{color:#fff}.navbar-fixed{position:relative;height:56px;z-index:997}.navbar-fixed nav{position:fixed}@media only screen and (min-width: 601px){nav.nav-extended .nav-wrapper{min-height:64px}nav,nav .nav-wrapper i,nav a.sidenav-trigger,nav a.sidenav-trigger i{height:64px;line-height:64px}.navbar-fixed{height:64px}}a{text-decoration:none}html{line-height:1.5;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-weight:normal;color:rgba(0,0,0,0.87)}@media only screen and (min-width: 0){html{font-size:14px}}@media only screen and (min-width: 992px){html{font-size:14.5px}}@media only screen and (min-width: 1200px){html{font-size:15px}}h1,h2,h3,h4,h5,h6{font-weight:400;line-height:1.3}h1 a,h2 a,h3 a,h4 a,h5 a,h6 a{font-weight:inherit}h1{font-size:4.2rem;line-height:110%;margin:2.8rem 0 1.68rem 0}h2{font-size:3.56rem;line-height:110%;margin:2.3733333333rem 0 1.424rem 0}h3{font-size:2.92rem;line-height:110%;margin:1.9466666667rem 0 1.168rem 0}h4{font-size:2.28rem;line-height:110%;margin:1.52rem 0 .912rem 0}h5{font-size:1.64rem;line-height:110%;margin:1.0933333333rem 0 .656rem 0}h6{font-size:1.15rem;line-height:110%;margin:.7666666667rem 0 .46rem 0}em{font-style:italic}strong{font-weight:500}small{font-size:75%}.light{font-weight:300}.thin{font-weight:200}@media only screen and (min-width: 360px){.flow-text{font-size:1.2rem}}@media only screen and (min-width: 390px){.flow-text{font-size:1.224rem}}@media only screen and (min-width: 420px){.flow-text{font-size:1.248rem}}@media only screen and (min-width: 450px){.flow-text{font-size:1.272rem}}@media only screen and (min-width: 480px){.flow-text{font-size:1.296rem}}@media only screen and (min-width: 510px){.flow-text{font-size:1.32rem}}@media only screen and (min-width: 540px){.flow-text{font-size:1.344rem}}@media only screen and (min-width: 570px){.flow-text{font-size:1.368rem}}@media only screen and (min-width: 600px){.flow-text{font-size:1.392rem}}@media only screen and (min-width: 630px){.flow-text{font-size:1.416rem}}@media only screen and (min-width: 660px){.flow-text{font-size:1.44rem}}@media only screen and (min-width: 690px){.flow-text{font-size:1.464rem}}@media only screen and (min-width: 720px){.flow-text{font-size:1.488rem}}@media only screen and (min-width: 750px){.flow-text{font-size:1.512rem}}@media only screen and (min-width: 780px){.flow-text{font-size:1.536rem}}@media only screen and (min-width: 810px){.flow-text{font-size:1.56rem}}@media only screen and (min-width: 840px){.flow-text{font-size:1.584rem}}@media only screen and (min-width: 870px){.flow-text{font-size:1.608rem}}@media only screen and (min-width: 900px){.flow-text{font-size:1.632rem}}@media only screen and (min-width: 930px){.flow-text{font-size:1.656rem}}@media only screen and (min-width: 960px){.flow-text{font-size:1.68rem}}@media only screen and (max-width: 360px){.flow-text{font-size:1.2rem}}.scale-transition{-webkit-transition:-webkit-transform 0.3s cubic-bezier(0.53, 0.01, 0.36, 1.63) !important;transition:-webkit-transform 0.3s cubic-bezier(0.53, 0.01, 0.36, 1.63) !important;transition:transform 0.3s cubic-bezier(0.53, 0.01, 0.36, 1.63) !important;transition:transform 0.3s cubic-bezier(0.53, 0.01, 0.36, 1.63), -webkit-transform 0.3s cubic-bezier(0.53, 0.01, 0.36, 1.63) !important}.scale-transition.scale-out{-webkit-transform:scale(0);transform:scale(0);-webkit-transition:-webkit-transform .2s !important;transition:-webkit-transform .2s !important;transition:transform .2s !important;transition:transform .2s, -webkit-transform .2s !important}.scale-transition.scale-in{-webkit-transform:scale(1);transform:scale(1)}.card-panel{-webkit-transition:-webkit-box-shadow .25s;transition:-webkit-box-shadow .25s;transition:box-shadow .25s;transition:box-shadow .25s, -webkit-box-shadow .25s;padding:24px;margin:.5rem 0 1rem 0;border-radius:2px;background-color:#fff}.card{position:relative;margin:.5rem 0 1rem 0;background-color:#fff;-webkit-transition:-webkit-box-shadow .25s;transition:-webkit-box-shadow .25s;transition:box-shadow .25s;transition:box-shadow .25s, -webkit-box-shadow .25s;border-radius:2px}.card .card-title{font-size:24px;font-weight:300}.card .card-title.activator{cursor:pointer}.card.small,.card.medium,.card.large{position:relative}.card.small .card-image,.card.medium .card-image,.card.large .card-image{max-height:60%;overflow:hidden}.card.small .card-image+.card-content,.card.medium .card-image+.card-content,.card.large .card-image+.card-content{max-height:40%}.card.small .card-content,.card.medium .card-content,.card.large .card-content{max-height:100%;overflow:hidden}.card.small .card-action,.card.medium .card-action,.card.large .card-action{position:absolute;bottom:0;left:0;right:0}.card.small{height:300px}.card.medium{height:400px}.card.large{height:500px}.card.horizontal{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.card.horizontal.small .card-image,.card.horizontal.medium .card-image,.card.horizontal.large .card-image{height:100%;max-height:none;overflow:visible}.card.horizontal.small .card-image img,.card.horizontal.medium .card-image img,.card.horizontal.large .card-image img{height:100%}.card.horizontal .card-image{max-width:50%}.card.horizontal .card-image img{border-radius:2px 0 0 2px;max-width:100%;width:auto}.card.horizontal .card-stacked{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1;position:relative}.card.horizontal .card-stacked .card-content{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.card.sticky-action .card-action{z-index:2}.card.sticky-action .card-reveal{z-index:1;padding-bottom:64px}.card .card-image{position:relative}.card .card-image img{display:block;border-radius:2px 2px 0 0;position:relative;left:0;right:0;top:0;bottom:0;width:100%}.card .card-image .card-title{color:#fff;position:absolute;bottom:0;left:0;max-width:100%;padding:24px}.card .card-content{padding:24px;border-radius:0 0 2px 2px}.card .card-content p{margin:0}.card .card-content .card-title{display:block;line-height:32px;margin-bottom:8px}.card .card-content .card-title i{line-height:32px}.card .card-action{background-color:inherit;border-top:1px solid rgba(160,160,160,0.2);position:relative;padding:16px 24px}.card .card-action:last-child{border-radius:0 0 2px 2px}.card .card-action a:not(.btn):not(.btn-large):not(.btn-small):not(.btn-large):not(.btn-floating){color:#ffab40;margin-right:24px;-webkit-transition:color .3s ease;transition:color .3s ease;text-transform:uppercase}.card .card-action a:not(.btn):not(.btn-large):not(.btn-small):not(.btn-large):not(.btn-floating):hover{color:#ffd8a6}.card .card-reveal{padding:24px;position:absolute;background-color:#fff;width:100%;overflow-y:auto;left:0;top:100%;height:100%;z-index:3;display:none}.card .card-reveal .card-title{cursor:pointer;display:block}#toast-container{display:block;position:fixed;z-index:10000}@media only screen and (max-width: 600px){#toast-container{min-width:100%;bottom:0%}}@media only screen and (min-width: 601px) and (max-width: 992px){#toast-container{left:5%;bottom:7%;max-width:90%}}@media only screen and (min-width: 993px){#toast-container{top:10%;right:7%;max-width:86%}}.toast{border-radius:2px;top:35px;width:auto;margin-top:10px;position:relative;max-width:100%;height:auto;min-height:48px;line-height:1.5em;word-break:break-all;background-color:#323232;padding:10px 25px;font-size:1.1rem;font-weight:300;color:#fff;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;cursor:default}.toast .toast-action{color:#eeff41;font-weight:500;margin-right:-25px;margin-left:3rem}.toast.rounded{border-radius:24px}@media only screen and (max-width: 600px){.toast{width:100%;border-radius:0}}.tabs{position:relative;overflow-x:auto;overflow-y:hidden;height:48px;width:100%;background-color:#fff;margin:0 auto;white-space:nowrap}.tabs.tabs-transparent{background-color:transparent}.tabs.tabs-transparent .tab a,.tabs.tabs-transparent .tab.disabled a,.tabs.tabs-transparent .tab.disabled a:hover{color:rgba(255,255,255,0.7)}.tabs.tabs-transparent .tab a:hover,.tabs.tabs-transparent .tab a.active{color:#fff}.tabs.tabs-transparent .indicator{background-color:#fff}.tabs.tabs-fixed-width{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.tabs.tabs-fixed-width .tab{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.tabs .tab{display:inline-block;text-align:center;line-height:48px;height:48px;padding:0;margin:0;text-transform:uppercase}.tabs .tab a{color:rgba(238,110,115,0.7);display:block;width:100%;height:100%;padding:0 24px;font-size:14px;text-overflow:ellipsis;overflow:hidden;-webkit-transition:color .28s ease, background-color .28s ease;transition:color .28s ease, background-color .28s ease}.tabs .tab a:focus,.tabs .tab a:focus.active{background-color:rgba(246,178,181,0.2);outline:none}.tabs .tab a:hover,.tabs .tab a.active{background-color:transparent;color:#ee6e73}.tabs .tab.disabled a,.tabs .tab.disabled a:hover{color:rgba(238,110,115,0.4);cursor:default}.tabs .indicator{position:absolute;bottom:0;height:2px;background-color:#f6b2b5;will-change:left, right}@media only screen and (max-width: 992px){.tabs{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.tabs .tab{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.tabs .tab a{padding:0 12px}}.material-tooltip{padding:10px 8px;font-size:1rem;z-index:2000;background-color:transparent;border-radius:2px;color:#fff;min-height:36px;line-height:120%;opacity:0;position:absolute;text-align:center;max-width:calc(100% - 4px);overflow:hidden;left:0;top:0;pointer-events:none;visibility:hidden;background-color:#323232}.backdrop{position:absolute;opacity:0;height:7px;width:14px;border-radius:0 0 50% 50%;background-color:#323232;z-index:-1;-webkit-transform-origin:50% 0%;transform-origin:50% 0%;visibility:hidden}.btn,.btn-large,.btn-small,.btn-flat{border:none;border-radius:2px;display:inline-block;height:36px;line-height:36px;padding:0 16px;text-transform:uppercase;vertical-align:middle;-webkit-tap-highlight-color:transparent}.btn.disabled,.disabled.btn-large,.disabled.btn-small,.btn-floating.disabled,.btn-large.disabled,.btn-small.disabled,.btn-flat.disabled,.btn:disabled,.btn-large:disabled,.btn-small:disabled,.btn-floating:disabled,.btn-large:disabled,.btn-small:disabled,.btn-flat:disabled,.btn[disabled],[disabled].btn-large,[disabled].btn-small,.btn-floating[disabled],.btn-large[disabled],.btn-small[disabled],.btn-flat[disabled]{pointer-events:none;background-color:#DFDFDF !important;-webkit-box-shadow:none;box-shadow:none;color:#9F9F9F !important;cursor:default}.btn.disabled:hover,.disabled.btn-large:hover,.disabled.btn-small:hover,.btn-floating.disabled:hover,.btn-large.disabled:hover,.btn-small.disabled:hover,.btn-flat.disabled:hover,.btn:disabled:hover,.btn-large:disabled:hover,.btn-small:disabled:hover,.btn-floating:disabled:hover,.btn-large:disabled:hover,.btn-small:disabled:hover,.btn-flat:disabled:hover,.btn[disabled]:hover,[disabled].btn-large:hover,[disabled].btn-small:hover,.btn-floating[disabled]:hover,.btn-large[disabled]:hover,.btn-small[disabled]:hover,.btn-flat[disabled]:hover{background-color:#DFDFDF !important;color:#9F9F9F !important}.btn,.btn-large,.btn-small,.btn-floating,.btn-large,.btn-small,.btn-flat{font-size:14px;outline:0}.btn i,.btn-large i,.btn-small i,.btn-floating i,.btn-large i,.btn-small i,.btn-flat i{font-size:1.3rem;line-height:inherit}.btn:focus,.btn-large:focus,.btn-small:focus,.btn-floating:focus{background-color:#1d7d74}.btn,.btn-large,.btn-small{text-decoration:none;color:#fff;background-color:#26a69a;text-align:center;letter-spacing:.5px;-webkit-transition:background-color .2s ease-out;transition:background-color .2s ease-out;cursor:pointer}.btn:hover,.btn-large:hover,.btn-small:hover{background-color:#2bbbad}.btn-floating{display:inline-block;color:#fff;position:relative;overflow:hidden;z-index:1;width:40px;height:40px;line-height:40px;padding:0;background-color:#26a69a;border-radius:50%;-webkit-transition:background-color .3s;transition:background-color .3s;cursor:pointer;vertical-align:middle}.btn-floating:hover{background-color:#26a69a}.btn-floating:before{border-radius:0}.btn-floating.btn-large{width:56px;height:56px;padding:0}.btn-floating.btn-large.halfway-fab{bottom:-28px}.btn-floating.btn-large i{line-height:56px}.btn-floating.btn-small{width:32.4px;height:32.4px}.btn-floating.btn-small.halfway-fab{bottom:-16.2px}.btn-floating.btn-small i{line-height:32.4px}.btn-floating.halfway-fab{position:absolute;right:24px;bottom:-20px}.btn-floating.halfway-fab.left{right:auto;left:24px}.btn-floating i{width:inherit;display:inline-block;text-align:center;color:#fff;font-size:1.6rem;line-height:40px}button.btn-floating{border:none}.fixed-action-btn{position:fixed;right:23px;bottom:23px;padding-top:15px;margin-bottom:0;z-index:997}.fixed-action-btn.active ul{visibility:visible}.fixed-action-btn.direction-left,.fixed-action-btn.direction-right{padding:0 0 0 15px}.fixed-action-btn.direction-left ul,.fixed-action-btn.direction-right ul{text-align:right;right:64px;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);height:100%;left:auto;width:500px}.fixed-action-btn.direction-left ul li,.fixed-action-btn.direction-right ul li{display:inline-block;margin:7.5px 15px 0 0}.fixed-action-btn.direction-right{padding:0 15px 0 0}.fixed-action-btn.direction-right ul{text-align:left;direction:rtl;left:64px;right:auto}.fixed-action-btn.direction-right ul li{margin:7.5px 0 0 15px}.fixed-action-btn.direction-bottom{padding:0 0 15px 0}.fixed-action-btn.direction-bottom ul{top:64px;bottom:auto;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:reverse;-webkit-flex-direction:column-reverse;-ms-flex-direction:column-reverse;flex-direction:column-reverse}.fixed-action-btn.direction-bottom ul li{margin:15px 0 0 0}.fixed-action-btn.toolbar{padding:0;height:56px}.fixed-action-btn.toolbar.active>a i{opacity:0}.fixed-action-btn.toolbar ul{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;top:0;bottom:0;z-index:1}.fixed-action-btn.toolbar ul li{-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1;display:inline-block;margin:0;height:100%;-webkit-transition:none;transition:none}.fixed-action-btn.toolbar ul li a{display:block;overflow:hidden;position:relative;width:100%;height:100%;background-color:transparent;-webkit-box-shadow:none;box-shadow:none;color:#fff;line-height:56px;z-index:1}.fixed-action-btn.toolbar ul li a i{line-height:inherit}.fixed-action-btn ul{left:0;right:0;text-align:center;position:absolute;bottom:64px;margin:0;visibility:hidden}.fixed-action-btn ul li{margin-bottom:15px}.fixed-action-btn ul a.btn-floating{opacity:0}.fixed-action-btn .fab-backdrop{position:absolute;top:0;left:0;z-index:-1;width:40px;height:40px;background-color:#26a69a;border-radius:50%;-webkit-transform:scale(0);transform:scale(0)}.btn-flat{-webkit-box-shadow:none;box-shadow:none;background-color:transparent;color:#343434;cursor:pointer;-webkit-transition:background-color .2s;transition:background-color .2s}.btn-flat:focus,.btn-flat:hover{-webkit-box-shadow:none;box-shadow:none}.btn-flat:focus{background-color:rgba(0,0,0,0.1)}.btn-flat.disabled{background-color:transparent !important;color:#b3b2b2 !important;cursor:default}.btn-large{height:54px;line-height:54px;font-size:15px;padding:0 28px}.btn-large i{font-size:1.6rem}.btn-small{height:32.4px;line-height:32.4px;font-size:13px}.btn-small i{font-size:1.2rem}.btn-block{display:block}.dropdown-content{background-color:#fff;margin:0;display:none;min-width:100px;overflow-y:auto;opacity:0;position:absolute;left:0;top:0;z-index:9999;-webkit-transform-origin:0 0;transform-origin:0 0}.dropdown-content:focus{outline:0}.dropdown-content li{clear:both;color:rgba(0,0,0,0.87);cursor:pointer;min-height:50px;line-height:1.5rem;width:100%;text-align:left}.dropdown-content li:hover,.dropdown-content li.active{background-color:#eee}.dropdown-content li:focus{outline:none;background-color:#dadada}.dropdown-content li.divider{min-height:0;height:1px}.dropdown-content li>a,.dropdown-content li>span{font-size:16px;color:#26a69a;display:block;line-height:22px;padding:14px 16px}.dropdown-content li>span>label{top:1px;left:0;height:18px}.dropdown-content li>a>i{height:inherit;line-height:inherit;float:left;margin:0 24px 0 0;width:24px}.input-field.col .dropdown-content [type="checkbox"]+label{top:1px;left:0;height:18px;-webkit-transform:none;transform:none}/*! + * Waves v0.6.0 + * http://fian.my.id/Waves + * + * Copyright 2014 Alfiana E. Sibuea and other contributors + * Released under the MIT license + * https://github.com/fians/Waves/blob/master/LICENSE + */.waves-effect{position:relative;cursor:pointer;display:inline-block;overflow:hidden;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;vertical-align:middle;z-index:1;-webkit-transition:.3s ease-out;transition:.3s ease-out}.waves-effect .waves-ripple{position:absolute;border-radius:50%;width:20px;height:20px;margin-top:-10px;margin-left:-10px;opacity:0;background:rgba(0,0,0,0.2);-webkit-transition:all 0.7s ease-out;transition:all 0.7s ease-out;-webkit-transition-property:opacity, -webkit-transform;transition-property:opacity, -webkit-transform;transition-property:transform, opacity;transition-property:transform, opacity, -webkit-transform;-webkit-transform:scale(0);transform:scale(0);pointer-events:none}.waves-effect.waves-light .waves-ripple{background-color:rgba(255,255,255,0.45)}.waves-effect.waves-red .waves-ripple{background-color:rgba(244,67,54,0.7)}.waves-effect.waves-yellow .waves-ripple{background-color:rgba(255,235,59,0.7)}.waves-effect.waves-orange .waves-ripple{background-color:rgba(255,152,0,0.7)}.waves-effect.waves-purple .waves-ripple{background-color:rgba(156,39,176,0.7)}.waves-effect.waves-green .waves-ripple{background-color:rgba(76,175,80,0.7)}.waves-effect.waves-teal .waves-ripple{background-color:rgba(0,150,136,0.7)}.waves-effect input[type="button"],.waves-effect input[type="reset"],.waves-effect input[type="submit"]{border:0;font-style:normal;font-size:inherit;text-transform:inherit;background:none}.waves-effect img{position:relative;z-index:-1}.waves-notransition{-webkit-transition:none !important;transition:none !important}.waves-circle{-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-mask-image:-webkit-radial-gradient(circle, white 100%, black 100%)}.waves-input-wrapper{border-radius:0.2em;vertical-align:bottom}.waves-input-wrapper .waves-button-input{position:relative;top:0;left:0;z-index:1}.waves-circle{text-align:center;width:2.5em;height:2.5em;line-height:2.5em;border-radius:50%;-webkit-mask-image:none}.waves-block{display:block}.waves-effect .waves-ripple{z-index:-1}.modal{display:none;position:fixed;left:0;right:0;background-color:#fafafa;padding:0;max-height:70%;width:55%;margin:auto;overflow-y:auto;border-radius:2px;will-change:top, opacity}@media only screen and (max-width: 992px){.modal{width:80%}}.modal h1,.modal h2,.modal h3,.modal h4{margin-top:0}.modal .modal-content{padding:24px}.modal .modal-close{cursor:pointer}.modal .modal-footer{border-radius:0 0 2px 2px;background-color:#fafafa;padding:4px 6px;height:56px;width:100%;text-align:right}.modal .modal-footer .btn,.modal .modal-footer .btn-large,.modal .modal-footer .btn-small,.modal .modal-footer .btn-flat{margin:6px 0}.modal-overlay{position:fixed;z-index:999;top:-25%;left:0;bottom:0;right:0;height:125%;width:100%;background:#000;display:none;will-change:opacity}.modal.modal-fixed-footer{padding:0;height:70%}.modal.modal-fixed-footer .modal-content{position:absolute;height:calc(100% - 56px);max-height:100%;width:100%;overflow-y:auto}.modal.modal-fixed-footer .modal-footer{border-top:1px solid rgba(0,0,0,0.1);position:absolute;bottom:0}.modal.bottom-sheet{top:auto;bottom:-100%;margin:0;width:100%;max-height:45%;border-radius:0;will-change:bottom, opacity}.collapsible{border-top:1px solid #ddd;border-right:1px solid #ddd;border-left:1px solid #ddd;margin:.5rem 0 1rem 0}.collapsible-header{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;cursor:pointer;-webkit-tap-highlight-color:transparent;line-height:1.5;padding:1rem;background-color:#fff;border-bottom:1px solid #ddd}.collapsible-header i{width:2rem;font-size:1.6rem;display:inline-block;text-align:center;margin-right:1rem}.collapsible-body{display:none;border-bottom:1px solid #ddd;-webkit-box-sizing:border-box;box-sizing:border-box;padding:2rem}.sidenav .collapsible,.sidenav.fixed .collapsible{border:none;-webkit-box-shadow:none;box-shadow:none}.sidenav .collapsible li,.sidenav.fixed .collapsible li{padding:0}.sidenav .collapsible-header,.sidenav.fixed .collapsible-header{background-color:transparent;border:none;line-height:inherit;height:inherit;padding:0 16px}.sidenav .collapsible-header:hover,.sidenav.fixed .collapsible-header:hover{background-color:rgba(0,0,0,0.05)}.sidenav .collapsible-header i,.sidenav.fixed .collapsible-header i{line-height:inherit}.sidenav .collapsible-body,.sidenav.fixed .collapsible-body{border:0;background-color:#fff}.sidenav .collapsible-body li a,.sidenav.fixed .collapsible-body li a{padding:0 23.5px 0 31px}.collapsible.popout{border:none;-webkit-box-shadow:none;box-shadow:none}.collapsible.popout>li{-webkit-box-shadow:0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12);box-shadow:0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12);margin:0 24px;-webkit-transition:margin 0.35s cubic-bezier(0.25, 0.46, 0.45, 0.94);transition:margin 0.35s cubic-bezier(0.25, 0.46, 0.45, 0.94)}.collapsible.popout>li.active{-webkit-box-shadow:0 5px 11px 0 rgba(0,0,0,0.18),0 4px 15px 0 rgba(0,0,0,0.15);box-shadow:0 5px 11px 0 rgba(0,0,0,0.18),0 4px 15px 0 rgba(0,0,0,0.15);margin:16px 0}.chip{display:inline-block;height:32px;font-size:13px;font-weight:500;color:rgba(0,0,0,0.6);line-height:32px;padding:0 12px;border-radius:16px;background-color:#e4e4e4;margin-bottom:5px;margin-right:5px}.chip:focus{outline:none;background-color:#26a69a;color:#fff}.chip>img{float:left;margin:0 8px 0 -12px;height:32px;width:32px;border-radius:50%}.chip .close{cursor:pointer;float:right;font-size:16px;line-height:32px;padding-left:8px}.chips{border:none;border-bottom:1px solid #9e9e9e;-webkit-box-shadow:none;box-shadow:none;margin:0 0 8px 0;min-height:45px;outline:none;-webkit-transition:all .3s;transition:all .3s}.chips.focus{border-bottom:1px solid #26a69a;-webkit-box-shadow:0 1px 0 0 #26a69a;box-shadow:0 1px 0 0 #26a69a}.chips:hover{cursor:text}.chips .input{background:none;border:0;color:rgba(0,0,0,0.6);display:inline-block;font-size:16px;height:3rem;line-height:32px;outline:0;margin:0;padding:0 !important;width:120px !important}.chips .input:focus{border:0 !important;-webkit-box-shadow:none !important;box-shadow:none !important}.chips .autocomplete-content{margin-top:0;margin-bottom:0}.prefix ~ .chips{margin-left:3rem;width:92%;width:calc(100% - 3rem)}.chips:empty ~ label{font-size:0.8rem;-webkit-transform:translateY(-140%);transform:translateY(-140%)}.materialboxed{display:block;cursor:-webkit-zoom-in;cursor:zoom-in;position:relative;-webkit-transition:opacity .4s;transition:opacity .4s;-webkit-backface-visibility:hidden}.materialboxed:hover:not(.active){opacity:.8}.materialboxed.active{cursor:-webkit-zoom-out;cursor:zoom-out}#materialbox-overlay{position:fixed;top:0;right:0;bottom:0;left:0;background-color:#292929;z-index:1000;will-change:opacity}.materialbox-caption{position:fixed;display:none;color:#fff;line-height:50px;bottom:0;left:0;width:100%;text-align:center;padding:0% 15%;height:50px;z-index:1000;-webkit-font-smoothing:antialiased}select:focus{outline:1px solid #c9f3ef}button:focus{outline:none;background-color:#2ab7a9}label{font-size:.8rem;color:#9e9e9e}::-webkit-input-placeholder{color:#d1d1d1}::-moz-placeholder{color:#d1d1d1}:-ms-input-placeholder{color:#d1d1d1}::placeholder{color:#d1d1d1}input:not([type]),input[type=text]:not(.browser-default),input[type=password]:not(.browser-default),input[type=email]:not(.browser-default),input[type=url]:not(.browser-default),input[type=time]:not(.browser-default),input[type=date]:not(.browser-default),input[type=datetime]:not(.browser-default),input[type=datetime-local]:not(.browser-default),input[type=tel]:not(.browser-default),input[type=number]:not(.browser-default),input[type=search]:not(.browser-default),textarea.materialize-textarea{background-color:transparent;border:none;border-bottom:1px solid #9e9e9e;border-radius:0;outline:none;height:3rem;width:100%;font-size:16px;margin:0 0 8px 0;padding:0;-webkit-box-shadow:none;box-shadow:none;-webkit-box-sizing:content-box;box-sizing:content-box;-webkit-transition:border .3s, -webkit-box-shadow .3s;transition:border .3s, -webkit-box-shadow .3s;transition:box-shadow .3s, border .3s;transition:box-shadow .3s, border .3s, -webkit-box-shadow .3s}input:not([type]):disabled,input:not([type])[readonly="readonly"],input[type=text]:not(.browser-default):disabled,input[type=text]:not(.browser-default)[readonly="readonly"],input[type=password]:not(.browser-default):disabled,input[type=password]:not(.browser-default)[readonly="readonly"],input[type=email]:not(.browser-default):disabled,input[type=email]:not(.browser-default)[readonly="readonly"],input[type=url]:not(.browser-default):disabled,input[type=url]:not(.browser-default)[readonly="readonly"],input[type=time]:not(.browser-default):disabled,input[type=time]:not(.browser-default)[readonly="readonly"],input[type=date]:not(.browser-default):disabled,input[type=date]:not(.browser-default)[readonly="readonly"],input[type=datetime]:not(.browser-default):disabled,input[type=datetime]:not(.browser-default)[readonly="readonly"],input[type=datetime-local]:not(.browser-default):disabled,input[type=datetime-local]:not(.browser-default)[readonly="readonly"],input[type=tel]:not(.browser-default):disabled,input[type=tel]:not(.browser-default)[readonly="readonly"],input[type=number]:not(.browser-default):disabled,input[type=number]:not(.browser-default)[readonly="readonly"],input[type=search]:not(.browser-default):disabled,input[type=search]:not(.browser-default)[readonly="readonly"],textarea.materialize-textarea:disabled,textarea.materialize-textarea[readonly="readonly"]{color:rgba(0,0,0,0.42);border-bottom:1px dotted rgba(0,0,0,0.42)}input:not([type]):disabled+label,input:not([type])[readonly="readonly"]+label,input[type=text]:not(.browser-default):disabled+label,input[type=text]:not(.browser-default)[readonly="readonly"]+label,input[type=password]:not(.browser-default):disabled+label,input[type=password]:not(.browser-default)[readonly="readonly"]+label,input[type=email]:not(.browser-default):disabled+label,input[type=email]:not(.browser-default)[readonly="readonly"]+label,input[type=url]:not(.browser-default):disabled+label,input[type=url]:not(.browser-default)[readonly="readonly"]+label,input[type=time]:not(.browser-default):disabled+label,input[type=time]:not(.browser-default)[readonly="readonly"]+label,input[type=date]:not(.browser-default):disabled+label,input[type=date]:not(.browser-default)[readonly="readonly"]+label,input[type=datetime]:not(.browser-default):disabled+label,input[type=datetime]:not(.browser-default)[readonly="readonly"]+label,input[type=datetime-local]:not(.browser-default):disabled+label,input[type=datetime-local]:not(.browser-default)[readonly="readonly"]+label,input[type=tel]:not(.browser-default):disabled+label,input[type=tel]:not(.browser-default)[readonly="readonly"]+label,input[type=number]:not(.browser-default):disabled+label,input[type=number]:not(.browser-default)[readonly="readonly"]+label,input[type=search]:not(.browser-default):disabled+label,input[type=search]:not(.browser-default)[readonly="readonly"]+label,textarea.materialize-textarea:disabled+label,textarea.materialize-textarea[readonly="readonly"]+label{color:rgba(0,0,0,0.42)}input:not([type]):focus:not([readonly]),input[type=text]:not(.browser-default):focus:not([readonly]),input[type=password]:not(.browser-default):focus:not([readonly]),input[type=email]:not(.browser-default):focus:not([readonly]),input[type=url]:not(.browser-default):focus:not([readonly]),input[type=time]:not(.browser-default):focus:not([readonly]),input[type=date]:not(.browser-default):focus:not([readonly]),input[type=datetime]:not(.browser-default):focus:not([readonly]),input[type=datetime-local]:not(.browser-default):focus:not([readonly]),input[type=tel]:not(.browser-default):focus:not([readonly]),input[type=number]:not(.browser-default):focus:not([readonly]),input[type=search]:not(.browser-default):focus:not([readonly]),textarea.materialize-textarea:focus:not([readonly]){border-bottom:1px solid #26a69a;-webkit-box-shadow:0 1px 0 0 #26a69a;box-shadow:0 1px 0 0 #26a69a}input:not([type]):focus:not([readonly])+label,input[type=text]:not(.browser-default):focus:not([readonly])+label,input[type=password]:not(.browser-default):focus:not([readonly])+label,input[type=email]:not(.browser-default):focus:not([readonly])+label,input[type=url]:not(.browser-default):focus:not([readonly])+label,input[type=time]:not(.browser-default):focus:not([readonly])+label,input[type=date]:not(.browser-default):focus:not([readonly])+label,input[type=datetime]:not(.browser-default):focus:not([readonly])+label,input[type=datetime-local]:not(.browser-default):focus:not([readonly])+label,input[type=tel]:not(.browser-default):focus:not([readonly])+label,input[type=number]:not(.browser-default):focus:not([readonly])+label,input[type=search]:not(.browser-default):focus:not([readonly])+label,textarea.materialize-textarea:focus:not([readonly])+label{color:#26a69a}input:not([type]):focus.valid ~ label,input[type=text]:not(.browser-default):focus.valid ~ label,input[type=password]:not(.browser-default):focus.valid ~ label,input[type=email]:not(.browser-default):focus.valid ~ label,input[type=url]:not(.browser-default):focus.valid ~ label,input[type=time]:not(.browser-default):focus.valid ~ label,input[type=date]:not(.browser-default):focus.valid ~ label,input[type=datetime]:not(.browser-default):focus.valid ~ label,input[type=datetime-local]:not(.browser-default):focus.valid ~ label,input[type=tel]:not(.browser-default):focus.valid ~ label,input[type=number]:not(.browser-default):focus.valid ~ label,input[type=search]:not(.browser-default):focus.valid ~ label,textarea.materialize-textarea:focus.valid ~ label{color:#4CAF50}input:not([type]):focus.invalid ~ label,input[type=text]:not(.browser-default):focus.invalid ~ label,input[type=password]:not(.browser-default):focus.invalid ~ label,input[type=email]:not(.browser-default):focus.invalid ~ label,input[type=url]:not(.browser-default):focus.invalid ~ label,input[type=time]:not(.browser-default):focus.invalid ~ label,input[type=date]:not(.browser-default):focus.invalid ~ label,input[type=datetime]:not(.browser-default):focus.invalid ~ label,input[type=datetime-local]:not(.browser-default):focus.invalid ~ label,input[type=tel]:not(.browser-default):focus.invalid ~ label,input[type=number]:not(.browser-default):focus.invalid ~ label,input[type=search]:not(.browser-default):focus.invalid ~ label,textarea.materialize-textarea:focus.invalid ~ label{color:#F44336}input:not([type]).validate+label,input[type=text]:not(.browser-default).validate+label,input[type=password]:not(.browser-default).validate+label,input[type=email]:not(.browser-default).validate+label,input[type=url]:not(.browser-default).validate+label,input[type=time]:not(.browser-default).validate+label,input[type=date]:not(.browser-default).validate+label,input[type=datetime]:not(.browser-default).validate+label,input[type=datetime-local]:not(.browser-default).validate+label,input[type=tel]:not(.browser-default).validate+label,input[type=number]:not(.browser-default).validate+label,input[type=search]:not(.browser-default).validate+label,textarea.materialize-textarea.validate+label{width:100%}input.valid:not([type]),input.valid:not([type]):focus,input[type=text].valid:not(.browser-default),input[type=text].valid:not(.browser-default):focus,input[type=password].valid:not(.browser-default),input[type=password].valid:not(.browser-default):focus,input[type=email].valid:not(.browser-default),input[type=email].valid:not(.browser-default):focus,input[type=url].valid:not(.browser-default),input[type=url].valid:not(.browser-default):focus,input[type=time].valid:not(.browser-default),input[type=time].valid:not(.browser-default):focus,input[type=date].valid:not(.browser-default),input[type=date].valid:not(.browser-default):focus,input[type=datetime].valid:not(.browser-default),input[type=datetime].valid:not(.browser-default):focus,input[type=datetime-local].valid:not(.browser-default),input[type=datetime-local].valid:not(.browser-default):focus,input[type=tel].valid:not(.browser-default),input[type=tel].valid:not(.browser-default):focus,input[type=number].valid:not(.browser-default),input[type=number].valid:not(.browser-default):focus,input[type=search].valid:not(.browser-default),input[type=search].valid:not(.browser-default):focus,textarea.materialize-textarea.valid,textarea.materialize-textarea.valid:focus,.select-wrapper.valid>input.select-dropdown{border-bottom:1px solid #4CAF50;-webkit-box-shadow:0 1px 0 0 #4CAF50;box-shadow:0 1px 0 0 #4CAF50}input.invalid:not([type]),input.invalid:not([type]):focus,input[type=text].invalid:not(.browser-default),input[type=text].invalid:not(.browser-default):focus,input[type=password].invalid:not(.browser-default),input[type=password].invalid:not(.browser-default):focus,input[type=email].invalid:not(.browser-default),input[type=email].invalid:not(.browser-default):focus,input[type=url].invalid:not(.browser-default),input[type=url].invalid:not(.browser-default):focus,input[type=time].invalid:not(.browser-default),input[type=time].invalid:not(.browser-default):focus,input[type=date].invalid:not(.browser-default),input[type=date].invalid:not(.browser-default):focus,input[type=datetime].invalid:not(.browser-default),input[type=datetime].invalid:not(.browser-default):focus,input[type=datetime-local].invalid:not(.browser-default),input[type=datetime-local].invalid:not(.browser-default):focus,input[type=tel].invalid:not(.browser-default),input[type=tel].invalid:not(.browser-default):focus,input[type=number].invalid:not(.browser-default),input[type=number].invalid:not(.browser-default):focus,input[type=search].invalid:not(.browser-default),input[type=search].invalid:not(.browser-default):focus,textarea.materialize-textarea.invalid,textarea.materialize-textarea.invalid:focus,.select-wrapper.invalid>input.select-dropdown,.select-wrapper.invalid>input.select-dropdown:focus{border-bottom:1px solid #F44336;-webkit-box-shadow:0 1px 0 0 #F44336;box-shadow:0 1px 0 0 #F44336}input:not([type]).valid ~ .helper-text[data-success],input:not([type]):focus.valid ~ .helper-text[data-success],input:not([type]).invalid ~ .helper-text[data-error],input:not([type]):focus.invalid ~ .helper-text[data-error],input[type=text]:not(.browser-default).valid ~ .helper-text[data-success],input[type=text]:not(.browser-default):focus.valid ~ .helper-text[data-success],input[type=text]:not(.browser-default).invalid ~ .helper-text[data-error],input[type=text]:not(.browser-default):focus.invalid ~ .helper-text[data-error],input[type=password]:not(.browser-default).valid ~ .helper-text[data-success],input[type=password]:not(.browser-default):focus.valid ~ .helper-text[data-success],input[type=password]:not(.browser-default).invalid ~ .helper-text[data-error],input[type=password]:not(.browser-default):focus.invalid ~ .helper-text[data-error],input[type=email]:not(.browser-default).valid ~ .helper-text[data-success],input[type=email]:not(.browser-default):focus.valid ~ .helper-text[data-success],input[type=email]:not(.browser-default).invalid ~ .helper-text[data-error],input[type=email]:not(.browser-default):focus.invalid ~ .helper-text[data-error],input[type=url]:not(.browser-default).valid ~ .helper-text[data-success],input[type=url]:not(.browser-default):focus.valid ~ .helper-text[data-success],input[type=url]:not(.browser-default).invalid ~ .helper-text[data-error],input[type=url]:not(.browser-default):focus.invalid ~ .helper-text[data-error],input[type=time]:not(.browser-default).valid ~ .helper-text[data-success],input[type=time]:not(.browser-default):focus.valid ~ .helper-text[data-success],input[type=time]:not(.browser-default).invalid ~ .helper-text[data-error],input[type=time]:not(.browser-default):focus.invalid ~ .helper-text[data-error],input[type=date]:not(.browser-default).valid ~ .helper-text[data-success],input[type=date]:not(.browser-default):focus.valid ~ .helper-text[data-success],input[type=date]:not(.browser-default).invalid ~ .helper-text[data-error],input[type=date]:not(.browser-default):focus.invalid ~ .helper-text[data-error],input[type=datetime]:not(.browser-default).valid ~ .helper-text[data-success],input[type=datetime]:not(.browser-default):focus.valid ~ .helper-text[data-success],input[type=datetime]:not(.browser-default).invalid ~ .helper-text[data-error],input[type=datetime]:not(.browser-default):focus.invalid ~ .helper-text[data-error],input[type=datetime-local]:not(.browser-default).valid ~ .helper-text[data-success],input[type=datetime-local]:not(.browser-default):focus.valid ~ .helper-text[data-success],input[type=datetime-local]:not(.browser-default).invalid ~ .helper-text[data-error],input[type=datetime-local]:not(.browser-default):focus.invalid ~ .helper-text[data-error],input[type=tel]:not(.browser-default).valid ~ .helper-text[data-success],input[type=tel]:not(.browser-default):focus.valid ~ .helper-text[data-success],input[type=tel]:not(.browser-default).invalid ~ .helper-text[data-error],input[type=tel]:not(.browser-default):focus.invalid ~ .helper-text[data-error],input[type=number]:not(.browser-default).valid ~ .helper-text[data-success],input[type=number]:not(.browser-default):focus.valid ~ .helper-text[data-success],input[type=number]:not(.browser-default).invalid ~ .helper-text[data-error],input[type=number]:not(.browser-default):focus.invalid ~ .helper-text[data-error],input[type=search]:not(.browser-default).valid ~ .helper-text[data-success],input[type=search]:not(.browser-default):focus.valid ~ .helper-text[data-success],input[type=search]:not(.browser-default).invalid ~ .helper-text[data-error],input[type=search]:not(.browser-default):focus.invalid ~ .helper-text[data-error],textarea.materialize-textarea.valid ~ .helper-text[data-success],textarea.materialize-textarea:focus.valid ~ .helper-text[data-success],textarea.materialize-textarea.invalid ~ .helper-text[data-error],textarea.materialize-textarea:focus.invalid ~ .helper-text[data-error],.select-wrapper.valid .helper-text[data-success],.select-wrapper.invalid ~ .helper-text[data-error]{color:transparent;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;pointer-events:none}input:not([type]).valid ~ .helper-text:after,input:not([type]):focus.valid ~ .helper-text:after,input[type=text]:not(.browser-default).valid ~ .helper-text:after,input[type=text]:not(.browser-default):focus.valid ~ .helper-text:after,input[type=password]:not(.browser-default).valid ~ .helper-text:after,input[type=password]:not(.browser-default):focus.valid ~ .helper-text:after,input[type=email]:not(.browser-default).valid ~ .helper-text:after,input[type=email]:not(.browser-default):focus.valid ~ .helper-text:after,input[type=url]:not(.browser-default).valid ~ .helper-text:after,input[type=url]:not(.browser-default):focus.valid ~ .helper-text:after,input[type=time]:not(.browser-default).valid ~ .helper-text:after,input[type=time]:not(.browser-default):focus.valid ~ .helper-text:after,input[type=date]:not(.browser-default).valid ~ .helper-text:after,input[type=date]:not(.browser-default):focus.valid ~ .helper-text:after,input[type=datetime]:not(.browser-default).valid ~ .helper-text:after,input[type=datetime]:not(.browser-default):focus.valid ~ .helper-text:after,input[type=datetime-local]:not(.browser-default).valid ~ .helper-text:after,input[type=datetime-local]:not(.browser-default):focus.valid ~ .helper-text:after,input[type=tel]:not(.browser-default).valid ~ .helper-text:after,input[type=tel]:not(.browser-default):focus.valid ~ .helper-text:after,input[type=number]:not(.browser-default).valid ~ .helper-text:after,input[type=number]:not(.browser-default):focus.valid ~ .helper-text:after,input[type=search]:not(.browser-default).valid ~ .helper-text:after,input[type=search]:not(.browser-default):focus.valid ~ .helper-text:after,textarea.materialize-textarea.valid ~ .helper-text:after,textarea.materialize-textarea:focus.valid ~ .helper-text:after,.select-wrapper.valid ~ .helper-text:after{content:attr(data-success);color:#4CAF50}input:not([type]).invalid ~ .helper-text:after,input:not([type]):focus.invalid ~ .helper-text:after,input[type=text]:not(.browser-default).invalid ~ .helper-text:after,input[type=text]:not(.browser-default):focus.invalid ~ .helper-text:after,input[type=password]:not(.browser-default).invalid ~ .helper-text:after,input[type=password]:not(.browser-default):focus.invalid ~ .helper-text:after,input[type=email]:not(.browser-default).invalid ~ .helper-text:after,input[type=email]:not(.browser-default):focus.invalid ~ .helper-text:after,input[type=url]:not(.browser-default).invalid ~ .helper-text:after,input[type=url]:not(.browser-default):focus.invalid ~ .helper-text:after,input[type=time]:not(.browser-default).invalid ~ .helper-text:after,input[type=time]:not(.browser-default):focus.invalid ~ .helper-text:after,input[type=date]:not(.browser-default).invalid ~ .helper-text:after,input[type=date]:not(.browser-default):focus.invalid ~ .helper-text:after,input[type=datetime]:not(.browser-default).invalid ~ .helper-text:after,input[type=datetime]:not(.browser-default):focus.invalid ~ .helper-text:after,input[type=datetime-local]:not(.browser-default).invalid ~ .helper-text:after,input[type=datetime-local]:not(.browser-default):focus.invalid ~ .helper-text:after,input[type=tel]:not(.browser-default).invalid ~ .helper-text:after,input[type=tel]:not(.browser-default):focus.invalid ~ .helper-text:after,input[type=number]:not(.browser-default).invalid ~ .helper-text:after,input[type=number]:not(.browser-default):focus.invalid ~ .helper-text:after,input[type=search]:not(.browser-default).invalid ~ .helper-text:after,input[type=search]:not(.browser-default):focus.invalid ~ .helper-text:after,textarea.materialize-textarea.invalid ~ .helper-text:after,textarea.materialize-textarea:focus.invalid ~ .helper-text:after,.select-wrapper.invalid ~ .helper-text:after{content:attr(data-error);color:#F44336}input:not([type])+label:after,input[type=text]:not(.browser-default)+label:after,input[type=password]:not(.browser-default)+label:after,input[type=email]:not(.browser-default)+label:after,input[type=url]:not(.browser-default)+label:after,input[type=time]:not(.browser-default)+label:after,input[type=date]:not(.browser-default)+label:after,input[type=datetime]:not(.browser-default)+label:after,input[type=datetime-local]:not(.browser-default)+label:after,input[type=tel]:not(.browser-default)+label:after,input[type=number]:not(.browser-default)+label:after,input[type=search]:not(.browser-default)+label:after,textarea.materialize-textarea+label:after,.select-wrapper+label:after{display:block;content:"";position:absolute;top:100%;left:0;opacity:0;-webkit-transition:.2s opacity ease-out, .2s color ease-out;transition:.2s opacity ease-out, .2s color ease-out}.input-field{position:relative;margin-top:1rem;margin-bottom:1rem}.input-field.inline{display:inline-block;vertical-align:middle;margin-left:5px}.input-field.inline input,.input-field.inline .select-dropdown{margin-bottom:1rem}.input-field.col label{left:.75rem}.input-field.col .prefix ~ label,.input-field.col .prefix ~ .validate ~ label{width:calc(100% - 3rem - 1.5rem)}.input-field>label{color:#9e9e9e;position:absolute;top:0;left:0;font-size:1rem;cursor:text;-webkit-transition:color .2s ease-out, -webkit-transform .2s ease-out;transition:color .2s ease-out, -webkit-transform .2s ease-out;transition:transform .2s ease-out, color .2s ease-out;transition:transform .2s ease-out, color .2s ease-out, -webkit-transform .2s ease-out;-webkit-transform-origin:0% 100%;transform-origin:0% 100%;text-align:initial;-webkit-transform:translateY(12px);transform:translateY(12px)}.input-field>label:not(.label-icon).active{-webkit-transform:translateY(-14px) scale(0.8);transform:translateY(-14px) scale(0.8);-webkit-transform-origin:0 0;transform-origin:0 0}.input-field>input[type=date]:not(.browser-default)+label,.input-field>input[type=time]:not(.browser-default)+label{-webkit-transform:translateY(-14px) scale(0.8);transform:translateY(-14px) scale(0.8);-webkit-transform-origin:0 0;transform-origin:0 0}.input-field .helper-text{position:relative;min-height:18px;display:block;font-size:12px;color:rgba(0,0,0,0.54)}.input-field .helper-text::after{opacity:1;position:absolute;top:0;left:0}.input-field .prefix{position:absolute;width:3rem;font-size:2rem;-webkit-transition:color .2s;transition:color .2s;top:.5rem}.input-field .prefix.active{color:#26a69a}.input-field .prefix ~ input,.input-field .prefix ~ textarea,.input-field .prefix ~ label,.input-field .prefix ~ .validate ~ label,.input-field .prefix ~ .helper-text,.input-field .prefix ~ .autocomplete-content{margin-left:3rem;width:92%;width:calc(100% - 3rem)}.input-field .prefix ~ label{margin-left:3rem}@media only screen and (max-width: 992px){.input-field .prefix ~ input{width:86%;width:calc(100% - 3rem)}}@media only screen and (max-width: 600px){.input-field .prefix ~ input{width:80%;width:calc(100% - 3rem)}}.input-field input[type=search]{display:block;line-height:inherit;-webkit-transition:.3s background-color;transition:.3s background-color}.nav-wrapper .input-field input[type=search]{height:inherit;padding-left:4rem;width:calc(100% - 4rem);border:0;-webkit-box-shadow:none;box-shadow:none}.input-field input[type=search]:focus:not(.browser-default){background-color:#fff;border:0;-webkit-box-shadow:none;box-shadow:none;color:#444}.input-field input[type=search]:focus:not(.browser-default)+label i,.input-field input[type=search]:focus:not(.browser-default) ~ .mdi-navigation-close,.input-field input[type=search]:focus:not(.browser-default) ~ .material-icons{color:#444}.input-field input[type=search]+.label-icon{-webkit-transform:none;transform:none;left:1rem}.input-field input[type=search] ~ .mdi-navigation-close,.input-field input[type=search] ~ .material-icons{position:absolute;top:0;right:1rem;color:transparent;cursor:pointer;font-size:2rem;-webkit-transition:.3s color;transition:.3s color}textarea{width:100%;height:3rem;background-color:transparent}textarea.materialize-textarea{line-height:normal;overflow-y:hidden;padding:.8rem 0 .8rem 0;resize:none;min-height:3rem;-webkit-box-sizing:border-box;box-sizing:border-box}.hiddendiv{visibility:hidden;white-space:pre-wrap;word-wrap:break-word;overflow-wrap:break-word;padding-top:1.2rem;position:absolute;top:0;z-index:-1}.autocomplete-content li .highlight{color:#444}.autocomplete-content li img{height:40px;width:40px;margin:5px 15px}.character-counter{min-height:18px}[type="radio"]:not(:checked),[type="radio"]:checked{position:absolute;opacity:0;pointer-events:none}[type="radio"]:not(:checked)+span,[type="radio"]:checked+span{position:relative;padding-left:35px;cursor:pointer;display:inline-block;height:25px;line-height:25px;font-size:1rem;-webkit-transition:.28s ease;transition:.28s ease;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}[type="radio"]+span:before,[type="radio"]+span:after{content:'';position:absolute;left:0;top:0;margin:4px;width:16px;height:16px;z-index:0;-webkit-transition:.28s ease;transition:.28s ease}[type="radio"]:not(:checked)+span:before,[type="radio"]:not(:checked)+span:after,[type="radio"]:checked+span:before,[type="radio"]:checked+span:after,[type="radio"].with-gap:checked+span:before,[type="radio"].with-gap:checked+span:after{border-radius:50%}[type="radio"]:not(:checked)+span:before,[type="radio"]:not(:checked)+span:after{border:2px solid #5a5a5a}[type="radio"]:not(:checked)+span:after{-webkit-transform:scale(0);transform:scale(0)}[type="radio"]:checked+span:before{border:2px solid transparent}[type="radio"]:checked+span:after,[type="radio"].with-gap:checked+span:before,[type="radio"].with-gap:checked+span:after{border:2px solid #26a69a}[type="radio"]:checked+span:after,[type="radio"].with-gap:checked+span:after{background-color:#26a69a}[type="radio"]:checked+span:after{-webkit-transform:scale(1.02);transform:scale(1.02)}[type="radio"].with-gap:checked+span:after{-webkit-transform:scale(0.5);transform:scale(0.5)}[type="radio"].tabbed:focus+span:before{-webkit-box-shadow:0 0 0 10px rgba(0,0,0,0.1);box-shadow:0 0 0 10px rgba(0,0,0,0.1)}[type="radio"].with-gap:disabled:checked+span:before{border:2px solid rgba(0,0,0,0.42)}[type="radio"].with-gap:disabled:checked+span:after{border:none;background-color:rgba(0,0,0,0.42)}[type="radio"]:disabled:not(:checked)+span:before,[type="radio"]:disabled:checked+span:before{background-color:transparent;border-color:rgba(0,0,0,0.42)}[type="radio"]:disabled+span{color:rgba(0,0,0,0.42)}[type="radio"]:disabled:not(:checked)+span:before{border-color:rgba(0,0,0,0.42)}[type="radio"]:disabled:checked+span:after{background-color:rgba(0,0,0,0.42);border-color:#949494}[type="checkbox"]:not(:checked),[type="checkbox"]:checked{position:absolute;opacity:0;pointer-events:none}[type="checkbox"]+span:not(.lever){position:relative;padding-left:35px;cursor:pointer;display:inline-block;height:25px;line-height:25px;font-size:1rem;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}[type="checkbox"]+span:not(.lever):before,[type="checkbox"]:not(.filled-in)+span:not(.lever):after{content:'';position:absolute;top:0;left:0;width:18px;height:18px;z-index:0;border:2px solid #5a5a5a;border-radius:1px;margin-top:3px;-webkit-transition:.2s;transition:.2s}[type="checkbox"]:not(.filled-in)+span:not(.lever):after{border:0;-webkit-transform:scale(0);transform:scale(0)}[type="checkbox"]:not(:checked):disabled+span:not(.lever):before{border:none;background-color:rgba(0,0,0,0.42)}[type="checkbox"].tabbed:focus+span:not(.lever):after{-webkit-transform:scale(1);transform:scale(1);border:0;border-radius:50%;-webkit-box-shadow:0 0 0 10px rgba(0,0,0,0.1);box-shadow:0 0 0 10px rgba(0,0,0,0.1);background-color:rgba(0,0,0,0.1)}[type="checkbox"]:checked+span:not(.lever):before{top:-4px;left:-5px;width:12px;height:22px;border-top:2px solid transparent;border-left:2px solid transparent;border-right:2px solid #26a69a;border-bottom:2px solid #26a69a;-webkit-transform:rotate(40deg);transform:rotate(40deg);-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-transform-origin:100% 100%;transform-origin:100% 100%}[type="checkbox"]:checked:disabled+span:before{border-right:2px solid rgba(0,0,0,0.42);border-bottom:2px solid rgba(0,0,0,0.42)}[type="checkbox"]:indeterminate+span:not(.lever):before{top:-11px;left:-12px;width:10px;height:22px;border-top:none;border-left:none;border-right:2px solid #26a69a;border-bottom:none;-webkit-transform:rotate(90deg);transform:rotate(90deg);-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-transform-origin:100% 100%;transform-origin:100% 100%}[type="checkbox"]:indeterminate:disabled+span:not(.lever):before{border-right:2px solid rgba(0,0,0,0.42);background-color:transparent}[type="checkbox"].filled-in+span:not(.lever):after{border-radius:2px}[type="checkbox"].filled-in+span:not(.lever):before,[type="checkbox"].filled-in+span:not(.lever):after{content:'';left:0;position:absolute;-webkit-transition:border .25s, background-color .25s, width .20s .1s, height .20s .1s, top .20s .1s, left .20s .1s;transition:border .25s, background-color .25s, width .20s .1s, height .20s .1s, top .20s .1s, left .20s .1s;z-index:1}[type="checkbox"].filled-in:not(:checked)+span:not(.lever):before{width:0;height:0;border:3px solid transparent;left:6px;top:10px;-webkit-transform:rotateZ(37deg);transform:rotateZ(37deg);-webkit-transform-origin:100% 100%;transform-origin:100% 100%}[type="checkbox"].filled-in:not(:checked)+span:not(.lever):after{height:20px;width:20px;background-color:transparent;border:2px solid #5a5a5a;top:0px;z-index:0}[type="checkbox"].filled-in:checked+span:not(.lever):before{top:0;left:1px;width:8px;height:13px;border-top:2px solid transparent;border-left:2px solid transparent;border-right:2px solid #fff;border-bottom:2px solid #fff;-webkit-transform:rotateZ(37deg);transform:rotateZ(37deg);-webkit-transform-origin:100% 100%;transform-origin:100% 100%}[type="checkbox"].filled-in:checked+span:not(.lever):after{top:0;width:20px;height:20px;border:2px solid #26a69a;background-color:#26a69a;z-index:0}[type="checkbox"].filled-in.tabbed:focus+span:not(.lever):after{border-radius:2px;border-color:#5a5a5a;background-color:rgba(0,0,0,0.1)}[type="checkbox"].filled-in.tabbed:checked:focus+span:not(.lever):after{border-radius:2px;background-color:#26a69a;border-color:#26a69a}[type="checkbox"].filled-in:disabled:not(:checked)+span:not(.lever):before{background-color:transparent;border:2px solid transparent}[type="checkbox"].filled-in:disabled:not(:checked)+span:not(.lever):after{border-color:transparent;background-color:#949494}[type="checkbox"].filled-in:disabled:checked+span:not(.lever):before{background-color:transparent}[type="checkbox"].filled-in:disabled:checked+span:not(.lever):after{background-color:#949494;border-color:#949494}.switch,.switch *{-webkit-tap-highlight-color:transparent;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.switch label{cursor:pointer}.switch label input[type=checkbox]{opacity:0;width:0;height:0}.switch label input[type=checkbox]:checked+.lever{background-color:#84c7c1}.switch label input[type=checkbox]:checked+.lever:before,.switch label input[type=checkbox]:checked+.lever:after{left:18px}.switch label input[type=checkbox]:checked+.lever:after{background-color:#26a69a}.switch label .lever{content:"";display:inline-block;position:relative;width:36px;height:14px;background-color:rgba(0,0,0,0.38);border-radius:15px;margin-right:10px;-webkit-transition:background 0.3s ease;transition:background 0.3s ease;vertical-align:middle;margin:0 16px}.switch label .lever:before,.switch label .lever:after{content:"";position:absolute;display:inline-block;width:20px;height:20px;border-radius:50%;left:0;top:-3px;-webkit-transition:left 0.3s ease, background .3s ease, -webkit-box-shadow 0.1s ease, -webkit-transform .1s ease;transition:left 0.3s ease, background .3s ease, -webkit-box-shadow 0.1s ease, -webkit-transform .1s ease;transition:left 0.3s ease, background .3s ease, box-shadow 0.1s ease, transform .1s ease;transition:left 0.3s ease, background .3s ease, box-shadow 0.1s ease, transform .1s ease, -webkit-box-shadow 0.1s ease, -webkit-transform .1s ease}.switch label .lever:before{background-color:rgba(38,166,154,0.15)}.switch label .lever:after{background-color:#F1F1F1;-webkit-box-shadow:0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12);box-shadow:0px 3px 1px -2px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 1px 5px 0px rgba(0,0,0,0.12)}input[type=checkbox]:checked:not(:disabled) ~ .lever:active::before,input[type=checkbox]:checked:not(:disabled).tabbed:focus ~ .lever::before{-webkit-transform:scale(2.4);transform:scale(2.4);background-color:rgba(38,166,154,0.15)}input[type=checkbox]:not(:disabled) ~ .lever:active:before,input[type=checkbox]:not(:disabled).tabbed:focus ~ .lever::before{-webkit-transform:scale(2.4);transform:scale(2.4);background-color:rgba(0,0,0,0.08)}.switch input[type=checkbox][disabled]+.lever{cursor:default;background-color:rgba(0,0,0,0.12)}.switch label input[type=checkbox][disabled]+.lever:after,.switch label input[type=checkbox][disabled]:checked+.lever:after{background-color:#949494}select{display:none}select.browser-default{display:block}select{background-color:rgba(255,255,255,0.9);width:100%;padding:5px;border:1px solid #f2f2f2;border-radius:2px;height:3rem}.select-label{position:absolute}.select-wrapper{position:relative}.select-wrapper.valid+label,.select-wrapper.invalid+label{width:100%;pointer-events:none}.select-wrapper input.select-dropdown{position:relative;cursor:pointer;background-color:transparent;border:none;border-bottom:1px solid #9e9e9e;outline:none;height:3rem;line-height:3rem;width:100%;font-size:16px;margin:0 0 8px 0;padding:0;display:block;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:1}.select-wrapper input.select-dropdown:focus{border-bottom:1px solid #26a69a}.select-wrapper .caret{position:absolute;right:0;top:0;bottom:0;margin:auto 0;z-index:0;fill:rgba(0,0,0,0.87)}.select-wrapper+label{position:absolute;top:-26px;font-size:.8rem}select:disabled{color:rgba(0,0,0,0.42)}.select-wrapper.disabled+label{color:rgba(0,0,0,0.42)}.select-wrapper.disabled .caret{fill:rgba(0,0,0,0.42)}.select-wrapper input.select-dropdown:disabled{color:rgba(0,0,0,0.42);cursor:default;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.select-wrapper i{color:rgba(0,0,0,0.3)}.select-dropdown li.disabled,.select-dropdown li.disabled>span,.select-dropdown li.optgroup{color:rgba(0,0,0,0.3);background-color:transparent}.select-dropdown.dropdown-content li:hover{background-color:rgba(0,0,0,0.08)}.select-dropdown.dropdown-content li.selected{background-color:rgba(0,0,0,0.03)}.select-dropdown.dropdown-content li:focus{background-color:rgba(0,0,0,0.08)}.prefix ~ .select-wrapper{margin-left:3rem;width:92%;width:calc(100% - 3rem)}.prefix ~ label{margin-left:3rem}.select-dropdown li img{height:40px;width:40px;margin:5px 15px;float:right}.select-dropdown li.optgroup{border-top:1px solid #eee}.select-dropdown li.optgroup.selected>span{color:rgba(0,0,0,0.7)}.select-dropdown li.optgroup>span{color:rgba(0,0,0,0.4)}.select-dropdown li.optgroup ~ li.optgroup-option{padding-left:1rem}.file-field{position:relative}.file-field .file-path-wrapper{overflow:hidden;padding-left:10px}.file-field input.file-path{width:100%}.file-field .btn,.file-field .btn-large,.file-field .btn-small{float:left;height:3rem;line-height:3rem}.file-field span{cursor:pointer}.file-field input[type=file]{position:absolute;top:0;right:0;left:0;bottom:0;width:100%;margin:0;padding:0;font-size:20px;cursor:pointer;opacity:0;filter:alpha(opacity=0)}.file-field input[type=file]::-webkit-file-upload-button{display:none}.range-field{position:relative}input[type=range],input[type=range]+.thumb{cursor:pointer}input[type=range]{position:relative;background-color:transparent;border:none;outline:none;width:100%;margin:15px 0;padding:0}input[type=range]:focus{outline:none}input[type=range]+.thumb{position:absolute;top:10px;left:0;border:none;height:0;width:0;border-radius:50%;background-color:#26a69a;margin-left:7px;-webkit-transform-origin:50% 50%;transform-origin:50% 50%;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}input[type=range]+.thumb .value{display:block;width:30px;text-align:center;color:#26a69a;font-size:0;-webkit-transform:rotate(45deg);transform:rotate(45deg)}input[type=range]+.thumb.active{border-radius:50% 50% 50% 0}input[type=range]+.thumb.active .value{color:#fff;margin-left:-1px;margin-top:8px;font-size:10px}input[type=range]{-webkit-appearance:none}input[type=range]::-webkit-slider-runnable-track{height:3px;background:#c2c0c2;border:none}input[type=range]::-webkit-slider-thumb{border:none;height:14px;width:14px;border-radius:50%;background:#26a69a;-webkit-transition:-webkit-box-shadow .3s;transition:-webkit-box-shadow .3s;transition:box-shadow .3s;transition:box-shadow .3s, -webkit-box-shadow .3s;-webkit-appearance:none;background-color:#26a69a;-webkit-transform-origin:50% 50%;transform-origin:50% 50%;margin:-5px 0 0 0}input[type=range].focused:focus:not(.active)::-webkit-slider-thumb{-webkit-box-shadow:0 0 0 10px rgba(38,166,154,0.26);box-shadow:0 0 0 10px rgba(38,166,154,0.26)}input[type=range]{border:1px solid white}input[type=range]::-moz-range-track{height:3px;background:#c2c0c2;border:none}input[type=range]::-moz-focus-inner{border:0}input[type=range]::-moz-range-thumb{border:none;height:14px;width:14px;border-radius:50%;background:#26a69a;-webkit-transition:-webkit-box-shadow .3s;transition:-webkit-box-shadow .3s;transition:box-shadow .3s;transition:box-shadow .3s, -webkit-box-shadow .3s;margin-top:-5px}input[type=range]:-moz-focusring{outline:1px solid #fff;outline-offset:-1px}input[type=range].focused:focus:not(.active)::-moz-range-thumb{box-shadow:0 0 0 10px rgba(38,166,154,0.26)}input[type=range]::-ms-track{height:3px;background:transparent;border-color:transparent;border-width:6px 0;color:transparent}input[type=range]::-ms-fill-lower{background:#777}input[type=range]::-ms-fill-upper{background:#ddd}input[type=range]::-ms-thumb{border:none;height:14px;width:14px;border-radius:50%;background:#26a69a;-webkit-transition:-webkit-box-shadow .3s;transition:-webkit-box-shadow .3s;transition:box-shadow .3s;transition:box-shadow .3s, -webkit-box-shadow .3s}input[type=range].focused:focus:not(.active)::-ms-thumb{box-shadow:0 0 0 10px rgba(38,166,154,0.26)}.table-of-contents.fixed{position:fixed}.table-of-contents li{padding:2px 0}.table-of-contents a{display:inline-block;font-weight:300;color:#757575;padding-left:16px;height:1.5rem;line-height:1.5rem;letter-spacing:.4;display:inline-block}.table-of-contents a:hover{color:#a8a8a8;padding-left:15px;border-left:1px solid #ee6e73}.table-of-contents a.active{font-weight:500;padding-left:14px;border-left:2px solid #ee6e73}.sidenav{position:fixed;width:300px;left:0;top:0;margin:0;-webkit-transform:translateX(-100%);transform:translateX(-100%);height:100%;height:calc(100% + 60px);height:-moz-calc(100%);padding-bottom:60px;background-color:#fff;z-index:999;overflow-y:auto;will-change:transform;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-transform:translateX(-105%);transform:translateX(-105%)}.sidenav.right-aligned{right:0;-webkit-transform:translateX(105%);transform:translateX(105%);left:auto;-webkit-transform:translateX(100%);transform:translateX(100%)}.sidenav .collapsible{margin:0}.sidenav li{float:none;line-height:48px}.sidenav li.active{background-color:rgba(0,0,0,0.05)}.sidenav li>a{color:rgba(0,0,0,0.87);display:block;font-size:14px;font-weight:500;height:48px;line-height:48px;padding:0 32px}.sidenav li>a:hover{background-color:rgba(0,0,0,0.05)}.sidenav li>a.btn,.sidenav li>a.btn-large,.sidenav li>a.btn-small,.sidenav li>a.btn-large,.sidenav li>a.btn-flat,.sidenav li>a.btn-floating{margin:10px 15px}.sidenav li>a.btn,.sidenav li>a.btn-large,.sidenav li>a.btn-small,.sidenav li>a.btn-large,.sidenav li>a.btn-floating{color:#fff}.sidenav li>a.btn-flat{color:#343434}.sidenav li>a.btn:hover,.sidenav li>a.btn-large:hover,.sidenav li>a.btn-small:hover,.sidenav li>a.btn-large:hover{background-color:#2bbbad}.sidenav li>a.btn-floating:hover{background-color:#26a69a}.sidenav li>a>i,.sidenav li>a>[class^="mdi-"],.sidenav li>a li>a>[class*="mdi-"],.sidenav li>a>i.material-icons{float:left;height:48px;line-height:48px;margin:0 32px 0 0;width:24px;color:rgba(0,0,0,0.54)}.sidenav .divider{margin:8px 0 0 0}.sidenav .subheader{cursor:initial;pointer-events:none;color:rgba(0,0,0,0.54);font-size:14px;font-weight:500;line-height:48px}.sidenav .subheader:hover{background-color:transparent}.sidenav .user-view{position:relative;padding:32px 32px 0;margin-bottom:8px}.sidenav .user-view>a{height:auto;padding:0}.sidenav .user-view>a:hover{background-color:transparent}.sidenav .user-view .background{overflow:hidden;position:absolute;top:0;right:0;bottom:0;left:0;z-index:-1}.sidenav .user-view .circle,.sidenav .user-view .name,.sidenav .user-view .email{display:block}.sidenav .user-view .circle{height:64px;width:64px}.sidenav .user-view .name,.sidenav .user-view .email{font-size:14px;line-height:24px}.sidenav .user-view .name{margin-top:16px;font-weight:500}.sidenav .user-view .email{padding-bottom:16px;font-weight:400}.drag-target{height:100%;width:10px;position:fixed;top:0;z-index:998}.drag-target.right-aligned{right:0}.sidenav.sidenav-fixed{left:0;-webkit-transform:translateX(0);transform:translateX(0);position:fixed}.sidenav.sidenav-fixed.right-aligned{right:0;left:auto}@media only screen and (max-width: 992px){.sidenav.sidenav-fixed{-webkit-transform:translateX(-105%);transform:translateX(-105%)}.sidenav.sidenav-fixed.right-aligned{-webkit-transform:translateX(105%);transform:translateX(105%)}.sidenav>a{padding:0 16px}.sidenav .user-view{padding:16px 16px 0}}.sidenav .collapsible-body>ul:not(.collapsible)>li.active,.sidenav.sidenav-fixed .collapsible-body>ul:not(.collapsible)>li.active{background-color:#ee6e73}.sidenav .collapsible-body>ul:not(.collapsible)>li.active a,.sidenav.sidenav-fixed .collapsible-body>ul:not(.collapsible)>li.active a{color:#fff}.sidenav .collapsible-body{padding:0}.sidenav-overlay{position:fixed;top:0;left:0;right:0;opacity:0;height:120vh;background-color:rgba(0,0,0,0.5);z-index:997;display:none}.preloader-wrapper{display:inline-block;position:relative;width:50px;height:50px}.preloader-wrapper.small{width:36px;height:36px}.preloader-wrapper.big{width:64px;height:64px}.preloader-wrapper.active{-webkit-animation:container-rotate 1568ms linear infinite;animation:container-rotate 1568ms linear infinite}@-webkit-keyframes container-rotate{to{-webkit-transform:rotate(360deg)}}@keyframes container-rotate{to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.spinner-layer{position:absolute;width:100%;height:100%;opacity:0;border-color:#26a69a}.spinner-blue,.spinner-blue-only{border-color:#4285f4}.spinner-red,.spinner-red-only{border-color:#db4437}.spinner-yellow,.spinner-yellow-only{border-color:#f4b400}.spinner-green,.spinner-green-only{border-color:#0f9d58}.active .spinner-layer.spinner-blue{-webkit-animation:fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,blue-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,blue-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}.active .spinner-layer.spinner-red{-webkit-animation:fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,red-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,red-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}.active .spinner-layer.spinner-yellow{-webkit-animation:fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,yellow-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,yellow-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}.active .spinner-layer.spinner-green{-webkit-animation:fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,green-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both,green-fade-in-out 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}.active .spinner-layer,.active .spinner-layer.spinner-blue-only,.active .spinner-layer.spinner-red-only,.active .spinner-layer.spinner-yellow-only,.active .spinner-layer.spinner-green-only{opacity:1;-webkit-animation:fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:fill-unfill-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}@-webkit-keyframes fill-unfill-rotate{12.5%{-webkit-transform:rotate(135deg)}25%{-webkit-transform:rotate(270deg)}37.5%{-webkit-transform:rotate(405deg)}50%{-webkit-transform:rotate(540deg)}62.5%{-webkit-transform:rotate(675deg)}75%{-webkit-transform:rotate(810deg)}87.5%{-webkit-transform:rotate(945deg)}to{-webkit-transform:rotate(1080deg)}}@keyframes fill-unfill-rotate{12.5%{-webkit-transform:rotate(135deg);transform:rotate(135deg)}25%{-webkit-transform:rotate(270deg);transform:rotate(270deg)}37.5%{-webkit-transform:rotate(405deg);transform:rotate(405deg)}50%{-webkit-transform:rotate(540deg);transform:rotate(540deg)}62.5%{-webkit-transform:rotate(675deg);transform:rotate(675deg)}75%{-webkit-transform:rotate(810deg);transform:rotate(810deg)}87.5%{-webkit-transform:rotate(945deg);transform:rotate(945deg)}to{-webkit-transform:rotate(1080deg);transform:rotate(1080deg)}}@-webkit-keyframes blue-fade-in-out{from{opacity:1}25%{opacity:1}26%{opacity:0}89%{opacity:0}90%{opacity:1}100%{opacity:1}}@keyframes blue-fade-in-out{from{opacity:1}25%{opacity:1}26%{opacity:0}89%{opacity:0}90%{opacity:1}100%{opacity:1}}@-webkit-keyframes red-fade-in-out{from{opacity:0}15%{opacity:0}25%{opacity:1}50%{opacity:1}51%{opacity:0}}@keyframes red-fade-in-out{from{opacity:0}15%{opacity:0}25%{opacity:1}50%{opacity:1}51%{opacity:0}}@-webkit-keyframes yellow-fade-in-out{from{opacity:0}40%{opacity:0}50%{opacity:1}75%{opacity:1}76%{opacity:0}}@keyframes yellow-fade-in-out{from{opacity:0}40%{opacity:0}50%{opacity:1}75%{opacity:1}76%{opacity:0}}@-webkit-keyframes green-fade-in-out{from{opacity:0}65%{opacity:0}75%{opacity:1}90%{opacity:1}100%{opacity:0}}@keyframes green-fade-in-out{from{opacity:0}65%{opacity:0}75%{opacity:1}90%{opacity:1}100%{opacity:0}}.gap-patch{position:absolute;top:0;left:45%;width:10%;height:100%;overflow:hidden;border-color:inherit}.gap-patch .circle{width:1000%;left:-450%}.circle-clipper{display:inline-block;position:relative;width:50%;height:100%;overflow:hidden;border-color:inherit}.circle-clipper .circle{width:200%;height:100%;border-width:3px;border-style:solid;border-color:inherit;border-bottom-color:transparent !important;border-radius:50%;-webkit-animation:none;animation:none;position:absolute;top:0;right:0;bottom:0}.circle-clipper.left .circle{left:0;border-right-color:transparent !important;-webkit-transform:rotate(129deg);transform:rotate(129deg)}.circle-clipper.right .circle{left:-100%;border-left-color:transparent !important;-webkit-transform:rotate(-129deg);transform:rotate(-129deg)}.active .circle-clipper.left .circle{-webkit-animation:left-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:left-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}.active .circle-clipper.right .circle{-webkit-animation:right-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;animation:right-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both}@-webkit-keyframes left-spin{from{-webkit-transform:rotate(130deg)}50%{-webkit-transform:rotate(-5deg)}to{-webkit-transform:rotate(130deg)}}@keyframes left-spin{from{-webkit-transform:rotate(130deg);transform:rotate(130deg)}50%{-webkit-transform:rotate(-5deg);transform:rotate(-5deg)}to{-webkit-transform:rotate(130deg);transform:rotate(130deg)}}@-webkit-keyframes right-spin{from{-webkit-transform:rotate(-130deg)}50%{-webkit-transform:rotate(5deg)}to{-webkit-transform:rotate(-130deg)}}@keyframes right-spin{from{-webkit-transform:rotate(-130deg);transform:rotate(-130deg)}50%{-webkit-transform:rotate(5deg);transform:rotate(5deg)}to{-webkit-transform:rotate(-130deg);transform:rotate(-130deg)}}#spinnerContainer.cooldown{-webkit-animation:container-rotate 1568ms linear infinite,fade-out 400ms cubic-bezier(0.4, 0, 0.2, 1);animation:container-rotate 1568ms linear infinite,fade-out 400ms cubic-bezier(0.4, 0, 0.2, 1)}@-webkit-keyframes fade-out{from{opacity:1}to{opacity:0}}@keyframes fade-out{from{opacity:1}to{opacity:0}}.slider{position:relative;height:400px;width:100%}.slider.fullscreen{height:100%;width:100%;position:absolute;top:0;left:0;right:0;bottom:0}.slider.fullscreen ul.slides{height:100%}.slider.fullscreen ul.indicators{z-index:2;bottom:30px}.slider .slides{background-color:#9e9e9e;margin:0;height:400px}.slider .slides li{opacity:0;position:absolute;top:0;left:0;z-index:1;width:100%;height:inherit;overflow:hidden}.slider .slides li img{height:100%;width:100%;background-size:cover;background-position:center}.slider .slides li .caption{color:#fff;position:absolute;top:15%;left:15%;width:70%;opacity:0}.slider .slides li .caption p{color:#e0e0e0}.slider .slides li.active{z-index:2}.slider .indicators{position:absolute;text-align:center;left:0;right:0;bottom:0;margin:0}.slider .indicators .indicator-item{display:inline-block;position:relative;cursor:pointer;height:16px;width:16px;margin:0 12px;background-color:#e0e0e0;-webkit-transition:background-color .3s;transition:background-color .3s;border-radius:50%}.slider .indicators .indicator-item.active{background-color:#4CAF50}.carousel{overflow:hidden;position:relative;width:100%;height:400px;-webkit-perspective:500px;perspective:500px;-webkit-transform-style:preserve-3d;transform-style:preserve-3d;-webkit-transform-origin:0% 50%;transform-origin:0% 50%}.carousel.carousel-slider{top:0;left:0}.carousel.carousel-slider .carousel-fixed-item{position:absolute;left:0;right:0;bottom:20px;z-index:1}.carousel.carousel-slider .carousel-fixed-item.with-indicators{bottom:68px}.carousel.carousel-slider .carousel-item{width:100%;height:100%;min-height:400px;position:absolute;top:0;left:0}.carousel.carousel-slider .carousel-item h2{font-size:24px;font-weight:500;line-height:32px}.carousel.carousel-slider .carousel-item p{font-size:15px}.carousel .carousel-item{visibility:hidden;width:200px;height:200px;position:absolute;top:0;left:0}.carousel .carousel-item>img{width:100%}.carousel .indicators{position:absolute;text-align:center;left:0;right:0;bottom:0;margin:0}.carousel .indicators .indicator-item{display:inline-block;position:relative;cursor:pointer;height:8px;width:8px;margin:24px 4px;background-color:rgba(255,255,255,0.5);-webkit-transition:background-color .3s;transition:background-color .3s;border-radius:50%}.carousel .indicators .indicator-item.active{background-color:#fff}.carousel.scrolling .carousel-item .materialboxed,.carousel .carousel-item:not(.active) .materialboxed{pointer-events:none}.tap-target-wrapper{width:800px;height:800px;position:fixed;z-index:1000;visibility:hidden;-webkit-transition:visibility 0s .3s;transition:visibility 0s .3s}.tap-target-wrapper.open{visibility:visible;-webkit-transition:visibility 0s;transition:visibility 0s}.tap-target-wrapper.open .tap-target{-webkit-transform:scale(1);transform:scale(1);opacity:.95;-webkit-transition:opacity 0.3s cubic-bezier(0.42, 0, 0.58, 1),-webkit-transform 0.3s cubic-bezier(0.42, 0, 0.58, 1);transition:opacity 0.3s cubic-bezier(0.42, 0, 0.58, 1),-webkit-transform 0.3s cubic-bezier(0.42, 0, 0.58, 1);transition:transform 0.3s cubic-bezier(0.42, 0, 0.58, 1),opacity 0.3s cubic-bezier(0.42, 0, 0.58, 1);transition:transform 0.3s cubic-bezier(0.42, 0, 0.58, 1),opacity 0.3s cubic-bezier(0.42, 0, 0.58, 1),-webkit-transform 0.3s cubic-bezier(0.42, 0, 0.58, 1)}.tap-target-wrapper.open .tap-target-wave::before{-webkit-transform:scale(1);transform:scale(1)}.tap-target-wrapper.open .tap-target-wave::after{visibility:visible;-webkit-animation:pulse-animation 1s cubic-bezier(0.24, 0, 0.38, 1) infinite;animation:pulse-animation 1s cubic-bezier(0.24, 0, 0.38, 1) infinite;-webkit-transition:opacity .3s, visibility 0s 1s, -webkit-transform .3s;transition:opacity .3s, visibility 0s 1s, -webkit-transform .3s;transition:opacity .3s, transform .3s, visibility 0s 1s;transition:opacity .3s, transform .3s, visibility 0s 1s, -webkit-transform .3s}.tap-target{position:absolute;font-size:1rem;border-radius:50%;background-color:#ee6e73;-webkit-box-shadow:0 20px 20px 0 rgba(0,0,0,0.14),0 10px 50px 0 rgba(0,0,0,0.12),0 30px 10px -20px rgba(0,0,0,0.2);box-shadow:0 20px 20px 0 rgba(0,0,0,0.14),0 10px 50px 0 rgba(0,0,0,0.12),0 30px 10px -20px rgba(0,0,0,0.2);width:100%;height:100%;opacity:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transition:opacity 0.3s cubic-bezier(0.42, 0, 0.58, 1),-webkit-transform 0.3s cubic-bezier(0.42, 0, 0.58, 1);transition:opacity 0.3s cubic-bezier(0.42, 0, 0.58, 1),-webkit-transform 0.3s cubic-bezier(0.42, 0, 0.58, 1);transition:transform 0.3s cubic-bezier(0.42, 0, 0.58, 1),opacity 0.3s cubic-bezier(0.42, 0, 0.58, 1);transition:transform 0.3s cubic-bezier(0.42, 0, 0.58, 1),opacity 0.3s cubic-bezier(0.42, 0, 0.58, 1),-webkit-transform 0.3s cubic-bezier(0.42, 0, 0.58, 1)}.tap-target-content{position:relative;display:table-cell}.tap-target-wave{position:absolute;border-radius:50%;z-index:10001}.tap-target-wave::before,.tap-target-wave::after{content:'';display:block;position:absolute;width:100%;height:100%;border-radius:50%;background-color:#ffffff}.tap-target-wave::before{-webkit-transform:scale(0);transform:scale(0);-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s, -webkit-transform .3s}.tap-target-wave::after{visibility:hidden;-webkit-transition:opacity .3s, visibility 0s, -webkit-transform .3s;transition:opacity .3s, visibility 0s, -webkit-transform .3s;transition:opacity .3s, transform .3s, visibility 0s;transition:opacity .3s, transform .3s, visibility 0s, -webkit-transform .3s;z-index:-1}.tap-target-origin{top:50%;left:50%;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%);z-index:10002;position:absolute !important}.tap-target-origin:not(.btn):not(.btn-large):not(.btn-small),.tap-target-origin:not(.btn):not(.btn-large):not(.btn-small):hover{background:none}@media only screen and (max-width: 600px){.tap-target,.tap-target-wrapper{width:600px;height:600px}}.pulse{overflow:visible;position:relative}.pulse::before{content:'';display:block;position:absolute;width:100%;height:100%;top:0;left:0;background-color:inherit;border-radius:inherit;-webkit-transition:opacity .3s, -webkit-transform .3s;transition:opacity .3s, -webkit-transform .3s;transition:opacity .3s, transform .3s;transition:opacity .3s, transform .3s, -webkit-transform .3s;-webkit-animation:pulse-animation 1s cubic-bezier(0.24, 0, 0.38, 1) infinite;animation:pulse-animation 1s cubic-bezier(0.24, 0, 0.38, 1) infinite;z-index:-1}@-webkit-keyframes pulse-animation{0%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}50%{opacity:0;-webkit-transform:scale(1.5);transform:scale(1.5)}100%{opacity:0;-webkit-transform:scale(1.5);transform:scale(1.5)}}@keyframes pulse-animation{0%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}50%{opacity:0;-webkit-transform:scale(1.5);transform:scale(1.5)}100%{opacity:0;-webkit-transform:scale(1.5);transform:scale(1.5)}}.datepicker-modal{max-width:325px;min-width:300px;max-height:none}.datepicker-container.modal-content{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:0}.datepicker-controls{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;width:280px;margin:0 auto}.datepicker-controls .selects-container{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.datepicker-controls .select-wrapper input{border-bottom:none;text-align:center;margin:0}.datepicker-controls .select-wrapper input:focus{border-bottom:none}.datepicker-controls .select-wrapper .caret{display:none}.datepicker-controls .select-year input{width:50px}.datepicker-controls .select-month input{width:70px}.month-prev,.month-next{margin-top:4px;cursor:pointer;background-color:transparent;border:none}.datepicker-date-display{-webkit-box-flex:1;-webkit-flex:1 auto;-ms-flex:1 auto;flex:1 auto;background-color:#26a69a;color:#fff;padding:20px 22px;font-weight:500}.datepicker-date-display .year-text{display:block;font-size:1.5rem;line-height:25px;color:rgba(255,255,255,0.7)}.datepicker-date-display .date-text{display:block;font-size:2.8rem;line-height:47px;font-weight:500}.datepicker-calendar-container{-webkit-box-flex:2.5;-webkit-flex:2.5 auto;-ms-flex:2.5 auto;flex:2.5 auto}.datepicker-table{width:280px;font-size:1rem;margin:0 auto}.datepicker-table thead{border-bottom:none}.datepicker-table th{padding:10px 5px;text-align:center}.datepicker-table tr{border:none}.datepicker-table abbr{text-decoration:none;color:#999}.datepicker-table td{border-radius:50%;padding:0}.datepicker-table td.is-today{color:#26a69a}.datepicker-table td.is-selected{background-color:#26a69a;color:#fff}.datepicker-table td.is-outside-current-month,.datepicker-table td.is-disabled{color:rgba(0,0,0,0.3);pointer-events:none}.datepicker-day-button{background-color:transparent;border:none;line-height:38px;display:block;width:100%;border-radius:50%;padding:0 5px;cursor:pointer;color:inherit}.datepicker-day-button:focus{background-color:rgba(43,161,150,0.25)}.datepicker-footer{width:280px;margin:0 auto;padding-bottom:5px;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between}.datepicker-cancel,.datepicker-clear,.datepicker-today,.datepicker-done{color:#26a69a;padding:0 1rem}.datepicker-clear{color:#F44336}@media only screen and (min-width: 601px){.datepicker-modal{max-width:625px}.datepicker-container.modal-content{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row}.datepicker-controls,.datepicker-table,.datepicker-footer{width:320px}.datepicker-day-button{line-height:44px}}.timepicker-modal{max-width:325px;max-height:none}.timepicker-container.modal-content{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:0}.text-primary{color:#fff}.timepicker-digital-display{-webkit-box-flex:1;-webkit-flex:1 auto;-ms-flex:1 auto;flex:1 auto;background-color:#26a69a;padding:10px;font-weight:300}.timepicker-text-container{font-size:4rem;font-weight:bold;text-align:center;color:rgba(255,255,255,0.6);font-weight:400;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.timepicker-span-hours,.timepicker-span-minutes,.timepicker-span-am-pm div{cursor:pointer}.timepicker-span-hours{margin-right:3px}.timepicker-span-minutes{margin-left:3px}.timepicker-display-am-pm{font-size:1.3rem;position:absolute;right:1rem;bottom:1rem;font-weight:400}.timepicker-analog-display{-webkit-box-flex:2.5;-webkit-flex:2.5 auto;-ms-flex:2.5 auto;flex:2.5 auto}.timepicker-plate{background-color:#eee;border-radius:50%;width:270px;height:270px;overflow:visible;position:relative;margin:auto;margin-top:25px;margin-bottom:5px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.timepicker-canvas,.timepicker-dial{position:absolute;left:0;right:0;top:0;bottom:0}.timepicker-minutes{visibility:hidden}.timepicker-tick{border-radius:50%;color:rgba(0,0,0,0.87);line-height:40px;text-align:center;width:40px;height:40px;position:absolute;cursor:pointer;font-size:15px}.timepicker-tick.active,.timepicker-tick:hover{background-color:rgba(38,166,154,0.25)}.timepicker-dial{-webkit-transition:opacity 350ms, -webkit-transform 350ms;transition:opacity 350ms, -webkit-transform 350ms;transition:transform 350ms, opacity 350ms;transition:transform 350ms, opacity 350ms, -webkit-transform 350ms}.timepicker-dial-out{opacity:0}.timepicker-dial-out.timepicker-hours{-webkit-transform:scale(1.1, 1.1);transform:scale(1.1, 1.1)}.timepicker-dial-out.timepicker-minutes{-webkit-transform:scale(0.8, 0.8);transform:scale(0.8, 0.8)}.timepicker-canvas{-webkit-transition:opacity 175ms;transition:opacity 175ms}.timepicker-canvas line{stroke:#26a69a;stroke-width:4;stroke-linecap:round}.timepicker-canvas-out{opacity:0.25}.timepicker-canvas-bearing{stroke:none;fill:#26a69a}.timepicker-canvas-bg{stroke:none;fill:#26a69a}.timepicker-footer{margin:0 auto;padding:5px 1rem;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between}.timepicker-clear{color:#F44336}.timepicker-close{color:#26a69a}.timepicker-clear,.timepicker-close{padding:0 20px}@media only screen and (min-width: 601px){.timepicker-modal{max-width:600px}.timepicker-container.modal-content{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row}.timepicker-text-container{top:32%}.timepicker-display-am-pm{position:relative;right:auto;bottom:auto;text-align:center;margin-top:1.2rem}} diff --git a/src/lib/materialize/js/materialize.js b/src/lib/materialize/js/materialize.js new file mode 100644 index 0000000..1d6bf90 --- /dev/null +++ b/src/lib/materialize/js/materialize.js @@ -0,0 +1,12255 @@ +/*! + * Materialize v1.0.0-beta (http://materializecss.com) + * Copyright 2014-2017 Materialize + * MIT License (https://raw.githubusercontent.com/Dogfalo/materialize/master/LICENSE) + */ +var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/*! cash-dom 1.3.5, https://github.com/kenwheeler/cash @license MIT */ +(function (factory) { + window.cash = factory(); +})(function () { + var doc = document, + win = window, + ArrayProto = Array.prototype, + slice = ArrayProto.slice, + filter = ArrayProto.filter, + push = ArrayProto.push; + + var noop = function () {}, + isFunction = function (item) { + // @see https://crbug.com/568448 + return typeof item === typeof noop && item.call; + }, + isString = function (item) { + return typeof item === typeof ""; + }; + + var idMatch = /^#[\w-]*$/, + classMatch = /^\.[\w-]*$/, + htmlMatch = /<.+>/, + singlet = /^\w+$/; + + function find(selector, context) { + context = context || doc; + var elems = classMatch.test(selector) ? context.getElementsByClassName(selector.slice(1)) : singlet.test(selector) ? context.getElementsByTagName(selector) : context.querySelectorAll(selector); + return elems; + } + + var frag; + function parseHTML(str) { + if (!frag) { + frag = doc.implementation.createHTMLDocument(null); + var base = frag.createElement("base"); + base.href = doc.location.href; + frag.head.appendChild(base); + } + + frag.body.innerHTML = str; + + return frag.body.childNodes; + } + + function onReady(fn) { + if (doc.readyState !== "loading") { + fn(); + } else { + doc.addEventListener("DOMContentLoaded", fn); + } + } + + function Init(selector, context) { + if (!selector) { + return this; + } + + // If already a cash collection, don't do any further processing + if (selector.cash && selector !== win) { + return selector; + } + + var elems = selector, + i = 0, + length; + + if (isString(selector)) { + elems = idMatch.test(selector) ? + // If an ID use the faster getElementById check + doc.getElementById(selector.slice(1)) : htmlMatch.test(selector) ? + // If HTML, parse it into real elements + parseHTML(selector) : + // else use `find` + find(selector, context); + + // If function, use as shortcut for DOM ready + } else if (isFunction(selector)) { + onReady(selector);return this; + } + + if (!elems) { + return this; + } + + // If a single DOM element is passed in or received via ID, return the single element + if (elems.nodeType || elems === win) { + this[0] = elems; + this.length = 1; + } else { + // Treat like an array and loop through each item. + length = this.length = elems.length; + for (; i < length; i++) { + this[i] = elems[i]; + } + } + + return this; + } + + function cash(selector, context) { + return new Init(selector, context); + } + + var fn = cash.fn = cash.prototype = Init.prototype = { // jshint ignore:line + cash: true, + length: 0, + push: push, + splice: ArrayProto.splice, + map: ArrayProto.map, + init: Init + }; + + Object.defineProperty(fn, "constructor", { value: cash }); + + cash.parseHTML = parseHTML; + cash.noop = noop; + cash.isFunction = isFunction; + cash.isString = isString; + + cash.extend = fn.extend = function (target) { + target = target || {}; + + var args = slice.call(arguments), + length = args.length, + i = 1; + + if (args.length === 1) { + target = this; + i = 0; + } + + for (; i < length; i++) { + if (!args[i]) { + continue; + } + for (var key in args[i]) { + if (args[i].hasOwnProperty(key)) { + target[key] = args[i][key]; + } + } + } + + return target; + }; + + function each(collection, callback) { + var l = collection.length, + i = 0; + + for (; i < l; i++) { + if (callback.call(collection[i], collection[i], i, collection) === false) { + break; + } + } + } + + function matches(el, selector) { + var m = el && (el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector || el.oMatchesSelector); + return !!m && m.call(el, selector); + } + + function getCompareFunction(selector) { + return ( + /* Use browser's `matches` function if string */ + isString(selector) ? matches : + /* Match a cash element */ + selector.cash ? function (el) { + return selector.is(el); + } : + /* Direct comparison */ + function (el, selector) { + return el === selector; + } + ); + } + + function unique(collection) { + return cash(slice.call(collection).filter(function (item, index, self) { + return self.indexOf(item) === index; + })); + } + + cash.extend({ + merge: function (first, second) { + var len = +second.length, + i = first.length, + j = 0; + + for (; j < len; i++, j++) { + first[i] = second[j]; + } + + first.length = i; + return first; + }, + + each: each, + matches: matches, + unique: unique, + isArray: Array.isArray, + isNumeric: function (n) { + return !isNaN(parseFloat(n)) && isFinite(n); + } + + }); + + var uid = cash.uid = "_cash" + Date.now(); + + function getDataCache(node) { + return node[uid] = node[uid] || {}; + } + + function setData(node, key, value) { + return getDataCache(node)[key] = value; + } + + function getData(node, key) { + var c = getDataCache(node); + if (c[key] === undefined) { + c[key] = node.dataset ? node.dataset[key] : cash(node).attr("data-" + key); + } + return c[key]; + } + + function removeData(node, key) { + var c = getDataCache(node); + if (c) { + delete c[key]; + } else if (node.dataset) { + delete node.dataset[key]; + } else { + cash(node).removeAttr("data-" + name); + } + } + + fn.extend({ + data: function (name, value) { + if (isString(name)) { + return value === undefined ? getData(this[0], name) : this.each(function (v) { + return setData(v, name, value); + }); + } + + for (var key in name) { + this.data(key, name[key]); + } + + return this; + }, + + removeData: function (key) { + return this.each(function (v) { + return removeData(v, key); + }); + } + + }); + + var notWhiteMatch = /\S+/g; + + function getClasses(c) { + return isString(c) && c.match(notWhiteMatch); + } + + function hasClass(v, c) { + return v.classList ? v.classList.contains(c) : new RegExp("(^| )" + c + "( |$)", "gi").test(v.className); + } + + function addClass(v, c, spacedName) { + if (v.classList) { + v.classList.add(c); + } else if (spacedName.indexOf(" " + c + " ")) { + v.className += " " + c; + } + } + + function removeClass(v, c) { + if (v.classList) { + v.classList.remove(c); + } else { + v.className = v.className.replace(c, ""); + } + } + + fn.extend({ + addClass: function (c) { + var classes = getClasses(c); + + return classes ? this.each(function (v) { + var spacedName = " " + v.className + " "; + each(classes, function (c) { + addClass(v, c, spacedName); + }); + }) : this; + }, + + attr: function (name, value) { + if (!name) { + return undefined; + } + + if (isString(name)) { + if (value === undefined) { + return this[0] ? this[0].getAttribute ? this[0].getAttribute(name) : this[0][name] : undefined; + } + + return this.each(function (v) { + if (v.setAttribute) { + v.setAttribute(name, value); + } else { + v[name] = value; + } + }); + } + + for (var key in name) { + this.attr(key, name[key]); + } + + return this; + }, + + hasClass: function (c) { + var check = false, + classes = getClasses(c); + if (classes && classes.length) { + this.each(function (v) { + check = hasClass(v, classes[0]); + return !check; + }); + } + return check; + }, + + prop: function (name, value) { + if (isString(name)) { + return value === undefined ? this[0][name] : this.each(function (v) { + v[name] = value; + }); + } + + for (var key in name) { + this.prop(key, name[key]); + } + + return this; + }, + + removeAttr: function (name) { + return this.each(function (v) { + if (v.removeAttribute) { + v.removeAttribute(name); + } else { + delete v[name]; + } + }); + }, + + removeClass: function (c) { + if (!arguments.length) { + return this.attr("class", ""); + } + var classes = getClasses(c); + return classes ? this.each(function (v) { + each(classes, function (c) { + removeClass(v, c); + }); + }) : this; + }, + + removeProp: function (name) { + return this.each(function (v) { + delete v[name]; + }); + }, + + toggleClass: function (c, state) { + if (state !== undefined) { + return this[state ? "addClass" : "removeClass"](c); + } + var classes = getClasses(c); + return classes ? this.each(function (v) { + var spacedName = " " + v.className + " "; + each(classes, function (c) { + if (hasClass(v, c)) { + removeClass(v, c); + } else { + addClass(v, c, spacedName); + } + }); + }) : this; + } }); + + fn.extend({ + add: function (selector, context) { + return unique(cash.merge(this, cash(selector, context))); + }, + + each: function (callback) { + each(this, callback); + return this; + }, + + eq: function (index) { + return cash(this.get(index)); + }, + + filter: function (selector) { + if (!selector) { + return this; + } + + var comparator = isFunction(selector) ? selector : getCompareFunction(selector); + + return cash(filter.call(this, function (e) { + return comparator(e, selector); + })); + }, + + first: function () { + return this.eq(0); + }, + + get: function (index) { + if (index === undefined) { + return slice.call(this); + } + return index < 0 ? this[index + this.length] : this[index]; + }, + + index: function (elem) { + var child = elem ? cash(elem)[0] : this[0], + collection = elem ? this : cash(child).parent().children(); + return slice.call(collection).indexOf(child); + }, + + last: function () { + return this.eq(-1); + } + + }); + + var camelCase = function () { + var camelRegex = /(?:^\w|[A-Z]|\b\w)/g, + whiteSpace = /[\s-_]+/g; + return function (str) { + return str.replace(camelRegex, function (letter, index) { + return letter[index === 0 ? "toLowerCase" : "toUpperCase"](); + }).replace(whiteSpace, ""); + }; + }(); + + var getPrefixedProp = function () { + var cache = {}, + doc = document, + div = doc.createElement("div"), + style = div.style; + + return function (prop) { + prop = camelCase(prop); + if (cache[prop]) { + return cache[prop]; + } + + var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1), + prefixes = ["webkit", "moz", "ms", "o"], + props = (prop + " " + prefixes.join(ucProp + " ") + ucProp).split(" "); + + each(props, function (p) { + if (p in style) { + cache[p] = prop = cache[prop] = p; + return false; + } + }); + + return cache[prop]; + }; + }(); + + cash.prefixedProp = getPrefixedProp; + cash.camelCase = camelCase; + + fn.extend({ + css: function (prop, value) { + if (isString(prop)) { + prop = getPrefixedProp(prop); + return arguments.length > 1 ? this.each(function (v) { + return v.style[prop] = value; + }) : win.getComputedStyle(this[0])[prop]; + } + + for (var key in prop) { + this.css(key, prop[key]); + } + + return this; + } + + }); + + function compute(el, prop) { + return parseInt(win.getComputedStyle(el[0], null)[prop], 10) || 0; + } + + each(["Width", "Height"], function (v) { + var lower = v.toLowerCase(); + + fn[lower] = function () { + return this[0].getBoundingClientRect()[lower]; + }; + + fn["inner" + v] = function () { + return this[0]["client" + v]; + }; + + fn["outer" + v] = function (margins) { + return this[0]["offset" + v] + (margins ? compute(this, "margin" + (v === "Width" ? "Left" : "Top")) + compute(this, "margin" + (v === "Width" ? "Right" : "Bottom")) : 0); + }; + }); + + function registerEvent(node, eventName, callback) { + var eventCache = getData(node, "_cashEvents") || setData(node, "_cashEvents", {}); + eventCache[eventName] = eventCache[eventName] || []; + eventCache[eventName].push(callback); + node.addEventListener(eventName, callback); + } + + function removeEvent(node, eventName, callback) { + var events = getData(node, "_cashEvents"), + eventCache = events && events[eventName], + index; + + if (!eventCache) { + return; + } + + if (callback) { + node.removeEventListener(eventName, callback); + index = eventCache.indexOf(callback); + if (index >= 0) { + eventCache.splice(index, 1); + } + } else { + each(eventCache, function (event) { + node.removeEventListener(eventName, event); + }); + eventCache = []; + } + } + + fn.extend({ + off: function (eventName, callback) { + return this.each(function (v) { + return removeEvent(v, eventName, callback); + }); + }, + + on: function (eventName, delegate, callback, runOnce) { + // jshint ignore:line + var originalCallback; + if (!isString(eventName)) { + for (var key in eventName) { + this.on(key, delegate, eventName[key]); + } + return this; + } + + if (isFunction(delegate)) { + callback = delegate; + delegate = null; + } + + if (eventName === "ready") { + onReady(callback); + return this; + } + + if (delegate) { + originalCallback = callback; + callback = function (e) { + var t = e.target; + while (!matches(t, delegate)) { + if (t === this || t === null) { + return t = false; + } + + t = t.parentNode; + } + + if (t) { + originalCallback.call(t, e); + } + }; + } + + return this.each(function (v) { + var finalCallback = callback; + if (runOnce) { + finalCallback = function () { + callback.apply(this, arguments); + removeEvent(v, eventName, finalCallback); + }; + } + registerEvent(v, eventName, finalCallback); + }); + }, + + one: function (eventName, delegate, callback) { + return this.on(eventName, delegate, callback, true); + }, + + ready: onReady, + + /** + * Modified + * Triggers browser event + * @param String eventName + * @param Object data - Add properties to event object + */ + trigger: function (eventName, data) { + if (document.createEvent) { + var evt = document.createEvent('HTMLEvents'); + evt.initEvent(eventName, true, false); + evt = this.extend(evt, data); + return this.each(function (v) { + return v.dispatchEvent(evt); + }); + } + } + + }); + + function encode(name, value) { + return "&" + encodeURIComponent(name) + "=" + encodeURIComponent(value).replace(/%20/g, "+"); + } + + function getSelectMultiple_(el) { + var values = []; + each(el.options, function (o) { + if (o.selected) { + values.push(o.value); + } + }); + return values.length ? values : null; + } + + function getSelectSingle_(el) { + var selectedIndex = el.selectedIndex; + return selectedIndex >= 0 ? el.options[selectedIndex].value : null; + } + + function getValue(el) { + var type = el.type; + if (!type) { + return null; + } + switch (type.toLowerCase()) { + case "select-one": + return getSelectSingle_(el); + case "select-multiple": + return getSelectMultiple_(el); + case "radio": + return el.checked ? el.value : null; + case "checkbox": + return el.checked ? el.value : null; + default: + return el.value ? el.value : null; + } + } + + fn.extend({ + serialize: function () { + var query = ""; + + each(this[0].elements || this, function (el) { + if (el.disabled || el.tagName === "FIELDSET") { + return; + } + var name = el.name; + switch (el.type.toLowerCase()) { + case "file": + case "reset": + case "submit": + case "button": + break; + case "select-multiple": + var values = getValue(el); + if (values !== null) { + each(values, function (value) { + query += encode(name, value); + }); + } + break; + default: + var value = getValue(el); + if (value !== null) { + query += encode(name, value); + } + } + }); + + return query.substr(1); + }, + + val: function (value) { + if (value === undefined) { + return getValue(this[0]); + } + + return this.each(function (v) { + return v.value = value; + }); + } + + }); + + function insertElement(el, child, prepend) { + if (prepend) { + var first = el.childNodes[0]; + el.insertBefore(child, first); + } else { + el.appendChild(child); + } + } + + function insertContent(parent, child, prepend) { + var str = isString(child); + + if (!str && child.length) { + each(child, function (v) { + return insertContent(parent, v, prepend); + }); + return; + } + + each(parent, str ? function (v) { + return v.insertAdjacentHTML(prepend ? "afterbegin" : "beforeend", child); + } : function (v, i) { + return insertElement(v, i === 0 ? child : child.cloneNode(true), prepend); + }); + } + + fn.extend({ + after: function (selector) { + cash(selector).insertAfter(this); + return this; + }, + + append: function (content) { + insertContent(this, content); + return this; + }, + + appendTo: function (parent) { + insertContent(cash(parent), this); + return this; + }, + + before: function (selector) { + cash(selector).insertBefore(this); + return this; + }, + + clone: function () { + return cash(this.map(function (v) { + return v.cloneNode(true); + })); + }, + + empty: function () { + this.html(""); + return this; + }, + + html: function (content) { + if (content === undefined) { + return this[0].innerHTML; + } + var source = content.nodeType ? content[0].outerHTML : content; + return this.each(function (v) { + return v.innerHTML = source; + }); + }, + + insertAfter: function (selector) { + var _this = this; + + cash(selector).each(function (el, i) { + var parent = el.parentNode, + sibling = el.nextSibling; + _this.each(function (v) { + parent.insertBefore(i === 0 ? v : v.cloneNode(true), sibling); + }); + }); + + return this; + }, + + insertBefore: function (selector) { + var _this2 = this; + cash(selector).each(function (el, i) { + var parent = el.parentNode; + _this2.each(function (v) { + parent.insertBefore(i === 0 ? v : v.cloneNode(true), el); + }); + }); + return this; + }, + + prepend: function (content) { + insertContent(this, content, true); + return this; + }, + + prependTo: function (parent) { + insertContent(cash(parent), this, true); + return this; + }, + + remove: function () { + return this.each(function (v) { + if (!!v.parentNode) { + return v.parentNode.removeChild(v); + } + }); + }, + + text: function (content) { + if (content === undefined) { + return this[0].textContent; + } + return this.each(function (v) { + return v.textContent = content; + }); + } + + }); + + var docEl = doc.documentElement; + + fn.extend({ + position: function () { + var el = this[0]; + return { + left: el.offsetLeft, + top: el.offsetTop + }; + }, + + offset: function () { + var rect = this[0].getBoundingClientRect(); + return { + top: rect.top + win.pageYOffset - docEl.clientTop, + left: rect.left + win.pageXOffset - docEl.clientLeft + }; + }, + + offsetParent: function () { + return cash(this[0].offsetParent); + } + + }); + + fn.extend({ + children: function (selector) { + var elems = []; + this.each(function (el) { + push.apply(elems, el.children); + }); + elems = unique(elems); + + return !selector ? elems : elems.filter(function (v) { + return matches(v, selector); + }); + }, + + closest: function (selector) { + if (!selector || this.length < 1) { + return cash(); + } + if (this.is(selector)) { + return this.filter(selector); + } + return this.parent().closest(selector); + }, + + is: function (selector) { + if (!selector) { + return false; + } + + var match = false, + comparator = getCompareFunction(selector); + + this.each(function (el) { + match = comparator(el, selector); + return !match; + }); + + return match; + }, + + find: function (selector) { + if (!selector || selector.nodeType) { + return cash(selector && this.has(selector).length ? selector : null); + } + + var elems = []; + this.each(function (el) { + push.apply(elems, find(selector, el)); + }); + + return unique(elems); + }, + + has: function (selector) { + var comparator = isString(selector) ? function (el) { + return find(selector, el).length !== 0; + } : function (el) { + return el.contains(selector); + }; + + return this.filter(comparator); + }, + + next: function () { + return cash(this[0].nextElementSibling); + }, + + not: function (selector) { + if (!selector) { + return this; + } + + var comparator = getCompareFunction(selector); + + return this.filter(function (el) { + return !comparator(el, selector); + }); + }, + + parent: function () { + var result = []; + + this.each(function (item) { + if (item && item.parentNode) { + result.push(item.parentNode); + } + }); + + return unique(result); + }, + + parents: function (selector) { + var last, + result = []; + + this.each(function (item) { + last = item; + + while (last && last.parentNode && last !== doc.body.parentNode) { + last = last.parentNode; + + if (!selector || selector && matches(last, selector)) { + result.push(last); + } + } + }); + + return unique(result); + }, + + prev: function () { + return cash(this[0].previousElementSibling); + }, + + siblings: function (selector) { + var collection = this.parent().children(selector), + el = this[0]; + + return collection.filter(function (i) { + return i !== el; + }); + } + + }); + + return cash; +}); +; +var Component = function () { + /** + * Generic constructor for all components + * @constructor + * @param {Element} el + * @param {Object} options + */ + function Component(classDef, el, options) { + _classCallCheck(this, Component); + + // Display error if el is valid HTML Element + if (!(el instanceof Element)) { + console.error(Error(el + ' is not an HTML Element')); + } + + // If exists, destroy and reinitialize in child + var ins = classDef.getInstance(el); + if (!!ins) { + ins.destroy(); + } + + this.el = el; + this.$el = cash(el); + } + + /** + * Initializes components + * @param {class} classDef + * @param {Element | NodeList | jQuery} els + * @param {Object} options + */ + + + _createClass(Component, null, [{ + key: "init", + value: function init(classDef, els, options) { + var instances = null; + if (els instanceof Element) { + instances = new classDef(els, options); + } else if (!!els && (els.jquery || els.cash || els instanceof NodeList)) { + var instancesArr = []; + for (var i = 0; i < els.length; i++) { + instancesArr.push(new classDef(els[i], options)); + } + instances = instancesArr; + } + + return instances; + } + }]); + + return Component; +}(); + +; // Required for Meteor package, the use of window prevents export by Meteor +(function (window) { + if (window.Package) { + M = {}; + } else { + window.M = {}; + } + + // Check for jQuery + M.jQueryLoaded = !!window.jQuery; +})(window); + +// AMD +if (typeof define === "function" && define.amd) { + define("M", [], function () { + return M; + }); + + // Common JS +} else if (typeof exports !== 'undefined' && !exports.nodeType) { + if (typeof module !== 'undefined' && !module.nodeType && module.exports) { + exports = module.exports = M; + } + exports.default = M; +} + +M.keys = { + TAB: 9, + ENTER: 13, + ESC: 27, + ARROW_UP: 38, + ARROW_DOWN: 40 +}; + +/** + * TabPress Keydown handler + */ +M.tabPressed = false; +var docHandleKeydown = function (e) { + if (e.which === M.keys.TAB) { + M.tabPressed = true; + } +}; +var docHandleKeyup = function (e) { + if (e.which === M.keys.TAB) { + M.tabPressed = false; + } +}; +document.addEventListener('keydown', docHandleKeydown); +document.addEventListener('keyup', docHandleKeyup); + +/** + * Initialize jQuery wrapper for plugin + * @param {Class} plugin javascript class + * @param {string} pluginName jQuery plugin name + * @param {string} classRef Class reference name + */ +M.initializeJqueryWrapper = function (plugin, pluginName, classRef) { + jQuery.fn[pluginName] = function (methodOrOptions) { + // Call plugin method if valid method name is passed in + if (plugin.prototype[methodOrOptions]) { + var params = Array.prototype.slice.call(arguments, 1); + + // Getter methods + if (methodOrOptions.slice(0, 3) === 'get') { + var instance = this.first()[0][classRef]; + return instance[methodOrOptions].apply(instance, params); + } + + // Void methods + return this.each(function () { + var instance = this[classRef]; + instance[methodOrOptions].apply(instance, params); + }); + + // Initialize plugin if options or no argument is passed in + } else if (typeof methodOrOptions === 'object' || !methodOrOptions) { + plugin.init(this, arguments[0]); + return this; + } + + // Return error if an unrecognized method name is passed in + jQuery.error("Method " + methodOrOptions + " does not exist on jQuery." + pluginName); + }; +}; + +/** + * Automatically initialize components + * @param {Element} context DOM Element to search within for components + */ +M.AutoInit = function (context) { + // Use document.body if no context is given + var root = !!context ? context : document.body; + + var registry = { + Autocomplete: root.querySelectorAll('.autocomplete:not(.no-autoinit)'), + Carousel: root.querySelectorAll('.carousel:not(.no-autoinit)'), + Chips: root.querySelectorAll('.chips:not(.no-autoinit)'), + Collapsible: root.querySelectorAll('.collapsible:not(.no-autoinit)'), + Datepicker: root.querySelectorAll('.datepicker:not(.no-autoinit)'), + Dropdown: root.querySelectorAll('.dropdown-trigger:not(.no-autoinit)'), + Materialbox: root.querySelectorAll('.materialboxed:not(.no-autoinit)'), + Modal: root.querySelectorAll('.modal:not(.no-autoinit)'), + Parallax: root.querySelectorAll('.parallax:not(.no-autoinit)'), + Pushpin: root.querySelectorAll('.pushpin:not(.no-autoinit)'), + ScrollSpy: root.querySelectorAll('.scrollspy:not(.no-autoinit)'), + FormSelect: root.querySelectorAll('select:not(.no-autoinit)'), + Sidenav: root.querySelectorAll('.sidenav:not(.no-autoinit)'), + Tabs: root.querySelectorAll('.tabs:not(.no-autoinit)'), + TapTarget: root.querySelectorAll('.tap-target:not(.no-autoinit)'), + Timepicker: root.querySelectorAll('.timepicker:not(.no-autoinit)'), + Tooltip: root.querySelectorAll('.tooltipped:not(.no-autoinit)'), + FloatingActionButton: root.querySelectorAll('.fixed-action-btn:not(.no-autoinit)') + }; + + for (var pluginName in registry) { + var plugin = M[pluginName]; + plugin.init(registry[pluginName]); + } +}; + +/** + * Generate approximated selector string for a jQuery object + * @param {jQuery} obj jQuery object to be parsed + * @returns {string} + */ +M.objectSelectorString = function (obj) { + var tagStr = obj.prop('tagName') || ''; + var idStr = obj.attr('id') || ''; + var classStr = obj.attr('class') || ''; + return (tagStr + idStr + classStr).replace(/\s/g, ''); +}; + +// Unique Random ID +M.guid = function () { + function s4() { + return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1); + } + return function () { + return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4(); + }; +}(); + +/** + * Escapes hash from special characters + * @param {string} hash String returned from this.hash + * @returns {string} + */ +M.escapeHash = function (hash) { + return hash.replace(/(:|\.|\[|\]|,|=|\/)/g, "\\$1"); +}; + +M.elementOrParentIsFixed = function (element) { + var $element = $(element); + var $checkElements = $element.add($element.parents()); + var isFixed = false; + $checkElements.each(function () { + if ($(this).css("position") === "fixed") { + isFixed = true; + return false; + } + }); + return isFixed; +}; + +/** + * @typedef {Object} Edges + * @property {Boolean} top If the top edge was exceeded + * @property {Boolean} right If the right edge was exceeded + * @property {Boolean} bottom If the bottom edge was exceeded + * @property {Boolean} left If the left edge was exceeded + */ + +/** + * @typedef {Object} Bounding + * @property {Number} left left offset coordinate + * @property {Number} top top offset coordinate + * @property {Number} width + * @property {Number} height + */ + +/** + * Escapes hash from special characters + * @param {Element} container Container element that acts as the boundary + * @param {Bounding} bounding element bounding that is being checked + * @param {Number} offset offset from edge that counts as exceeding + * @returns {Edges} + */ +M.checkWithinContainer = function (container, bounding, offset) { + var edges = { + top: false, + right: false, + bottom: false, + left: false + }; + + var containerRect = container.getBoundingClientRect(); + + var scrollLeft = container.scrollLeft; + var scrollTop = container.scrollTop; + + var scrolledX = bounding.left - scrollLeft; + var scrolledY = bounding.top - scrollTop; + + // Check for container and viewport for each edge + if (scrolledX < containerRect.left + offset || scrolledX < offset) { + edges.left = true; + } + + if (scrolledX + bounding.width > containerRect.right - offset || scrolledX + bounding.width > window.innerWidth - offset) { + edges.right = true; + } + + if (scrolledY < containerRect.top + offset || scrolledY < offset) { + edges.top = true; + } + + if (scrolledY + bounding.height > containerRect.bottom - offset || scrolledY + bounding.height > window.innerHeight - offset) { + edges.bottom = true; + } + + return edges; +}; + +M.checkPossibleAlignments = function (el, container, bounding, offset) { + var canAlign = { + top: true, + right: true, + bottom: true, + left: true, + spaceOnTop: null, + spaceOnRight: null, + spaceOnBottom: null, + spaceOnLeft: null + }; + + var containerAllowsOverflow = getComputedStyle(container).overflow === 'visible'; + var containerRect = container.getBoundingClientRect(); + var containerHeight = Math.min(containerRect.height, window.innerHeight); + var containerWidth = Math.min(containerRect.width, window.innerWidth); + var elOffsetRect = el.getBoundingClientRect(); + + var scrollLeft = container.scrollLeft; + var scrollTop = container.scrollTop; + + var scrolledX = bounding.left - scrollLeft; + var scrolledYTopEdge = bounding.top - scrollTop; + var scrolledYBottomEdge = bounding.top + elOffsetRect.height - scrollTop; + + // Check for container and viewport for left + canAlign.spaceOnRight = !containerAllowsOverflow ? containerWidth - (scrolledX + bounding.width) : window.innerWidth - (elOffsetRect.left + bounding.width); + if (canAlign.spaceOnRight < 0) { + canAlign.left = false; + } + + // Check for container and viewport for Right + canAlign.spaceOnLeft = !containerAllowsOverflow ? scrolledX - bounding.width + elOffsetRect.width : elOffsetRect.right - bounding.width; + if (canAlign.spaceOnLeft < 0) { + canAlign.right = false; + } + + // Check for container and viewport for Top + canAlign.spaceOnBottom = !containerAllowsOverflow ? containerHeight - (scrolledYTopEdge + bounding.height + offset) : window.innerHeight - (elOffsetRect.top + bounding.height + offset); + if (canAlign.spaceOnBottom < 0) { + canAlign.top = false; + } + + // Check for container and viewport for Bottom + canAlign.spaceOnTop = !containerAllowsOverflow ? scrolledYBottomEdge - (bounding.height - offset) : elOffsetRect.bottom - (bounding.height + offset); + if (canAlign.spaceOnTop < 0) { + canAlign.bottom = false; + } + + return canAlign; +}; + +M.getOverflowParent = function (element) { + if (element == null) { + return null; + } + + if (element === document.body || getComputedStyle(element).overflow !== 'visible') { + return element; + } + + return M.getOverflowParent(element.parentElement); +}; + +/** + * Gets id of component from a trigger + * @param {Element} trigger trigger + * @returns {string} + */ +M.getIdFromTrigger = function (trigger) { + var id = trigger.getAttribute('data-target'); + if (!id) { + id = trigger.getAttribute('href'); + if (id) { + id = id.slice(1); + } else { + id = ""; + } + } + return id; +}; + +/** + * Multi browser support for document scroll top + * @returns {Number} + */ +M.getDocumentScrollTop = function () { + return window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0; +}; + +/** + * Multi browser support for document scroll left + * @returns {Number} + */ +M.getDocumentScrollLeft = function () { + return window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0; +}; + +/** + * @typedef {Object} Edges + * @property {Boolean} top If the top edge was exceeded + * @property {Boolean} right If the right edge was exceeded + * @property {Boolean} bottom If the bottom edge was exceeded + * @property {Boolean} left If the left edge was exceeded + */ + +/** + * @typedef {Object} Bounding + * @property {Number} left left offset coordinate + * @property {Number} top top offset coordinate + * @property {Number} width + * @property {Number} height + */ + +/** + * Get time in ms + * @license https://raw.github.com/jashkenas/underscore/master/LICENSE + * @type {function} + * @return {number} + */ +var getTime = Date.now || function () { + return new Date().getTime(); +}; + +/** + * Returns a function, that, when invoked, will only be triggered at most once + * during a given window of time. Normally, the throttled function will run + * as much as it can, without ever going more than once per `wait` duration; + * but if you'd like to disable the execution on the leading edge, pass + * `{leading: false}`. To disable execution on the trailing edge, ditto. + * @license https://raw.github.com/jashkenas/underscore/master/LICENSE + * @param {function} func + * @param {number} wait + * @param {Object=} options + * @returns {Function} + */ +M.throttle = function (func, wait, options) { + var context = void 0, + args = void 0, + result = void 0; + var timeout = null; + var previous = 0; + options || (options = {}); + var later = function () { + previous = options.leading === false ? 0 : getTime(); + timeout = null; + result = func.apply(context, args); + context = args = null; + }; + return function () { + var now = getTime(); + if (!previous && options.leading === false) previous = now; + var remaining = wait - (now - previous); + context = this; + args = arguments; + if (remaining <= 0) { + clearTimeout(timeout); + timeout = null; + previous = now; + result = func.apply(context, args); + context = args = null; + } else if (!timeout && options.trailing !== false) { + timeout = setTimeout(later, remaining); + } + return result; + }; +}; +; /* + v2.2.0 + 2017 Julian Garnier + Released under the MIT license + */ +var $jscomp = { scope: {} };$jscomp.defineProperty = "function" == typeof Object.defineProperties ? Object.defineProperty : function (e, r, p) { + if (p.get || p.set) throw new TypeError("ES3 does not support getters and setters.");e != Array.prototype && e != Object.prototype && (e[r] = p.value); +};$jscomp.getGlobal = function (e) { + return "undefined" != typeof window && window === e ? e : "undefined" != typeof global && null != global ? global : e; +};$jscomp.global = $jscomp.getGlobal(this);$jscomp.SYMBOL_PREFIX = "jscomp_symbol_"; +$jscomp.initSymbol = function () { + $jscomp.initSymbol = function () {};$jscomp.global.Symbol || ($jscomp.global.Symbol = $jscomp.Symbol); +};$jscomp.symbolCounter_ = 0;$jscomp.Symbol = function (e) { + return $jscomp.SYMBOL_PREFIX + (e || "") + $jscomp.symbolCounter_++; +}; +$jscomp.initSymbolIterator = function () { + $jscomp.initSymbol();var e = $jscomp.global.Symbol.iterator;e || (e = $jscomp.global.Symbol.iterator = $jscomp.global.Symbol("iterator"));"function" != typeof Array.prototype[e] && $jscomp.defineProperty(Array.prototype, e, { configurable: !0, writable: !0, value: function () { + return $jscomp.arrayIterator(this); + } });$jscomp.initSymbolIterator = function () {}; +};$jscomp.arrayIterator = function (e) { + var r = 0;return $jscomp.iteratorPrototype(function () { + return r < e.length ? { done: !1, value: e[r++] } : { done: !0 }; + }); +}; +$jscomp.iteratorPrototype = function (e) { + $jscomp.initSymbolIterator();e = { next: e };e[$jscomp.global.Symbol.iterator] = function () { + return this; + };return e; +};$jscomp.array = $jscomp.array || {};$jscomp.iteratorFromArray = function (e, r) { + $jscomp.initSymbolIterator();e instanceof String && (e += "");var p = 0, + m = { next: function () { + if (p < e.length) { + var u = p++;return { value: r(u, e[u]), done: !1 }; + }m.next = function () { + return { done: !0, value: void 0 }; + };return m.next(); + } };m[Symbol.iterator] = function () { + return m; + };return m; +}; +$jscomp.polyfill = function (e, r, p, m) { + if (r) { + p = $jscomp.global;e = e.split(".");for (m = 0; m < e.length - 1; m++) { + var u = e[m];u in p || (p[u] = {});p = p[u]; + }e = e[e.length - 1];m = p[e];r = r(m);r != m && null != r && $jscomp.defineProperty(p, e, { configurable: !0, writable: !0, value: r }); + } +};$jscomp.polyfill("Array.prototype.keys", function (e) { + return e ? e : function () { + return $jscomp.iteratorFromArray(this, function (e) { + return e; + }); + }; +}, "es6-impl", "es3");var $jscomp$this = this; +(function (r) { + M.anime = r(); +})(function () { + function e(a) { + if (!h.col(a)) try { + return document.querySelectorAll(a); + } catch (c) {} + }function r(a, c) { + for (var d = a.length, b = 2 <= arguments.length ? arguments[1] : void 0, f = [], n = 0; n < d; n++) { + if (n in a) { + var k = a[n];c.call(b, k, n, a) && f.push(k); + } + }return f; + }function p(a) { + return a.reduce(function (a, d) { + return a.concat(h.arr(d) ? p(d) : d); + }, []); + }function m(a) { + if (h.arr(a)) return a; + h.str(a) && (a = e(a) || a);return a instanceof NodeList || a instanceof HTMLCollection ? [].slice.call(a) : [a]; + }function u(a, c) { + return a.some(function (a) { + return a === c; + }); + }function C(a) { + var c = {}, + d;for (d in a) { + c[d] = a[d]; + }return c; + }function D(a, c) { + var d = C(a), + b;for (b in a) { + d[b] = c.hasOwnProperty(b) ? c[b] : a[b]; + }return d; + }function z(a, c) { + var d = C(a), + b;for (b in c) { + d[b] = h.und(a[b]) ? c[b] : a[b]; + }return d; + }function T(a) { + a = a.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i, function (a, c, d, k) { + return c + c + d + d + k + k; + });var c = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(a); + a = parseInt(c[1], 16);var d = parseInt(c[2], 16), + c = parseInt(c[3], 16);return "rgba(" + a + "," + d + "," + c + ",1)"; + }function U(a) { + function c(a, c, b) { + 0 > b && (b += 1);1 < b && --b;return b < 1 / 6 ? a + 6 * (c - a) * b : .5 > b ? c : b < 2 / 3 ? a + (c - a) * (2 / 3 - b) * 6 : a; + }var d = /hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.exec(a) || /hsla\((\d+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)\)/g.exec(a);a = parseInt(d[1]) / 360;var b = parseInt(d[2]) / 100, + f = parseInt(d[3]) / 100, + d = d[4] || 1;if (0 == b) f = b = a = f;else { + var n = .5 > f ? f * (1 + b) : f + b - f * b, + k = 2 * f - n, + f = c(k, n, a + 1 / 3), + b = c(k, n, a);a = c(k, n, a - 1 / 3); + }return "rgba(" + 255 * f + "," + 255 * b + "," + 255 * a + "," + d + ")"; + }function y(a) { + if (a = /([\+\-]?[0-9#\.]+)(%|px|pt|em|rem|in|cm|mm|ex|ch|pc|vw|vh|vmin|vmax|deg|rad|turn)?$/.exec(a)) return a[2]; + }function V(a) { + if (-1 < a.indexOf("translate") || "perspective" === a) return "px";if (-1 < a.indexOf("rotate") || -1 < a.indexOf("skew")) return "deg"; + }function I(a, c) { + return h.fnc(a) ? a(c.target, c.id, c.total) : a; + }function E(a, c) { + if (c in a.style) return getComputedStyle(a).getPropertyValue(c.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase()) || "0"; + }function J(a, c) { + if (h.dom(a) && u(W, c)) return "transform";if (h.dom(a) && (a.getAttribute(c) || h.svg(a) && a[c])) return "attribute";if (h.dom(a) && "transform" !== c && E(a, c)) return "css";if (null != a[c]) return "object"; + }function X(a, c) { + var d = V(c), + d = -1 < c.indexOf("scale") ? 1 : 0 + d;a = a.style.transform;if (!a) return d;for (var b = [], f = [], n = [], k = /(\w+)\((.+?)\)/g; b = k.exec(a);) { + f.push(b[1]), n.push(b[2]); + }a = r(n, function (a, b) { + return f[b] === c; + });return a.length ? a[0] : d; + }function K(a, c) { + switch (J(a, c)) {case "transform": + return X(a, c);case "css": + return E(a, c);case "attribute": + return a.getAttribute(c);}return a[c] || 0; + }function L(a, c) { + var d = /^(\*=|\+=|-=)/.exec(a);if (!d) return a;var b = y(a) || 0;c = parseFloat(c);a = parseFloat(a.replace(d[0], ""));switch (d[0][0]) {case "+": + return c + a + b;case "-": + return c - a + b;case "*": + return c * a + b;} + }function F(a, c) { + return Math.sqrt(Math.pow(c.x - a.x, 2) + Math.pow(c.y - a.y, 2)); + }function M(a) { + a = a.points;for (var c = 0, d, b = 0; b < a.numberOfItems; b++) { + var f = a.getItem(b);0 < b && (c += F(d, f));d = f; + }return c; + }function N(a) { + if (a.getTotalLength) return a.getTotalLength();switch (a.tagName.toLowerCase()) {case "circle": + return 2 * Math.PI * a.getAttribute("r");case "rect": + return 2 * a.getAttribute("width") + 2 * a.getAttribute("height");case "line": + return F({ x: a.getAttribute("x1"), y: a.getAttribute("y1") }, { x: a.getAttribute("x2"), y: a.getAttribute("y2") });case "polyline": + return M(a);case "polygon": + var c = a.points;return M(a) + F(c.getItem(c.numberOfItems - 1), c.getItem(0));} + }function Y(a, c) { + function d(b) { + b = void 0 === b ? 0 : b;return a.el.getPointAtLength(1 <= c + b ? c + b : 0); + }var b = d(), + f = d(-1), + n = d(1);switch (a.property) {case "x": + return b.x;case "y": + return b.y; + case "angle": + return 180 * Math.atan2(n.y - f.y, n.x - f.x) / Math.PI;} + }function O(a, c) { + var d = /-?\d*\.?\d+/g, + b;b = h.pth(a) ? a.totalLength : a;if (h.col(b)) { + if (h.rgb(b)) { + var f = /rgb\((\d+,\s*[\d]+,\s*[\d]+)\)/g.exec(b);b = f ? "rgba(" + f[1] + ",1)" : b; + } else b = h.hex(b) ? T(b) : h.hsl(b) ? U(b) : void 0; + } else f = (f = y(b)) ? b.substr(0, b.length - f.length) : b, b = c && !/\s/g.test(b) ? f + c : f;b += "";return { original: b, numbers: b.match(d) ? b.match(d).map(Number) : [0], strings: h.str(a) || c ? b.split(d) : [] }; + }function P(a) { + a = a ? p(h.arr(a) ? a.map(m) : m(a)) : [];return r(a, function (a, d, b) { + return b.indexOf(a) === d; + }); + }function Z(a) { + var c = P(a);return c.map(function (a, b) { + return { target: a, id: b, total: c.length }; + }); + }function aa(a, c) { + var d = C(c);if (h.arr(a)) { + var b = a.length;2 !== b || h.obj(a[0]) ? h.fnc(c.duration) || (d.duration = c.duration / b) : a = { value: a }; + }return m(a).map(function (a, b) { + b = b ? 0 : c.delay;a = h.obj(a) && !h.pth(a) ? a : { value: a };h.und(a.delay) && (a.delay = b);return a; + }).map(function (a) { + return z(a, d); + }); + }function ba(a, c) { + var d = {}, + b;for (b in a) { + var f = I(a[b], c);h.arr(f) && (f = f.map(function (a) { + return I(a, c); + }), 1 === f.length && (f = f[0]));d[b] = f; + }d.duration = parseFloat(d.duration);d.delay = parseFloat(d.delay);return d; + }function ca(a) { + return h.arr(a) ? A.apply(this, a) : Q[a]; + }function da(a, c) { + var d;return a.tweens.map(function (b) { + b = ba(b, c);var f = b.value, + e = K(c.target, a.name), + k = d ? d.to.original : e, + k = h.arr(f) ? f[0] : k, + w = L(h.arr(f) ? f[1] : f, k), + e = y(w) || y(k) || y(e);b.from = O(k, e);b.to = O(w, e);b.start = d ? d.end : a.offset;b.end = b.start + b.delay + b.duration;b.easing = ca(b.easing);b.elasticity = (1E3 - Math.min(Math.max(b.elasticity, 1), 999)) / 1E3;b.isPath = h.pth(f);b.isColor = h.col(b.from.original);b.isColor && (b.round = 1);return d = b; + }); + }function ea(a, c) { + return r(p(a.map(function (a) { + return c.map(function (b) { + var c = J(a.target, b.name);if (c) { + var d = da(b, a);b = { type: c, property: b.name, animatable: a, tweens: d, duration: d[d.length - 1].end, delay: d[0].delay }; + } else b = void 0;return b; + }); + })), function (a) { + return !h.und(a); + }); + }function R(a, c, d, b) { + var f = "delay" === a;return c.length ? (f ? Math.min : Math.max).apply(Math, c.map(function (b) { + return b[a]; + })) : f ? b.delay : d.offset + b.delay + b.duration; + }function fa(a) { + var c = D(ga, a), + d = D(S, a), + b = Z(a.targets), + f = [], + e = z(c, d), + k;for (k in a) { + e.hasOwnProperty(k) || "targets" === k || f.push({ name: k, offset: e.offset, tweens: aa(a[k], d) }); + }a = ea(b, f);return z(c, { children: [], animatables: b, animations: a, duration: R("duration", a, c, d), delay: R("delay", a, c, d) }); + }function q(a) { + function c() { + return window.Promise && new Promise(function (a) { + return p = a; + }); + }function d(a) { + return g.reversed ? g.duration - a : a; + }function b(a) { + for (var b = 0, c = {}, d = g.animations, f = d.length; b < f;) { + var e = d[b], + k = e.animatable, + h = e.tweens, + n = h.length - 1, + l = h[n];n && (l = r(h, function (b) { + return a < b.end; + })[0] || l);for (var h = Math.min(Math.max(a - l.start - l.delay, 0), l.duration) / l.duration, w = isNaN(h) ? 1 : l.easing(h, l.elasticity), h = l.to.strings, p = l.round, n = [], m = void 0, m = l.to.numbers.length, t = 0; t < m; t++) { + var x = void 0, + x = l.to.numbers[t], + q = l.from.numbers[t], + x = l.isPath ? Y(l.value, w * x) : q + w * (x - q);p && (l.isColor && 2 < t || (x = Math.round(x * p) / p));n.push(x); + }if (l = h.length) for (m = h[0], w = 0; w < l; w++) { + p = h[w + 1], t = n[w], isNaN(t) || (m = p ? m + (t + p) : m + (t + " ")); + } else m = n[0];ha[e.type](k.target, e.property, m, c, k.id);e.currentValue = m;b++; + }if (b = Object.keys(c).length) for (d = 0; d < b; d++) { + H || (H = E(document.body, "transform") ? "transform" : "-webkit-transform"), g.animatables[d].target.style[H] = c[d].join(" "); + }g.currentTime = a;g.progress = a / g.duration * 100; + }function f(a) { + if (g[a]) g[a](g); + }function e() { + g.remaining && !0 !== g.remaining && g.remaining--; + }function k(a) { + var k = g.duration, + n = g.offset, + w = n + g.delay, + r = g.currentTime, + x = g.reversed, + q = d(a);if (g.children.length) { + var u = g.children, + v = u.length; + if (q >= g.currentTime) for (var G = 0; G < v; G++) { + u[G].seek(q); + } else for (; v--;) { + u[v].seek(q); + } + }if (q >= w || !k) g.began || (g.began = !0, f("begin")), f("run");if (q > n && q < k) b(q);else if (q <= n && 0 !== r && (b(0), x && e()), q >= k && r !== k || !k) b(k), x || e();f("update");a >= k && (g.remaining ? (t = h, "alternate" === g.direction && (g.reversed = !g.reversed)) : (g.pause(), g.completed || (g.completed = !0, f("complete"), "Promise" in window && (p(), m = c()))), l = 0); + }a = void 0 === a ? {} : a;var h, + t, + l = 0, + p = null, + m = c(), + g = fa(a);g.reset = function () { + var a = g.direction, + c = g.loop;g.currentTime = 0;g.progress = 0;g.paused = !0;g.began = !1;g.completed = !1;g.reversed = "reverse" === a;g.remaining = "alternate" === a && 1 === c ? 2 : c;b(0);for (a = g.children.length; a--;) { + g.children[a].reset(); + } + };g.tick = function (a) { + h = a;t || (t = h);k((l + h - t) * q.speed); + };g.seek = function (a) { + k(d(a)); + };g.pause = function () { + var a = v.indexOf(g);-1 < a && v.splice(a, 1);g.paused = !0; + };g.play = function () { + g.paused && (g.paused = !1, t = 0, l = d(g.currentTime), v.push(g), B || ia()); + };g.reverse = function () { + g.reversed = !g.reversed;t = 0;l = d(g.currentTime); + };g.restart = function () { + g.pause(); + g.reset();g.play(); + };g.finished = m;g.reset();g.autoplay && g.play();return g; + }var ga = { update: void 0, begin: void 0, run: void 0, complete: void 0, loop: 1, direction: "normal", autoplay: !0, offset: 0 }, + S = { duration: 1E3, delay: 0, easing: "easeOutElastic", elasticity: 500, round: 0 }, + W = "translateX translateY translateZ rotate rotateX rotateY rotateZ scale scaleX scaleY scaleZ skewX skewY perspective".split(" "), + H, + h = { arr: function (a) { + return Array.isArray(a); + }, obj: function (a) { + return -1 < Object.prototype.toString.call(a).indexOf("Object"); + }, + pth: function (a) { + return h.obj(a) && a.hasOwnProperty("totalLength"); + }, svg: function (a) { + return a instanceof SVGElement; + }, dom: function (a) { + return a.nodeType || h.svg(a); + }, str: function (a) { + return "string" === typeof a; + }, fnc: function (a) { + return "function" === typeof a; + }, und: function (a) { + return "undefined" === typeof a; + }, hex: function (a) { + return (/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(a) + ); + }, rgb: function (a) { + return (/^rgb/.test(a) + ); + }, hsl: function (a) { + return (/^hsl/.test(a) + ); + }, col: function (a) { + return h.hex(a) || h.rgb(a) || h.hsl(a); + } }, + A = function () { + function a(a, d, b) { + return (((1 - 3 * b + 3 * d) * a + (3 * b - 6 * d)) * a + 3 * d) * a; + }return function (c, d, b, f) { + if (0 <= c && 1 >= c && 0 <= b && 1 >= b) { + var e = new Float32Array(11);if (c !== d || b !== f) for (var k = 0; 11 > k; ++k) { + e[k] = a(.1 * k, c, b); + }return function (k) { + if (c === d && b === f) return k;if (0 === k) return 0;if (1 === k) return 1;for (var h = 0, l = 1; 10 !== l && e[l] <= k; ++l) { + h += .1; + }--l;var l = h + (k - e[l]) / (e[l + 1] - e[l]) * .1, + n = 3 * (1 - 3 * b + 3 * c) * l * l + 2 * (3 * b - 6 * c) * l + 3 * c;if (.001 <= n) { + for (h = 0; 4 > h; ++h) { + n = 3 * (1 - 3 * b + 3 * c) * l * l + 2 * (3 * b - 6 * c) * l + 3 * c;if (0 === n) break;var m = a(l, c, b) - k, + l = l - m / n; + }k = l; + } else if (0 === n) k = l;else { + var l = h, + h = h + .1, + g = 0;do { + m = l + (h - l) / 2, n = a(m, c, b) - k, 0 < n ? h = m : l = m; + } while (1e-7 < Math.abs(n) && 10 > ++g);k = m; + }return a(k, d, f); + }; + } + }; + }(), + Q = function () { + function a(a, b) { + return 0 === a || 1 === a ? a : -Math.pow(2, 10 * (a - 1)) * Math.sin(2 * (a - 1 - b / (2 * Math.PI) * Math.asin(1)) * Math.PI / b); + }var c = "Quad Cubic Quart Quint Sine Expo Circ Back Elastic".split(" "), + d = { In: [[.55, .085, .68, .53], [.55, .055, .675, .19], [.895, .03, .685, .22], [.755, .05, .855, .06], [.47, 0, .745, .715], [.95, .05, .795, .035], [.6, .04, .98, .335], [.6, -.28, .735, .045], a], Out: [[.25, .46, .45, .94], [.215, .61, .355, 1], [.165, .84, .44, 1], [.23, 1, .32, 1], [.39, .575, .565, 1], [.19, 1, .22, 1], [.075, .82, .165, 1], [.175, .885, .32, 1.275], function (b, c) { + return 1 - a(1 - b, c); + }], InOut: [[.455, .03, .515, .955], [.645, .045, .355, 1], [.77, 0, .175, 1], [.86, 0, .07, 1], [.445, .05, .55, .95], [1, 0, 0, 1], [.785, .135, .15, .86], [.68, -.55, .265, 1.55], function (b, c) { + return .5 > b ? a(2 * b, c) / 2 : 1 - a(-2 * b + 2, c) / 2; + }] }, + b = { linear: A(.25, .25, .75, .75) }, + f = {}, + e;for (e in d) { + f.type = e, d[f.type].forEach(function (a) { + return function (d, f) { + b["ease" + a.type + c[f]] = h.fnc(d) ? d : A.apply($jscomp$this, d); + }; + }(f)), f = { type: f.type }; + }return b; + }(), + ha = { css: function (a, c, d) { + return a.style[c] = d; + }, attribute: function (a, c, d) { + return a.setAttribute(c, d); + }, object: function (a, c, d) { + return a[c] = d; + }, transform: function (a, c, d, b, f) { + b[f] || (b[f] = []);b[f].push(c + "(" + d + ")"); + } }, + v = [], + B = 0, + ia = function () { + function a() { + B = requestAnimationFrame(c); + }function c(c) { + var b = v.length;if (b) { + for (var d = 0; d < b;) { + v[d] && v[d].tick(c), d++; + }a(); + } else cancelAnimationFrame(B), B = 0; + }return a; + }();q.version = "2.2.0";q.speed = 1;q.running = v;q.remove = function (a) { + a = P(a);for (var c = v.length; c--;) { + for (var d = v[c], b = d.animations, f = b.length; f--;) { + u(a, b[f].animatable.target) && (b.splice(f, 1), b.length || d.pause()); + } + } + };q.getValue = K;q.path = function (a, c) { + var d = h.str(a) ? e(a)[0] : a, + b = c || 100;return function (a) { + return { el: d, property: a, totalLength: N(d) * (b / 100) }; + }; + };q.setDashoffset = function (a) { + var c = N(a);a.setAttribute("stroke-dasharray", c);return c; + };q.bezier = A;q.easings = Q;q.timeline = function (a) { + var c = q(a);c.pause();c.duration = 0;c.add = function (d) { + c.children.forEach(function (a) { + a.began = !0;a.completed = !0; + });m(d).forEach(function (b) { + var d = z(b, D(S, a || {}));d.targets = d.targets || a.targets;b = c.duration;var e = d.offset;d.autoplay = !1;d.direction = c.direction;d.offset = h.und(e) ? b : L(e, b);c.began = !0;c.completed = !0;c.seek(d.offset);d = q(d);d.began = !0;d.completed = !0;d.duration > b && (c.duration = d.duration);c.children.push(d); + });c.seek(0);c.reset();c.autoplay && c.restart();return c; + };return c; + };q.random = function (a, c) { + return Math.floor(Math.random() * (c - a + 1)) + a; + };return q; +}); +;(function ($, anim) { + 'use strict'; + + var _defaults = { + accordion: true, + onOpenStart: undefined, + onOpenEnd: undefined, + onCloseStart: undefined, + onCloseEnd: undefined, + inDuration: 300, + outDuration: 300 + }; + + /** + * @class + * + */ + + var Collapsible = function (_Component) { + _inherits(Collapsible, _Component); + + /** + * Construct Collapsible instance + * @constructor + * @param {Element} el + * @param {Object} options + */ + function Collapsible(el, options) { + _classCallCheck(this, Collapsible); + + var _this3 = _possibleConstructorReturn(this, (Collapsible.__proto__ || Object.getPrototypeOf(Collapsible)).call(this, Collapsible, el, options)); + + _this3.el.M_Collapsible = _this3; + + /** + * Options for the collapsible + * @member Collapsible#options + * @prop {Boolean} [accordion=false] - Type of the collapsible + * @prop {Function} onOpenStart - Callback function called before collapsible is opened + * @prop {Function} onOpenEnd - Callback function called after collapsible is opened + * @prop {Function} onCloseStart - Callback function called before collapsible is closed + * @prop {Function} onCloseEnd - Callback function called after collapsible is closed + * @prop {Number} inDuration - Transition in duration in milliseconds. + * @prop {Number} outDuration - Transition duration in milliseconds. + */ + _this3.options = $.extend({}, Collapsible.defaults, options); + + // Setup tab indices + _this3.$headers = _this3.$el.children('li').children('.collapsible-header'); + _this3.$headers.attr('tabindex', 0); + + _this3._setupEventHandlers(); + + // Open first active + var $activeBodies = _this3.$el.children('li.active').children('.collapsible-body'); + if (_this3.options.accordion) { + // Handle Accordion + $activeBodies.first().css('display', 'block'); + } else { + // Handle Expandables + $activeBodies.css('display', 'block'); + } + return _this3; + } + + _createClass(Collapsible, [{ + key: "destroy", + + + /** + * Teardown component + */ + value: function destroy() { + this._removeEventHandlers(); + this.el.M_Collapsible = undefined; + } + + /** + * Setup Event Handlers + */ + + }, { + key: "_setupEventHandlers", + value: function _setupEventHandlers() { + var _this4 = this; + + this._handleCollapsibleClickBound = this._handleCollapsibleClick.bind(this); + this._handleCollapsibleKeydownBound = this._handleCollapsibleKeydown.bind(this); + this.el.addEventListener('click', this._handleCollapsibleClickBound); + this.$headers.each(function (header) { + header.addEventListener('keydown', _this4._handleCollapsibleKeydownBound); + }); + } + + /** + * Remove Event Handlers + */ + + }, { + key: "_removeEventHandlers", + value: function _removeEventHandlers() { + this.el.removeEventListener('click', this._handleCollapsibleClickBound); + } + + /** + * Handle Collapsible Click + * @param {Event} e + */ + + }, { + key: "_handleCollapsibleClick", + value: function _handleCollapsibleClick(e) { + var $header = $(e.target).closest('.collapsible-header'); + if (e.target && $header.length) { + var $collapsible = $header.closest('.collapsible'); + if ($collapsible[0] === this.el) { + var $collapsibleLi = $header.closest('li'); + var $collapsibleLis = $collapsible.children('li'); + var isActive = $collapsibleLi[0].classList.contains('active'); + var index = $collapsibleLis.index($collapsibleLi); + + if (isActive) { + this.close(index); + } else { + this.open(index); + } + } + } + } + + /** + * Handle Collapsible Keydown + * @param {Event} e + */ + + }, { + key: "_handleCollapsibleKeydown", + value: function _handleCollapsibleKeydown(e) { + if (e.keyCode === 13) { + this._handleCollapsibleClickBound(e); + } + } + + /** + * Animate in collapsible slide + * @param {Number} index - 0th index of slide + */ + + }, { + key: "_animateIn", + value: function _animateIn(index) { + var _this5 = this; + + var $collapsibleLi = this.$el.children('li').eq(index); + if ($collapsibleLi.length) { + var $body = $collapsibleLi.children('.collapsible-body'); + + anim.remove($body[0]); + $body.css({ + display: 'block', + overflow: 'hidden', + height: 0, + paddingTop: '', + paddingBottom: '' + }); + + var pTop = $body.css('padding-top'); + var pBottom = $body.css('padding-bottom'); + var finalHeight = $body[0].scrollHeight; + $body.css({ + paddingTop: 0, + paddingBottom: 0 + }); + + anim({ + targets: $body[0], + height: finalHeight, + paddingTop: pTop, + paddingBottom: pBottom, + duration: this.options.inDuration, + easing: 'easeInOutCubic', + complete: function (anim) { + $body.css({ + overflow: '', + paddingTop: '', + paddingBottom: '', + height: '' + }); + + // onOpenEnd callback + if (typeof _this5.options.onOpenEnd === 'function') { + _this5.options.onOpenEnd.call(_this5, $collapsibleLi[0]); + } + } + }); + } + } + + /** + * Animate out collapsible slide + * @param {Number} index - 0th index of slide to open + */ + + }, { + key: "_animateOut", + value: function _animateOut(index) { + var _this6 = this; + + var $collapsibleLi = this.$el.children('li').eq(index); + if ($collapsibleLi.length) { + var $body = $collapsibleLi.children('.collapsible-body'); + anim.remove($body[0]); + $body.css('overflow', 'hidden'); + anim({ + targets: $body[0], + height: 0, + paddingTop: 0, + paddingBottom: 0, + duration: this.options.outDuration, + easing: 'easeInOutCubic', + complete: function () { + $body.css({ + height: '', + overflow: '', + padding: '', + display: '' + }); + + // onCloseEnd callback + if (typeof _this6.options.onCloseEnd === 'function') { + _this6.options.onCloseEnd.call(_this6, $collapsibleLi[0]); + } + } + }); + } + } + + /** + * Open Collapsible + * @param {Number} index - 0th index of slide + */ + + }, { + key: "open", + value: function open(index) { + var _this7 = this; + + var $collapsibleLi = this.$el.children('li').eq(index); + if ($collapsibleLi.length && !$collapsibleLi[0].classList.contains('active')) { + + // onOpenStart callback + if (typeof this.options.onOpenStart === 'function') { + this.options.onOpenStart.call(this, $collapsibleLi[0]); + } + + // Handle accordion behavior + if (this.options.accordion) { + var $collapsibleLis = this.$el.children('li'); + var $activeLis = this.$el.children('li.active'); + $activeLis.each(function (el) { + var index = $collapsibleLis.index($(el)); + _this7.close(index); + }); + } + + // Animate in + $collapsibleLi[0].classList.add('active'); + this._animateIn(index); + } + } + + /** + * Close Collapsible + * @param {Number} index - 0th index of slide + */ + + }, { + key: "close", + value: function close(index) { + var $collapsibleLi = this.$el.children('li').eq(index); + if ($collapsibleLi.length && $collapsibleLi[0].classList.contains('active')) { + + // onCloseStart callback + if (typeof this.options.onCloseStart === 'function') { + this.options.onCloseStart.call(this, $collapsibleLi[0]); + } + + // Animate out + $collapsibleLi[0].classList.remove('active'); + this._animateOut(index); + } + } + }], [{ + key: "init", + value: function init(els, options) { + return _get(Collapsible.__proto__ || Object.getPrototypeOf(Collapsible), "init", this).call(this, this, els, options); + } + + /** + * Get Instance + */ + + }, { + key: "getInstance", + value: function getInstance(el) { + var domElem = !!el.jquery ? el[0] : el; + return domElem.M_Collapsible; + } + }, { + key: "defaults", + get: function () { + return _defaults; + } + }]); + + return Collapsible; + }(Component); + + M.Collapsible = Collapsible; + + if (M.jQueryLoaded) { + M.initializeJqueryWrapper(Collapsible, 'collapsible', 'M_Collapsible'); + } +})(cash, M.anime); +;(function ($, anim) { + 'use strict'; + + var _defaults = { + alignment: 'left', + autoFocus: true, + constrainWidth: true, + container: null, + coverTrigger: true, + closeOnClick: true, + hover: false, + inDuration: 150, + outDuration: 250, + onOpenStart: null, + onOpenEnd: null, + onCloseStart: null, + onCloseEnd: null + }; + + /** + * @class + */ + + var Dropdown = function (_Component2) { + _inherits(Dropdown, _Component2); + + function Dropdown(el, options) { + _classCallCheck(this, Dropdown); + + var _this8 = _possibleConstructorReturn(this, (Dropdown.__proto__ || Object.getPrototypeOf(Dropdown)).call(this, Dropdown, el, options)); + + _this8.el.M_Dropdown = _this8; + Dropdown._dropdowns.push(_this8); + + _this8.id = M.getIdFromTrigger(el); + _this8.dropdownEl = document.getElementById(_this8.id); + _this8.$dropdownEl = $(_this8.dropdownEl); + + /** + * Options for the dropdown + * @member Dropdown#options + * @prop {String} [alignment='left'] - Edge which the dropdown is aligned to + * @prop {Boolean} [autoFocus=true] - Automatically focus dropdown el for keyboard + * @prop {Boolean} [constrainWidth=true] - Constrain width to width of the button + * @prop {Element} container - Container element to attach dropdown to (optional) + * @prop {Boolean} [coverTrigger=true] - Place dropdown over trigger + * @prop {Boolean} [closeOnClick=true] - Close on click of dropdown item + * @prop {Boolean} [hover=false] - Open dropdown on hover + * @prop {Number} [inDuration=150] - Duration of open animation in ms + * @prop {Number} [outDuration=250] - Duration of close animation in ms + * @prop {Function} onOpenStart - Function called when dropdown starts opening + * @prop {Function} onOpenEnd - Function called when dropdown finishes opening + * @prop {Function} onCloseStart - Function called when dropdown starts closing + * @prop {Function} onCloseEnd - Function called when dropdown finishes closing + */ + _this8.options = $.extend({}, Dropdown.defaults, options); + + /** + * Describes open/close state of dropdown + * @type {Boolean} + */ + _this8.isOpen = false; + + /** + * Describes if dropdown content is scrollable + * @type {Boolean} + */ + _this8.isScrollable = false; + + /** + * Describes if touch moving on dropdown content + * @type {Boolean} + */ + _this8.isTouchMoving = false; + + _this8.focusedIndex = -1; + _this8.filterQuery = []; + + // Move dropdown-content after dropdown-trigger + if (!!_this8.options.container) { + $(_this8.options.container).append(_this8.dropdownEl); + } else { + _this8.$el.after(_this8.dropdownEl); + } + + _this8._makeDropdownFocusable(); + _this8._resetFilterQueryBound = _this8._resetFilterQuery.bind(_this8); + _this8._handleDocumentClickBound = _this8._handleDocumentClick.bind(_this8); + _this8._handleDocumentTouchmoveBound = _this8._handleDocumentTouchmove.bind(_this8); + _this8._handleDropdownKeydownBound = _this8._handleDropdownKeydown.bind(_this8); + _this8._handleTriggerKeydownBound = _this8._handleTriggerKeydown.bind(_this8); + _this8._setupEventHandlers(); + return _this8; + } + + _createClass(Dropdown, [{ + key: "destroy", + + + /** + * Teardown component + */ + value: function destroy() { + this._resetDropdownStyles(); + this._removeEventHandlers(); + Dropdown._dropdowns.splice(Dropdown._dropdowns.indexOf(this), 1); + this.el.M_Dropdown = undefined; + } + + /** + * Setup Event Handlers + */ + + }, { + key: "_setupEventHandlers", + value: function _setupEventHandlers() { + // Trigger keydown handler + this.el.addEventListener('keydown', this._handleTriggerKeydownBound); + + // Hover event handlers + if (this.options.hover) { + this._handleMouseEnterBound = this._handleMouseEnter.bind(this); + this.el.addEventListener('mouseenter', this._handleMouseEnterBound); + this._handleMouseLeaveBound = this._handleMouseLeave.bind(this); + this.el.addEventListener('mouseleave', this._handleMouseLeaveBound); + this.dropdownEl.addEventListener('mouseleave', this._handleMouseLeaveBound); + + // Click event handlers + } else { + this._handleClickBound = this._handleClick.bind(this); + this.el.addEventListener('click', this._handleClickBound); + } + } + + /** + * Remove Event Handlers + */ + + }, { + key: "_removeEventHandlers", + value: function _removeEventHandlers() { + // Trigger keydown handler + this.el.removeEventListener('keydown', this._handleTriggerKeydownBound); + + if (this.options.hover) { + this.el.removeEventHandlers('mouseenter', this._handleMouseEnterBound); + this.el.removeEventHandlers('mouseleave', this._handleMouseLeaveBound); + this.dropdownEl.removeEventHandlers('mouseleave', this._handleMouseLeaveBound); + } else { + this.el.removeEventListener('click', this._handleClickBound); + } + } + }, { + key: "_setupTemporaryEventHandlers", + value: function _setupTemporaryEventHandlers() { + // Use capture phase event handler to prevent click + document.body.addEventListener('click', this._handleDocumentClickBound, true); + document.body.addEventListener('touchend', this._handleDocumentClickBound); + document.body.addEventListener('touchmove', this._handleDocumentTouchmoveBound); + this.dropdownEl.addEventListener('keydown', this._handleDropdownKeydownBound); + } + }, { + key: "_removeTemporaryEventHandlers", + value: function _removeTemporaryEventHandlers() { + // Use capture phase event handler to prevent click + document.body.removeEventListener('click', this._handleDocumentClickBound, true); + document.body.removeEventListener('touchend', this._handleDocumentClickBound); + document.body.removeEventListener('touchmove', this._handleDocumentTouchmoveBound); + this.dropdownEl.removeEventListener('keydown', this._handleDropdownKeydownBound); + } + }, { + key: "_handleClick", + value: function _handleClick(e) { + e.preventDefault(); + this.open(); + } + }, { + key: "_handleMouseEnter", + value: function _handleMouseEnter() { + this.open(); + } + }, { + key: "_handleMouseLeave", + value: function _handleMouseLeave(e) { + var toEl = e.toElement || e.relatedTarget; + var leaveToDropdownContent = !!$(toEl).closest('.dropdown-content').length; + var leaveToActiveDropdownTrigger = false; + + var $closestTrigger = $(toEl).closest('.dropdown-trigger'); + if ($closestTrigger.length && !!$closestTrigger[0].M_Dropdown && $closestTrigger[0].M_Dropdown.isOpen) { + leaveToActiveDropdownTrigger = true; + } + + // Close hover dropdown if mouse did not leave to either active dropdown-trigger or dropdown-content + if (!leaveToActiveDropdownTrigger && !leaveToDropdownContent) { + this.close(); + } + } + }, { + key: "_handleDocumentClick", + value: function _handleDocumentClick(e) { + var _this9 = this; + + var $target = $(e.target); + if (this.options.closeOnClick && $target.closest('.dropdown-content').length && !this.isTouchMoving) { + // isTouchMoving to check if scrolling on mobile. + setTimeout(function () { + _this9.close(); + }, 0); + } else if ($target.closest('.dropdown-trigger').length || !$target.closest('.dropdown-content').length) { + setTimeout(function () { + _this9.close(); + }, 0); + } + this.isTouchMoving = false; + } + }, { + key: "_handleTriggerKeydown", + value: function _handleTriggerKeydown(e) { + // ARROW DOWN OR ENTER WHEN SELECT IS CLOSED - open Dropdown + if ((e.which === M.keys.ARROW_DOWN || e.which === M.keys.ENTER) && !this.isOpen) { + e.preventDefault(); + this.open(); + } + } + + /** + * Handle Document Touchmove + * @param {Event} e + */ + + }, { + key: "_handleDocumentTouchmove", + value: function _handleDocumentTouchmove(e) { + var $target = $(e.target); + if ($target.closest('.dropdown-content').length) { + this.isTouchMoving = true; + } + } + + /** + * Handle Dropdown Keydown + * @param {Event} e + */ + + }, { + key: "_handleDropdownKeydown", + value: function _handleDropdownKeydown(e) { + if (e.which === M.keys.TAB) { + e.preventDefault(); + this.close(); + + // Navigate down dropdown list + } else if ((e.which === M.keys.ARROW_DOWN || e.which === M.keys.ARROW_UP) && this.isOpen) { + e.preventDefault(); + var direction = e.which === M.keys.ARROW_DOWN ? 1 : -1; + var newFocusedIndex = this.focusedIndex; + var foundNewIndex = false; + do { + newFocusedIndex = newFocusedIndex + direction; + + if (!!this.dropdownEl.children[newFocusedIndex] && this.dropdownEl.children[newFocusedIndex].tabIndex !== -1) { + foundNewIndex = true; + break; + } + } while (newFocusedIndex < this.dropdownEl.children.length && newFocusedIndex >= 0); + + if (foundNewIndex) { + this.focusedIndex = newFocusedIndex; + this._focusFocusedItem(); + } + + // ENTER selects choice on focused item + } else if (e.which === M.keys.ENTER && this.isOpen) { + // Search for and ' + ''; + } + }, { + key: "renderRow", + value: function renderRow(days, isRTL, isRowSelected) { + return '' + (isRTL ? days.reverse() : days).join('') + ''; + } + }, { + key: "renderTable", + value: function renderTable(opts, data, randId) { + return '
' + this.renderHead(opts) + this.renderBody(data) + '
'; + } + }, { + key: "renderHead", + value: function renderHead(opts) { + var i = void 0, + arr = []; + for (i = 0; i < 7; i++) { + arr.push('' + this.renderDayName(opts, i, true) + ''); + } + return '' + (opts.isRTL ? arr.reverse() : arr).join('') + ''; + } + }, { + key: "renderBody", + value: function renderBody(rows) { + return '' + rows.join('') + ''; + } + }, { + key: "renderTitle", + value: function renderTitle(instance, c, year, month, refYear, randId) { + var i = void 0, + j = void 0, + arr = void 0, + opts = this.options, + isMinYear = year === opts.minYear, + isMaxYear = year === opts.maxYear, + html = '
', + monthHtml = void 0, + yearHtml = void 0, + prev = true, + next = true; + + for (arr = [], i = 0; i < 12; i++) { + arr.push(''); + } + + monthHtml = ''; + + if ($.isArray(opts.yearRange)) { + i = opts.yearRange[0]; + j = opts.yearRange[1] + 1; + } else { + i = year - opts.yearRange; + j = 1 + year + opts.yearRange; + } + + for (arr = []; i < j && i <= opts.maxYear; i++) { + if (i >= opts.minYear) { + arr.push(''); + } + } + + yearHtml = ''; + + var leftArrow = ''; + html += ''; + + html += '
'; + if (opts.showMonthAfterYear) { + html += yearHtml + monthHtml; + } else { + html += monthHtml + yearHtml; + } + html += '
'; + + if (isMinYear && (month === 0 || opts.minMonth >= month)) { + prev = false; + } + + if (isMaxYear && (month === 11 || opts.maxMonth <= month)) { + next = false; + } + + // if (c === (this.options.numberOfMonths - 1) ) { + var rightArrow = ''; + html += ''; + // } + + return html += '
'; + } + + /** + * refresh the HTML + */ + + }, { + key: "draw", + value: function draw(force) { + if (!this.isOpen && !force) { + return; + } + var opts = this.options, + minYear = opts.minYear, + maxYear = opts.maxYear, + minMonth = opts.minMonth, + maxMonth = opts.maxMonth, + html = '', + randId = void 0; + + if (this._y <= minYear) { + this._y = minYear; + if (!isNaN(minMonth) && this._m < minMonth) { + this._m = minMonth; + } + } + if (this._y >= maxYear) { + this._y = maxYear; + if (!isNaN(maxMonth) && this._m > maxMonth) { + this._m = maxMonth; + } + } + + randId = 'pika-title-' + Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 2); + + for (var c = 0; c < 1; c++) { + this._renderDateDisplay(); + html += this.renderTitle(this, c, this.calendars[c].year, this.calendars[c].month, this.calendars[0].year, randId) + this.render(this.calendars[c].year, this.calendars[c].month, randId); + } + + this.destroySelects(); + + this.calendarEl.innerHTML = html; + + // Init Materialize Select + var yearSelect = this.calendarEl.querySelector('.pika-select-year'); + var monthSelect = this.calendarEl.querySelector('.pika-select-month'); + M.FormSelect.init(yearSelect, { classes: 'select-year', dropdownOptions: { container: document.body, constrainWidth: false } }); + M.FormSelect.init(monthSelect, { classes: 'select-month', dropdownOptions: { container: document.body, constrainWidth: false } }); + + // Add change handlers for select + yearSelect.addEventListener('change', this._handleYearChange.bind(this)); + monthSelect.addEventListener('change', this._handleMonthChange.bind(this)); + + if (typeof this.options.onDraw === 'function') { + this.options.onDraw(this); + } + } + + /** + * Setup Event Handlers + */ + + }, { + key: "_setupEventHandlers", + value: function _setupEventHandlers() { + this._handleInputKeydownBound = this._handleInputKeydown.bind(this); + this._handleInputClickBound = this._handleInputClick.bind(this); + this._handleInputChangeBound = this._handleInputChange.bind(this); + this._handleCalendarClickBound = this._handleCalendarClick.bind(this); + this._finishSelectionBound = this._finishSelection.bind(this); + this._handleMonthChange = this._handleMonthChange.bind(this); + this._closeBound = this.close.bind(this); + + this.el.addEventListener('click', this._handleInputClickBound); + this.el.addEventListener('keydown', this._handleInputKeydownBound); + this.el.addEventListener('change', this._handleInputChangeBound); + this.calendarEl.addEventListener('click', this._handleCalendarClickBound); + this.doneBtn.addEventListener('click', this._finishSelectionBound); + this.cancelBtn.addEventListener('click', this._closeBound); + + if (this.options.showClearBtn) { + this._handleClearClickBound = this._handleClearClick.bind(this); + this.clearBtn.addEventListener('click', this._handleClearClickBound); + } + } + }, { + key: "_setupVariables", + value: function _setupVariables() { + var _this55 = this; + + this.$modalEl = $(Datepicker._template); + this.modalEl = this.$modalEl[0]; + + this.calendarEl = this.modalEl.querySelector('.pika-single'); + + this.yearTextEl = this.modalEl.querySelector('.year-text'); + this.dateTextEl = this.modalEl.querySelector('.date-text'); + if (this.options.showClearBtn) { + this.clearBtn = this.modalEl.querySelector('.datepicker-clear'); + } + this.doneBtn = this.modalEl.querySelector('.datepicker-done'); + this.cancelBtn = this.modalEl.querySelector('.datepicker-cancel'); + + this.formats = { + + d: function () { + return _this55.date.getDate(); + }, + dd: function () { + var d = _this55.date.getDate(); + return (d < 10 ? '0' : '') + d; + }, + ddd: function () { + return _this55.options.i18n.weekdaysShort[_this55.date.getDay()]; + }, + dddd: function () { + return _this55.options.i18n.weekdays[_this55.date.getDay()]; + }, + m: function () { + return _this55.date.getMonth() + 1; + }, + mm: function () { + var m = _this55.date.getMonth() + 1; + return (m < 10 ? '0' : '') + m; + }, + mmm: function () { + return _this55.options.i18n.monthsShort[_this55.date.getMonth()]; + }, + mmmm: function () { + return _this55.options.i18n.months[_this55.date.getMonth()]; + }, + yy: function () { + return ('' + _this55.date.getFullYear()).slice(2); + }, + yyyy: function () { + return _this55.date.getFullYear(); + } + }; + } + + /** + * Remove Event Handlers + */ + + }, { + key: "_removeEventHandlers", + value: function _removeEventHandlers() { + this.el.removeEventListener('click', this._handleInputClickBound); + this.el.removeEventListener('keydown', this._handleInputKeydownBound); + this.el.removeEventListener('change', this._handleInputChangeBound); + this.calendarEl.removeEventListener('click', this._handleCalendarClickBound); + } + }, { + key: "_handleInputClick", + value: function _handleInputClick() { + this.open(); + } + }, { + key: "_handleInputKeydown", + value: function _handleInputKeydown(e) { + if (e.which === M.keys.ENTER) { + e.preventDefault(); + this.open(); + } + } + }, { + key: "_handleCalendarClick", + value: function _handleCalendarClick(e) { + if (!this.isOpen) { + return; + } + + var $target = $(e.target); + if (!$target.hasClass('is-disabled')) { + if ($target.hasClass('datepicker-day-button') && !$target.hasClass('is-empty') && !$target.parent().hasClass('is-disabled')) { + this.setDate(new Date(e.target.getAttribute('data-pika-year'), e.target.getAttribute('data-pika-month'), e.target.getAttribute('data-pika-day'))); + } else if ($target.closest('.month-prev').length) { + this.prevMonth(); + } else if ($target.closest('.month-next').length) { + this.nextMonth(); + } + } + // if (!$target.hasClass('pika-select')) { + // // if this is touch event prevent mouse events emulation + // // if (e.preventDefault) { + // // e.preventDefault(); + // // } else { + // // e.returnValue = false; + // // return false; + // // } + // } else { + // this._c = true; + // } + } + }, { + key: "_handleClearClick", + value: function _handleClearClick() { + this.date = null; + this.setInputValue(); + this.close(); + } + }, { + key: "_handleMonthChange", + value: function _handleMonthChange(e) { + this.gotoMonth(e.target.value); + } + }, { + key: "_handleYearChange", + value: function _handleYearChange(e) { + this.gotoYear(e.target.value); + } + + /** + * change view to a specific month (zero-index, e.g. 0: January) + */ + + }, { + key: "gotoMonth", + value: function gotoMonth(month) { + if (!isNaN(month)) { + this.calendars[0].month = parseInt(month, 10); + this.adjustCalendars(); + } + } + + /** + * change view to a specific full year (e.g. "2012") + */ + + }, { + key: "gotoYear", + value: function gotoYear(year) { + if (!isNaN(year)) { + this.calendars[0].year = parseInt(year, 10); + this.adjustCalendars(); + } + } + }, { + key: "_handleInputChange", + value: function _handleInputChange(e) { + var date = void 0; + + // Prevent change event from being fired when triggered by the plugin + if (e.firedBy === this) { + return; + } + if (this.options.parse) { + date = this.options.parse(this.el.value, this.options.format); + } else { + date = new Date(Date.parse(this.el.value)); + } + + if (Datepicker._isDate(date)) { + this.setDate(date); + } + // if (!self._v) { + // self.show(); + // } + } + }, { + key: "renderDayName", + value: function renderDayName(opts, day, abbr) { + day += opts.firstDay; + while (day >= 7) { + day -= 7; + } + return abbr ? opts.i18n.weekdaysAbbrev[day] : opts.i18n.weekdays[day]; + } + + /** + * Set input value to the selected date and close Datepicker + */ + + }, { + key: "_finishSelection", + value: function _finishSelection() { + this.setInputValue(); + this.close(); + } + + /** + * Open Datepicker + */ + + }, { + key: "open", + value: function open() { + if (this.isOpen) { + return; + } + + this.isOpen = true; + if (typeof this.options.onOpen === 'function') { + this.options.onOpen.call(this); + } + this.draw(); + this.modal.open(); + return this; + } + + /** + * Close Datepicker + */ + + }, { + key: "close", + value: function close() { + if (!this.isOpen) { + return; + } + + this.isOpen = false; + if (typeof this.options.onClose === 'function') { + this.options.onClose.call(this); + } + this.modal.close(); + return this; + } + }], [{ + key: "init", + value: function init(els, options) { + return _get(Datepicker.__proto__ || Object.getPrototypeOf(Datepicker), "init", this).call(this, this, els, options); + } + }, { + key: "_isDate", + value: function _isDate(obj) { + return (/Date/.test(Object.prototype.toString.call(obj)) && !isNaN(obj.getTime()) + ); + } + }, { + key: "_isWeekend", + value: function _isWeekend(date) { + var day = date.getDay(); + return day === 0 || day === 6; + } + }, { + key: "_setToStartOfDay", + value: function _setToStartOfDay(date) { + if (Datepicker._isDate(date)) date.setHours(0, 0, 0, 0); + } + }, { + key: "_getDaysInMonth", + value: function _getDaysInMonth(year, month) { + return [31, Datepicker._isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]; + } + }, { + key: "_isLeapYear", + value: function _isLeapYear(year) { + // solution by Matti Virkkunen: http://stackoverflow.com/a/4881951 + return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0; + } + }, { + key: "_compareDates", + value: function _compareDates(a, b) { + // weak date comparison (use setToStartOfDay(date) to ensure correct result) + return a.getTime() === b.getTime(); + } + }, { + key: "_setToStartOfDay", + value: function _setToStartOfDay(date) { + if (Datepicker._isDate(date)) date.setHours(0, 0, 0, 0); + } + + /** + * Get Instance + */ + + }, { + key: "getInstance", + value: function getInstance(el) { + var domElem = !!el.jquery ? el[0] : el; + return domElem.M_Datepicker; + } + }, { + key: "defaults", + get: function () { + return _defaults; + } + }]); + + return Datepicker; + }(Component); + + Datepicker._template = [''].join(''); + + M.Datepicker = Datepicker; + + if (M.jQueryLoaded) { + M.initializeJqueryWrapper(Datepicker, 'datepicker', 'M_Datepicker'); + } +})(cash); +;(function ($) { + 'use strict'; + + var _defaults = { + dialRadius: 135, + outerRadius: 105, + innerRadius: 70, + tickRadius: 20, + duration: 350, + container: null, + defaultTime: 'now', // default time, 'now' or '13:14' e.g. + fromNow: 0, // Millisecond offset from the defaultTime + showClearBtn: false, + + // internationalization + i18n: { + cancel: 'Cancel', + clear: 'Clear', + done: 'Ok' + }, + + autoClose: false, // auto close when minute is selected + twelveHour: true, // change to 12 hour AM/PM clock from 24 hour + vibrate: true // vibrate the device when dragging clock hand + }; + + /** + * @class + * + */ + + var Timepicker = function (_Component16) { + _inherits(Timepicker, _Component16); + + function Timepicker(el, options) { + _classCallCheck(this, Timepicker); + + var _this56 = _possibleConstructorReturn(this, (Timepicker.__proto__ || Object.getPrototypeOf(Timepicker)).call(this, Timepicker, el, options)); + + _this56.el.M_Timepicker = _this56; + + _this56.options = $.extend({}, Timepicker.defaults, options); + + _this56.id = M.guid(); + _this56._insertHTMLIntoDOM(); + _this56._setupModal(); + _this56._setupVariables(); + _this56._setupEventHandlers(); + + _this56._clockSetup(); + _this56._pickerSetup(); + return _this56; + } + + _createClass(Timepicker, [{ + key: "destroy", + + + /** + * Teardown component + */ + value: function destroy() { + this._removeEventHandlers(); + this.modal.destroy(); + $(this.modalEl).remove(); + this.el.M_Timepicker = undefined; + } + + /** + * Setup Event Handlers + */ + + }, { + key: "_setupEventHandlers", + value: function _setupEventHandlers() { + this._handleInputKeydownBound = this._handleInputKeydown.bind(this); + this._handleInputClickBound = this._handleInputClick.bind(this); + this._handleClockClickStartBound = this._handleClockClickStart.bind(this); + this._handleDocumentClickMoveBound = this._handleDocumentClickMove.bind(this); + this._handleDocumentClickEndBound = this._handleDocumentClickEnd.bind(this); + + this.el.addEventListener('click', this._handleInputClickBound); + this.el.addEventListener('keydown', this._handleInputKeydownBound); + this.plate.addEventListener('mousedown', this._handleClockClickStartBound); + this.plate.addEventListener('touchstart', this._handleClockClickStartBound); + + $(this.spanHours).on('click', this.showView.bind(this, 'hours')); + $(this.spanMinutes).on('click', this.showView.bind(this, 'minutes')); + } + }, { + key: "_removeEventHandlers", + value: function _removeEventHandlers() { + this.el.removeEventListener('click', this._handleInputClickBound); + this.el.removeEventListener('keydown', this._handleInputKeydownBound); + } + }, { + key: "_handleInputClick", + value: function _handleInputClick() { + this.open(); + } + }, { + key: "_handleInputKeydown", + value: function _handleInputKeydown(e) { + if (e.which === M.keys.ENTER) { + e.preventDefault(); + this.open(); + } + } + }, { + key: "_handleClockClickStart", + value: function _handleClockClickStart(e) { + e.preventDefault(); + var clockPlateBR = this.plate.getBoundingClientRect(); + var offset = { x: clockPlateBR.left, y: clockPlateBR.top }; + + this.x0 = offset.x + this.options.dialRadius; + this.y0 = offset.y + this.options.dialRadius; + this.moved = false; + var clickPos = Timepicker._Pos(e); + this.dx = clickPos.x - this.x0; + this.dy = clickPos.y - this.y0; + + // Set clock hands + this.setHand(this.dx, this.dy, false); + + // Mousemove on document + document.addEventListener('mousemove', this._handleDocumentClickMoveBound); + document.addEventListener('touchmove', this._handleDocumentClickMoveBound); + + // Mouseup on document + document.addEventListener('mouseup', this._handleDocumentClickEndBound); + document.addEventListener('touchend', this._handleDocumentClickEndBound); + } + }, { + key: "_handleDocumentClickMove", + value: function _handleDocumentClickMove(e) { + e.preventDefault(); + var clickPos = Timepicker._Pos(e); + var x = clickPos.x - this.x0; + var y = clickPos.y - this.y0; + this.moved = true; + this.setHand(x, y, false, true); + } + }, { + key: "_handleDocumentClickEnd", + value: function _handleDocumentClickEnd(e) { + var _this57 = this; + + e.preventDefault(); + document.removeEventListener('mouseup', this._handleDocumentClickEndBound); + document.removeEventListener('touchend', this._handleDocumentClickEndBound); + var clickPos = Timepicker._Pos(e); + var x = clickPos.x - this.x0; + var y = clickPos.y - this.y0; + if (this.moved && x === this.dx && y === this.dy) { + this.setHand(x, y); + } + + if (this.currentView === 'hours') { + this.showView('minutes', this.options.duration / 2); + } else if (this.options.autoClose) { + $(this.minutesView).addClass('timepicker-dial-out'); + setTimeout(function () { + _this57.done(); + }, this.options.duration / 2); + } + + // Unbind mousemove event + document.removeEventListener('mousemove', this._handleDocumentClickMoveBound); + document.removeEventListener('touchmove', this._handleDocumentClickMoveBound); + } + }, { + key: "_insertHTMLIntoDOM", + value: function _insertHTMLIntoDOM() { + this.$modalEl = $(Timepicker._template); + this.modalEl = this.$modalEl[0]; + this.modalEl.id = 'modal-' + this.id; + + // Append popover to input by default + var containerEl = document.querySelector(this.options.container); + if (this.options.container && !!containerEl) { + this.$modalEl.appendTo(containerEl); + } else { + this.$modalEl.insertBefore(this.el); + } + } + }, { + key: "_setupModal", + value: function _setupModal() { + var _this58 = this; + + this.modal = M.Modal.init(this.modalEl, { + onCloseEnd: function () { + _this58.isOpen = false; + } + }); + } + }, { + key: "_setupVariables", + value: function _setupVariables() { + this.currentView = 'hours'; + this.vibrate = navigator.vibrate ? 'vibrate' : navigator.webkitVibrate ? 'webkitVibrate' : null; + + this._canvas = this.modalEl.querySelector('.timepicker-canvas'); + this.plate = this.modalEl.querySelector('.timepicker-plate'); + + this.hoursView = this.modalEl.querySelector('.timepicker-hours'); + this.minutesView = this.modalEl.querySelector('.timepicker-minutes'); + this.spanHours = this.modalEl.querySelector('.timepicker-span-hours'); + this.spanMinutes = this.modalEl.querySelector('.timepicker-span-minutes'); + this.spanAmPm = this.modalEl.querySelector('.timepicker-span-am-pm'); + this.footer = this.modalEl.querySelector('.timepicker-footer'); + this.amOrPm = 'PM'; + } + }, { + key: "_pickerSetup", + value: function _pickerSetup() { + + var $clearBtn = $('').appendTo(this.footer).on('click', this.clear.bind(this)); + if (this.options.showClearBtn) { + $clearBtn.css({ visibility: '' }); + } + + var confirmationBtnsContainer = $('
'); + $('').appendTo(confirmationBtnsContainer).on('click', this.close.bind(this)); + $('').appendTo(confirmationBtnsContainer).on('click', this.done.bind(this)); + confirmationBtnsContainer.appendTo(this.footer); + } + }, { + key: "_clockSetup", + value: function _clockSetup() { + if (this.options.twelveHour) { + this.$amBtn = $('
AM
'); + this.$pmBtn = $('
PM
'); + this.$amBtn.on('click', this._handleAmPmClick.bind(this)).appendTo(this.spanAmPm); + this.$pmBtn.on('click', this._handleAmPmClick.bind(this)).appendTo(this.spanAmPm); + } + + this._buildHoursView(); + this._buildMinutesView(); + this._buildSVGClock(); + } + }, { + key: "_buildSVGClock", + value: function _buildSVGClock() { + // Draw clock hands and others + var dialRadius = this.options.dialRadius; + var tickRadius = this.options.tickRadius; + var diameter = dialRadius * 2; + + var svg = Timepicker._createSVGEl('svg'); + svg.setAttribute('class', 'timepicker-svg'); + svg.setAttribute('width', diameter); + svg.setAttribute('height', diameter); + var g = Timepicker._createSVGEl('g'); + g.setAttribute('transform', 'translate(' + dialRadius + ',' + dialRadius + ')'); + var bearing = Timepicker._createSVGEl('circle'); + bearing.setAttribute('class', 'timepicker-canvas-bearing'); + bearing.setAttribute('cx', 0); + bearing.setAttribute('cy', 0); + bearing.setAttribute('r', 4); + var hand = Timepicker._createSVGEl('line'); + hand.setAttribute('x1', 0); + hand.setAttribute('y1', 0); + var bg = Timepicker._createSVGEl('circle'); + bg.setAttribute('class', 'timepicker-canvas-bg'); + bg.setAttribute('r', tickRadius); + g.appendChild(hand); + g.appendChild(bg); + g.appendChild(bearing); + svg.appendChild(g); + this._canvas.appendChild(svg); + + this.hand = hand; + this.bg = bg; + this.bearing = bearing; + this.g = g; + } + }, { + key: "_buildHoursView", + value: function _buildHoursView() { + var $tick = $('
'); + // Hours view + if (this.options.twelveHour) { + for (var i = 1; i < 13; i += 1) { + var tick = $tick.clone(); + var radian = i / 6 * Math.PI; + var radius = this.options.outerRadius; + tick.css({ + left: this.options.dialRadius + Math.sin(radian) * radius - this.options.tickRadius + 'px', + top: this.options.dialRadius - Math.cos(radian) * radius - this.options.tickRadius + 'px' + }); + tick.html(i === 0 ? '00' : i); + this.hoursView.appendChild(tick[0]); + // tick.on(mousedownEvent, mousedown); + } + } else { + for (var _i2 = 0; _i2 < 24; _i2 += 1) { + var _tick = $tick.clone(); + var _radian = _i2 / 6 * Math.PI; + var inner = _i2 > 0 && _i2 < 13; + var _radius = inner ? this.options.innerRadius : this.options.outerRadius; + _tick.css({ + left: this.options.dialRadius + Math.sin(_radian) * _radius - this.options.tickRadius + 'px', + top: this.options.dialRadius - Math.cos(_radian) * _radius - this.options.tickRadius + 'px' + }); + _tick.html(_i2 === 0 ? '00' : _i2); + this.hoursView.appendChild(_tick[0]); + // tick.on(mousedownEvent, mousedown); + } + } + } + }, { + key: "_buildMinutesView", + value: function _buildMinutesView() { + var $tick = $('
'); + // Minutes view + for (var i = 0; i < 60; i += 5) { + var tick = $tick.clone(); + var radian = i / 30 * Math.PI; + tick.css({ + left: this.options.dialRadius + Math.sin(radian) * this.options.outerRadius - this.options.tickRadius + 'px', + top: this.options.dialRadius - Math.cos(radian) * this.options.outerRadius - this.options.tickRadius + 'px' + }); + tick.html(Timepicker._addLeadingZero(i)); + this.minutesView.appendChild(tick[0]); + } + } + }, { + key: "_handleAmPmClick", + value: function _handleAmPmClick(e) { + var $btnClicked = $(e.target); + this.amOrPm = $btnClicked.hasClass('am-btn') ? 'AM' : 'PM'; + this._updateAmPmView(); + } + }, { + key: "_updateAmPmView", + value: function _updateAmPmView() { + if (this.options.twelveHour) { + this.$amBtn.toggleClass('text-primary', this.amOrPm === 'AM'); + this.$pmBtn.toggleClass('text-primary', this.amOrPm === 'PM'); + } + } + }, { + key: "_updateTimeFromInput", + value: function _updateTimeFromInput() { + // Get the time + var value = ((this.el.value || this.options.defaultTime || '') + '').split(':'); + if (this.options.twelveHour && !(typeof value[1] === 'undefined')) { + if (value[1].toUpperCase().indexOf("AM") > 0) { + this.amOrPm = 'AM'; + } else { + this.amOrPm = 'PM'; + } + value[1] = value[1].replace("AM", "").replace("PM", ""); + } + if (value[0] === 'now') { + var now = new Date(+new Date() + this.options.fromNow); + value = [now.getHours(), now.getMinutes()]; + if (this.options.twelveHour) { + this.amOrPm = value[0] >= 12 && value[0] < 24 ? 'PM' : 'AM'; + } + } + this.hours = +value[0] || 0; + this.minutes = +value[1] || 0; + this.spanHours.innerHTML = this.hours; + this.spanMinutes.innerHTML = Timepicker._addLeadingZero(this.minutes); + + this._updateAmPmView(); + } + }, { + key: "showView", + value: function showView(view, delay) { + if (view === 'minutes' && $(this.hoursView).css("visibility") === "visible") { + // raiseCallback(this.options.beforeHourSelect); + } + var isHours = view === 'hours', + nextView = isHours ? this.hoursView : this.minutesView, + hideView = isHours ? this.minutesView : this.hoursView; + this.currentView = view; + + $(this.spanHours).toggleClass('text-primary', isHours); + $(this.spanMinutes).toggleClass('text-primary', !isHours); + + // Transition view + hideView.classList.add('timepicker-dial-out'); + $(nextView).css('visibility', 'visible').removeClass('timepicker-dial-out'); + + // Reset clock hand + this.resetClock(delay); + + // After transitions ended + clearTimeout(this.toggleViewTimer); + this.toggleViewTimer = setTimeout(function () { + $(hideView).css('visibility', 'hidden'); + }, this.options.duration); + } + }, { + key: "resetClock", + value: function resetClock(delay) { + var view = this.currentView, + value = this[view], + isHours = view === 'hours', + unit = Math.PI / (isHours ? 6 : 30), + radian = value * unit, + radius = isHours && value > 0 && value < 13 ? this.options.innerRadius : this.options.outerRadius, + x = Math.sin(radian) * radius, + y = -Math.cos(radian) * radius, + self = this; + + if (delay) { + $(this.canvas).addClass('timepicker-canvas-out'); + setTimeout(function () { + $(self.canvas).removeClass('timepicker-canvas-out'); + self.setHand(x, y); + }, delay); + } else { + this.setHand(x, y); + } + } + }, { + key: "setHand", + value: function setHand(x, y, roundBy5) { + var _this59 = this; + + var radian = Math.atan2(x, -y), + isHours = this.currentView === 'hours', + unit = Math.PI / (isHours || roundBy5 ? 6 : 30), + z = Math.sqrt(x * x + y * y), + inner = isHours && z < (this.options.outerRadius + this.options.innerRadius) / 2, + radius = inner ? this.options.innerRadius : this.options.outerRadius; + + if (this.options.twelveHour) { + radius = this.options.outerRadius; + } + + // Radian should in range [0, 2PI] + if (radian < 0) { + radian = Math.PI * 2 + radian; + } + + // Get the round value + var value = Math.round(radian / unit); + + // Get the round radian + radian = value * unit; + + // Correct the hours or minutes + if (this.options.twelveHour) { + if (isHours) { + if (value === 0) value = 12; + } else { + if (roundBy5) value *= 5; + if (value === 60) value = 0; + } + } else { + if (isHours) { + if (value === 12) { + value = 0; + } + value = inner ? value === 0 ? 12 : value : value === 0 ? 0 : value + 12; + } else { + if (roundBy5) { + value *= 5; + } + if (value === 60) { + value = 0; + } + } + } + + // Once hours or minutes changed, vibrate the device + if (this[this.currentView] !== value) { + if (this.vibrate && this.options.vibrate) { + // Do not vibrate too frequently + if (!this.vibrateTimer) { + navigator[this.vibrate](10); + this.vibrateTimer = setTimeout(function () { + _this59.vibrateTimer = null; + }, 100); + } + } + } + + this[this.currentView] = value; + if (isHours) { + this['spanHours'].innerHTML = value; + } else { + this['spanMinutes'].innerHTML = Timepicker._addLeadingZero(value); + } + + // Set clock hand and others' position + var cx1 = Math.sin(radian) * (radius - this.options.tickRadius), + cy1 = -Math.cos(radian) * (radius - this.options.tickRadius), + cx2 = Math.sin(radian) * radius, + cy2 = -Math.cos(radian) * radius; + this.hand.setAttribute('x2', cx1); + this.hand.setAttribute('y2', cy1); + this.bg.setAttribute('cx', cx2); + this.bg.setAttribute('cy', cy2); + } + }, { + key: "open", + value: function open() { + if (this.isOpen) { + return; + } + + this.isOpen = true; + this._updateTimeFromInput(); + this.showView('hours'); + this.modal.open(); + } + }, { + key: "close", + value: function close() { + if (!this.isOpen) { + return; + } + + this.isOpen = false; + this.modal.close(); + } + + /** + * Finish timepicker selection. + */ + + }, { + key: "done", + value: function done(e, clearValue) { + // Set input value + var last = this.el.value; + var value = clearValue ? '' : Timepicker._addLeadingZero(this.hours) + ':' + Timepicker._addLeadingZero(this.minutes); + this.time = value; + if (!clearValue && this.options.twelveHour) { + value = value + " " + this.amOrPm; + } + this.el.value = value; + + // Trigger change event + if (value !== last) { + this.$el.trigger('change'); + } + + this.close(); + this.el.focus(); + } + }, { + key: "clear", + value: function clear() { + this.done(null, true); + } + }], [{ + key: "init", + value: function init(els, options) { + return _get(Timepicker.__proto__ || Object.getPrototypeOf(Timepicker), "init", this).call(this, this, els, options); + } + }, { + key: "_addLeadingZero", + value: function _addLeadingZero(num) { + return (num < 10 ? '0' : '') + num; + } + }, { + key: "_createSVGEl", + value: function _createSVGEl(name) { + var svgNS = 'http://www.w3.org/2000/svg'; + return document.createElementNS(svgNS, name); + } + + /** + * @typedef {Object} Point + * @property {number} x The X Coordinate + * @property {number} y The Y Coordinate + */ + + /** + * Get x position of mouse or touch event + * @param {Event} e + * @return {Point} x and y location + */ + + }, { + key: "_Pos", + value: function _Pos(e) { + if (e.targetTouches && e.targetTouches.length >= 1) { + return { x: e.targetTouches[0].clientX, y: e.targetTouches[0].clientY }; + } + // mouse event + return { x: e.clientX, y: e.clientY }; + } + + /** + * Get Instance + */ + + }, { + key: "getInstance", + value: function getInstance(el) { + var domElem = !!el.jquery ? el[0] : el; + return domElem.M_Timepicker; + } + }, { + key: "defaults", + get: function () { + return _defaults; + } + }]); + + return Timepicker; + }(Component); + + Timepicker._template = [''].join(''); + + M.Timepicker = Timepicker; + + if (M.jQueryLoaded) { + M.initializeJqueryWrapper(Timepicker, 'timepicker', 'M_Timepicker'); + } +})(cash); +;(function ($) { + 'use strict'; + + var _defaults = {}; + + /** + * @class + * + */ + + var CharacterCounter = function (_Component17) { + _inherits(CharacterCounter, _Component17); + + /** + * Construct CharacterCounter instance + * @constructor + * @param {Element} el + * @param {Object} options + */ + function CharacterCounter(el, options) { + _classCallCheck(this, CharacterCounter); + + var _this60 = _possibleConstructorReturn(this, (CharacterCounter.__proto__ || Object.getPrototypeOf(CharacterCounter)).call(this, CharacterCounter, el, options)); + + _this60.el.M_CharacterCounter = _this60; + + /** + * Options for the character counter + */ + _this60.options = $.extend({}, CharacterCounter.defaults, options); + + _this60.isInvalid = false; + _this60.isValidLength = false; + _this60._setupCounter(); + _this60._setupEventHandlers(); + return _this60; + } + + _createClass(CharacterCounter, [{ + key: "destroy", + + + /** + * Teardown component + */ + value: function destroy() { + this._removeEventHandlers(); + this.el.CharacterCounter = undefined; + this._removeCounter(); + } + + /** + * Setup Event Handlers + */ + + }, { + key: "_setupEventHandlers", + value: function _setupEventHandlers() { + this._handleUpdateCounterBound = this.updateCounter.bind(this); + + this.el.addEventListener('focus', this._handleUpdateCounterBound, true); + this.el.addEventListener('input', this._handleUpdateCounterBound, true); + } + + /** + * Remove Event Handlers + */ + + }, { + key: "_removeEventHandlers", + value: function _removeEventHandlers() { + this.el.removeEventListener('focus', this._handleUpdateCounterBound, true); + this.el.removeEventListener('input', this._handleUpdateCounterBound, true); + } + + /** + * Setup counter element + */ + + }, { + key: "_setupCounter", + value: function _setupCounter() { + this.counterEl = document.createElement('span'); + $(this.counterEl).addClass('character-counter').css({ + float: 'right', + 'font-size': '12px', + height: 1 + }); + + this.$el.parent().append(this.counterEl); + } + + /** + * Remove counter element + */ + + }, { + key: "_removeCounter", + value: function _removeCounter() { + $(this.counterEl).remove(); + } + + /** + * Update counter + */ + + }, { + key: "updateCounter", + value: function updateCounter() { + var maxLength = +this.$el.attr('data-length'), + actualLength = this.el.value.length; + this.isValidLength = actualLength <= maxLength; + var counterString = actualLength; + + if (maxLength) { + counterString += '/' + maxLength; + this._validateInput(); + } + + $(this.counterEl).html(counterString); + } + + /** + * Add validation classes + */ + + }, { + key: "_validateInput", + value: function _validateInput() { + if (this.isValidLength && this.isInvalid) { + this.isInvalid = false; + this.$el.removeClass('invalid'); + } else if (!this.isValidLength && !this.isInvalid) { + this.isInvalid = true; + this.$el.removeClass('valid'); + this.$el.addClass('invalid'); + } + } + }], [{ + key: "init", + value: function init(els, options) { + return _get(CharacterCounter.__proto__ || Object.getPrototypeOf(CharacterCounter), "init", this).call(this, this, els, options); + } + + /** + * Get Instance + */ + + }, { + key: "getInstance", + value: function getInstance(el) { + var domElem = !!el.jquery ? el[0] : el; + return domElem.M_CharacterCounter; + } + }, { + key: "defaults", + get: function () { + return _defaults; + } + }]); + + return CharacterCounter; + }(Component); + + M.CharacterCounter = CharacterCounter; + + if (M.jQueryLoaded) { + M.initializeJqueryWrapper(CharacterCounter, 'characterCounter', 'M_CharacterCounter'); + } +})(cash); +;(function ($) { + 'use strict'; + + var _defaults = { + duration: 200, // ms + dist: -100, // zoom scale TODO: make this more intuitive as an option + shift: 0, // spacing for center image + padding: 0, // Padding between non center items + numVisible: 5, // Number of visible items in carousel + fullWidth: false, // Change to full width styles + indicators: false, // Toggle indicators + noWrap: false, // Don't wrap around and cycle through items. + onCycleTo: null // Callback for when a new slide is cycled to. + }; + + /** + * @class + * + */ + + var Carousel = function (_Component18) { + _inherits(Carousel, _Component18); + + /** + * Construct Carousel instance + * @constructor + * @param {Element} el + * @param {Object} options + */ + function Carousel(el, options) { + _classCallCheck(this, Carousel); + + var _this61 = _possibleConstructorReturn(this, (Carousel.__proto__ || Object.getPrototypeOf(Carousel)).call(this, Carousel, el, options)); + + _this61.el.M_Carousel = _this61; + + /** + * Options for the carousel + * @member Carousel#options + * @prop {Number} duration + * @prop {Number} dist + * @prop {Number} shift + * @prop {Number} padding + * @prop {Number} numVisible + * @prop {Boolean} fullWidth + * @prop {Boolean} indicators + * @prop {Boolean} noWrap + * @prop {Function} onCycleTo + */ + _this61.options = $.extend({}, Carousel.defaults, options); + + // Setup + _this61.hasMultipleSlides = _this61.$el.find('.carousel-item').length > 1; + _this61.showIndicators = _this61.options.indicators && _this61.hasMultipleSlides; + _this61.noWrap = _this61.options.noWrap || !_this61.hasMultipleSlides; + _this61.pressed = false; + _this61.dragged = false; + _this61.offset = _this61.target = 0; + _this61.images = []; + _this61.itemWidth = _this61.$el.find('.carousel-item').first().innerWidth(); + _this61.itemHeight = _this61.$el.find('.carousel-item').first().innerHeight(); + _this61.dim = _this61.itemWidth * 2 + _this61.options.padding || 1; // Make sure dim is non zero for divisions. + _this61._autoScrollBound = _this61._autoScroll.bind(_this61); + _this61._trackBound = _this61._track.bind(_this61); + + // Full Width carousel setup + if (_this61.options.fullWidth) { + _this61.options.dist = 0; + _this61._setCarouselHeight(); + + // Offset fixed items when indicators. + if (_this61.showIndicators) { + _this61.$el.find('.carousel-fixed-item').addClass('with-indicators'); + } + } + + // Iterate through slides + _this61.$indicators = $('
    '); + _this61.$el.find('.carousel-item').each(function (el, i) { + _this61.images.push(el); + if (_this61.showIndicators) { + var $indicator = $('
  • '); + + // Add active to first by default. + if (i === 0) { + $indicator[0].classList.add('active'); + } + + _this61.$indicators.append($indicator); + } + }); + if (_this61.showIndicators) { + _this61.$el.append(_this61.$indicators); + } + _this61.count = _this61.images.length; + + // Cap numVisible at count + _this61.options.numVisible = Math.min(_this61.count, _this61.options.numVisible); + + // Setup cross browser string + _this61.xform = 'transform'; + ['webkit', 'Moz', 'O', 'ms'].every(function (prefix) { + var e = prefix + 'Transform'; + if (typeof document.body.style[e] !== 'undefined') { + _this61.xform = e; + return false; + } + return true; + }); + + _this61._setupEventHandlers(); + _this61._scroll(_this61.offset); + return _this61; + } + + _createClass(Carousel, [{ + key: "destroy", + + + /** + * Teardown component + */ + value: function destroy() { + this._removeEventHandlers(); + this.el.M_Carousel = undefined; + } + + /** + * Setup Event Handlers + */ + + }, { + key: "_setupEventHandlers", + value: function _setupEventHandlers() { + var _this62 = this; + + this._handleCarouselTapBound = this._handleCarouselTap.bind(this); + this._handleCarouselDragBound = this._handleCarouselDrag.bind(this); + this._handleCarouselReleaseBound = this._handleCarouselRelease.bind(this); + this._handleCarouselClickBound = this._handleCarouselClick.bind(this); + + if (typeof window.ontouchstart !== 'undefined') { + this.el.addEventListener('touchstart', this._handleCarouselTapBound); + this.el.addEventListener('touchmove', this._handleCarouselDragBound); + this.el.addEventListener('touchend', this._handleCarouselReleaseBound); + } + + this.el.addEventListener('mousedown', this._handleCarouselTapBound); + this.el.addEventListener('mousemove', this._handleCarouselDragBound); + this.el.addEventListener('mouseup', this._handleCarouselReleaseBound); + this.el.addEventListener('mouseleave', this._handleCarouselReleaseBound); + this.el.addEventListener('click', this._handleCarouselClickBound); + + if (this.showIndicators && this.$indicators) { + this._handleIndicatorClickBound = this._handleIndicatorClick.bind(this); + this.$indicators.find('.indicator-item').each(function (el, i) { + el.addEventListener('click', _this62._handleIndicatorClickBound); + }); + } + + // Resize + var throttledResize = M.throttle(this._handleResize, 200); + this._handleThrottledResizeBound = throttledResize.bind(this); + + window.addEventListener('resize', this._handleThrottledResizeBound); + } + + /** + * Remove Event Handlers + */ + + }, { + key: "_removeEventHandlers", + value: function _removeEventHandlers() { + var _this63 = this; + + if (typeof window.ontouchstart !== 'undefined') { + this.el.removeEventListener('touchstart', this._handleCarouselTapBound); + this.el.removeEventListener('touchmove', this._handleCarouselDragBound); + this.el.removeEventListener('touchend', this._handleCarouselReleaseBound); + } + this.el.removeEventListener('mousedown', this._handleCarouselTapBound); + this.el.removeEventListener('mousemove', this._handleCarouselDragBound); + this.el.removeEventListener('mouseup', this._handleCarouselReleaseBound); + this.el.removeEventListener('mouseleave', this._handleCarouselReleaseBound); + this.el.removeEventListener('click', this._handleCarouselClickBound); + + if (this.showIndicators && this.$indicators) { + this.$indicators.find('.indicator-item').each(function (el, i) { + el.removeEventListener('click', _this63._handleIndicatorClickBound); + }); + } + + window.removeEventListener('resize', this._handleThrottledResizeBound); + } + + /** + * Handle Carousel Tap + * @param {Event} e + */ + + }, { + key: "_handleCarouselTap", + value: function _handleCarouselTap(e) { + // Fixes firefox draggable image bug + if (e.type === 'mousedown' && $(e.target).is('img')) { + e.preventDefault(); + } + this.pressed = true; + this.dragged = false; + this.verticalDragged = false; + this.reference = this._xpos(e); + this.referenceY = this._ypos(e); + + this.velocity = this.amplitude = 0; + this.frame = this.offset; + this.timestamp = Date.now(); + clearInterval(this.ticker); + this.ticker = setInterval(this._trackBound, 100); + } + + /** + * Handle Carousel Drag + * @param {Event} e + */ + + }, { + key: "_handleCarouselDrag", + value: function _handleCarouselDrag(e) { + var x = void 0, + y = void 0, + delta = void 0, + deltaY = void 0; + if (this.pressed) { + x = this._xpos(e); + y = this._ypos(e); + delta = this.reference - x; + deltaY = Math.abs(this.referenceY - y); + if (deltaY < 30 && !this.verticalDragged) { + // If vertical scrolling don't allow dragging. + if (delta > 2 || delta < -2) { + this.dragged = true; + this.reference = x; + this._scroll(this.offset + delta); + } + } else if (this.dragged) { + // If dragging don't allow vertical scroll. + e.preventDefault(); + e.stopPropagation(); + return false; + } else { + // Vertical scrolling. + this.verticalDragged = true; + } + } + + if (this.dragged) { + // If dragging don't allow vertical scroll. + e.preventDefault(); + e.stopPropagation(); + return false; + } + } + + /** + * Handle Carousel Release + * @param {Event} e + */ + + }, { + key: "_handleCarouselRelease", + value: function _handleCarouselRelease(e) { + if (this.pressed) { + this.pressed = false; + } else { + return; + } + + clearInterval(this.ticker); + this.target = this.offset; + if (this.velocity > 10 || this.velocity < -10) { + this.amplitude = 0.9 * this.velocity; + this.target = this.offset + this.amplitude; + } + this.target = Math.round(this.target / this.dim) * this.dim; + + // No wrap of items. + if (this.noWrap) { + if (this.target >= this.dim * (this.count - 1)) { + this.target = this.dim * (this.count - 1); + } else if (this.target < 0) { + this.target = 0; + } + } + this.amplitude = this.target - this.offset; + this.timestamp = Date.now(); + requestAnimationFrame(this._autoScrollBound); + + if (this.dragged) { + e.preventDefault(); + e.stopPropagation(); + } + return false; + } + + /** + * Handle Carousel CLick + * @param {Event} e + */ + + }, { + key: "_handleCarouselClick", + value: function _handleCarouselClick(e) { + // Disable clicks if carousel was dragged. + if (this.dragged) { + e.preventDefault(); + e.stopPropagation(); + return false; + } else if (!this.options.fullWidth) { + var clickedIndex = $(e.target).closest('.carousel-item').index(); + var diff = this._wrap(this.center) - clickedIndex; + + // Disable clicks if carousel was shifted by click + if (diff !== 0) { + e.preventDefault(); + e.stopPropagation(); + } + this._cycleTo(clickedIndex); + } + } + + /** + * Handle Indicator CLick + * @param {Event} e + */ + + }, { + key: "_handleIndicatorClick", + value: function _handleIndicatorClick(e) { + e.stopPropagation(); + + var indicator = $(e.target).closest('.indicator-item'); + if (indicator.length) { + this._cycleTo(indicator.index()); + } + } + + /** + * Handle Throttle Resize + * @param {Event} e + */ + + }, { + key: "_handleResize", + value: function _handleResize(e) { + if (this.options.fullWidth) { + this.itemWidth = this.$el.find('.carousel-item').first().innerWidth(); + this.imageHeight = this.$el.find('.carousel-item.active').height(); + this.dim = this.itemWidth * 2 + this.options.padding; + this.offset = this.center * 2 * this.itemWidth; + this.target = this.offset; + this._setCarouselHeight(true); + } else { + this._scroll(); + } + } + + /** + * Set carousel height based on first slide + * @param {Booleam} imageOnly - true for image slides + */ + + }, { + key: "_setCarouselHeight", + value: function _setCarouselHeight(imageOnly) { + var _this64 = this; + + var firstSlide = this.$el.find('.carousel-item.active').length ? this.$el.find('.carousel-item.active').first() : this.$el.find('.carousel-item').first(); + var firstImage = firstSlide.find('img').first(); + if (firstImage.length) { + if (firstImage[0].complete) { + // If image won't trigger the load event + var imageHeight = firstImage.height(); + if (imageHeight > 0) { + this.$el.css('height', imageHeight + 'px'); + } else { + // If image still has no height, use the natural dimensions to calculate + var naturalWidth = firstImage[0].naturalWidth; + var naturalHeight = firstImage[0].naturalHeight; + var adjustedHeight = this.$el.width() / naturalWidth * naturalHeight; + this.$el.css('height', adjustedHeight + 'px'); + } + } else { + // Get height when image is loaded normally + firstImage.one('load', function (el, i) { + _this64.$el.css('height', el.offsetHeight + 'px'); + }); + } + } else if (!imageOnly) { + var slideHeight = firstSlide.height(); + this.$el.css('height', slideHeight + 'px'); + } + } + + /** + * Get x position from event + * @param {Event} e + */ + + }, { + key: "_xpos", + value: function _xpos(e) { + // touch event + if (e.targetTouches && e.targetTouches.length >= 1) { + return e.targetTouches[0].clientX; + } + + // mouse event + return e.clientX; + } + + /** + * Get y position from event + * @param {Event} e + */ + + }, { + key: "_ypos", + value: function _ypos(e) { + // touch event + if (e.targetTouches && e.targetTouches.length >= 1) { + return e.targetTouches[0].clientY; + } + + // mouse event + return e.clientY; + } + + /** + * Wrap index + * @param {Number} x + */ + + }, { + key: "_wrap", + value: function _wrap(x) { + return x >= this.count ? x % this.count : x < 0 ? this._wrap(this.count + x % this.count) : x; + } + + /** + * Tracks scrolling information + */ + + }, { + key: "_track", + value: function _track() { + var now = void 0, + elapsed = void 0, + delta = void 0, + v = void 0; + + now = Date.now(); + elapsed = now - this.timestamp; + this.timestamp = now; + delta = this.offset - this.frame; + this.frame = this.offset; + + v = 1000 * delta / (1 + elapsed); + this.velocity = 0.8 * v + 0.2 * this.velocity; + } + + /** + * Auto scrolls to nearest carousel item. + */ + + }, { + key: "_autoScroll", + value: function _autoScroll() { + var elapsed = void 0, + delta = void 0; + + if (this.amplitude) { + elapsed = Date.now() - this.timestamp; + delta = this.amplitude * Math.exp(-elapsed / this.options.duration); + if (delta > 2 || delta < -2) { + this._scroll(this.target - delta); + requestAnimationFrame(this._autoScrollBound); + } else { + this._scroll(this.target); + } + } + } + + /** + * Scroll to target + * @param {Number} x + */ + + }, { + key: "_scroll", + value: function _scroll(x) { + var _this65 = this; + + // Track scrolling state + if (!this.$el.hasClass('scrolling')) { + this.el.classList.add('scrolling'); + } + if (this.scrollingTimeout != null) { + window.clearTimeout(this.scrollingTimeout); + } + this.scrollingTimeout = window.setTimeout(function () { + _this65.$el.removeClass('scrolling'); + }, this.options.duration); + + // Start actual scroll + var i = void 0, + half = void 0, + delta = void 0, + dir = void 0, + tween = void 0, + el = void 0, + alignment = void 0, + zTranslation = void 0, + tweenedOpacity = void 0, + centerTweenedOpacity = void 0; + var lastCenter = this.center; + var numVisibleOffset = 1 / this.options.numVisible; + + this.offset = typeof x === 'number' ? x : this.offset; + this.center = Math.floor((this.offset + this.dim / 2) / this.dim); + delta = this.offset - this.center * this.dim; + dir = delta < 0 ? 1 : -1; + tween = -dir * delta * 2 / this.dim; + half = this.count >> 1; + + if (this.options.fullWidth) { + alignment = 'translateX(0)'; + centerTweenedOpacity = 1; + } else { + alignment = 'translateX(' + (this.el.clientWidth - this.itemWidth) / 2 + 'px) '; + alignment += 'translateY(' + (this.el.clientHeight - this.itemHeight) / 2 + 'px)'; + centerTweenedOpacity = 1 - numVisibleOffset * tween; + } + + // Set indicator active + if (this.showIndicators) { + var diff = this.center % this.count; + var activeIndicator = this.$indicators.find('.indicator-item.active'); + if (activeIndicator.index() !== diff) { + activeIndicator.removeClass('active'); + this.$indicators.find('.indicator-item').eq(diff)[0].classList.add('active'); + } + } + + // center + // Don't show wrapped items. + if (!this.noWrap || this.center >= 0 && this.center < this.count) { + el = this.images[this._wrap(this.center)]; + + // Add active class to center item. + if (!$(el).hasClass('active')) { + this.$el.find('.carousel-item').removeClass('active'); + el.classList.add('active'); + } + var transformString = alignment + ' translateX(' + -delta / 2 + 'px)' + ' translateX(' + dir * this.options.shift * tween * i + 'px)' + ' translateZ(' + this.options.dist * tween + 'px)'; + this._updateItemStyle(el, centerTweenedOpacity, 0, transformString); + } + + for (i = 1; i <= half; ++i) { + // right side + if (this.options.fullWidth) { + zTranslation = this.options.dist; + tweenedOpacity = i === half && delta < 0 ? 1 - tween : 1; + } else { + zTranslation = this.options.dist * (i * 2 + tween * dir); + tweenedOpacity = 1 - numVisibleOffset * (i * 2 + tween * dir); + } + // Don't show wrapped items. + if (!this.noWrap || this.center + i < this.count) { + el = this.images[this._wrap(this.center + i)]; + var _transformString = alignment + ' translateX(' + (this.options.shift + (this.dim * i - delta) / 2) + 'px)' + ' translateZ(' + zTranslation + 'px)'; + this._updateItemStyle(el, tweenedOpacity, -i, _transformString); + } + + // left side + if (this.options.fullWidth) { + zTranslation = this.options.dist; + tweenedOpacity = i === half && delta > 0 ? 1 - tween : 1; + } else { + zTranslation = this.options.dist * (i * 2 - tween * dir); + tweenedOpacity = 1 - numVisibleOffset * (i * 2 - tween * dir); + } + // Don't show wrapped items. + if (!this.noWrap || this.center - i >= 0) { + el = this.images[this._wrap(this.center - i)]; + var _transformString2 = alignment + ' translateX(' + (-this.options.shift + (-this.dim * i - delta) / 2) + 'px)' + ' translateZ(' + zTranslation + 'px)'; + this._updateItemStyle(el, tweenedOpacity, -i, _transformString2); + } + } + + // center + // Don't show wrapped items. + if (!this.noWrap || this.center >= 0 && this.center < this.count) { + el = this.images[this._wrap(this.center)]; + var _transformString3 = alignment + ' translateX(' + -delta / 2 + 'px)' + ' translateX(' + dir * this.options.shift * tween + 'px)' + ' translateZ(' + this.options.dist * tween + 'px)'; + this._updateItemStyle(el, centerTweenedOpacity, 0, _transformString3); + } + + // onCycleTo callback + var $currItem = this.$el.find('.carousel-item').eq(this._wrap(this.center)); + if (lastCenter !== this.center && typeof this.options.onCycleTo === "function") { + this.options.onCycleTo.call(this, $currItem[0], this.dragged); + } + + // One time callback + if (typeof this.oneTimeCallback === "function") { + this.oneTimeCallback.call(this, $currItem[0], this.dragged); + this.oneTimeCallback = null; + } + } + + /** + * Cycle to target + * @param {Element} el + * @param {Number} opacity + * @param {Number} zIndex + * @param {String} transform + */ + + }, { + key: "_updateItemStyle", + value: function _updateItemStyle(el, opacity, zIndex, transform) { + el.style[this.xform] = transform; + el.style.zIndex = zIndex; + el.style.opacity = opacity; + el.style.visibility = 'visible'; + } + + /** + * Cycle to target + * @param {Number} n + * @param {Function} callback + */ + + }, { + key: "_cycleTo", + value: function _cycleTo(n, callback) { + var diff = this.center % this.count - n; + + // Account for wraparound. + if (!this.noWrap) { + if (diff < 0) { + if (Math.abs(diff + this.count) < Math.abs(diff)) { + diff += this.count; + } + } else if (diff > 0) { + if (Math.abs(diff - this.count) < diff) { + diff -= this.count; + } + } + } + + this.target = this.dim * Math.round(this.offset / this.dim); + // Next + if (diff < 0) { + this.target += this.dim * Math.abs(diff); + + // Prev + } else if (diff > 0) { + this.target -= this.dim * diff; + } + + // Set one time callback + if (typeof callback === "function") { + this.oneTimeCallback = callback; + } + + // Scroll + if (this.offset !== this.target) { + this.amplitude = this.target - this.offset; + this.timestamp = Date.now(); + requestAnimationFrame(this._autoScrollBound); + } + } + + /** + * Cycle to next item + * @param {Number} [n] + */ + + }, { + key: "next", + value: function next(n) { + if (n === undefined || isNaN(n)) { + n = 1; + } + + var index = this.center + n; + if (index > this.count || index < 0) { + if (this.noWrap) { + return; + } + + index = this._wrap(index); + } + this._cycleTo(index); + } + + /** + * Cycle to previous item + * @param {Number} [n] + */ + + }, { + key: "prev", + value: function prev(n) { + if (n === undefined || isNaN(n)) { + n = 1; + } + + var index = this.center - n; + if (index > this.count || index < 0) { + if (this.noWrap) { + return; + } + + index = this._wrap(index); + } + + this._cycleTo(index); + } + + /** + * Cycle to nth item + * @param {Number} [n] + * @param {Function} callback + */ + + }, { + key: "set", + value: function set(n, callback) { + if (n === undefined || isNaN(n)) { + n = 0; + } + + if (n > this.count || n < 0) { + if (this.noWrap) { + return; + } + + n = this._wrap(n); + } + + this._cycleTo(n, callback); + } + }], [{ + key: "init", + value: function init(els, options) { + return _get(Carousel.__proto__ || Object.getPrototypeOf(Carousel), "init", this).call(this, this, els, options); + } + + /** + * Get Instance + */ + + }, { + key: "getInstance", + value: function getInstance(el) { + var domElem = !!el.jquery ? el[0] : el; + return domElem.M_Carousel; + } + }, { + key: "defaults", + get: function () { + return _defaults; + } + }]); + + return Carousel; + }(Component); + + M.Carousel = Carousel; + + if (M.jQueryLoaded) { + M.initializeJqueryWrapper(Carousel, 'carousel', 'M_Carousel'); + } +})(cash); +;(function ($) { + 'use strict'; + + var _defaults = { + onOpen: undefined, + onClose: undefined + }; + + /** + * @class + * + */ + + var TapTarget = function (_Component19) { + _inherits(TapTarget, _Component19); + + /** + * Construct TapTarget instance + * @constructor + * @param {Element} el + * @param {Object} options + */ + function TapTarget(el, options) { + _classCallCheck(this, TapTarget); + + var _this66 = _possibleConstructorReturn(this, (TapTarget.__proto__ || Object.getPrototypeOf(TapTarget)).call(this, TapTarget, el, options)); + + _this66.el.M_TapTarget = _this66; + + /** + * Options for the select + * @member TapTarget#options + * @prop {Function} onOpen - Callback function called when feature discovery is opened + * @prop {Function} onClose - Callback function called when feature discovery is closed + */ + _this66.options = $.extend({}, TapTarget.defaults, options); + + _this66.isOpen = false; + + // setup + _this66.$origin = $('#' + _this66.$el.attr('data-target')); + _this66._setup(); + + _this66._calculatePositioning(); + _this66._setupEventHandlers(); + return _this66; + } + + _createClass(TapTarget, [{ + key: "destroy", + + + /** + * Teardown component + */ + value: function destroy() { + this._removeEventHandlers(); + this.el.TapTarget = undefined; + } + + /** + * Setup Event Handlers + */ + + }, { + key: "_setupEventHandlers", + value: function _setupEventHandlers() { + this._handleDocumentClickBound = this._handleDocumentClick.bind(this); + this._handleTargetClickBound = this._handleTargetClick.bind(this); + this._handleOriginClickBound = this._handleOriginClick.bind(this); + + this.el.addEventListener('click', this._handleTargetClickBound); + this.originEl.addEventListener('click', this._handleOriginClickBound); + + // Resize + var throttledResize = M.throttle(this._handleResize, 200); + this._handleThrottledResizeBound = throttledResize.bind(this); + + window.addEventListener('resize', this._handleThrottledResizeBound); + } + + /** + * Remove Event Handlers + */ + + }, { + key: "_removeEventHandlers", + value: function _removeEventHandlers() { + this.el.removeEventListener('click', this._handleTargetClickBound); + this.originEl.removeEventListener('click', this._handleOriginClickBound); + window.removeEventListener('resize', this._handleThrottledResizeBound); + } + + /** + * Handle Target Click + * @param {Event} e + */ + + }, { + key: "_handleTargetClick", + value: function _handleTargetClick(e) { + this.open(); + } + + /** + * Handle Origin Click + * @param {Event} e + */ + + }, { + key: "_handleOriginClick", + value: function _handleOriginClick(e) { + this.close(); + } + + /** + * Handle Resize + * @param {Event} e + */ + + }, { + key: "_handleResize", + value: function _handleResize(e) { + this._calculatePositioning(); + } + + /** + * Handle Resize + * @param {Event} e + */ + + }, { + key: "_handleDocumentClick", + value: function _handleDocumentClick(e) { + if (!$(e.target).closest('.tap-target-wrapper').length) { + this.close(); + e.preventDefault(); + e.stopPropagation(); + } + } + + /** + * Setup Tap Target + */ + + }, { + key: "_setup", + value: function _setup() { + // Creating tap target + this.wrapper = this.$el.parent()[0]; + this.waveEl = $(this.wrapper).find('.tap-target-wave')[0]; + this.originEl = $(this.wrapper).find('.tap-target-origin')[0]; + this.contentEl = this.$el.find('.tap-target-content')[0]; + + // Creating wrapper + if (!$(this.wrapper).hasClass('.tap-target-wrapper')) { + this.wrapper = document.createElement('div'); + this.wrapper.classList.add('tap-target-wrapper'); + this.$el.before($(this.wrapper)); + this.wrapper.append(this.el); + } + + // Creating content + if (!this.contentEl) { + this.contentEl = document.createElement('div'); + this.contentEl.classList.add('tap-target-content'); + this.$el.append(this.contentEl); + } + + // Creating foreground wave + if (!this.waveEl) { + this.waveEl = document.createElement('div'); + this.waveEl.classList.add('tap-target-wave'); + + // Creating origin + if (!this.originEl) { + this.originEl = this.$origin.clone(true, true); + this.originEl.addClass('tap-target-origin'); + this.originEl.removeAttr('id'); + this.originEl.removeAttr('style'); + this.originEl = this.originEl[0]; + this.waveEl.append(this.originEl); + } + + this.wrapper.append(this.waveEl); + } + } + + /** + * Calculate positioning + */ + + }, { + key: "_calculatePositioning", + value: function _calculatePositioning() { + // Element or parent is fixed position? + var isFixed = this.$origin.css('position') === 'fixed'; + if (!isFixed) { + var parents = this.$origin.parents(); + for (var i = 0; i < parents.length; i++) { + isFixed = $(parents[i]).css('position') == 'fixed'; + if (isFixed) { + break; + } + } + } + + // Calculating origin + var originWidth = this.$origin.outerWidth(); + var originHeight = this.$origin.outerHeight(); + var originTop = isFixed ? this.$origin.offset().top - M.getDocumentScrollTop() : this.$origin.offset().top; + var originLeft = isFixed ? this.$origin.offset().left - M.getDocumentScrollLeft() : this.$origin.offset().left; + + // Calculating screen + var windowWidth = window.innerWidth; + var windowHeight = window.innerHeight; + var centerX = windowWidth / 2; + var centerY = windowHeight / 2; + var isLeft = originLeft <= centerX; + var isRight = originLeft > centerX; + var isTop = originTop <= centerY; + var isBottom = originTop > centerY; + var isCenterX = originLeft >= windowWidth * 0.25 && originLeft <= windowWidth * 0.75; + + // Calculating tap target + var tapTargetWidth = this.$el.outerWidth(); + var tapTargetHeight = this.$el.outerHeight(); + var tapTargetTop = originTop + originHeight / 2 - tapTargetHeight / 2; + var tapTargetLeft = originLeft + originWidth / 2 - tapTargetWidth / 2; + var tapTargetPosition = isFixed ? 'fixed' : 'absolute'; + + // Calculating content + var tapTargetTextWidth = isCenterX ? tapTargetWidth : tapTargetWidth / 2 + originWidth; + var tapTargetTextHeight = tapTargetHeight / 2; + var tapTargetTextTop = isTop ? tapTargetHeight / 2 : 0; + var tapTargetTextBottom = 0; + var tapTargetTextLeft = isLeft && !isCenterX ? tapTargetWidth / 2 - originWidth : 0; + var tapTargetTextRight = 0; + var tapTargetTextPadding = originWidth; + var tapTargetTextAlign = isBottom ? 'bottom' : 'top'; + + // Calculating wave + var tapTargetWaveWidth = originWidth > originHeight ? originWidth * 2 : originWidth * 2; + var tapTargetWaveHeight = tapTargetWaveWidth; + var tapTargetWaveTop = tapTargetHeight / 2 - tapTargetWaveHeight / 2; + var tapTargetWaveLeft = tapTargetWidth / 2 - tapTargetWaveWidth / 2; + + // Setting tap target + var tapTargetWrapperCssObj = {}; + tapTargetWrapperCssObj.top = isTop ? tapTargetTop + 'px' : ''; + tapTargetWrapperCssObj.right = isRight ? windowWidth - tapTargetLeft - tapTargetWidth + 'px' : ''; + tapTargetWrapperCssObj.bottom = isBottom ? windowHeight - tapTargetTop - tapTargetHeight + 'px' : ''; + tapTargetWrapperCssObj.left = isLeft ? tapTargetLeft + 'px' : ''; + tapTargetWrapperCssObj.position = tapTargetPosition; + $(this.wrapper).css(tapTargetWrapperCssObj); + + // Setting content + $(this.contentEl).css({ + width: tapTargetTextWidth + 'px', + height: tapTargetTextHeight + 'px', + top: tapTargetTextTop + 'px', + right: tapTargetTextRight + 'px', + bottom: tapTargetTextBottom + 'px', + left: tapTargetTextLeft + 'px', + padding: tapTargetTextPadding + 'px', + verticalAlign: tapTargetTextAlign + }); + + // Setting wave + $(this.waveEl).css({ + top: tapTargetWaveTop + 'px', + left: tapTargetWaveLeft + 'px', + width: tapTargetWaveWidth + 'px', + height: tapTargetWaveHeight + 'px' + }); + } + + /** + * Open TapTarget + */ + + }, { + key: "open", + value: function open() { + if (this.isOpen) { + return; + } + + // onOpen callback + if (typeof this.options.onOpen === 'function') { + this.options.onOpen.call(this, this.$origin[0]); + } + + this.isOpen = true; + this.wrapper.classList.add('open'); + + document.body.addEventListener('click', this._handleDocumentClickBound, true); + document.body.addEventListener('touchend', this._handleDocumentClickBound); + } + + /** + * Close Tap Target + */ + + }, { + key: "close", + value: function close() { + if (!this.isOpen) { + return; + } + + // onClose callback + if (typeof this.options.onClose === 'function') { + this.options.onClose.call(this, this.$origin[0]); + } + + this.isOpen = false; + this.wrapper.classList.remove('open'); + + document.body.removeEventListener('click', this._handleDocumentClickBound, true); + document.body.removeEventListener('touchend', this._handleDocumentClickBound); + } + }], [{ + key: "init", + value: function init(els, options) { + return _get(TapTarget.__proto__ || Object.getPrototypeOf(TapTarget), "init", this).call(this, this, els, options); + } + + /** + * Get Instance + */ + + }, { + key: "getInstance", + value: function getInstance(el) { + var domElem = !!el.jquery ? el[0] : el; + return domElem.M_TapTarget; + } + }, { + key: "defaults", + get: function () { + return _defaults; + } + }]); + + return TapTarget; + }(Component); + + M.TapTarget = TapTarget; + + if (M.jQueryLoaded) { + M.initializeJqueryWrapper(TapTarget, 'tapTarget', 'M_TapTarget'); + } +})(cash); +;(function ($) { + 'use strict'; + + var _defaults = { + classes: '', + dropdownOptions: {} + }; + + /** + * @class + * + */ + + var FormSelect = function (_Component20) { + _inherits(FormSelect, _Component20); + + /** + * Construct FormSelect instance + * @constructor + * @param {Element} el + * @param {Object} options + */ + function FormSelect(el, options) { + _classCallCheck(this, FormSelect); + + // Don't init if browser default version + var _this67 = _possibleConstructorReturn(this, (FormSelect.__proto__ || Object.getPrototypeOf(FormSelect)).call(this, FormSelect, el, options)); + + if (_this67.$el.hasClass('browser-default')) { + return _possibleConstructorReturn(_this67); + } + + _this67.el.M_FormSelect = _this67; + + /** + * Options for the select + * @member FormSelect#options + */ + _this67.options = $.extend({}, FormSelect.defaults, options); + + _this67.isMultiple = _this67.$el.prop('multiple'); + + // Setup + _this67.el.tabIndex = -1; + _this67._keysSelected = {}; + _this67._valueDict = {}; // Maps key to original and generated option element. + _this67._setupDropdown(); + + _this67._setupEventHandlers(); + return _this67; + } + + _createClass(FormSelect, [{ + key: "destroy", + + + /** + * Teardown component + */ + value: function destroy() { + this._removeEventHandlers(); + this._removeDropdown(); + this.el.M_FormSelect = undefined; + } + + /** + * Setup Event Handlers + */ + + }, { + key: "_setupEventHandlers", + value: function _setupEventHandlers() { + var _this68 = this; + + this._handleSelectChangeBound = this._handleSelectChange.bind(this); + this._handleOptionClickBound = this._handleOptionClick.bind(this); + this._handleInputClickBound = this._handleInputClick.bind(this); + + $(this.dropdownOptions).find('li:not(.optgroup)').each(function (el) { + el.addEventListener('click', _this68._handleOptionClickBound); + }); + this.el.addEventListener('change', this._handleSelectChangeBound); + this.input.addEventListener('click', this._handleInputClickBound); + } + + /** + * Remove Event Handlers + */ + + }, { + key: "_removeEventHandlers", + value: function _removeEventHandlers() { + var _this69 = this; + + $(this.dropdownOptions).find('li:not(.optgroup)').each(function (el) { + el.removeEventListener('click', _this69._handleOptionClickBound); + }); + this.el.removeEventListener('change', this._handleSelectChangeBound); + this.input.removeEventListener('click', this._handleInputClickBound); + } + + /** + * Handle Select Change + * @param {Event} e + */ + + }, { + key: "_handleSelectChange", + value: function _handleSelectChange(e) { + this._setValueToInput(); + } + + /** + * Handle Option Click + * @param {Event} e + */ + + }, { + key: "_handleOptionClick", + value: function _handleOptionClick(e) { + e.preventDefault(); + var option = $(e.target).closest('li')[0]; + var key = option.id; + if (!$(option).hasClass('disabled') && !$(option).hasClass('optgroup') && key.length) { + var selected = true; + + if (this.isMultiple) { + // Deselect placeholder option if still selected. + var placeholderOption = $(this.dropdownOptions).find('li.disabled.selected'); + if (placeholderOption.length) { + placeholderOption.removeClass('selected'); + placeholderOption.find('input[type="checkbox"]').prop('checked', false); + this._toggleEntryFromArray(placeholderOption[0].id); + } + + var checkbox = $(option).find('input[type="checkbox"]'); + checkbox.prop('checked', !checkbox.prop('checked')); + selected = this._toggleEntryFromArray(key); + } else { + $(this.dropdownOptions).find('li').removeClass('active'); + $(option).toggleClass('active'); + this.input.value = option.textContent; + } + + this._activateOption($(this.dropdownOptions), option); + $(this._valueDict[key].el).prop('selected', selected); + this.$el.trigger('change'); + } + + e.stopPropagation(); + } + + /** + * Handle Input Click + */ + + }, { + key: "_handleInputClick", + value: function _handleInputClick() { + if (this.dropdown && this.dropdown.isOpen) { + this._setValueToInput(); + this._setSelectedStates(); + } + } + + /** + * Setup dropdown + */ + + }, { + key: "_setupDropdown", + value: function _setupDropdown() { + var _this70 = this; + + this.wrapper = document.createElement('div'); + $(this.wrapper).addClass('select-wrapper' + ' ' + this.options.classes); + this.$el.before($(this.wrapper)); + this.wrapper.appendChild(this.el); + + if (this.el.disabled) { + this.wrapper.classList.add('disabled'); + } + + // Create dropdown + this.$selectOptions = this.$el.children('option, optgroup'); + this.dropdownOptions = document.createElement('ul'); + this.dropdownOptions.id = "select-options-" + M.guid(); + $(this.dropdownOptions).addClass('dropdown-content select-dropdown ' + (this.isMultiple ? 'multiple-select-dropdown' : '')); + + // Create dropdown structure. + if (this.$selectOptions.length) { + this.$selectOptions.each(function (el) { + if ($(el).is('option')) { + // Direct descendant option. + var optionEl = void 0; + if (_this70.isMultiple) { + optionEl = _this70._appendOptionWithIcon(_this70.$el, el, 'multiple'); + } else { + optionEl = _this70._appendOptionWithIcon(_this70.$el, el); + } + + _this70._addOptionToValueDict(el, optionEl); + } else if ($(el).is('optgroup')) { + // Optgroup. + var selectOptions = $(el).children('option'); + $(_this70.dropdownOptions).append($('
  • ' + el.getAttribute('label') + '
  • ')[0]); + + selectOptions.each(function (el) { + var optionEl = _this70._appendOptionWithIcon(_this70.$el, el, 'optgroup-option'); + _this70._addOptionToValueDict(el, optionEl); + }); + } + }); + } + + this.$el.after(this.dropdownOptions); + + // Add input dropdown + this.input = document.createElement('input'); + $(this.input).addClass('select-dropdown dropdown-trigger'); + this.input.setAttribute('type', 'text'); + this.input.setAttribute('readonly', 'true'); + this.input.setAttribute('data-target', this.dropdownOptions.id); + if (this.el.disabled) { + $(this.input).prop('disabled', 'true'); + } + + this.$el.before(this.input); + this._setValueToInput(); + + // Add caret + var dropdownIcon = $(''); + this.$el.before(dropdownIcon[0]); + + // Initialize dropdown + if (!this.el.disabled) { + var dropdownOptions = $.extend({}, this.options.dropdownOptions); + + // Add callback for centering selected option when dropdown content is scrollable + dropdownOptions.onOpenEnd = function (el) { + var selectedOption = $(_this70.dropdownOptions).find('.selected').first(); + if (_this70.dropdown.isScrollable && selectedOption.length) { + var scrollOffset = selectedOption[0].getBoundingClientRect().top - _this70.dropdownOptions.getBoundingClientRect().top; // scroll to selected option + scrollOffset -= _this70.dropdownOptions.clientHeight / 2; // center in dropdown + _this70.dropdownOptions.scrollTop = scrollOffset; + } + }; + + if (this.isMultiple) { + dropdownOptions.closeOnClick = false; + } + this.dropdown = M.Dropdown.init(this.input, dropdownOptions); + } + + // Add initial selections + this._setSelectedStates(); + } + + /** + * Add option to value dict + * @param {Element} el original option element + * @param {Element} optionEl generated option element + */ + + }, { + key: "_addOptionToValueDict", + value: function _addOptionToValueDict(el, optionEl) { + var index = Object.keys(this._valueDict).length; + var key = this.dropdownOptions.id + index; + var obj = {}; + optionEl.id = key; + + obj.el = el; + obj.optionEl = optionEl; + this._valueDict[key] = obj; + } + + /** + * Remove dropdown + */ + + }, { + key: "_removeDropdown", + value: function _removeDropdown() { + $(this.wrapper).find('.caret').remove(); + $(this.input).remove(); + $(this.dropdownOptions).remove(); + $(this.wrapper).before(this.$el); + $(this.wrapper).remove(); + } + + /** + * Setup dropdown + * @param {Element} select select element + * @param {Element} option option element from select + * @param {String} type + * @return {Element} option element added + */ + + }, { + key: "_appendOptionWithIcon", + value: function _appendOptionWithIcon(select, option, type) { + // Add disabled attr if disabled + var disabledClass = option.disabled ? 'disabled ' : ''; + var optgroupClass = type === 'optgroup-option' ? 'optgroup-option ' : ''; + var multipleCheckbox = this.isMultiple ? "" : option.innerHTML; + var liEl = $('
  • '); + var spanEl = $(''); + spanEl.html(multipleCheckbox); + liEl.addClass(disabledClass + " " + optgroupClass); + liEl.append(spanEl); + + // add icons + var iconUrl = option.getAttribute('data-icon'); + var classes = option.getAttribute('class'); + if (!!iconUrl) { + var imgEl = $(''); + liEl.prepend(imgEl); + } + + // Check for multiple type. + $(this.dropdownOptions).append(liEl[0]); + return liEl[0]; + } + + /** + * Toggle entry from option + * @param {String} key Option key + * @return {Boolean} if entry was added or removed + */ + + }, { + key: "_toggleEntryFromArray", + value: function _toggleEntryFromArray(key) { + var notAdded = !this._keysSelected.hasOwnProperty(key); + if (notAdded) { + this._keysSelected[key] = true; + } else { + delete this._keysSelected[key]; + } + + $(this._valueDict[key].optionEl).toggleClass('active'); + + // use notAdded instead of true (to detect if the option is selected or not) + $(this._valueDict[key].el).prop('selected', notAdded); + + return notAdded; + } + + /** + * Set value to input + */ + + }, { + key: "_setValueToInput", + value: function _setValueToInput() { + var value = ''; + var options = this.$el.find('option'); + + options.each(function (el) { + if ($(el).prop('selected')) { + var text = $(el).text(); + value === '' ? value += text : value += ', ' + text; + } + }); + + if (value === '') { + var firstDisabled = this.$el.find('option:disabled').eq(0); + if (firstDisabled.length) { + value = firstDisabled.text(); + } + } + + this.input.value = value; + } + + /** + * Set selected state of dropdown too match actual select element + */ + + }, { + key: "_setSelectedStates", + value: function _setSelectedStates() { + this._keysSelected = {}; + + for (var key in this._valueDict) { + var option = this._valueDict[key]; + if ($(option.el).prop('selected')) { + $(option.optionEl).find('input[type="checkbox"]').prop("checked", true); + this._activateOption($(this.dropdownOptions), $(option.optionEl)); + this._keysSelected[key] = true; + } else { + $(option.optionEl).find('input[type="checkbox"]').prop("checked", false); + $(option.optionEl).removeClass('selected'); + } + } + } + + /** + * Make option as selected and scroll to selected position + * @param {jQuery} collection Select options jQuery element + * @param {Element} newOption element of the new option + */ + + }, { + key: "_activateOption", + value: function _activateOption(collection, newOption) { + if (newOption) { + if (!this.isMultiple) { + collection.find('li.selected').removeClass('selected'); + } + + var option = $(newOption); + option.addClass('selected'); + } + } + + /** + * Get Selected Values + * @return {Array} Array of selected values + */ + + }, { + key: "getSelectedValues", + value: function getSelectedValues() { + var selectedValues = []; + for (var key in this._keysSelected) { + selectedValues.push(this._valueDict[key].el.value); + } + return selectedValues; + } + }], [{ + key: "init", + value: function init(els, options) { + return _get(FormSelect.__proto__ || Object.getPrototypeOf(FormSelect), "init", this).call(this, this, els, options); + } + + /** + * Get Instance + */ + + }, { + key: "getInstance", + value: function getInstance(el) { + var domElem = !!el.jquery ? el[0] : el; + return domElem.M_FormSelect; + } + }, { + key: "defaults", + get: function () { + return _defaults; + } + }]); + + return FormSelect; + }(Component); + + M.FormSelect = FormSelect; + + if (M.jQueryLoaded) { + M.initializeJqueryWrapper(FormSelect, 'formSelect', 'M_FormSelect'); + } +})(cash); +;(function ($, anim) { + 'use strict'; + + var _defaults = {}; + + /** + * @class + * + */ + + var Range = function (_Component21) { + _inherits(Range, _Component21); + + /** + * Construct Range instance + * @constructor + * @param {Element} el + * @param {Object} options + */ + function Range(el, options) { + _classCallCheck(this, Range); + + var _this71 = _possibleConstructorReturn(this, (Range.__proto__ || Object.getPrototypeOf(Range)).call(this, Range, el, options)); + + _this71.el.M_Range = _this71; + + /** + * Options for the range + * @member Range#options + */ + _this71.options = $.extend({}, Range.defaults, options); + + _this71._mousedown = false; + + // Setup + _this71._setupThumb(); + + _this71._setupEventHandlers(); + return _this71; + } + + _createClass(Range, [{ + key: "destroy", + + + /** + * Teardown component + */ + value: function destroy() { + this._removeEventHandlers(); + this._removeThumb(); + this.el.M_Range = undefined; + } + + /** + * Setup Event Handlers + */ + + }, { + key: "_setupEventHandlers", + value: function _setupEventHandlers() { + this._handleRangeChangeBound = this._handleRangeChange.bind(this); + this._handleRangeFocusBound = this._handleRangeFocus.bind(this); + this._handleRangeMousedownTouchstartBound = this._handleRangeMousedownTouchstart.bind(this); + this._handleRangeInputMousemoveTouchmoveBound = this._handleRangeInputMousemoveTouchmove.bind(this); + this._handleRangeMouseupTouchendBound = this._handleRangeMouseupTouchend.bind(this); + this._handleRangeBlurMouseoutTouchleaveBound = this._handleRangeBlurMouseoutTouchleave.bind(this); + + this.el.addEventListener('change', this._handleRangeChangeBound); + this.el.addEventListener('focus', this._handleRangeFocusBound); + + this.el.addEventListener('mousedown', this._handleRangeMousedownTouchstartBound); + this.el.addEventListener('touchstart', this._handleRangeMousedownTouchstartBound); + + this.el.addEventListener('input', this._handleRangeInputMousemoveTouchmoveBound); + this.el.addEventListener('mousemove', this._handleRangeInputMousemoveTouchmoveBound); + this.el.addEventListener('touchmove', this._handleRangeInputMousemoveTouchmoveBound); + + this.el.addEventListener('mouseup', this._handleRangeMouseupTouchendBound); + this.el.addEventListener('touchend', this._handleRangeMouseupTouchendBound); + + this.el.addEventListener('blur', this._handleRangeBlurMouseoutTouchleaveBound); + this.el.addEventListener('mouseout', this._handleRangeBlurMouseoutTouchleaveBound); + this.el.addEventListener('touchleave', this._handleRangeBlurMouseoutTouchleaveBound); + } + + /** + * Remove Event Handlers + */ + + }, { + key: "_removeEventHandlers", + value: function _removeEventHandlers() { + this.el.removeEventListener('change', this._handleRangeChangeBound); + this.el.removeEventListener('focus', this._handleRangeFocusBound); + + this.el.removeEventListener('mousedown', this._handleRangeMousedownTouchstartBound); + this.el.removeEventListener('touchstart', this._handleRangeMousedownTouchstartBound); + + this.el.removeEventListener('input', this._handleRangeInputMousemoveTouchmoveBound); + this.el.removeEventListener('mousemove', this._handleRangeInputMousemoveTouchmoveBound); + this.el.removeEventListener('touchmove', this._handleRangeInputMousemoveTouchmoveBound); + + this.el.removeEventListener('mouseup', this._handleRangeMouseupTouchendBound); + this.el.removeEventListener('touchend', this._handleRangeMouseupTouchendBound); + + this.el.removeEventListener('blur', this._handleRangeBlurMouseoutTouchleaveBound); + this.el.removeEventListener('mouseout', this._handleRangeBlurMouseoutTouchleaveBound); + this.el.removeEventListener('touchleave', this._handleRangeBlurMouseoutTouchleaveBound); + } + + /** + * Handle Range Change + * @param {Event} e + */ + + }, { + key: "_handleRangeChange", + value: function _handleRangeChange() { + $(this.value).html(this.$el.val()); + + if (!$(this.thumb).hasClass('active')) { + this._showRangeBubble(); + } + + var offsetLeft = this._calcRangeOffset(); + $(this.thumb).addClass('active').css('left', offsetLeft + 'px'); + } + + /** + * Handle Range Focus + * @param {Event} e + */ + + }, { + key: "_handleRangeFocus", + value: function _handleRangeFocus() { + if (M.tabPressed) { + this.$el.addClass('focused'); + } + } + + /** + * Handle Range Mousedown and Touchstart + * @param {Event} e + */ + + }, { + key: "_handleRangeMousedownTouchstart", + value: function _handleRangeMousedownTouchstart(e) { + // Set indicator value + $(this.value).html(this.$el.val()); + + this._mousedown = true; + this.$el.addClass('active'); + + if (!$(this.thumb).hasClass('active')) { + this._showRangeBubble(); + } + + if (e.type !== 'input') { + var offsetLeft = this._calcRangeOffset(); + $(this.thumb).addClass('active').css('left', offsetLeft + 'px'); + } + } + + /** + * Handle Range Input, Mousemove and Touchmove + */ + + }, { + key: "_handleRangeInputMousemoveTouchmove", + value: function _handleRangeInputMousemoveTouchmove() { + if (this._mousedown) { + if (!$(this.thumb).hasClass('active')) { + this._showRangeBubble(); + } + + var offsetLeft = this._calcRangeOffset(); + $(this.thumb).addClass('active').css('left', offsetLeft + 'px'); + $(this.value).html(this.$el.val()); + } + } + + /** + * Handle Range Mouseup and Touchend + */ + + }, { + key: "_handleRangeMouseupTouchend", + value: function _handleRangeMouseupTouchend() { + this._mousedown = false; + this.$el.removeClass('active'); + } + + /** + * Handle Range Blur, Mouseout and Touchleave + */ + + }, { + key: "_handleRangeBlurMouseoutTouchleave", + value: function _handleRangeBlurMouseoutTouchleave() { + if (!this._mousedown) { + this.$el.removeClass('focused'); + var paddingLeft = parseInt(this.$el.css('padding-left')); + var marginLeft = 7 + paddingLeft + 'px'; + + if ($(this.thumb).hasClass('active')) { + anim.remove(this.thumb); + anim({ + targets: this.thumb, + height: 0, + width: 0, + top: 10, + easing: 'easeOutQuad', + marginLeft: marginLeft, + duration: 100 + }); + } + $(this.thumb).removeClass('active'); + } + } + + /** + * Setup dropdown + */ + + }, { + key: "_setupThumb", + value: function _setupThumb() { + this.thumb = document.createElement('span'); + this.value = document.createElement('span'); + $(this.thumb).addClass('thumb'); + $(this.value).addClass('value'); + $(this.thumb).append(this.value); + this.$el.after(this.thumb); + } + + /** + * Remove dropdown + */ + + }, { + key: "_removeThumb", + value: function _removeThumb() { + $(this.thumb).remove(); + } + + /** + * morph thumb into bubble + */ + + }, { + key: "_showRangeBubble", + value: function _showRangeBubble() { + var paddingLeft = parseInt($(this.thumb).parent().css('padding-left')); + var marginLeft = -7 + paddingLeft + 'px'; // TODO: fix magic number? + anim.remove(this.thumb); + anim({ + targets: this.thumb, + height: 30, + width: 30, + top: -30, + marginLeft: marginLeft, + duration: 300, + easing: 'easeOutQuint' + }); + } + + /** + * Calculate the offset of the thumb + * @return {Number} offset in pixels + */ + + }, { + key: "_calcRangeOffset", + value: function _calcRangeOffset() { + var width = this.$el.width() - 15; + var max = parseFloat(this.$el.attr('max')); + var min = parseFloat(this.$el.attr('min')); + var percent = (parseFloat(this.$el.val()) - min) / (max - min); + return percent * width; + } + }], [{ + key: "init", + value: function init(els, options) { + return _get(Range.__proto__ || Object.getPrototypeOf(Range), "init", this).call(this, this, els, options); + } + + /** + * Get Instance + */ + + }, { + key: "getInstance", + value: function getInstance(el) { + var domElem = !!el.jquery ? el[0] : el; + return domElem.M_Range; + } + }, { + key: "defaults", + get: function () { + return _defaults; + } + }]); + + return Range; + }(Component); + + M.Range = Range; + + if (M.jQueryLoaded) { + M.initializeJqueryWrapper(Range, 'range', 'M_Range'); + } + + Range.init($('input[type=range]')); +})(cash, M.anime); diff --git a/src/lib/materialize/js/materialize.min.js b/src/lib/materialize/js/materialize.min.js new file mode 100644 index 0000000..f940b3f --- /dev/null +++ b/src/lib/materialize/js/materialize.min.js @@ -0,0 +1,6 @@ +/*! + * Materialize v1.0.0-beta (http://materializecss.com) + * Copyright 2014-2017 Materialize + * MIT License (https://raw.githubusercontent.com/Dogfalo/materialize/master/LICENSE) + */ +function _possibleConstructorReturn(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function _inherits(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function _classCallCheck(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var _get=function t(e,i,n){null===e&&(e=Function.prototype);var s=Object.getOwnPropertyDescriptor(e,i);if(void 0===s){var o=Object.getPrototypeOf(e);return null===o?void 0:t(o,i,n)}if("value"in s)return s.value;var a=s.get;if(void 0!==a)return a.call(n)},_createClass=function(){function t(t,e){for(var i=0;i=0&&a.splice(n,1)):(o(a,function(i){t.removeEventListener(e,i)}),a=[]))}function k(t,e){return"&"+encodeURIComponent(t)+"="+encodeURIComponent(e).replace(/%20/g,"+")}function b(t){var e=[];return o(t.options,function(t){t.selected&&e.push(t.value)}),e.length?e:null}function w(t){var e=t.selectedIndex;return e>=0?t.options[e].value:null}function C(t){var e=t.type;if(!e)return null;switch(e.toLowerCase()){case"select-one":return w(t);case"select-multiple":return b(t);case"radio":case"checkbox":return t.checked?t.value:null;default:return t.value?t.value:null}}function E(t,e,i){if(i){var n=t.childNodes[0];t.insertBefore(e,n)}else t.appendChild(e)}function M(t,e,i){var n=A(e);n||!e.length?o(t,n?function(t){return t.insertAdjacentHTML(i?"afterbegin":"beforeend",e)}:function(t,n){return E(t,0===n?e:e.cloneNode(!0),i)}):o(e,function(e){return M(t,e,i)})}var x,O=document,T=window,L=Array.prototype,$=L.slice,B=L.filter,D=L.push,S=function(){},I=function(t){return typeof t==typeof S&&t.call},A=function(t){return"string"==typeof t},R=/^#[\w-]*$/,H=/^\.[\w-]*$/,P=/<.+>/,W=/^\w+$/,j=s.fn=s.prototype=n.prototype={cash:!0,length:0,push:D,splice:L.splice,map:L.map,init:n};Object.defineProperty(j,"constructor",{value:s}),s.parseHTML=e,s.noop=S,s.isFunction=I,s.isString=A,s.extend=j.extend=function(t){t=t||{};var e=$.call(arguments),i=e.length,n=1;for(1===e.length&&(t=this,n=0);n1?this.each(function(i){return i.style[t]=e}):T.getComputedStyle(this[0])[t];for(var i in t)this.css(i,t[i]);return this}}),o(["Width","Height"],function(t){var e=t.toLowerCase();j[e]=function(){return this[0].getBoundingClientRect()[e]},j["inner"+t]=function(){return this[0]["client"+t]},j["outer"+t]=function(e){return this[0]["offset"+t]+(e?g(this,"margin"+("Width"===t?"Left":"Top"))+g(this,"margin"+("Width"===t?"Right":"Bottom")):0)}}),j.extend({off:function(t,e){return this.each(function(i){return y(i,t,e)})},on:function(t,e,n,s){var o;if(!A(t)){for(var r in t)this.on(r,e,t[r]);return this}return I(e)&&(n=e,e=null),"ready"===t?(i(n),this):(e&&(o=n,n=function(t){for(var i=t.target;!a(i,e);){if(i===this||null===i)return i=!1;i=i.parentNode}i&&o.call(i,t)}),this.each(function(e){var i=n;s&&(i=function(){n.apply(this,arguments),y(e,t,i)}),_(e,t,i)}))},one:function(t,e,i){return this.on(t,e,i,!0)},ready:i,trigger:function(t,e){if(document.createEvent){var i=document.createEvent("HTMLEvents");return i.initEvent(t,!0,!1),i=this.extend(i,e),this.each(function(t){return t.dispatchEvent(i)})}}}),j.extend({serialize:function(){var t="";return o(this[0].elements||this,function(e){if(!e.disabled&&"FIELDSET"!==e.tagName){var i=e.name;switch(e.type.toLowerCase()){case"file":case"reset":case"submit":case"button":break;case"select-multiple":var n=C(e);null!==n&&o(n,function(e){t+=k(i,e)});break;default:var s=C(e);null!==s&&(t+=k(i,s))}}}),t.substr(1)},val:function(t){return void 0===t?C(this[0]):this.each(function(e){return e.value=t})}}),j.extend({after:function(t){return s(t).insertAfter(this),this},append:function(t){return M(this,t),this},appendTo:function(t){return M(s(t),this),this},before:function(t){return s(t).insertBefore(this),this},clone:function(){return s(this.map(function(t){return t.cloneNode(!0)}))},empty:function(){return this.html(""),this},html:function(t){if(void 0===t)return this[0].innerHTML;var e=t.nodeType?t[0].outerHTML:t;return this.each(function(t){return t.innerHTML=e})},insertAfter:function(t){var e=this;return s(t).each(function(t,i){var n=t.parentNode,s=t.nextSibling;e.each(function(t){n.insertBefore(0===i?t:t.cloneNode(!0),s)})}),this},insertBefore:function(t){var e=this;return s(t).each(function(t,i){var n=t.parentNode;e.each(function(e){n.insertBefore(0===i?e:e.cloneNode(!0),t)})}),this},prepend:function(t){return M(this,t,!0),this},prependTo:function(t){return M(s(t),this,!0),this},remove:function(){return this.each(function(t){if(t.parentNode)return t.parentNode.removeChild(t)})},text:function(t){return void 0===t?this[0].textContent:this.each(function(e){return e.textContent=t})}});var V=O.documentElement;return j.extend({position:function(){var t=this[0];return{left:t.offsetLeft,top:t.offsetTop}},offset:function(){var t=this[0].getBoundingClientRect();return{top:t.top+T.pageYOffset-V.clientTop,left:t.left+T.pageXOffset-V.clientLeft}},offsetParent:function(){return s(this[0].offsetParent)}}),j.extend({children:function(t){var e=[];return this.each(function(t){D.apply(e,t.children)}),e=l(e),t?e.filter(function(e){return a(e,t)}):e},closest:function(t){return!t||this.length<1?s():this.is(t)?this.filter(t):this.parent().closest(t)},is:function(t){if(!t)return!1;var e=!1,i=r(t);return this.each(function(n){return!(e=i(n,t))}),e},find:function(e){if(!e||e.nodeType)return s(e&&this.has(e).length?e:null);var i=[];return this.each(function(n){D.apply(i,t(e,n))}),l(i)},has:function(e){var i=A(e)?function(i){return 0!==t(e,i).length}:function(t){return t.contains(e)};return this.filter(i)},next:function(){return s(this[0].nextElementSibling)},not:function(t){if(!t)return this;var e=r(t);return this.filter(function(i){return!e(i,t)})},parent:function(){var t=[];return this.each(function(e){e&&e.parentNode&&t.push(e.parentNode)}),l(t)},parents:function(t){var e,i=[];return this.each(function(n){for(e=n;e&&e.parentNode&&e!==O.body.parentNode;)e=e.parentNode,(!t||t&&a(e,t))&&i.push(e)}),l(i)},prev:function(){return s(this[0].previousElementSibling)},siblings:function(t){var e=this.parent().children(t),i=this[0];return e.filter(function(t){return t!==i})}}),s});var Component=function(){function t(e,i,n){_classCallCheck(this,t),i instanceof Element||console.error(Error(i+" is not an HTML Element"));var s=e.getInstance(i);s&&s.destroy(),this.el=i,this.$el=cash(i)}return _createClass(t,null,[{key:"init",value:function(t,e,i){var n=null;if(e instanceof Element)n=new t(e,i);else if(e&&(e.jquery||e.cash||e instanceof NodeList)){for(var s=[],o=0;os.right-i||r+e.width>window.innerWidth-i)&&(n.right=!0),(ls.bottom-i||l+e.height>window.innerHeight-i)&&(n.bottom=!0),n},M.checkPossibleAlignments=function(t,e,i,n){var s={top:!0,right:!0,bottom:!0,left:!0,spaceOnTop:null,spaceOnRight:null,spaceOnBottom:null,spaceOnLeft:null},o="visible"===getComputedStyle(e).overflow,a=e.getBoundingClientRect(),r=Math.min(a.height,window.innerHeight),l=Math.min(a.width,window.innerWidth),h=t.getBoundingClientRect(),d=e.scrollLeft,u=e.scrollTop,c=i.left-d,p=i.top-u,v=i.top+h.height-u;return s.spaceOnRight=o?window.innerWidth-(h.left+i.width):l-(c+i.width),s.spaceOnRight<0&&(s.left=!1),s.spaceOnLeft=o?h.right-i.width:c-i.width+h.width,s.spaceOnLeft<0&&(s.right=!1),s.spaceOnBottom=o?window.innerHeight-(h.top+i.height+n):r-(p+i.height+n),s.spaceOnBottom<0&&(s.top=!1),s.spaceOnTop=o?h.bottom-(i.height+n):v-(i.height-n),s.spaceOnTop<0&&(s.bottom=!1),s},M.getOverflowParent=function(t){return null==t?null:t===document.body||"visible"!==getComputedStyle(t).overflow?t:M.getOverflowParent(t.parentElement)},M.getIdFromTrigger=function(t){var e=t.getAttribute("data-target");return e||(e=(e=t.getAttribute("href"))?e.slice(1):""),e},M.getDocumentScrollTop=function(){return window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0},M.getDocumentScrollLeft=function(){return window.pageXOffset||document.documentElement.scrollLeft||document.body.scrollLeft||0};var getTime=Date.now||function(){return(new Date).getTime()};M.throttle=function(t,e,i){var n=void 0,s=void 0,o=void 0,a=null,r=0;i||(i={});var l=function(){r=!1===i.leading?0:getTime(),a=null,o=t.apply(n,s),n=s=null};return function(){var h=getTime();r||!1!==i.leading||(r=h);var d=e-(h-r);return n=this,s=arguments,d<=0?(clearTimeout(a),a=null,r=h,o=t.apply(n,s),n=s=null):a||!1===i.trailing||(a=setTimeout(l,d)),o}};var $jscomp={scope:{}};$jscomp.defineProperty="function"==typeof Object.defineProperties?Object.defineProperty:function(t,e,i){if(i.get||i.set)throw new TypeError("ES3 does not support getters and setters.");t!=Array.prototype&&t!=Object.prototype&&(t[e]=i.value)},$jscomp.getGlobal=function(t){return"undefined"!=typeof window&&window===t?t:"undefined"!=typeof global&&null!=global?global:t},$jscomp.global=$jscomp.getGlobal(this),$jscomp.SYMBOL_PREFIX="jscomp_symbol_",$jscomp.initSymbol=function(){$jscomp.initSymbol=function(){},$jscomp.global.Symbol||($jscomp.global.Symbol=$jscomp.Symbol)},$jscomp.symbolCounter_=0,$jscomp.Symbol=function(t){return $jscomp.SYMBOL_PREFIX+(t||"")+$jscomp.symbolCounter_++},$jscomp.initSymbolIterator=function(){$jscomp.initSymbol();var t=$jscomp.global.Symbol.iterator;t||(t=$jscomp.global.Symbol.iterator=$jscomp.global.Symbol("iterator")),"function"!=typeof Array.prototype[t]&&$jscomp.defineProperty(Array.prototype,t,{configurable:!0,writable:!0,value:function(){return $jscomp.arrayIterator(this)}}),$jscomp.initSymbolIterator=function(){}},$jscomp.arrayIterator=function(t){var e=0;return $jscomp.iteratorPrototype(function(){return ei&&(i+=1),1i?e:i<2/3?t+(e-t)*(2/3-i)*6:t}s=/hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.exec(t)||/hsla\((\d+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)\)/g.exec(t);t=parseInt(s[1])/360;var i=parseInt(s[2])/100,n=parseInt(s[3])/100,s=s[4]||1;if(0==i)n=i=t=n;else{var o=.5>n?n*(1+i):n+i-n*i,a=2*n-o,n=e(a,o,t+1/3),i=e(a,o,t);t=e(a,o,t-1/3)}return"rgba("+255*n+","+255*i+","+255*t+","+s+")"}function d(t){if(t=/([\+\-]?[0-9#\.]+)(%|px|pt|em|rem|in|cm|mm|ex|ch|pc|vw|vh|vmin|vmax|deg|rad|turn)?$/.exec(t))return t[2]}function u(t){return-1=v.currentTime)for(var k=0;k=p||!e)&&(v.began||(v.began=!0,o("begin")),o("run")),g>r&&g=e&&f!==e||!e)&&(s(e),m||a())),o("update"),t>=e&&(v.remaining?(h=l,"alternate"===v.direction&&(v.reversed=!v.reversed)):(v.pause(),v.completed||(v.completed=!0,o("complete"),"Promise"in window&&(u(),c=i()))),d=0)}t=void 0===t?{}:t;var l,h,d=0,u=null,c=i(),v=B(t);return v.reset=function(){var t=v.direction,e=v.loop;for(v.currentTime=0,v.progress=0,v.paused=!0,v.began=!1,v.completed=!1,v.reversed="reverse"===t,v.remaining="alternate"===t&&1===e?2:e,s(0),t=v.children.length;t--;)v.children[t].reset()},v.tick=function(t){l=t,h||(h=l),r((d+l-h)*D.speed)},v.seek=function(t){r(n(t))},v.pause=function(){var t=F.indexOf(v);-1=e&&0<=n&&1>=n){var o=new Float32Array(11);if(e!==i||n!==s)for(var a=0;11>a;++a)o[a]=t(.1*a,e,n);return function(a){if(e===i&&n===s)return a;if(0===a)return 0;if(1===a)return 1;for(var r=0,l=1;10!==l&&o[l]<=a;++l)r+=.1;var l=r+(a-o[--l])/(o[l+1]-o[l])*.1,h=3*(1-3*n+3*e)*l*l+2*(3*n-6*e)*l+3*e;if(.001<=h){for(r=0;4>r&&0!=(h=3*(1-3*n+3*e)*l*l+2*(3*n-6*e)*l+3*e);++r)var d=t(l,e,n)-a,l=l-d/h;a=l}else if(0===h)a=l;else{var l=r,r=r+.1,u=0;do{0<(h=t(d=l+(r-l)/2,e,n)-a)?r=d:l=d}while(1e-7++u);a=d}return t(a,i,s)}}}}(),W=function(){function t(t,e){return 0===t||1===t?t:-Math.pow(2,10*(t-1))*Math.sin(2*(t-1-e/(2*Math.PI)*Math.asin(1))*Math.PI/e)}var e,i="Quad Cubic Quart Quint Sine Expo Circ Back Elastic".split(" "),n={In:[[.55,.085,.68,.53],[.55,.055,.675,.19],[.895,.03,.685,.22],[.755,.05,.855,.06],[.47,0,.745,.715],[.95,.05,.795,.035],[.6,.04,.98,.335],[.6,-.28,.735,.045],t],Out:[[.25,.46,.45,.94],[.215,.61,.355,1],[.165,.84,.44,1],[.23,1,.32,1],[.39,.575,.565,1],[.19,1,.22,1],[.075,.82,.165,1],[.175,.885,.32,1.275],function(e,i){return 1-t(1-e,i)}],InOut:[[.455,.03,.515,.955],[.645,.045,.355,1],[.77,0,.175,1],[.86,0,.07,1],[.445,.05,.55,.95],[1,0,0,1],[.785,.135,.15,.86],[.68,-.55,.265,1.55],function(e,i){return.5>e?t(2*e,i)/2:1-t(-2*e+2,i)/2}]},s={linear:P(.25,.25,.75,.75)},o={};for(e in n)o.type=e,n[o.type].forEach(function(t){return function(e,n){s["ease"+t.type+i[n]]=H.fnc(e)?e:P.apply($jscomp$this,e)}}(o)),o={type:o.type};return s}(),j={css:function(t,e,i){return t.style[e]=i},attribute:function(t,e,i){return t.setAttribute(e,i)},object:function(t,e,i){return t[e]=i},transform:function(t,e,i,n,s){n[s]||(n[s]=[]),n[s].push(e+"("+i+")")}},F=[],q=0,z=function(){function t(){q=requestAnimationFrame(e)}function e(e){var i=F.length;if(i){for(var n=0;ni&&(e.duration=n.duration),e.children.push(n)}),e.seek(0),e.reset(),e.autoplay&&e.restart(),e},e},D.random=function(t,e){return Math.floor(Math.random()*(e-t+1))+t},D}),function(t,e){"use strict";var i={accordion:!0,onOpenStart:void 0,onOpenEnd:void 0,onCloseStart:void 0,onCloseEnd:void 0,inDuration:300,outDuration:300},n=function(n){function s(e,i){_classCallCheck(this,s);var n=_possibleConstructorReturn(this,(s.__proto__||Object.getPrototypeOf(s)).call(this,s,e,i));n.el.M_Collapsible=n,n.options=t.extend({},s.defaults,i),n.$headers=n.$el.children("li").children(".collapsible-header"),n.$headers.attr("tabindex",0),n._setupEventHandlers();var o=n.$el.children("li.active").children(".collapsible-body");return n.options.accordion?o.first().css("display","block"):o.css("display","block"),n}return _inherits(s,Component),_createClass(s,[{key:"destroy",value:function(){this._removeEventHandlers(),this.el.M_Collapsible=void 0}},{key:"_setupEventHandlers",value:function(){var t=this;this._handleCollapsibleClickBound=this._handleCollapsibleClick.bind(this),this._handleCollapsibleKeydownBound=this._handleCollapsibleKeydown.bind(this),this.el.addEventListener("click",this._handleCollapsibleClickBound),this.$headers.each(function(e){e.addEventListener("keydown",t._handleCollapsibleKeydownBound)})}},{key:"_removeEventHandlers",value:function(){this.el.removeEventListener("click",this._handleCollapsibleClickBound)}},{key:"_handleCollapsibleClick",value:function(e){var i=t(e.target).closest(".collapsible-header");if(e.target&&i.length){var n=i.closest(".collapsible");if(n[0]===this.el){var s=i.closest("li"),o=n.children("li"),a=s[0].classList.contains("active"),r=o.index(s);a?this.close(r):this.open(r)}}}},{key:"_handleCollapsibleKeydown",value:function(t){13===t.keyCode&&this._handleCollapsibleClickBound(t)}},{key:"_animateIn",value:function(t){var i=this,n=this.$el.children("li").eq(t);if(n.length){var s=n.children(".collapsible-body");e.remove(s[0]),s.css({display:"block",overflow:"hidden",height:0,paddingTop:"",paddingBottom:""});var o=s.css("padding-top"),a=s.css("padding-bottom"),r=s[0].scrollHeight;s.css({paddingTop:0,paddingBottom:0}),e({targets:s[0],height:r,paddingTop:o,paddingBottom:a,duration:this.options.inDuration,easing:"easeInOutCubic",complete:function(t){s.css({overflow:"",paddingTop:"",paddingBottom:"",height:""}),"function"==typeof i.options.onOpenEnd&&i.options.onOpenEnd.call(i,n[0])}})}}},{key:"_animateOut",value:function(t){var i=this,n=this.$el.children("li").eq(t);if(n.length){var s=n.children(".collapsible-body");e.remove(s[0]),s.css("overflow","hidden"),e({targets:s[0],height:0,paddingTop:0,paddingBottom:0,duration:this.options.outDuration,easing:"easeInOutCubic",complete:function(){s.css({height:"",overflow:"",padding:"",display:""}),"function"==typeof i.options.onCloseEnd&&i.options.onCloseEnd.call(i,n[0])}})}}},{key:"open",value:function(e){var i=this,n=this.$el.children("li").eq(e);if(n.length&&!n[0].classList.contains("active")){if("function"==typeof this.options.onOpenStart&&this.options.onOpenStart.call(this,n[0]),this.options.accordion){var s=this.$el.children("li");this.$el.children("li.active").each(function(e){var n=s.index(t(e));i.close(n)})}n[0].classList.add("active"),this._animateIn(e)}}},{key:"close",value:function(t){var e=this.$el.children("li").eq(t);e.length&&e[0].classList.contains("active")&&("function"==typeof this.options.onCloseStart&&this.options.onCloseStart.call(this,e[0]),e[0].classList.remove("active"),this._animateOut(t))}}],[{key:"init",value:function(t,e){return _get(s.__proto__||Object.getPrototypeOf(s),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Collapsible}},{key:"defaults",get:function(){return i}}]),s}();M.Collapsible=n,M.jQueryLoaded&&M.initializeJqueryWrapper(n,"collapsible","M_Collapsible")}(cash,M.anime),function(t,e){"use strict";var i={alignment:"left",autoFocus:!0,constrainWidth:!0,container:null,coverTrigger:!0,closeOnClick:!0,hover:!1,inDuration:150,outDuration:250,onOpenStart:null,onOpenEnd:null,onCloseStart:null,onCloseEnd:null},n=function(n){function s(e,i){_classCallCheck(this,s);var n=_possibleConstructorReturn(this,(s.__proto__||Object.getPrototypeOf(s)).call(this,s,e,i));return n.el.M_Dropdown=n,s._dropdowns.push(n),n.id=M.getIdFromTrigger(e),n.dropdownEl=document.getElementById(n.id),n.$dropdownEl=t(n.dropdownEl),n.options=t.extend({},s.defaults,i),n.isOpen=!1,n.isScrollable=!1,n.isTouchMoving=!1,n.focusedIndex=-1,n.filterQuery=[],n.options.container?t(n.options.container).append(n.dropdownEl):n.$el.after(n.dropdownEl),n._makeDropdownFocusable(),n._resetFilterQueryBound=n._resetFilterQuery.bind(n),n._handleDocumentClickBound=n._handleDocumentClick.bind(n),n._handleDocumentTouchmoveBound=n._handleDocumentTouchmove.bind(n),n._handleDropdownKeydownBound=n._handleDropdownKeydown.bind(n),n._handleTriggerKeydownBound=n._handleTriggerKeydown.bind(n),n._setupEventHandlers(),n}return _inherits(s,Component),_createClass(s,[{key:"destroy",value:function(){this._resetDropdownStyles(),this._removeEventHandlers(),s._dropdowns.splice(s._dropdowns.indexOf(this),1),this.el.M_Dropdown=void 0}},{key:"_setupEventHandlers",value:function(){this.el.addEventListener("keydown",this._handleTriggerKeydownBound),this.options.hover?(this._handleMouseEnterBound=this._handleMouseEnter.bind(this),this.el.addEventListener("mouseenter",this._handleMouseEnterBound),this._handleMouseLeaveBound=this._handleMouseLeave.bind(this),this.el.addEventListener("mouseleave",this._handleMouseLeaveBound),this.dropdownEl.addEventListener("mouseleave",this._handleMouseLeaveBound)):(this._handleClickBound=this._handleClick.bind(this),this.el.addEventListener("click",this._handleClickBound))}},{key:"_removeEventHandlers",value:function(){this.el.removeEventListener("keydown",this._handleTriggerKeydownBound),this.options.hover?(this.el.removeEventHandlers("mouseenter",this._handleMouseEnterBound),this.el.removeEventHandlers("mouseleave",this._handleMouseLeaveBound),this.dropdownEl.removeEventHandlers("mouseleave",this._handleMouseLeaveBound)):this.el.removeEventListener("click",this._handleClickBound)}},{key:"_setupTemporaryEventHandlers",value:function(){document.body.addEventListener("click",this._handleDocumentClickBound,!0),document.body.addEventListener("touchend",this._handleDocumentClickBound),document.body.addEventListener("touchmove",this._handleDocumentTouchmoveBound),this.dropdownEl.addEventListener("keydown",this._handleDropdownKeydownBound)}},{key:"_removeTemporaryEventHandlers",value:function(){document.body.removeEventListener("click",this._handleDocumentClickBound,!0),document.body.removeEventListener("touchend",this._handleDocumentClickBound),document.body.removeEventListener("touchmove",this._handleDocumentTouchmoveBound),this.dropdownEl.removeEventListener("keydown",this._handleDropdownKeydownBound)}},{key:"_handleClick",value:function(t){t.preventDefault(),this.open()}},{key:"_handleMouseEnter",value:function(){this.open()}},{key:"_handleMouseLeave",value:function(e){var i=e.toElement||e.relatedTarget,n=!!t(i).closest(".dropdown-content").length,s=!1,o=t(i).closest(".dropdown-trigger");o.length&&o[0].M_Dropdown&&o[0].M_Dropdown.isOpen&&(s=!0),s||n||this.close()}},{key:"_handleDocumentClick",value:function(e){var i=this,n=t(e.target);this.options.closeOnClick&&n.closest(".dropdown-content").length&&!this.isTouchMoving?setTimeout(function(){i.close()},0):!n.closest(".dropdown-trigger").length&&n.closest(".dropdown-content").length||setTimeout(function(){i.close()},0),this.isTouchMoving=!1}},{key:"_handleTriggerKeydown",value:function(t){t.which!==M.keys.ARROW_DOWN&&t.which!==M.keys.ENTER||this.isOpen||(t.preventDefault(),this.open())}},{key:"_handleDocumentTouchmove",value:function(e){t(e.target).closest(".dropdown-content").length&&(this.isTouchMoving=!0)}},{key:"_handleDropdownKeydown",value:function(e){if(e.which===M.keys.TAB)e.preventDefault(),this.close();else if(e.which!==M.keys.ARROW_DOWN&&e.which!==M.keys.ARROW_UP||!this.isOpen)if(e.which===M.keys.ENTER&&this.isOpen){var i=this.dropdownEl.children[this.focusedIndex],n=t(i).find("a, button").first();n.length?n[0].click():i.click()}else e.which===M.keys.ESC&&this.isOpen&&(e.preventDefault(),this.close());else{e.preventDefault();var s=e.which===M.keys.ARROW_DOWN?1:-1,o=this.focusedIndex,a=!1;do{if(o+=s,this.dropdownEl.children[o]&&-1!==this.dropdownEl.children[o].tabIndex){a=!0;break}}while(o=0);a&&(this.focusedIndex=o,this._focusFocusedItem())}var r=String.fromCharCode(e.which).toLowerCase(),l=[9,13,27,38,40];if(r&&-1===l.indexOf(e.which)){this.filterQuery.push(r);var h=this.filterQuery.join(""),d=t(this.dropdownEl).find("li").filter(function(e){return 0===t(e).text().toLowerCase().indexOf(h)})[0];d&&(this.focusedIndex=t(d).index(),this._focusFocusedItem())}this.filterTimeout=setTimeout(this._resetFilterQueryBound,1e3)}},{key:"_resetFilterQuery",value:function(){this.filterQuery=[]}},{key:"_resetDropdownStyles",value:function(){this.$dropdownEl.css({display:"",width:"",height:"",left:"",top:"","transform-origin":"",transform:"",opacity:""})}},{key:"_makeDropdownFocusable",value:function(){this.dropdownEl.tabIndex=0,t(this.dropdownEl).children().each(function(t){t.getAttribute("tabindex")||t.setAttribute("tabindex",0)})}},{key:"_focusFocusedItem",value:function(){this.focusedIndex>=0&&this.focusedIndexl.spaceOnBottom?(h="bottom",i+=l.spaceOnTop,o-=l.spaceOnTop):i+=l.spaceOnBottom)),!l[d]){var u="left"===d?"right":"left";l[u]?d=u:l.spaceOnLeft>l.spaceOnRight?(d="right",n+=l.spaceOnLeft,s-=l.spaceOnLeft):(d="left",n+=l.spaceOnRight)}return"bottom"===h&&(o=o-e.height+(this.options.coverTrigger?t.height:0)),"right"===d&&(s=s-e.width+t.width),{x:s,y:o,verticalAlignment:h,horizontalAlignment:d,height:i,width:n}}},{key:"_animateIn",value:function(){var t=this;e.remove(this.dropdownEl),e({targets:this.dropdownEl,opacity:{value:[0,1],easing:"easeOutQuad"},scaleX:[.3,1],scaleY:[.3,1],duration:this.options.inDuration,easing:"easeOutQuint",complete:function(e){if(t.options.autoFocus&&t.dropdownEl.focus(),"function"==typeof t.options.onOpenEnd){var i=e.animatables[0].target;t.options.onOpenEnd.call(i,t.el)}}})}},{key:"_animateOut",value:function(){var t=this;e.remove(this.dropdownEl),e({targets:this.dropdownEl,opacity:{value:0,easing:"easeOutQuint"},scaleX:.3,scaleY:.3,duration:this.options.outDuration,easing:"easeOutQuint",complete:function(e){if(t._resetDropdownStyles(),"function"==typeof t.options.onCloseEnd){e.animatables[0].target;t.options.onCloseEnd.call(t,t.el)}}})}},{key:"_placeDropdown",value:function(){var t=this.options.constrainWidth?this.el.getBoundingClientRect().width:this.dropdownEl.getBoundingClientRect().width;this.dropdownEl.style.width=t+"px";var e=this._getDropdownPosition();this.dropdownEl.style.left=e.x+"px",this.dropdownEl.style.top=e.y+"px",this.dropdownEl.style.height=e.height+"px",this.dropdownEl.style.width=e.width+"px",this.dropdownEl.style.transformOrigin=("left"===e.horizontalAlignment?"0":"100%")+" "+("top"===e.verticalAlignment?"0":"100%")}},{key:"open",value:function(){this.isOpen||(this.isOpen=!0,"function"==typeof this.options.onOpenStart&&this.options.onOpenStart.call(this,this.el),this._resetDropdownStyles(),this.dropdownEl.style.display="block",this._placeDropdown(),this._animateIn(),this._setupTemporaryEventHandlers())}},{key:"close",value:function(){this.isOpen&&(this.isOpen=!1,this.focusedIndex=-1,"function"==typeof this.options.onCloseStart&&this.options.onCloseStart.call(this,this.el),this._animateOut(),this._removeTemporaryEventHandlers(),this.options.autoFocus&&this.el.focus())}},{key:"recalculateDimensions",value:function(){this.isOpen&&(this.$dropdownEl.css({width:"",height:"",left:"",top:"","transform-origin":""}),this._placeDropdown())}}],[{key:"init",value:function(t,e){return _get(s.__proto__||Object.getPrototypeOf(s),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Dropdown}},{key:"defaults",get:function(){return i}}]),s}();n._dropdowns=[],window.M.Dropdown=n,M.jQueryLoaded&&M.initializeJqueryWrapper(n,"dropdown","M_Dropdown")}(cash,M.anime),function(t,e){"use strict";var i={opacity:.5,inDuration:250,outDuration:250,onOpenStart:null,onOpenEnd:null,onCloseStart:null,onCloseEnd:null,preventScrolling:!0,dismissible:!0,startingTop:"4%",endingTop:"10%"},n=function(n){function s(e,i){_classCallCheck(this,s);var n=_possibleConstructorReturn(this,(s.__proto__||Object.getPrototypeOf(s)).call(this,s,e,i));return n.el.M_Modal=n,n.options=t.extend({},s.defaults,i),n.isOpen=!1,n.id=n.$el.attr("id"),n._openingTrigger=void 0,n.$overlay=t(''),n.el.tabIndex=0,s._count++,n._setupEventHandlers(),n}return _inherits(s,Component),_createClass(s,[{key:"destroy",value:function(){s._count--,this._removeEventHandlers(),this.el.removeAttribute("style"),this.$overlay.remove(),this.el.M_Modal=void 0}},{key:"_setupEventHandlers",value:function(){this._handleOverlayClickBound=this._handleOverlayClick.bind(this),this._handleModalCloseClickBound=this._handleModalCloseClick.bind(this),1===s._count&&document.body.addEventListener("click",this._handleTriggerClick),this.$overlay[0].addEventListener("click",this._handleOverlayClickBound),this.el.addEventListener("click",this._handleModalCloseClickBound)}},{key:"_removeEventHandlers",value:function(){0===s._count&&document.body.removeEventListener("click",this._handleTriggerClick),this.$overlay[0].removeEventListener("click",this._handleOverlayClickBound),this.el.removeEventListener("click",this._handleModalCloseClickBound)}},{key:"_handleTriggerClick",value:function(e){var i=t(e.target).closest(".modal-trigger");if(i.length){var n=M.getIdFromTrigger(i[0]),s=document.getElementById(n).M_Modal;s&&s.open(i),e.preventDefault()}}},{key:"_handleOverlayClick",value:function(){this.options.dismissible&&this.close()}},{key:"_handleModalCloseClick",value:function(e){t(e.target).closest(".modal-close").length&&this.close()}},{key:"_handleKeydown",value:function(t){27===t.keyCode&&this.options.dismissible&&this.close()}},{key:"_handleFocus",value:function(t){this.el.contains(t.target)||this.el.focus()}},{key:"_animateIn",value:function(){var i=this;t.extend(this.el.style,{display:"block",opacity:0}),t.extend(this.$overlay[0].style,{display:"block",opacity:0}),e({targets:this.$overlay[0],opacity:this.options.opacity,duration:this.options.inDuration,easing:"easeOutQuad"});var n={targets:this.el,duration:this.options.inDuration,easing:"easeOutCubic",complete:function(){"function"==typeof i.options.onOpenEnd&&i.options.onOpenEnd.call(i,i.el,i._openingTrigger)}};this.el.classList.contains("bottom-sheet")?(t.extend(n,{bottom:0,opacity:1}),e(n)):(t.extend(n,{top:[this.options.startingTop,this.options.endingTop],opacity:1,scaleX:[.8,1],scaleY:[.8,1]}),e(n))}},{key:"_animateOut",value:function(){var i=this;e({targets:this.$overlay[0],opacity:0,duration:this.options.outDuration,easing:"easeOutQuart"});var n={targets:this.el,duration:this.options.outDuration,easing:"easeOutCubic",complete:function(){i.el.style.display="none",i.$overlay.remove(),"function"==typeof i.options.onCloseEnd&&i.options.onCloseEnd.call(i,i.el)}};this.el.classList.contains("bottom-sheet")?(t.extend(n,{bottom:"-100%",opacity:0}),e(n)):(t.extend(n,{top:[this.options.endingTop,this.options.startingTop],opacity:0,scaleX:.8,scaleY:.8}),e(n))}},{key:"open",value:function(t){if(!this.isOpen)return this.isOpen=!0,s._modalsOpen++,this.$overlay[0].style.zIndex=1e3+2*s._modalsOpen,this.el.style.zIndex=1e3+2*s._modalsOpen+1,this._openingTrigger=t?t[0]:void 0,"function"==typeof this.options.onOpenStart&&this.options.onOpenStart.call(this,this.el,this._openingTrigger),this.options.preventScrolling&&(document.body.style.overflow="hidden"),this.el.classList.add("open"),this.el.insertAdjacentElement("afterend",this.$overlay[0]),this.options.dismissible&&(this._handleKeydownBound=this._handleKeydown.bind(this),this._handleFocusBound=this._handleFocus.bind(this),document.addEventListener("keydown",this._handleKeydownBound),document.addEventListener("focus",this._handleFocusBound,!0)),e.remove(this.el),e.remove(this.$overlay[0]),this._animateIn(),this.el.focus(),this}},{key:"close",value:function(){if(this.isOpen)return this.isOpen=!1,s._modalsOpen--,"function"==typeof this.options.onCloseStart&&this.options.onCloseStart.call(this,this.el),this.el.classList.remove("open"),0===s._modalsOpen&&(document.body.style.overflow=""),this.options.dismissible&&(document.removeEventListener("keydown",this._handleKeydownBound),document.removeEventListener("focus",this._handleFocusBound)),e.remove(this.el),e.remove(this.$overlay[0]),this._animateOut(),this}}],[{key:"init",value:function(t,e){return _get(s.__proto__||Object.getPrototypeOf(s),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Modal}},{key:"defaults",get:function(){return i}}]),s}();n._modalsOpen=0,n._count=0,M.Modal=n,M.jQueryLoaded&&M.initializeJqueryWrapper(n,"modal","M_Modal")}(cash,M.anime),function(t,e){"use strict";var i={inDuration:275,outDuration:200,onOpenStart:null,onOpenEnd:null,onCloseStart:null,onCloseEnd:null},n=function(n){function s(e,i){_classCallCheck(this,s);var n=_possibleConstructorReturn(this,(s.__proto__||Object.getPrototypeOf(s)).call(this,s,e,i));return n.el.M_Materialbox=n,n.options=t.extend({},s.defaults,i),n.overlayActive=!1,n.doneAnimating=!0,n.placeholder=t("
    ").addClass("material-placeholder"),n.originalWidth=0,n.originalHeight=0,n.originInlineStyles=n.$el.attr("style"),n.caption=n.el.getAttribute("data-caption")||"",n.$el.before(n.placeholder),n.placeholder.append(n.$el),n._setupEventHandlers(),n}return _inherits(s,Component),_createClass(s,[{key:"destroy",value:function(){this._removeEventHandlers(),this.el.M_Materialbox=void 0}},{key:"_setupEventHandlers",value:function(){this._handleMaterialboxClickBound=this._handleMaterialboxClick.bind(this),this.el.addEventListener("click",this._handleMaterialboxClickBound)}},{key:"_removeEventHandlers",value:function(){this.el.removeEventListener("click",this._handleMaterialboxClickBound)}},{key:"_handleMaterialboxClick",value:function(t){!1===this.doneAnimating||this.overlayActive&&this.doneAnimating?this.close():this.open()}},{key:"_handleWindowScroll",value:function(){this.overlayActive&&this.close()}},{key:"_handleWindowResize",value:function(){this.overlayActive&&this.close()}},{key:"_handleWindowEscape",value:function(t){27===t.keyCode&&this.doneAnimating&&this.overlayActive&&this.close()}},{key:"_makeAncestorsOverflowVisible",value:function(){this.ancestorsChanged=t();for(var e=this.placeholder[0].parentNode;null!==e&&!t(e).is(document);){var i=t(e);"visible"!==i.css("overflow")&&(i.css("overflow","visible"),void 0===this.ancestorsChanged?this.ancestorsChanged=i:this.ancestorsChanged=this.ancestorsChanged.add(i)),e=e.parentNode}}},{key:"_animateImageIn",value:function(){var t=this,i={targets:this.el,height:[this.originalHeight,this.newHeight],width:[this.originalWidth,this.newWidth],left:M.getDocumentScrollLeft()+this.windowWidth/2-this.placeholder.offset().left-this.newWidth/2,top:M.getDocumentScrollTop()+this.windowHeight/2-this.placeholder.offset().top-this.newHeight/2,duration:this.options.inDuration,easing:"easeOutQuad",complete:function(){t.doneAnimating=!0,"function"==typeof t.options.onOpenEnd&&t.options.onOpenEnd.call(t,t.el)}};this.maxWidth=this.$el.css("max-width"),this.maxHeight=this.$el.css("max-height"),"none"!==this.maxWidth&&(i.maxWidth=this.newWidth),"none"!==this.maxHeight&&(i.maxHeight=this.newHeight),e(i)}},{key:"_animateImageOut",value:function(){var t=this,i={targets:this.el,width:this.originalWidth,height:this.originalHeight,left:0,top:0,duration:this.options.outDuration,easing:"easeOutQuad",complete:function(){t.placeholder.css({height:"",width:"",position:"",top:"",left:""}),t.attrWidth&&t.$el.attr("width",t.attrWidth),t.attrHeight&&t.$el.attr("height",t.attrHeight),t.$el.removeAttr("style"),t.$el.attr("style",t.originInlineStyles),t.$el.removeClass("active"),t.doneAnimating=!0,t.ancestorsChanged.length&&t.ancestorsChanged.css("overflow",""),"function"==typeof t.options.onCloseEnd&&t.options.onCloseEnd.call(t,t.el)}};e(i)}},{key:"_updateVars",value:function(){this.windowWidth=window.innerWidth,this.windowHeight=window.innerHeight,this.caption=this.el.getAttribute("data-caption")||""}},{key:"open",value:function(){var i=this;this._updateVars(),this.originalWidth=this.el.getBoundingClientRect().width,this.originalHeight=this.el.getBoundingClientRect().height,this.doneAnimating=!1,this.$el.addClass("active"),this.overlayActive=!0,"function"==typeof this.options.onOpenStart&&this.options.onOpenStart.call(this,this.el),this.placeholder.css({width:this.placeholder[0].getBoundingClientRect().width+"px",height:this.placeholder[0].getBoundingClientRect().height+"px",position:"relative",top:0,left:0}),this._makeAncestorsOverflowVisible(),this.$el.css({position:"absolute","z-index":1e3,"will-change":"left, top, width, height"}),this.attrWidth=this.$el.attr("width"),this.attrHeight=this.$el.attr("height"),this.attrWidth&&(this.$el.css("width",this.attrWidth+"px"),this.$el.removeAttr("width")),this.attrHeight&&(this.$el.css("width",this.attrHeight+"px"),this.$el.removeAttr("height")),this.$overlay=t('
    ').css({opacity:0}).one("click",function(){i.doneAnimating&&i.close()}),this.$el.before(this.$overlay);var n=this.$overlay[0].getBoundingClientRect();this.$overlay.css({width:this.windowWidth+"px",height:this.windowHeight+"px",left:-1*n.left+"px",top:-1*n.top+"px"}),e.remove(this.el),e.remove(this.$overlay[0]),e({targets:this.$overlay[0],opacity:1,duration:this.options.inDuration,easing:"easeOutQuad"}),""!==this.caption&&(this.$photocaption&&e.remove(this.$photoCaption[0]),this.$photoCaption=t('
    '),this.$photoCaption.text(this.caption),t("body").append(this.$photoCaption),this.$photoCaption.css({display:"inline"}),e({targets:this.$photoCaption[0],opacity:1,duration:this.options.inDuration,easing:"easeOutQuad"}));var s=0,o=this.originalWidth/this.windowWidth,a=this.originalHeight/this.windowHeight;this.newWidth=0,this.newHeight=0,o>a?(s=this.originalHeight/this.originalWidth,this.newWidth=.9*this.windowWidth,this.newHeight=.9*this.windowWidth*s):(s=this.originalWidth/this.originalHeight,this.newWidth=.9*this.windowHeight*s,this.newHeight=.9*this.windowHeight),this._animateImageIn(),this._handleWindowScrollBound=this._handleWindowScroll.bind(this),this._handleWindowResizeBound=this._handleWindowResize.bind(this),this._handleWindowEscapeBound=this._handleWindowEscape.bind(this),window.addEventListener("scroll",this._handleWindowScrollBound),window.addEventListener("resize",this._handleWindowResizeBound),window.addEventListener("keyup",this._handleWindowEscapeBound)}},{key:"close",value:function(){var t=this;this._updateVars(),this.doneAnimating=!1,"function"==typeof this.options.onCloseStart&&this.options.onCloseStart.call(this,this.el),e.remove(this.el),e.remove(this.$overlay[0]),""!==this.caption&&e.remove(this.$photoCaption[0]),window.removeEventListener("scroll",this._handleWindowScrollBound),window.removeEventListener("resize",this._handleWindowResizeBound),window.removeEventListener("keyup",this._handleWindowEscapeBound),e({targets:this.$overlay[0],opacity:0,duration:this.options.outDuration,easing:"easeOutQuad",complete:function(){t.overlayActive=!1,t.$overlay.remove()}}),this._animateImageOut(),""!==this.caption&&e({targets:this.$photoCaption[0],opacity:0,duration:this.options.outDuration,easing:"easeOutQuad",complete:function(){t.$photoCaption.remove()}})}}],[{key:"init",value:function(t,e){return _get(s.__proto__||Object.getPrototypeOf(s),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Materialbox}},{key:"defaults",get:function(){return i}}]),s}();M.Materialbox=n,M.jQueryLoaded&&M.initializeJqueryWrapper(n,"materialbox","M_Materialbox")}(cash,M.anime),function(t){"use strict";var e={responsiveThreshold:0},i=function(i){function n(e,i){_classCallCheck(this,n);var s=_possibleConstructorReturn(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,n,e,i));return s.el.M_Parallax=s,s.options=t.extend({},n.defaults,i),s._enabled=window.innerWidth>s.options.responsiveThreshold,s.$img=s.$el.find("img").first(),s.$img.each(function(){var e=this;e.complete&&t(e).trigger("load")}),s._updateParallax(),s._setupEventHandlers(),s._setupStyles(),n._parallaxes.push(s),s}return _inherits(n,Component),_createClass(n,[{key:"destroy",value:function(){n._parallaxes.splice(n._parallaxes.indexOf(this),1),this.$img[0].style.transform="",this._removeEventHandlers(),this.$el[0].M_Parallax=void 0}},{key:"_setupEventHandlers",value:function(){this._handleImageLoadBound=this._handleImageLoad.bind(this),this.$img[0].addEventListener("load",this._handleImageLoadBound),0===n._parallaxes.length&&(n._handleScrollThrottled=M.throttle(n._handleScroll,5),window.addEventListener("scroll",n._handleScrollThrottled),n._handleWindowResizeThrottled=M.throttle(n._handleWindowResize,5),window.addEventListener("resize",n._handleWindowResizeThrottled))}},{key:"_removeEventHandlers",value:function(){this.$img[0].removeEventListener("load",this._handleImageLoadBound),0===n._parallaxes.length&&(window.removeEventListener("scroll",n._handleScrollThrottled),window.removeEventListener("resize",n._handleWindowResizeThrottled))}},{key:"_setupStyles",value:function(){this.$img[0].style.opacity=1}},{key:"_handleImageLoad",value:function(){this._updateParallax()}},{key:"_updateParallax",value:function(){var t=this.$el.height()>0?this.el.parentNode.offsetHeight:500,e=this.$img[0].offsetHeight-t,i=this.$el.offset().top+t,n=this.$el.offset().top,s=M.getDocumentScrollTop(),o=window.innerHeight,a=e*((s+o-n)/(t+o));this._enabled?i>s&&ne.options.responsiveThreshold}}},{key:"defaults",get:function(){return e}}]),n}();i._parallaxes=[],M.Parallax=i,M.jQueryLoaded&&M.initializeJqueryWrapper(i,"parallax","M_Parallax")}(cash),function(t,e){"use strict";var i={duration:300,onShow:null,swipeable:!1,responsiveThreshold:1/0},n=function(n){function s(e,i){_classCallCheck(this,s);var n=_possibleConstructorReturn(this,(s.__proto__||Object.getPrototypeOf(s)).call(this,s,e,i));return n.el.M_Tabs=n,n.options=t.extend({},s.defaults,i),n.$tabLinks=n.$el.children("li.tab").children("a"),n.index=0,n._setTabsAndTabWidth(),n._setupActiveTabLink(),n._createIndicator(),n.options.swipeable?n._setupSwipeableTabs():n._setupNormalTabs(),n._setupEventHandlers(),n}return _inherits(s,Component),_createClass(s,[{key:"destroy",value:function(){this._removeEventHandlers(),this._indicator.parentNode.removeChild(this._indicator),this.options.swipeable?this._teardownSwipeableTabs():this._teardownNormalTabs(),this.$el[0].M_Tabs=void 0}},{key:"_setupEventHandlers",value:function(){this._handleWindowResizeBound=this._handleWindowResize.bind(this),window.addEventListener("resize",this._handleWindowResizeBound),this._handleTabClickBound=this._handleTabClick.bind(this),this.el.addEventListener("click",this._handleTabClickBound)}},{key:"_removeEventHandlers",value:function(){window.removeEventListener("resize",this._handleWindowResizeBound),this.el.removeEventListener("click",this._handleTabClickBound)}},{key:"_handleWindowResize",value:function(){this._setTabsAndTabWidth(),0!==this.tabWidth&&0!==this.tabsWidth&&(this._indicator.style.left=this._calcLeftPos(this.$activeTabLink)+"px",this._indicator.style.right=this._calcRightPos(this.$activeTabLink)+"px")}},{key:"_handleTabClick",value:function(e){var i=this,n=t(e.target).closest("li.tab"),s=t(e.target).closest("a");if(s.length&&s.parent().hasClass("tab"))if(n.hasClass("disabled"))e.preventDefault();else if(!s.attr("target")){this._setTabsAndTabWidth(),this.$activeTabLink.removeClass("active");var o=this.$content;this.$activeTabLink=s,this.$content=t(M.escapeHash(s[0].hash)),this.$tabLinks=this.$el.children("li.tab").children("a"),this.$activeTabLink.addClass("active");var a=this.index;this.index=Math.max(this.$tabLinks.index(s),0),this.options.swipeable?this._tabsCarousel&&this._tabsCarousel.set(this.index,function(){"function"==typeof i.options.onShow&&i.options.onShow.call(i,i.$content[0])}):this.$content.length&&(this.$content[0].style.display="block",this.$content.addClass("active"),"function"==typeof this.options.onShow&&this.options.onShow.call(this,this.$content[0]),o.length&&!o.is(this.$content)&&(o[0].style.display="none",o.removeClass("active"))),this._animateIndicator(a),e.preventDefault()}}},{key:"_createIndicator",value:function(){var t=this,e=document.createElement("li");e.classList.add("indicator"),this.el.appendChild(e),this._indicator=e,setTimeout(function(){t._indicator.style.left=t._calcLeftPos(t.$activeTabLink)+"px",t._indicator.style.right=t._calcRightPos(t.$activeTabLink)+"px"},0)}},{key:"_setupActiveTabLink",value:function(){this.$activeTabLink=t(this.$tabLinks.filter('[href="'+location.hash+'"]')),0===this.$activeTabLink.length&&(this.$activeTabLink=this.$el.children("li.tab").children("a.active").first()),0===this.$activeTabLink.length&&(this.$activeTabLink=this.$el.children("li.tab").children("a").first()),this.$tabLinks.removeClass("active"),this.$activeTabLink[0].classList.add("active"),this.index=Math.max(this.$tabLinks.index(this.$activeTabLink),0),this.$activeTabLink.length&&(this.$content=t(M.escapeHash(this.$activeTabLink[0].hash)),this.$content.addClass("active"))}},{key:"_setupSwipeableTabs",value:function(){var e=this;window.innerWidth>this.options.responsiveThreshold&&(this.options.swipeable=!1);var i=t();this.$tabLinks.each(function(e){var n=t(M.escapeHash(e.hash));n.addClass("carousel-item"),i=i.add(n)});var n=t('');i.first().before(n),n.append(i),i[0].style.display="";var s=this.$activeTabLink.closest(".tab").index();this._tabsCarousel=M.Carousel.init(n[0],{fullWidth:!0,noWrap:!0,onCycleTo:function(i){var n=e.index;e.index=t(i).index(),e.$activeTabLink.removeClass("active"),e.$activeTabLink=e.$tabLinks.eq(e.index),e.$activeTabLink.addClass("active"),e._animateIndicator(n),"function"==typeof e.options.onShow&&e.options.onShow.call(e,e.$content[0])}}),this._tabsCarousel.set(s)}},{key:"_teardownSwipeableTabs",value:function(){var t=this._tabsCarousel.$el;this._tabsCarousel.destroy(),t.after(t.children()),t.remove()}},{key:"_setupNormalTabs",value:function(){this.$tabLinks.not(this.$activeTabLink).each(function(e){if(e.hash){var i=t(M.escapeHash(e.hash));i.length&&(i[0].style.display="none")}})}},{key:"_teardownNormalTabs",value:function(){this.$tabLinks.each(function(e){if(e.hash){var i=t(M.escapeHash(e.hash));i.length&&(i[0].style.display="")}})}},{key:"_setTabsAndTabWidth",value:function(){this.tabsWidth=this.$el.width(),this.tabWidth=Math.max(this.tabsWidth,this.el.scrollWidth)/this.$tabLinks.length}},{key:"_calcRightPos",value:function(t){return Math.ceil(this.tabsWidth-t.position().left-t[0].getBoundingClientRect().width)}},{key:"_calcLeftPos",value:function(t){return Math.floor(t.position().left)}},{key:"updateTabIndicator",value:function(){this._animateIndicator(this.index)}},{key:"_animateIndicator",value:function(t){var i=0,n=0;this.index-t>=0?i=90:n=90;var s={targets:this._indicator,left:{value:this._calcLeftPos(this.$activeTabLink),delay:i},right:{value:this._calcRightPos(this.$activeTabLink),delay:n},duration:this.options.duration,easing:"easeOutQuad"};e.remove(this._indicator),e(s)}},{key:"select",value:function(t){var e=this.$tabLinks.filter('[href="#'+t+'"]');e.length&&e.trigger("click")}}],[{key:"init",value:function(t,e){return _get(s.__proto__||Object.getPrototypeOf(s),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Tabs}},{key:"defaults",get:function(){return i}}]),s}();window.M.Tabs=n,M.jQueryLoaded&&M.initializeJqueryWrapper(n,"tabs","M_Tabs")}(cash,M.anime),function(t,e){"use strict";var i={exitDelay:200,enterDelay:0,html:null,margin:5,inDuration:250,outDuration:200,position:"bottom",transitionMovement:10},n=function(n){function s(e,i){_classCallCheck(this,s);var n=_possibleConstructorReturn(this,(s.__proto__||Object.getPrototypeOf(s)).call(this,s,e,i));return n.el.M_Tooltip=n,n.options=t.extend({},s.defaults,i),n.isOpen=!1,n.isHovered=!1,n.isFocused=!1,n._appendTooltipEl(),n._setupEventHandlers(),n}return _inherits(s,Component),_createClass(s,[{key:"destroy",value:function(){t(this.tooltipEl).remove(),this._removeEventHandlers(),this.el.M_Tooltip=void 0}},{key:"_appendTooltipEl",value:function(){var t=document.createElement("div");t.classList.add("material-tooltip"),this.tooltipEl=t;var e=document.createElement("div");e.classList.add("tooltip-content"),e.innerHTML=this.options.html,t.appendChild(e),document.body.appendChild(t)}},{key:"_updateTooltipContent",value:function(){this.tooltipEl.querySelector(".tooltip-content").innerHTML=this.options.html}},{key:"_setupEventHandlers",value:function(){this._handleMouseEnterBound=this._handleMouseEnter.bind(this),this._handleMouseLeaveBound=this._handleMouseLeave.bind(this),this._handleFocusBound=this._handleFocus.bind(this),this._handleBlurBound=this._handleBlur.bind(this),this.el.addEventListener("mouseenter",this._handleMouseEnterBound),this.el.addEventListener("mouseleave",this._handleMouseLeaveBound),this.el.addEventListener("focus",this._handleFocusBound,!0),this.el.addEventListener("blur",this._handleBlurBound,!0)}},{key:"_removeEventHandlers",value:function(){this.el.removeEventListener("mouseenter",this._handleMouseEnterBound),this.el.removeEventListener("mouseleave",this._handleMouseLeaveBound),this.el.removeEventListener("focus",this._handleFocusBound,!0),this.el.removeEventListener("blur",this._handleBlurBound,!0)}},{key:"open",value:function(){this.isOpen||(this.isOpen=!0,this.options=t.extend({},this.options,this._getAttributeOptions()),this._updateTooltipContent(),this._setEnterDelayTimeout())}},{key:"close",value:function(){this.isOpen&&(this.isOpen=!1,this._setExitDelayTimeout())}},{key:"_setExitDelayTimeout",value:function(){var t=this;clearTimeout(this._exitDelayTimeout),this._exitDelayTimeout=setTimeout(function(){t.isHovered||t.isFocused||t._animateOut()},this.options.exitDelay)}},{key:"_setEnterDelayTimeout",value:function(){var t=this;clearTimeout(this._enterDelayTimeout),this._enterDelayTimeout=setTimeout(function(){(t.isHovered||t.isFocused)&&t._animateIn()},this.options.enterDelay)}},{key:"_positionTooltip",value:function(){var e=this.el,i=this.tooltipEl,n=e.offsetHeight,s=e.offsetWidth,o=i.offsetHeight,a=i.offsetWidth,r=void 0,l=this.options.margin,h=void 0,d=void 0;this.xMovement=0,this.yMovement=0,h=e.getBoundingClientRect().top+M.getDocumentScrollTop(),d=e.getBoundingClientRect().left+M.getDocumentScrollLeft(),"top"===this.options.position?(h+=-o-l,d+=s/2-a/2,this.yMovement=-this.options.transitionMovement):"right"===this.options.position?(h+=n/2-o/2,d+=s+l,this.xMovement=this.options.transitionMovement):"left"===this.options.position?(h+=n/2-o/2,d+=-a-l,this.xMovement=-this.options.transitionMovement):(h+=n+l,d+=s/2-a/2,this.yMovement=this.options.transitionMovement),r=this._repositionWithinScreen(d,h,a,o),t(i).css({top:r.y+"px",left:r.x+"px"})}},{key:"_repositionWithinScreen",value:function(t,e,i,n){var s=M.getDocumentScrollLeft(),o=M.getDocumentScrollTop(),a=t-s,r=e-o,l={left:a,top:r,width:i,height:n},h=this.options.margin+this.options.transitionMovement,d=M.checkWithinContainer(document.body,l,h);return d.left?a=h:d.right&&(a-=a+i-window.innerWidth),d.top?r=h:d.bottom&&(r-=r+n-window.innerHeight),{x:a+s,y:r+o}}},{key:"_animateIn",value:function(){this._positionTooltip(),this.tooltipEl.style.visibility="visible",e.remove(this.tooltipEl),e({targets:this.tooltipEl,opacity:1,translateX:this.xMovement,translateY:this.yMovement,duration:this.options.inDuration,easing:"easeOutCubic"})}},{key:"_animateOut",value:function(){e.remove(this.tooltipEl),e({targets:this.tooltipEl,opacity:0,translateX:0,translateY:0,duration:this.options.outDuration,easing:"easeOutCubic"})}},{key:"_handleMouseEnter",value:function(){this.isHovered=!0,this.open()}},{key:"_handleMouseLeave",value:function(){this.isHovered=!1,this.close()}},{key:"_handleFocus",value:function(){this.isFocused=!0,this.open()}},{key:"_handleBlur",value:function(){this.isFocused=!1,this.close()}},{key:"_getAttributeOptions",value:function(){var t={},e=this.el.getAttribute("data-tooltip"),i=this.el.getAttribute("data-position");return e&&(t.html=e),i&&(t.position=i),t}}],[{key:"init",value:function(t,e){return _get(s.__proto__||Object.getPrototypeOf(s),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Tooltip}},{key:"defaults",get:function(){return i}}]),s}();M.Tooltip=n,M.jQueryLoaded&&M.initializeJqueryWrapper(n,"tooltip","M_Tooltip")}(cash,M.anime),function(t){"use strict";function e(t){return null!==t&&t===t.window}function i(t){return e(t)?t:9===t.nodeType&&t.defaultView}function n(t){var e,n,s={top:0,left:0},o=t&&t.ownerDocument;return e=o.documentElement,void 0!==t.getBoundingClientRect&&(s=t.getBoundingClientRect()),n=i(o),{top:s.top+n.pageYOffset-e.clientTop,left:s.left+n.pageXOffset-e.clientLeft}}function s(t){var e="";for(var i in t)t.hasOwnProperty(i)&&(e+=i+":"+t[i]+";");return e}function o(t){if(!1===d.allowEvent(t))return null;for(var e=null,i=t.target||t.srcElement;null!==i.parentNode;){if(!(i instanceof SVGElement)&&-1!==i.className.indexOf("waves-effect")){e=i;break}i=i.parentNode}return e}function a(e){var i=o(e);null!==i&&(h.show(e,i),"ontouchstart"in t&&(i.addEventListener("touchend",h.hide,!1),i.addEventListener("touchcancel",h.hide,!1)),i.addEventListener("mouseup",h.hide,!1),i.addEventListener("mouseleave",h.hide,!1),i.addEventListener("dragend",h.hide,!1))}var r=r||{},l=document.querySelectorAll.bind(document),h={duration:750,show:function(t,e){if(2===t.button)return!1;var i=e||this,o=document.createElement("div");o.className="waves-ripple",i.appendChild(o);var a=n(i),r=t.pageY-a.top,l=t.pageX-a.left,d="scale("+i.clientWidth/100*10+")";"touches"in t&&(r=t.touches[0].pageY-a.top,l=t.touches[0].pageX-a.left),o.setAttribute("data-hold",Date.now()),o.setAttribute("data-scale",d),o.setAttribute("data-x",l),o.setAttribute("data-y",r);var u={top:r+"px",left:l+"px"};o.className=o.className+" waves-notransition",o.setAttribute("style",s(u)),o.className=o.className.replace("waves-notransition",""),u["-webkit-transform"]=d,u["-moz-transform"]=d,u["-ms-transform"]=d,u["-o-transform"]=d,u.transform=d,u.opacity="1",u["-webkit-transition-duration"]=h.duration+"ms",u["-moz-transition-duration"]=h.duration+"ms",u["-o-transition-duration"]=h.duration+"ms",u["transition-duration"]=h.duration+"ms",u["-webkit-transition-timing-function"]="cubic-bezier(0.250, 0.460, 0.450, 0.940)",u["-moz-transition-timing-function"]="cubic-bezier(0.250, 0.460, 0.450, 0.940)",u["-o-transition-timing-function"]="cubic-bezier(0.250, 0.460, 0.450, 0.940)",u["transition-timing-function"]="cubic-bezier(0.250, 0.460, 0.450, 0.940)",o.setAttribute("style",s(u))},hide:function(t){d.touchup(t);var e=this,i=(e.clientWidth,null),n=e.getElementsByClassName("waves-ripple");if(!(n.length>0))return!1;var o=(i=n[n.length-1]).getAttribute("data-x"),a=i.getAttribute("data-y"),r=i.getAttribute("data-scale"),l=350-(Date.now()-Number(i.getAttribute("data-hold")));l<0&&(l=0),setTimeout(function(){var t={top:a+"px",left:o+"px",opacity:"0","-webkit-transition-duration":h.duration+"ms","-moz-transition-duration":h.duration+"ms","-o-transition-duration":h.duration+"ms","transition-duration":h.duration+"ms","-webkit-transform":r,"-moz-transform":r,"-ms-transform":r,"-o-transform":r,transform:r};i.setAttribute("style",s(t)),setTimeout(function(){try{e.removeChild(i)}catch(t){return!1}},h.duration)},l)},wrapInput:function(t){for(var e=0;e0&&(d.touches-=1)},500):"mousedown"===t.type&&d.touches>0&&(e=!1),e},touchup:function(t){d.allowEvent(t)}};r.displayEffect=function(e){"duration"in(e=e||{})&&(h.duration=e.duration),h.wrapInput(l(".waves-effect")),"ontouchstart"in t&&document.body.addEventListener("touchstart",a,!1),document.body.addEventListener("mousedown",a,!1)},r.attach=function(e){"input"===e.tagName.toLowerCase()&&(h.wrapInput([e]),e=e.parentNode),"ontouchstart"in t&&e.addEventListener("touchstart",a,!1),e.addEventListener("mousedown",a,!1)},t.Waves=r,document.addEventListener("DOMContentLoaded",function(){r.displayEffect()},!1)}(window),function(t,e){"use strict";var i={html:"",displayLength:4e3,inDuration:300,outDuration:375,classes:"",completeCallback:null,activationPercent:.8},n=function(){function n(e){_classCallCheck(this,n),this.options=t.extend({},n.defaults,e),this.message=this.options.html,this.panning=!1,this.timeRemaining=this.options.displayLength,0===n._toasts.length&&n._createContainer(),n._toasts.push(this);var i=this._createToast();i.M_Toast=this,this.el=i,this._animateIn(),this._setTimer()}return _createClass(n,[{key:"_createToast",value:function(){var e=document.createElement("div");return e.classList.add("toast"),this.options.classes.length&&t(e).addClass(this.options.classes),("object"==typeof HTMLElement?this.message instanceof HTMLElement:this.message&&"object"==typeof this.message&&null!==this.message&&1===this.message.nodeType&&"string"==typeof this.message.nodeName)?e.appendChild(this.message):this.message.jquery?t(e).append(this.message[0]):e.innerHTML=this.message,n._container.appendChild(e),e}},{key:"_animateIn",value:function(){e({targets:this.el,top:0,opacity:1,duration:300,easing:"easeOutCubic"})}},{key:"_setTimer",value:function(){var t=this;this.timeRemaining!==1/0&&(this.counterInterval=setInterval(function(){t.panning||(t.timeRemaining-=20),t.timeRemaining<=0&&t.dismiss()},20))}},{key:"dismiss",value:function(){var t=this;window.clearInterval(this.counterInterval);var i=this.el.offsetWidth*this.options.activationPercent;this.wasSwiped&&(this.el.style.transition="transform .05s, opacity .05s",this.el.style.transform="translateX("+i+"px)",this.el.style.opacity=0),e({targets:this.el,opacity:0,marginTop:-40,duration:this.options.outDuration,easing:"easeOutExpo",complete:function(){"function"==typeof t.options.completeCallback&&t.options.completeCallback(),t.el.parentNode.removeChild(t.el),n._toasts.splice(n._toasts.indexOf(t),1),0===n._toasts.length&&n._removeContainer()}})}}],[{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Toast}},{key:"_createContainer",value:function(){var t=document.createElement("div");t.setAttribute("id","toast-container"),t.addEventListener("touchstart",n._onDragStart),t.addEventListener("touchmove",n._onDragMove),t.addEventListener("touchend",n._onDragEnd),t.addEventListener("mousedown",n._onDragStart),document.addEventListener("mousemove",n._onDragMove),document.addEventListener("mouseup",n._onDragEnd),document.body.appendChild(t),n._container=t}},{key:"_removeContainer",value:function(){document.removeEventListener("mousemove",n._onDragMove),document.removeEventListener("mouseup",n._onDragEnd),n._container.parentNode.removeChild(n._container),n._container=null}},{key:"_onDragStart",value:function(e){if(e.target&&t(e.target).closest(".toast").length){var i=t(e.target).closest(".toast")[0].M_Toast;i.panning=!0,n._draggedToast=i,i.el.classList.add("panning"),i.el.style.transition="",i.startingXPos=n._xPos(e),i.time=Date.now(),i.xPos=n._xPos(e)}}},{key:"_onDragMove",value:function(t){if(n._draggedToast){t.preventDefault();var e=n._draggedToast;e.deltaX=Math.abs(e.xPos-n._xPos(t)),e.xPos=n._xPos(t),e.velocityX=e.deltaX/(Date.now()-e.time),e.time=Date.now();var i=e.xPos-e.startingXPos,s=e.el.offsetWidth*e.options.activationPercent;e.el.style.transform="translateX("+i+"px)",e.el.style.opacity=1-Math.abs(i/s)}}},{key:"_onDragEnd",value:function(){if(n._draggedToast){var t=n._draggedToast;t.panning=!1,t.el.classList.remove("panning");var e=t.xPos-t.startingXPos,i=t.el.offsetWidth*t.options.activationPercent;Math.abs(e)>i||t.velocityX>1?(t.wasSwiped=!0,t.dismiss()):(t.el.style.transition="transform .2s, opacity .2s",t.el.style.transform="",t.el.style.opacity=""),n._draggedToast=null}}},{key:"_xPos",value:function(t){return t.targetTouches&&t.targetTouches.length>=1?t.targetTouches[0].clientX:t.clientX}},{key:"dismissAll",value:function(){for(var t in n._toasts)n._toasts[t].dismiss()}},{key:"defaults",get:function(){return i}}]),n}();n._toasts=[],n._container=null,n._draggedToast=null,M.Toast=n,M.toast=function(t){return new n(t)}}(cash,M.anime),function(t,e){"use strict";var i={edge:"left",draggable:!0,inDuration:250,outDuration:200,onOpenStart:null,onOpenEnd:null,onCloseStart:null,onCloseEnd:null,preventScrolling:!0},n=function(n){function s(e,i){_classCallCheck(this,s);var n=_possibleConstructorReturn(this,(s.__proto__||Object.getPrototypeOf(s)).call(this,s,e,i));return n.el.M_Sidenav=n,n.id=n.$el.attr("id"),n.options=t.extend({},s.defaults,i),n.isOpen=!1,n.isFixed=n.el.classList.contains("sidenav-fixed"),n.isDragged=!1,n.lastWindowWidth=window.innerWidth,n.lastWindowHeight=window.innerHeight,n._createOverlay(),n._createDragTarget(),n._setupEventHandlers(),n._setupClasses(),n._setupFixed(),s._sidenavs.push(n),n}return _inherits(s,Component),_createClass(s,[{key:"destroy",value:function(){this._removeEventHandlers(),this._overlay.parentNode.removeChild(this._overlay),this.dragTarget.parentNode.removeChild(this.dragTarget),this.el.M_Sidenav=void 0;var t=s._sidenavs.indexOf(this);t>=0&&s._sidenavs.splice(t,1)}},{key:"_createOverlay",value:function(){var t=document.createElement("div");this._closeBound=this.close.bind(this),t.classList.add("sidenav-overlay"),t.addEventListener("click",this._closeBound),document.body.appendChild(t),this._overlay=t}},{key:"_setupEventHandlers",value:function(){0===s._sidenavs.length&&document.body.addEventListener("click",this._handleTriggerClick),this._handleDragTargetDragBound=this._handleDragTargetDrag.bind(this),this._handleDragTargetReleaseBound=this._handleDragTargetRelease.bind(this),this._handleCloseDragBound=this._handleCloseDrag.bind(this),this._handleCloseReleaseBound=this._handleCloseRelease.bind(this),this._handleCloseTriggerClickBound=this._handleCloseTriggerClick.bind(this),this.dragTarget.addEventListener("touchmove",this._handleDragTargetDragBound),this.dragTarget.addEventListener("touchend",this._handleDragTargetReleaseBound),this._overlay.addEventListener("touchmove",this._handleCloseDragBound),this._overlay.addEventListener("touchend",this._handleCloseReleaseBound),this.el.addEventListener("touchmove",this._handleCloseDragBound),this.el.addEventListener("touchend",this._handleCloseReleaseBound),this.el.addEventListener("click",this._handleCloseTriggerClickBound),this.isFixed&&(this._handleWindowResizeBound=this._handleWindowResize.bind(this),window.addEventListener("resize",this._handleWindowResizeBound))}},{key:"_removeEventHandlers",value:function(){1===s._sidenavs.length&&document.body.removeEventListener("click",this._handleTriggerClick),this.dragTarget.removeEventListener("touchmove",this._handleDragTargetDragBound),this.dragTarget.removeEventListener("touchend",this._handleDragTargetReleaseBound),this._overlay.removeEventListener("touchmove",this._handleCloseDragBound),this._overlay.removeEventListener("touchend",this._handleCloseReleaseBound),this.el.removeEventListener("touchmove",this._handleCloseDragBound),this.el.removeEventListener("touchend",this._handleCloseReleaseBound),this.el.removeEventListener("click",this._handleCloseTriggerClickBound),this.isFixed&&window.removeEventListener("resize",this._handleWindowResizeBound)}},{key:"_handleTriggerClick",value:function(e){var i=t(e.target).closest(".sidenav-trigger");if(e.target&&i.length){var n=M.getIdFromTrigger(i[0]),s=document.getElementById(n).M_Sidenav;s&&s.open(i),e.preventDefault()}}},{key:"_startDrag",value:function(t){var i=t.targetTouches[0].clientX;this.isDragged=!0,this._startingXpos=i,this._xPos=this._startingXpos,this._time=Date.now(),this._width=this.el.getBoundingClientRect().width,this._overlay.style.display="block",this._initialScrollTop=this.isOpen?this.el.scrollTop:M.getDocumentScrollTop(),this._verticallyScrolling=!1,e.remove(this.el),e.remove(this._overlay)}},{key:"_dragMoveUpdate",value:function(t){var e=t.targetTouches[0].clientX,i=this.isOpen?this.el.scrollTop:M.getDocumentScrollTop();this.deltaX=Math.abs(this._xPos-e),this._xPos=e,this.velocityX=this.deltaX/(Date.now()-this._time),this._time=Date.now(),this._initialScrollTop!==i&&(this._verticallyScrolling=!0)}},{key:"_handleDragTargetDrag",value:function(t){if(this.options.draggable&&!this._isCurrentlyFixed()&&!this._verticallyScrolling){this.isDragged||this._startDrag(t),this._dragMoveUpdate(t);var e=this._xPos-this._startingXpos,i=e>0?"right":"left";e=Math.min(this._width,Math.abs(e)),this.options.edge===i&&(e=0);var n=e,s="translateX(-100%)";"right"===this.options.edge&&(s="translateX(100%)",n=-n),this.percentOpen=Math.min(1,e/this._width),this.el.style.transform=s+" translateX("+n+"px)",this._overlay.style.opacity=this.percentOpen}}},{key:"_handleDragTargetRelease",value:function(){this.isDragged&&(this.percentOpen>.5?this.open():this._animateOut(),this.isDragged=!1,this._verticallyScrolling=!1)}},{key:"_handleCloseDrag",value:function(t){if(this.isOpen){if(!this.options.draggable||this._isCurrentlyFixed()||this._verticallyScrolling)return;this.isDragged||this._startDrag(t),this._dragMoveUpdate(t);var e=this._xPos-this._startingXpos,i=e>0?"right":"left";e=Math.min(this._width,Math.abs(e)),this.options.edge!==i&&(e=0);var n=-e;"right"===this.options.edge&&(n=-n),this.percentOpen=Math.min(1,1-e/this._width),this.el.style.transform="translateX("+n+"px)",this._overlay.style.opacity=this.percentOpen}}},{key:"_handleCloseRelease",value:function(){this.isOpen&&this.isDragged&&(this.percentOpen>.5?this._animateIn():this.close(),this.isDragged=!1,this._verticallyScrolling=!1)}},{key:"_handleCloseTriggerClick",value:function(e){t(e.target).closest(".sidenav-close").length&&!this._isCurrentlyFixed()&&this.close()}},{key:"_handleWindowResize",value:function(){this.lastWindowWidth!==window.innerWidth&&(window.innerWidth>992?this.open():this.close()),this.lastWindowWidth=window.innerWidth,this.lastWindowHeight=window.innerHeight}},{key:"_setupClasses",value:function(){"right"===this.options.edge&&(this.el.classList.add("right-aligned"),this.dragTarget.classList.add("right-aligned"))}},{key:"_removeClasses",value:function(){this.el.classList.remove("right-aligned"),this.dragTarget.classList.remove("right-aligned")}},{key:"_setupFixed",value:function(){this._isCurrentlyFixed()&&this.open()}},{key:"_isCurrentlyFixed",value:function(){return this.isFixed&&window.innerWidth>992}},{key:"_createDragTarget",value:function(){var t=document.createElement("div");t.classList.add("drag-target"),document.body.appendChild(t),this.dragTarget=t}},{key:"_preventBodyScrolling",value:function(){document.body.style.overflow="hidden"}},{key:"_enableBodyScrolling",value:function(){document.body.style.overflow=""}},{key:"open",value:function(){!0!==this.isOpen&&(this.isOpen=!0,"function"==typeof this.options.onOpenStart&&this.options.onOpenStart.call(this,this.el),this._isCurrentlyFixed()?(e.remove(this.el),e({targets:this.el,translateX:0,duration:0,easing:"easeOutQuad"}),this._enableBodyScrolling(),this._overlay.style.display="none"):(this.options.preventScrolling&&this._preventBodyScrolling(),this.isDragged&&1==this.percentOpen||this._animateIn()))}},{key:"close",value:function(){if(!1!==this.isOpen)if(this.isOpen=!1,"function"==typeof this.options.onCloseStart&&this.options.onCloseStart.call(this,this.el),this._isCurrentlyFixed()){var t="left"===this.options.edge?"-105%":"105%";this.el.style.transform="translateX("+t+")"}else this._enableBodyScrolling(),this.isDragged&&0==this.percentOpen?this._overlay.style.display="none":this._animateOut()}},{key:"_animateIn",value:function(){this._animateSidenavIn(),this._animateOverlayIn()}},{key:"_animateSidenavIn",value:function(){var t=this,i="left"===this.options.edge?-1:1;this.isDragged&&(i="left"===this.options.edge?i+this.percentOpen:i-this.percentOpen),e.remove(this.el),e({targets:this.el,translateX:[100*i+"%",0],duration:this.options.inDuration,easing:"easeOutQuad",complete:function(){"function"==typeof t.options.onOpenEnd&&t.options.onOpenEnd.call(t,t.el)}})}},{key:"_animateOverlayIn",value:function(){var i=0;this.isDragged?i=this.percentOpen:t(this._overlay).css({display:"block"}),e.remove(this._overlay),e({targets:this._overlay,opacity:[i,1],duration:this.options.inDuration,easing:"easeOutQuad"})}},{key:"_animateOut",value:function(){this._animateSidenavOut(),this._animateOverlayOut()}},{key:"_animateSidenavOut",value:function(){var t=this,i="left"===this.options.edge?-1:1,n=0;this.isDragged&&(n="left"===this.options.edge?i+this.percentOpen:i-this.percentOpen),e.remove(this.el),e({targets:this.el,translateX:[100*n+"%",105*i+"%"],duration:this.options.outDuration,easing:"easeOutQuad",complete:function(){"function"==typeof t.options.onCloseEnd&&t.options.onCloseEnd.call(t,t.el)}})}},{key:"_animateOverlayOut",value:function(){var i=this;e.remove(this._overlay),e({targets:this._overlay,opacity:0,duration:this.options.outDuration,easing:"easeOutQuad",complete:function(){t(i._overlay).css("display","none")}})}}],[{key:"init",value:function(t,e){return _get(s.__proto__||Object.getPrototypeOf(s),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Sidenav}},{key:"defaults",get:function(){return i}}]),s}();n._sidenavs=[],window.M.Sidenav=n,M.jQueryLoaded&&M.initializeJqueryWrapper(n,"sidenav","M_Sidenav")}(cash,M.anime),function(t,e){"use strict";var i={throttle:100,scrollOffset:200,activeClass:"active",getActiveElement:function(t){return'a[href="#'+t+'"]'}},n=function(n){function s(e,i){_classCallCheck(this,s);var n=_possibleConstructorReturn(this,(s.__proto__||Object.getPrototypeOf(s)).call(this,s,e,i));return n.el.M_ScrollSpy=n,n.options=t.extend({},s.defaults,i),s._elements.push(n),s._count++,s._increment++,n.tickId=-1,n.id=s._increment,n._setupEventHandlers(),n._handleWindowScroll(),n}return _inherits(s,Component),_createClass(s,[{key:"destroy",value:function(){s._elements.splice(s._elements.indexOf(this),1),s._elementsInView.splice(s._elementsInView.indexOf(this),1),s._visibleElements.splice(s._visibleElements.indexOf(this.$el),1),s._count--,this._removeEventHandlers(),t(this.options.getActiveElement(this.$el.attr("id"))).removeClass(this.options.activeClass),this.el.M_ScrollSpy=void 0}},{key:"_setupEventHandlers",value:function(){var t=M.throttle(this._handleWindowScroll,200);this._handleThrottledResizeBound=t.bind(this),this._handleWindowScrollBound=this._handleWindowScroll.bind(this),1===s._count&&(window.addEventListener("scroll",this._handleWindowScrollBound),window.addEventListener("resize",this._handleThrottledResizeBound),document.body.addEventListener("click",this._handleTriggerClick))}},{key:"_removeEventHandlers",value:function(){0===s._count&&(window.removeEventListener("scroll",this._handleWindowScrollBound),window.removeEventListener("resize",this._handleThrottledResizeBound),document.body.removeEventListener("click",this._handleTriggerClick))}},{key:"_handleTriggerClick",value:function(i){for(var n=t(i.target),o=s._elements.length-1;o>=0;o--){var a=s._elements[o];if(n.is('a[href="#'+a.$el.attr("id")+'"]')){i.preventDefault();var r=a.$el.offset().top+1;e({targets:[document.documentElement,document.body],scrollTop:r-a.options.scrollOffset,duration:400,easing:"easeOutCubic"});break}}}},{key:"_handleWindowScroll",value:function(){s._ticks++;for(var t=M.getDocumentScrollTop(),e=M.getDocumentScrollLeft(),i=e+window.innerWidth,n=t+window.innerHeight,o=s._findElements(t,i,n,e),a=0;a=0&&d!==s._ticks&&(h._exit(),h.tickId=-1)}s._elementsInView=o}},{key:"_enter",value:function(){s._visibleElements=s._visibleElements.filter(function(t){return 0!=t.height()}),s._visibleElements[0]?(t(this.options.getActiveElement(s._visibleElements[0].attr("id"))).removeClass(this.options.activeClass),s._visibleElements[0][0].M_ScrollSpy&&this.id0){var h=r.$el.offset().top,d=r.$el.offset().left,u=d+r.$el.width(),c=h+r.$el.height();!(d>e||ui||c=this.options.minLength&&(this.isOpen=!0,this._renderDropdown(this.options.data,i)),this.dropdown.isOpen?this.dropdown.recalculateDimensions():setTimeout(function(){e.dropdown.open()},100)),this.oldVal=i)}},{key:"_handleInputKeydown",value:function(e){n._keydown=!0;var i=e.keyCode,s=void 0,o=t(this.container).children("li").length;13===i&&this.activeIndex>=0?(s=t(this.container).children("li").eq(this.activeIndex)).length&&(this.selectOption(s),e.preventDefault()):38!==i&&40!==i||(e.preventDefault(),38===i&&this.activeIndex>0&&this.activeIndex--,40===i&&this.activeIndex=0&&(this.$active=t(this.container).children("li").eq(this.activeIndex),this.$active.addClass("active")))}},{key:"_handleContainerMousedownAndTouchstart",value:function(e){var i=t(e.target).closest("li");this.selectOption(i)}},{key:"_highlight",value:function(t,e){var i=e.find("img"),n=e.text().toLowerCase().indexOf(""+t.toLowerCase()),s=n+t.length-1,o=e.text().slice(0,n),a=e.text().slice(n,s+1),r=e.text().slice(s+1);e.html(""+o+""+a+""+r+""),i.length&&e.prepend(i)}},{key:"_resetCurrentElement",value:function(){this.activeIndex=-1,this.$active.removeClass("active")}},{key:"_resetAutocomplete",value:function(){t(this.container).empty(),this._resetCurrentElement(),this.oldVal=null,this.isOpen=!1}},{key:"selectOption",value:function(t){var e=t.text().trim();this.el.value=e,this.$el.trigger("change"),this._resetAutocomplete(),this.dropdown.close(),"function"==typeof this.options.onAutocomplete&&this.options.onAutocomplete.call(this,e)}},{key:"_renderDropdown",value:function(e,i){var n=this;this._resetAutocomplete();var s=[];for(var o in e)if(e.hasOwnProperty(o)&&-1!==o.toLowerCase().indexOf(i)){if(this.count>=this.options.limit)break;var a={data:e[o],key:o};s.push(a),this.count++}s.sort(function(t,e){return n.options.sortFunction(t.key.toLowerCase(),e.key.toLowerCase(),i.toLowerCase())});for(var r=0;r");l.data?h.append(''+l.key+""):h.append(""+l.key+""),t(this.container).append(h),this._highlight(i,h)}}},{key:"updateData",value:function(t){var e=this.el.value.toLowerCase();this.options.data=t,this.isOpen&&this._renderDropdown(t,e)}}],[{key:"init",value:function(t,e){return _get(n.__proto__||Object.getPrototypeOf(n),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Autocomplete}},{key:"defaults",get:function(){return e}}]),n}();i._keydown=!1,M.Autocomplete=i,M.jQueryLoaded&&M.initializeJqueryWrapper(i,"autocomplete","M_Autocomplete")}(cash),function(t){M.updateTextFields=function(){t("input[type=text], input[type=password], input[type=email], input[type=url], input[type=tel], input[type=number], input[type=search], input[type=date], input[type=time], textarea").each(function(e,i){var n=t(this);e.value.length>0||t(e).is(":focus")||e.autofocus||null!==n.attr("placeholder")?n.siblings("label").addClass("active"):e.validity?n.siblings("label").toggleClass("active",!0===e.validity.badInput):n.siblings("label").removeClass("active")})},M.validate_field=function(t){var e=null!==t.attr("data-length"),i=parseInt(t.attr("data-length")),n=t[0].value.length;0!==n||!1!==t[0].validity.badInput||t.is(":required")?t.hasClass("validate")&&(t.is(":valid")&&e&&n<=i||t.is(":valid")&&!e?(t.removeClass("invalid"),t.addClass("valid")):(t.removeClass("valid"),t.addClass("invalid"))):t.hasClass("validate")&&(t.removeClass("valid"),t.removeClass("invalid"))},M.textareaAutoResize=function(e){if(e instanceof Element&&(e=t(e)),e.length){var i=t(".hiddendiv").first();i.length||(i=t('
    '),t("body").append(i));var n=e.css("font-family"),s=e.css("font-size"),o=e.css("line-height"),a=e.css("padding-top"),r=e.css("padding-right"),l=e.css("padding-bottom"),h=e.css("padding-left");s&&i.css("font-size",s),n&&i.css("font-family",n),o&&i.css("line-height",o),a&&i.css("padding-top",a),r&&i.css("padding-right",r),l&&i.css("padding-bottom",l),h&&i.css("padding-left",h),e.data("original-height")||e.data("original-height",e.height()),"off"===e.attr("wrap")&&i.css("overflow-wrap","normal").css("white-space","pre"),i.text(e[0].value+"\n");var d=i.html().replace(/\n/g,"
    ");i.html(d),e[0].offsetWidth>0&&e[0].offsetHeight>0?i.css("width",e.width()+"px"):i.css("width",window.innerWidth/2+"px"),e.data("original-height")<=i.innerHeight()?e.css("height",i.innerHeight()+"px"):e[0].value.length'),this.$slides.each(function(i,n){var s=t('
  • ');e.$indicators.append(s[0])}),this.$el.append(this.$indicators[0]),this.$indicators=this.$indicators.children("li.indicator-item"))}},{key:"_removeIndicators",value:function(){this.$el.find("ul.indicators").remove()}},{key:"set",value:function(t){var i=this;if(t>=this.$slides.length?t=0:t<0&&(t=this.$slides.length-1),this.activeIndex!=t){this.$active=this.$slides.eq(this.activeIndex);var n=this.$active.find(".caption");this.$active.removeClass("active"),e({targets:this.$active[0],opacity:0,duration:this.options.duration,easing:"easeOutQuad",complete:function(){i.$slides.not(".active").each(function(t){e({targets:t,opacity:0,translateX:0,translateY:0,duration:0,easing:"easeOutQuad"})})}}),this._animateCaptionIn(n[0],this.options.duration),this.options.indicators&&(this.$indicators.eq(this.activeIndex).removeClass("active"),this.$indicators.eq(t).addClass("active")),e({targets:this.$slides.eq(t)[0],opacity:1,duration:this.options.duration,easing:"easeOutQuad"}),e({targets:this.$slides.eq(t).find(".caption")[0],opacity:1,translateX:0,translateY:0,duration:this.options.duration,delay:this.options.duration,easing:"easeOutQuad"}),this.$slides.eq(t).addClass("active"),this.activeIndex=t,this.start()}}},{key:"pause",value:function(){clearInterval(this.interval)}},{key:"start",value:function(){clearInterval(this.interval),this.interval=setInterval(this._handleIntervalBound,this.options.duration+this.options.interval)}},{key:"next",value:function(){var t=this.activeIndex+1;t>=this.$slides.length?t=0:t<0&&(t=this.$slides.length-1),this.set(t)}},{key:"prev",value:function(){var t=this.activeIndex-1;t>=this.$slides.length?t=0:t<0&&(t=this.$slides.length-1),this.set(t)}}],[{key:"init",value:function(t,e){return _get(s.__proto__||Object.getPrototypeOf(s),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Slider}},{key:"defaults",get:function(){return i}}]),s}();M.Slider=n,M.jQueryLoaded&&M.initializeJqueryWrapper(n,"slider","M_Slider")}(cash,M.anime),function(t,e){t(document).on("click",".card",function(i){if(t(this).children(".card-reveal").length){var n=t(i.target).closest(".card");void 0===n.data("initialOverflow")&&n.data("initialOverflow",void 0===n.css("overflow")?"":n.css("overflow"));var s=t(this).find(".card-reveal");t(i.target).is(t(".card-reveal .card-title"))||t(i.target).is(t(".card-reveal .card-title i"))?e({targets:s[0],translateY:0,duration:225,easing:"easeInOutQuad",complete:function(e){var i=e.animatables[0].target;t(i).css({display:"none"}),n.css("overflow",n.data("initialOverflow"))}}):(t(i.target).is(t(".card .activator"))||t(i.target).is(t(".card .activator i")))&&(n.css("overflow","hidden"),s.css({display:"block"}),e({targets:s[0],translateY:"-100%",duration:300,easing:"easeInOutQuad"}))}})}(cash,M.anime),function(t){"use strict";var e={data:[],placeholder:"",secondaryPlaceholder:"",autocompleteOptions:{},limit:1/0,onChipAdd:null,onChipSelect:null,onChipDelete:null},i=function(i){function n(e,i){_classCallCheck(this,n);var s=_possibleConstructorReturn(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,n,e,i));return s.el.M_Chips=s,s.options=t.extend({},n.defaults,i),s.$el.addClass("chips input-field"),s.chipsData=[],s.$chips=t(),s._setupInput(),s.hasAutocomplete=Object.keys(s.options.autocompleteOptions).length>0,s.$input.attr("id")||s.$input.attr("id",M.guid()),s.options.data.length&&(s.chipsData=s.options.data,s._renderChips(s.chipsData)),s.hasAutocomplete&&s._setupAutocomplete(),s._setPlaceholder(),s._setupLabel(),s._setupEventHandlers(),s}return _inherits(n,Component),_createClass(n,[{key:"getData",value:function(){return this.chipsData}},{key:"destroy",value:function(){this._removeEventHandlers(),this.$chips.remove(),this.el.M_Chips=void 0}},{key:"_setupEventHandlers",value:function(){this._handleChipClickBound=this._handleChipClick.bind(this),this._handleInputKeydownBound=this._handleInputKeydown.bind(this),this._handleInputFocusBound=this._handleInputFocus.bind(this),this._handleInputBlurBound=this._handleInputBlur.bind(this),this.el.addEventListener("click",this._handleChipClickBound),document.addEventListener("keydown",n._handleChipsKeydown),document.addEventListener("keyup",n._handleChipsKeyup),this.el.addEventListener("blur",n._handleChipsBlur,!0),this.$input[0].addEventListener("focus",this._handleInputFocusBound),this.$input[0].addEventListener("blur",this._handleInputBlurBound),this.$input[0].addEventListener("keydown",this._handleInputKeydownBound)}},{key:"_removeEventHandlers",value:function(){this.el.removeEventListener("click",this._handleChipClickBound),document.removeEventListener("keydown",n._handleChipsKeydown),document.removeEventListener("keyup",n._handleChipsKeyup),this.el.removeEventListener("blur",n._handleChipsBlur,!0),this.$input[0].removeEventListener("focus",this._handleInputFocusBound),this.$input[0].removeEventListener("blur",this._handleInputBlurBound),this.$input[0].removeEventListener("keydown",this._handleInputKeydownBound)}},{key:"_handleChipClick",value:function(e){var i=t(e.target).closest(".chip"),n=t(e.target).is(".close");if(i.length){var s=i.index();n?(this.deleteChip(s),this.$input[0].focus()):this.selectChip(s)}else this.$input[0].focus()}},{key:"_handleInputFocus",value:function(){this.$el.addClass("focus")}},{key:"_handleInputBlur",value:function(){this.$el.removeClass("focus")}},{key:"_handleInputKeydown",value:function(t){if(n._keydown=!0,13===t.keyCode){if(this.hasAutocomplete&&this.autocomplete&&this.autocomplete.isOpen)return;t.preventDefault(),this.addChip({tag:this.$input[0].value}),this.$input[0].value=""}else 8!==t.keyCode&&37!==t.keyCode||""!==this.$input[0].value||!this.chipsData.length||(t.preventDefault(),this.selectChip(this.chipsData.length-1))}},{key:"_renderChip",value:function(e){if(e.tag){var i=document.createElement("div"),n=document.createElement("i");if(i.classList.add("chip"),i.textContent=e.tag,i.setAttribute("tabindex",0),t(n).addClass("material-icons close"),n.textContent="close",e.image){var s=document.createElement("img");s.setAttribute("src",e.image),i.insertBefore(s,i.firstChild)}return i.appendChild(n),i}}},{key:"_renderChips",value:function(){this.$chips.remove();for(var t=0;t"),this.$el.append(this.$input)),this.$input.addClass("input")}},{key:"_setupLabel",value:function(){this.$label=this.$el.find("label"),this.$label.length&&this.$label.setAttribute("for",this.$input.attr("id"))}},{key:"_setPlaceholder",value:function(){void 0!==this.chipsData&&!this.chipsData.length&&this.options.placeholder?t(this.$input).prop("placeholder",this.options.placeholder):(void 0===this.chipsData||this.chipsData.length)&&this.options.secondaryPlaceholder&&t(this.$input).prop("placeholder",this.options.secondaryPlaceholder)}},{key:"_isValid",value:function(t){if(t.hasOwnProperty("tag")&&""!==t.tag){for(var e=!1,i=0;i=this.options.limit)){var i=this._renderChip(e);this.$chips.add(i),this.chipsData.push(e),t(this.$input).before(i),this._setPlaceholder(),"function"==typeof this.options.onChipAdd&&this.options.onChipAdd.call(this,this.$el,i)}}},{key:"deleteChip",value:function(e){var i=this.$chips.eq(e);this.$chips.eq(e).remove(),this.$chips=this.$chips.filter(function(e){return t(e).index()>=0}),this.chipsData.splice(e,1),this._setPlaceholder(),"function"==typeof this.options.onChipDelete&&this.options.onChipDelete.call(this,this.$el,i[0])}},{key:"selectChip",value:function(t){var e=this.$chips.eq(t);this._selectedChip=e,e[0].focus(),"function"==typeof this.options.onChipSelect&&this.options.onChipSelect.call(this,this.$el,e[0])}}],[{key:"init",value:function(t,e){return _get(n.__proto__||Object.getPrototypeOf(n),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Chips}},{key:"_handleChipsKeydown",value:function(e){n._keydown=!0;var i=t(e.target).closest(".chips"),s=e.target&&i.length;if(!t(e.target).is("input, textarea")&&s){var o=i[0].M_Chips;if(8===e.keyCode||46===e.keyCode){e.preventDefault();var a=o.chipsData.length;if(o._selectedChip){var r=o._selectedChip.index();o.deleteChip(r),o._selectedChip=null,a=Math.max(r-1,0)}o.chipsData.length&&o.selectChip(a)}else if(37===e.keyCode){if(o._selectedChip){var l=o._selectedChip.index()-1;if(l<0)return;o.selectChip(l)}}else if(39===e.keyCode&&o._selectedChip){var h=o._selectedChip.index()+1;h>=o.chipsData.length?o.$input[0].focus():o.selectChip(h)}}}},{key:"_handleChipsKeyup",value:function(t){n._keydown=!1}},{key:"_handleChipsBlur",value:function(e){n._keydown||(t(e.target).closest(".chips")[0].M_Chips._selectedChip=null)}},{key:"defaults",get:function(){return e}}]),n}();i._keydown=!1,M.Chips=i,M.jQueryLoaded&&M.initializeJqueryWrapper(i,"chips","M_Chips"),t(document).ready(function(){t(document.body).on("click",".chip .close",function(){var e=t(this).closest(".chips");e.length&&e[0].M_Chips||t(this).closest(".chip").remove()})})}(cash),function(t){"use strict";var e={top:0,bottom:1/0,offset:0,onPositionChange:null},i=function(i){function n(e,i){_classCallCheck(this,n);var s=_possibleConstructorReturn(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,n,e,i));return s.el.M_Pushpin=s,s.options=t.extend({},n.defaults,i),s.originalOffset=s.el.offsetTop,n._pushpins.push(s),s._setupEventHandlers(),s._updatePosition(),s}return _inherits(n,Component),_createClass(n,[{key:"destroy",value:function(){this.el.style.top=null,this._removePinClasses(),this._removeEventHandlers();var t=n._pushpins.indexOf(this);n._pushpins.splice(t,1)}},{key:"_setupEventHandlers",value:function(){document.addEventListener("scroll",n._updateElements)}},{key:"_removeEventHandlers",value:function(){document.removeEventListener("scroll",n._updateElements)}},{key:"_updatePosition",value:function(){var t=M.getDocumentScrollTop()+this.options.offset;this.options.top<=t&&this.options.bottom>=t&&!this.el.classList.contains("pinned")&&(this._removePinClasses(),this.el.style.top=this.options.offset+"px",this.el.classList.add("pinned"),"function"==typeof this.options.onPositionChange&&this.options.onPositionChange.call(this,"pinned")),tthis.options.bottom&&!this.el.classList.contains("pin-bottom")&&(this._removePinClasses(),this.el.classList.add("pin-bottom"),this.el.style.top=this.options.bottom-this.originalOffset+"px","function"==typeof this.options.onPositionChange&&this.options.onPositionChange.call(this,"pin-bottom"))}},{key:"_removePinClasses",value:function(){this.el.classList.remove("pin-top","pinned","pin-bottom")}}],[{key:"init",value:function(t,e){return _get(n.__proto__||Object.getPrototypeOf(n),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Pushpin}},{key:"_updateElements",value:function(){for(var t in n._pushpins)n._pushpins[t]._updatePosition()}},{key:"defaults",get:function(){return e}}]),n}();i._pushpins=[],M.Pushpin=i,M.jQueryLoaded&&M.initializeJqueryWrapper(i,"pushpin","M_Pushpin")}(cash),function(t,e){"use strict";var i={direction:"top",hoverEnabled:!0,toolbarEnabled:!1};t.fn.reverse=[].reverse;var n=function(n){function s(e,i){_classCallCheck(this,s);var n=_possibleConstructorReturn(this,(s.__proto__||Object.getPrototypeOf(s)).call(this,s,e,i));return n.el.M_FloatingActionButton=n,n.options=t.extend({},s.defaults,i),n.isOpen=!1,n.$anchor=n.$el.children("a").first(),n.$menu=n.$el.children("ul").first(),n.$floatingBtns=n.$el.find("ul .btn-floating"),n.$floatingBtnsReverse=n.$el.find("ul .btn-floating").reverse(),n.offsetY=0,n.offsetX=0,"top"===n.options.direction?(n.$el.addClass("direction-top"),n.offsetY=40):"right"===n.options.direction?(n.$el.addClass("direction-right"),n.offsetX=-40):"bottom"===n.options.direction?(n.$el.addClass("direction-bottom"),n.offsetY=-40):(n.$el.addClass("direction-left"),n.offsetX=40),n._setupEventHandlers(),n}return _inherits(s,Component),_createClass(s,[{key:"destroy",value:function(){this._removeEventHandlers(),this.el.M_FloatingActionButton=void 0}},{key:"_setupEventHandlers",value:function(){this._handleFABClickBound=this._handleFABClick.bind(this),this._handleOpenBound=this.open.bind(this),this._handleCloseBound=this.close.bind(this),this.options.hoverEnabled&&!this.options.toolbarEnabled?(this.el.addEventListener("mouseenter",this._handleOpenBound),this.el.addEventListener("mouseleave",this._handleCloseBound)):this.el.addEventListener("click",this._handleFABClickBound)}},{key:"_removeEventHandlers",value:function(){this.options.hoverEnabled&&!this.options.toolbarEnabled?(this.el.removeEventListener("mouseenter",this._handleOpenBound),this.el.removeEventListener("mouseleave",this._handleCloseBound)):this.el.removeEventListener("click",this._handleFABClickBound)}},{key:"_handleFABClick",value:function(){this.isOpen?this.close():this.open()}},{key:"_handleDocumentClick",value:function(e){t(e.target).closest(this.$menu).length||this.close()}},{key:"open",value:function(){this.isOpen||(this.options.toolbarEnabled?this._animateInToolbar():this._animateInFAB(),this.isOpen=!0)}},{key:"close",value:function(){this.isOpen&&(this.options.toolbarEnabled?(window.removeEventListener("scroll",this._handleCloseBound,!0),document.body.removeEventListener("click",this._handleDocumentClickBound,!0),this._animateOutToolbar()):this._animateOutFAB(),this.isOpen=!1)}},{key:"_animateInFAB",value:function(){var t=this;this.$el.addClass("active");var i=0;this.$floatingBtnsReverse.each(function(n){e({targets:n,opacity:1,scale:[.4,1],translateY:[t.offsetY,0],translateX:[t.offsetX,0],duration:275,delay:i,easing:"easeInOutQuad"}),i+=40})}},{key:"_animateOutFAB",value:function(){var t=this;this.$floatingBtnsReverse.each(function(i){e.remove(i),e({targets:i,opacity:0,scale:.4,translateY:t.offsetY,translateX:t.offsetX,duration:175,easing:"easeOutQuad",complete:function(){t.$el.removeClass("active")}})})}},{key:"_animateInToolbar",value:function(){var e=this,i=void 0,n=window.innerWidth,s=window.innerHeight,o=this.el.getBoundingClientRect(),a=t('
    '),r=this.$anchor.css("background-color");this.$anchor.append(a),this.offsetX=o.left-n/2+o.width/2,this.offsetY=s-o.bottom,i=n/a[0].clientWidth,this.btnBottom=o.bottom,this.btnLeft=o.left,this.btnWidth=o.width,this.$el.addClass("active"),this.$el.css({"text-align":"center",width:"100%",bottom:0,left:0,transform:"translateX("+this.offsetX+"px)",transition:"none"}),this.$anchor.css({transform:"translateY("+-this.offsetY+"px)",transition:"none"}),a.css({"background-color":r}),setTimeout(function(){e.$el.css({transform:"",transition:"transform .2s cubic-bezier(0.550, 0.085, 0.680, 0.530), background-color 0s linear .2s"}),e.$anchor.css({overflow:"visible",transform:"",transition:"transform .2s"}),setTimeout(function(){e.$el.css({overflow:"hidden","background-color":r}),a.css({transform:"scale("+i+")",transition:"transform .2s cubic-bezier(0.550, 0.055, 0.675, 0.190)"}),e.$menu.children("li").children("a").css({opacity:1}),e._handleDocumentClickBound=e._handleDocumentClick.bind(e),window.addEventListener("scroll",e._handleCloseBound,!0),document.body.addEventListener("click",e._handleDocumentClickBound,!0)},100)},0)}},{key:"_animateOutToolbar",value:function(){var t=this,e=window.innerWidth,i=window.innerHeight,n=this.$el.find(".fab-backdrop"),s=this.$anchor.css("background-color");this.offsetX=this.btnLeft-e/2+this.btnWidth/2,this.offsetY=i-this.btnBottom,this.$el.removeClass("active"),this.$el.css({"background-color":"transparent",transition:"none"}),this.$anchor.css({transition:"none"}),n.css({transform:"scale(0)","background-color":s}),this.$menu.children("li").children("a").css({opacity:""}),setTimeout(function(){n.remove(),t.$el.css({"text-align":"",width:"",bottom:"",left:"",overflow:"","background-color":"",transform:"translate3d("+-t.offsetX+"px,0,0)"}),t.$anchor.css({overflow:"",transform:"translate3d(0,"+t.offsetY+"px,0)"}),setTimeout(function(){t.$el.css({transform:"translate3d(0,0,0)",transition:"transform .2s"}),t.$anchor.css({transform:"translate3d(0,0,0)",transition:"transform .2s cubic-bezier(0.550, 0.055, 0.675, 0.190)"})},20)},200)}}],[{key:"init",value:function(t,e){return _get(s.__proto__||Object.getPrototypeOf(s),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_FloatingActionButton}},{key:"defaults",get:function(){return i}}]),s}();M.FloatingActionButton=n,M.jQueryLoaded&&M.initializeJqueryWrapper(n,"floatingActionButton","M_FloatingActionButton")}(cash,M.anime),function(t){"use strict";var e={format:"mmm dd, yyyy",parse:null,defaultDate:null,setDefaultDate:!1,disableWeekends:!1,disableDayFn:null,firstDay:0,minDate:null,maxDate:null,yearRange:10,minYear:0,maxYear:9999,minMonth:void 0,maxMonth:void 0,startRange:null,endRange:null,isRTL:!1,showMonthAfterYear:!1,showDaysInNextAndPreviousMonths:!1,container:null,showClearBtn:!1,i18n:{cancel:"Cancel",clear:"Clear",done:"Ok",previousMonth:"‹",nextMonth:"›",months:["January","February","March","April","May","June","July","August","September","October","November","December"],monthsShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],weekdays:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],weekdaysShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],weekdaysAbbrev:["S","M","T","W","T","F","S"]},events:[],onSelect:null,onOpen:null,onClose:null,onDraw:null},i=function(i){function n(e,i){_classCallCheck(this,n);var s=_possibleConstructorReturn(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,n,e,i));s.el.M_Datepicker=s,s.options=t.extend({},n.defaults,i),i&&i.hasOwnProperty("i18n")&&"object"==typeof i.i18n&&(s.options.i18n=t.extend({},n.defaults.i18n,i.i18n)),s.options.minDate&&s.options.minDate.setHours(0,0,0,0),s.options.maxDate&&s.options.maxDate.setHours(0,0,0,0),s.id=M.guid(),s._setupVariables(),s._insertHTMLIntoDOM(),s._setupModal(),s._setupEventHandlers(),s.options.defaultDate||(s.options.defaultDate=new Date(Date.parse(s.el.value)),s.options.setDefaultDate=!0);var o=s.options.defaultDate;return n._isDate(o)?s.options.setDefaultDate?s.setDate(o,!0):s.gotoDate(o):s.gotoDate(new Date),s.isOpen=!1,s}return _inherits(n,Component),_createClass(n,[{key:"destroy",value:function(){this._removeEventHandlers(),this.modal.destroy(),t(this.modalEl).remove(),this.destroySelects(),this.el.M_Datepicker=void 0}},{key:"destroySelects",value:function(){var t=this.calendarEl.querySelector(".pika-select-year");t&&M.FormSelect.getInstance(t).destroy();var e=this.calendarEl.querySelector(".pika-select-month");e&&M.FormSelect.getInstance(e).destroy()}},{key:"_insertHTMLIntoDOM",value:function(){this.options.showClearBtn&&(t(this.clearBtn).css({visibility:""}),this.clearBtn.innerHTML=this.options.i18n.clear),this.doneBtn.innerHTML=this.options.i18n.done,this.cancelBtn.innerHTML=this.options.i18n.cancel,this.options.container?this.$modalEl.appendTo(this.options.container):this.$modalEl.insertBefore(this.el)}},{key:"_setupModal",value:function(){var t=this;this.modalEl.id="modal-"+this.id,this.modal=M.Modal.init(this.modalEl,{onCloseEnd:function(){t.isOpen=!1}})}},{key:"toString",value:function(t){var e=this;return t=t||this.options.format,n._isDate(this.date)?t.split(/(d{1,4}|m{1,4}|y{4}|yy|!.)/g).map(function(t){return e.formats[t]?e.formats[t]():t}).join(""):""}},{key:"setDate",value:function(t,e){if(!t)return this.date=null,this._renderDateDisplay(),this.draw();if("string"==typeof t&&(t=new Date(Date.parse(t))),n._isDate(t)){var i=this.options.minDate,s=this.options.maxDate;n._isDate(i)&&ts&&(t=s),this.date=new Date(t.getTime()),this._renderDateDisplay(),n._setToStartOfDay(this.date),this.gotoDate(this.date),e||"function"!=typeof this.options.onSelect||this.options.onSelect.call(this,this.date)}}},{key:"setInputValue",value:function(){this.el.value=this.toString(),this.$el.trigger("change",{firedBy:this})}},{key:"_renderDateDisplay",value:function(){var t=n._isDate(this.date)?this.date:new Date,e=this.options.i18n,i=e.weekdaysShort[t.getDay()],s=e.monthsShort[t.getMonth()],o=t.getDate();this.yearTextEl.innerHTML=t.getFullYear(),this.dateTextEl.innerHTML=i+", "+s+" "+o}},{key:"gotoDate",value:function(t){var e=!0;if(n._isDate(t)){if(this.calendars){var i=new Date(this.calendars[0].year,this.calendars[0].month,1),s=new Date(this.calendars[this.calendars.length-1].year,this.calendars[this.calendars.length-1].month,1),o=t.getTime();s.setMonth(s.getMonth()+1),s.setDate(s.getDate()-1),e=o11&&(t.year+=Math.floor(Math.abs(t.month)/12),t.month-=12),t}},{key:"nextMonth",value:function(){this.calendars[0].month++,this.adjustCalendars()}},{key:"prevMonth",value:function(){this.calendars[0].month--,this.adjustCalendars()}},{key:"render",value:function(t,e,i){var s=this.options,o=new Date,a=n._getDaysInMonth(t,e),r=new Date(t,e,1).getDay(),l=[],h=[];n._setToStartOfDay(o),s.firstDay>0&&(r-=s.firstDay)<0&&(r+=7);for(var d=0===e?11:e-1,u=11===e?0:e+1,c=0===e?t-1:t,p=11===e?t+1:t,v=n._getDaysInMonth(c,d),f=a+r,m=f;m>7;)m-=7;f+=7-m;for(var g=!1,_=0,y=0;_=a+r,M=_-r+1,x=e,O=t,T=s.startRange&&n._compareDates(s.startRange,k),L=s.endRange&&n._compareDates(s.endRange,k),$=s.startRange&&s.endRange&&s.startRanges.maxDate||s.disableWeekends&&n._isWeekend(k)||s.disableDayFn&&s.disableDayFn(k);E&&(_';e.push("is-outside-current-month"),e.push("is-selection-disabled")}return t.isDisabled&&e.push("is-disabled"),t.isToday&&e.push("is-today"),t.isSelected&&(e.push("is-selected"),i="true"),t.hasEvent&&e.push("has-event"),t.isInRange&&e.push("is-inrange"),t.isStartRange&&e.push("is-startrange"),t.isEndRange&&e.push("is-endrange"),'"}},{key:"renderRow",value:function(t,e,i){return''+(e?t.reverse():t).join("")+""}},{key:"renderTable",value:function(t,e,i){return'
    '+this.renderHead(t)+this.renderBody(e)+"
    "}},{key:"renderHead",value:function(t){var e=void 0,i=[];for(e=0;e<7;e++)i.push(''+this.renderDayName(t,e,!0)+"");return""+(t.isRTL?i.reverse():i).join("")+""}},{key:"renderBody",value:function(t){return""+t.join("")+""}},{key:"renderTitle",value:function(e,i,n,s,o,a){var r=void 0,l=void 0,h=void 0,d=this.options,u=n===d.minYear,c=n===d.maxYear,p='
    ',v=void 0,f=void 0,m=!0,g=!0;for(h=[],r=0;r<12;r++)h.push('");for(v='",t.isArray(d.yearRange)?(r=d.yearRange[0],l=d.yearRange[1]+1):(r=n-d.yearRange,l=1+n+d.yearRange),h=[];r=d.minYear&&h.push('");f='";p+='',p+='
    ',d.showMonthAfterYear?p+=f+v:p+=v+f,p+="
    ",u&&(0===s||d.minMonth>=s)&&(m=!1),c&&(11===s||d.maxMonth<=s)&&(g=!1);return p+='',p+="
    "}},{key:"draw",value:function(t){if(this.isOpen||t){var e=this.options,i=e.minYear,n=e.maxYear,s=e.minMonth,o=e.maxMonth,a="",r=void 0;this._y<=i&&(this._y=i,!isNaN(s)&&this._m=n&&(this._y=n,!isNaN(o)&&this._m>o&&(this._m=o)),r="pika-title-"+Math.random().toString(36).replace(/[^a-z]+/g,"").substr(0,2);for(var l=0;l<1;l++)this._renderDateDisplay(),a+=this.renderTitle(this,l,this.calendars[l].year,this.calendars[l].month,this.calendars[0].year,r)+this.render(this.calendars[l].year,this.calendars[l].month,r);this.destroySelects(),this.calendarEl.innerHTML=a;var h=this.calendarEl.querySelector(".pika-select-year"),d=this.calendarEl.querySelector(".pika-select-month");M.FormSelect.init(h,{classes:"select-year",dropdownOptions:{container:document.body,constrainWidth:!1}}),M.FormSelect.init(d,{classes:"select-month",dropdownOptions:{container:document.body,constrainWidth:!1}}),h.addEventListener("change",this._handleYearChange.bind(this)),d.addEventListener("change",this._handleMonthChange.bind(this)),"function"==typeof this.options.onDraw&&this.options.onDraw(this)}}},{key:"_setupEventHandlers",value:function(){this._handleInputKeydownBound=this._handleInputKeydown.bind(this),this._handleInputClickBound=this._handleInputClick.bind(this),this._handleInputChangeBound=this._handleInputChange.bind(this),this._handleCalendarClickBound=this._handleCalendarClick.bind(this),this._finishSelectionBound=this._finishSelection.bind(this),this._handleMonthChange=this._handleMonthChange.bind(this),this._closeBound=this.close.bind(this),this.el.addEventListener("click",this._handleInputClickBound),this.el.addEventListener("keydown",this._handleInputKeydownBound),this.el.addEventListener("change",this._handleInputChangeBound),this.calendarEl.addEventListener("click",this._handleCalendarClickBound),this.doneBtn.addEventListener("click",this._finishSelectionBound),this.cancelBtn.addEventListener("click",this._closeBound),this.options.showClearBtn&&(this._handleClearClickBound=this._handleClearClick.bind(this),this.clearBtn.addEventListener("click",this._handleClearClickBound))}},{key:"_setupVariables",value:function(){var e=this;this.$modalEl=t(n._template),this.modalEl=this.$modalEl[0],this.calendarEl=this.modalEl.querySelector(".pika-single"),this.yearTextEl=this.modalEl.querySelector(".year-text"),this.dateTextEl=this.modalEl.querySelector(".date-text"),this.options.showClearBtn&&(this.clearBtn=this.modalEl.querySelector(".datepicker-clear")),this.doneBtn=this.modalEl.querySelector(".datepicker-done"),this.cancelBtn=this.modalEl.querySelector(".datepicker-cancel"),this.formats={d:function(){return e.date.getDate()},dd:function(){var t=e.date.getDate();return(t<10?"0":"")+t},ddd:function(){return e.options.i18n.weekdaysShort[e.date.getDay()]},dddd:function(){return e.options.i18n.weekdays[e.date.getDay()]},m:function(){return e.date.getMonth()+1},mm:function(){var t=e.date.getMonth()+1;return(t<10?"0":"")+t},mmm:function(){return e.options.i18n.monthsShort[e.date.getMonth()]},mmmm:function(){return e.options.i18n.months[e.date.getMonth()]},yy:function(){return(""+e.date.getFullYear()).slice(2)},yyyy:function(){return e.date.getFullYear()}}}},{key:"_removeEventHandlers",value:function(){this.el.removeEventListener("click",this._handleInputClickBound),this.el.removeEventListener("keydown",this._handleInputKeydownBound),this.el.removeEventListener("change",this._handleInputChangeBound),this.calendarEl.removeEventListener("click",this._handleCalendarClickBound)}},{key:"_handleInputClick",value:function(){this.open()}},{key:"_handleInputKeydown",value:function(t){t.which===M.keys.ENTER&&(t.preventDefault(),this.open())}},{key:"_handleCalendarClick",value:function(e){if(this.isOpen){var i=t(e.target);i.hasClass("is-disabled")||(!i.hasClass("datepicker-day-button")||i.hasClass("is-empty")||i.parent().hasClass("is-disabled")?i.closest(".month-prev").length?this.prevMonth():i.closest(".month-next").length&&this.nextMonth():this.setDate(new Date(e.target.getAttribute("data-pika-year"),e.target.getAttribute("data-pika-month"),e.target.getAttribute("data-pika-day"))))}}},{key:"_handleClearClick",value:function(){this.date=null,this.setInputValue(),this.close()}},{key:"_handleMonthChange",value:function(t){this.gotoMonth(t.target.value)}},{key:"_handleYearChange",value:function(t){this.gotoYear(t.target.value)}},{key:"gotoMonth",value:function(t){isNaN(t)||(this.calendars[0].month=parseInt(t,10),this.adjustCalendars())}},{key:"gotoYear",value:function(t){isNaN(t)||(this.calendars[0].year=parseInt(t,10),this.adjustCalendars())}},{key:"_handleInputChange",value:function(t){var e=void 0;t.firedBy!==this&&(e=this.options.parse?this.options.parse(this.el.value,this.options.format):new Date(Date.parse(this.el.value)),n._isDate(e)&&this.setDate(e))}},{key:"renderDayName",value:function(t,e,i){for(e+=t.firstDay;e>=7;)e-=7;return i?t.i18n.weekdaysAbbrev[e]:t.i18n.weekdays[e]}},{key:"_finishSelection",value:function(){this.setInputValue(),this.close()}},{key:"open",value:function(){if(!this.isOpen)return this.isOpen=!0,"function"==typeof this.options.onOpen&&this.options.onOpen.call(this),this.draw(),this.modal.open(),this}},{key:"close",value:function(){if(this.isOpen)return this.isOpen=!1,"function"==typeof this.options.onClose&&this.options.onClose.call(this),this.modal.close(),this}}],[{key:"init",value:function(t,e){return _get(n.__proto__||Object.getPrototypeOf(n),"init",this).call(this,this,t,e)}},{key:"_isDate",value:function(t){return/Date/.test(Object.prototype.toString.call(t))&&!isNaN(t.getTime())}},{key:"_isWeekend",value:function(t){var e=t.getDay();return 0===e||6===e}},{key:"_setToStartOfDay",value:function(t){n._isDate(t)&&t.setHours(0,0,0,0)}},{key:"_getDaysInMonth",value:function(t,e){return[31,n._isLeapYear(t)?29:28,31,30,31,30,31,31,30,31,30,31][e]}},{key:"_isLeapYear",value:function(t){return t%4==0&&t%100!=0||t%400==0}},{key:"_compareDates",value:function(t,e){return t.getTime()===e.getTime()}},{key:"_setToStartOfDay",value:function(t){n._isDate(t)&&t.setHours(0,0,0,0)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Datepicker}},{key:"defaults",get:function(){return e}}]),n}();i._template=['"].join(""),M.Datepicker=i,M.jQueryLoaded&&M.initializeJqueryWrapper(i,"datepicker","M_Datepicker")}(cash),function(t){"use strict";var e={dialRadius:135,outerRadius:105,innerRadius:70,tickRadius:20,duration:350,container:null,defaultTime:"now",fromNow:0,showClearBtn:!1,i18n:{cancel:"Cancel",clear:"Clear",done:"Ok"},autoClose:!1,twelveHour:!0,vibrate:!0},i=function(i){function n(e,i){_classCallCheck(this,n);var s=_possibleConstructorReturn(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,n,e,i));return s.el.M_Timepicker=s,s.options=t.extend({},n.defaults,i),s.id=M.guid(),s._insertHTMLIntoDOM(),s._setupModal(),s._setupVariables(),s._setupEventHandlers(),s._clockSetup(),s._pickerSetup(),s}return _inherits(n,Component),_createClass(n,[{key:"destroy",value:function(){this._removeEventHandlers(),this.modal.destroy(),t(this.modalEl).remove(),this.el.M_Timepicker=void 0}},{key:"_setupEventHandlers",value:function(){this._handleInputKeydownBound=this._handleInputKeydown.bind(this),this._handleInputClickBound=this._handleInputClick.bind(this),this._handleClockClickStartBound=this._handleClockClickStart.bind(this),this._handleDocumentClickMoveBound=this._handleDocumentClickMove.bind(this),this._handleDocumentClickEndBound=this._handleDocumentClickEnd.bind(this),this.el.addEventListener("click",this._handleInputClickBound),this.el.addEventListener("keydown",this._handleInputKeydownBound),this.plate.addEventListener("mousedown",this._handleClockClickStartBound),this.plate.addEventListener("touchstart",this._handleClockClickStartBound),t(this.spanHours).on("click",this.showView.bind(this,"hours")),t(this.spanMinutes).on("click",this.showView.bind(this,"minutes"))}},{key:"_removeEventHandlers",value:function(){this.el.removeEventListener("click",this._handleInputClickBound),this.el.removeEventListener("keydown",this._handleInputKeydownBound)}},{key:"_handleInputClick",value:function(){this.open()}},{key:"_handleInputKeydown",value:function(t){t.which===M.keys.ENTER&&(t.preventDefault(),this.open())}},{key:"_handleClockClickStart",value:function(t){t.preventDefault();var e=this.plate.getBoundingClientRect(),i={x:e.left,y:e.top};this.x0=i.x+this.options.dialRadius,this.y0=i.y+this.options.dialRadius,this.moved=!1;var s=n._Pos(t);this.dx=s.x-this.x0,this.dy=s.y-this.y0,this.setHand(this.dx,this.dy,!1),document.addEventListener("mousemove",this._handleDocumentClickMoveBound),document.addEventListener("touchmove",this._handleDocumentClickMoveBound),document.addEventListener("mouseup",this._handleDocumentClickEndBound),document.addEventListener("touchend",this._handleDocumentClickEndBound)}},{key:"_handleDocumentClickMove",value:function(t){t.preventDefault();var e=n._Pos(t),i=e.x-this.x0,s=e.y-this.y0;this.moved=!0,this.setHand(i,s,!1,!0)}},{key:"_handleDocumentClickEnd",value:function(e){var i=this;e.preventDefault(),document.removeEventListener("mouseup",this._handleDocumentClickEndBound),document.removeEventListener("touchend",this._handleDocumentClickEndBound);var s=n._Pos(e),o=s.x-this.x0,a=s.y-this.y0;this.moved&&o===this.dx&&a===this.dy&&this.setHand(o,a),"hours"===this.currentView?this.showView("minutes",this.options.duration/2):this.options.autoClose&&(t(this.minutesView).addClass("timepicker-dial-out"),setTimeout(function(){i.done()},this.options.duration/2)),document.removeEventListener("mousemove",this._handleDocumentClickMoveBound),document.removeEventListener("touchmove",this._handleDocumentClickMoveBound)}},{key:"_insertHTMLIntoDOM",value:function(){this.$modalEl=t(n._template),this.modalEl=this.$modalEl[0],this.modalEl.id="modal-"+this.id;var e=document.querySelector(this.options.container);this.options.container&&e?this.$modalEl.appendTo(e):this.$modalEl.insertBefore(this.el)}},{key:"_setupModal",value:function(){var t=this;this.modal=M.Modal.init(this.modalEl,{onCloseEnd:function(){t.isOpen=!1}})}},{key:"_setupVariables",value:function(){this.currentView="hours",this.vibrate=navigator.vibrate?"vibrate":navigator.webkitVibrate?"webkitVibrate":null,this._canvas=this.modalEl.querySelector(".timepicker-canvas"),this.plate=this.modalEl.querySelector(".timepicker-plate"),this.hoursView=this.modalEl.querySelector(".timepicker-hours"),this.minutesView=this.modalEl.querySelector(".timepicker-minutes"),this.spanHours=this.modalEl.querySelector(".timepicker-span-hours"),this.spanMinutes=this.modalEl.querySelector(".timepicker-span-minutes"),this.spanAmPm=this.modalEl.querySelector(".timepicker-span-am-pm"),this.footer=this.modalEl.querySelector(".timepicker-footer"),this.amOrPm="PM"}},{key:"_pickerSetup",value:function(){var e=t('").appendTo(this.footer).on("click",this.clear.bind(this));this.options.showClearBtn&&e.css({visibility:""});var i=t('
    ');t('").appendTo(i).on("click",this.close.bind(this)),t('").appendTo(i).on("click",this.done.bind(this)),i.appendTo(this.footer)}},{key:"_clockSetup",value:function(){this.options.twelveHour&&(this.$amBtn=t('
    AM
    '),this.$pmBtn=t('
    PM
    '),this.$amBtn.on("click",this._handleAmPmClick.bind(this)).appendTo(this.spanAmPm),this.$pmBtn.on("click",this._handleAmPmClick.bind(this)).appendTo(this.spanAmPm)),this._buildHoursView(),this._buildMinutesView(),this._buildSVGClock()}},{key:"_buildSVGClock",value:function(){var t=this.options.dialRadius,e=this.options.tickRadius,i=2*t,s=n._createSVGEl("svg");s.setAttribute("class","timepicker-svg"),s.setAttribute("width",i),s.setAttribute("height",i);var o=n._createSVGEl("g");o.setAttribute("transform","translate("+t+","+t+")");var a=n._createSVGEl("circle");a.setAttribute("class","timepicker-canvas-bearing"),a.setAttribute("cx",0),a.setAttribute("cy",0),a.setAttribute("r",4);var r=n._createSVGEl("line");r.setAttribute("x1",0),r.setAttribute("y1",0);var l=n._createSVGEl("circle");l.setAttribute("class","timepicker-canvas-bg"),l.setAttribute("r",e),o.appendChild(r),o.appendChild(l),o.appendChild(a),s.appendChild(o),this._canvas.appendChild(s),this.hand=r,this.bg=l,this.bearing=a,this.g=o}},{key:"_buildHoursView",value:function(){var e=t('
    ');if(this.options.twelveHour)for(var i=1;i<13;i+=1){var n=e.clone(),s=i/6*Math.PI,o=this.options.outerRadius;n.css({left:this.options.dialRadius+Math.sin(s)*o-this.options.tickRadius+"px",top:this.options.dialRadius-Math.cos(s)*o-this.options.tickRadius+"px"}),n.html(0===i?"00":i),this.hoursView.appendChild(n[0])}else for(var a=0;a<24;a+=1){var r=e.clone(),l=a/6*Math.PI,h=a>0&&a<13?this.options.innerRadius:this.options.outerRadius;r.css({left:this.options.dialRadius+Math.sin(l)*h-this.options.tickRadius+"px",top:this.options.dialRadius-Math.cos(l)*h-this.options.tickRadius+"px"}),r.html(0===a?"00":a),this.hoursView.appendChild(r[0])}}},{key:"_buildMinutesView",value:function(){for(var e=t('
    '),i=0;i<60;i+=5){var s=e.clone(),o=i/30*Math.PI;s.css({left:this.options.dialRadius+Math.sin(o)*this.options.outerRadius-this.options.tickRadius+"px",top:this.options.dialRadius-Math.cos(o)*this.options.outerRadius-this.options.tickRadius+"px"}),s.html(n._addLeadingZero(i)),this.minutesView.appendChild(s[0])}}},{key:"_handleAmPmClick",value:function(e){var i=t(e.target);this.amOrPm=i.hasClass("am-btn")?"AM":"PM",this._updateAmPmView()}},{key:"_updateAmPmView",value:function(){this.options.twelveHour&&(this.$amBtn.toggleClass("text-primary","AM"===this.amOrPm),this.$pmBtn.toggleClass("text-primary","PM"===this.amOrPm))}},{key:"_updateTimeFromInput",value:function(){var t=((this.el.value||this.options.defaultTime||"")+"").split(":");if(this.options.twelveHour&&void 0!==t[1]&&(t[1].toUpperCase().indexOf("AM")>0?this.amOrPm="AM":this.amOrPm="PM",t[1]=t[1].replace("AM","").replace("PM","")),"now"===t[0]){var e=new Date(+new Date+this.options.fromNow);t=[e.getHours(),e.getMinutes()],this.options.twelveHour&&(this.amOrPm=t[0]>=12&&t[0]<24?"PM":"AM")}this.hours=+t[0]||0,this.minutes=+t[1]||0,this.spanHours.innerHTML=this.hours,this.spanMinutes.innerHTML=n._addLeadingZero(this.minutes),this._updateAmPmView()}},{key:"showView",value:function(e,i){"minutes"===e&&t(this.hoursView).css("visibility");var n="hours"===e,s=n?this.hoursView:this.minutesView,o=n?this.minutesView:this.hoursView;this.currentView=e,t(this.spanHours).toggleClass("text-primary",n),t(this.spanMinutes).toggleClass("text-primary",!n),o.classList.add("timepicker-dial-out"),t(s).css("visibility","visible").removeClass("timepicker-dial-out"),this.resetClock(i),clearTimeout(this.toggleViewTimer),this.toggleViewTimer=setTimeout(function(){t(o).css("visibility","hidden")},this.options.duration)}},{key:"resetClock",value:function(e){var i=this.currentView,n=this[i],s="hours"===i,o=n*(Math.PI/(s?6:30)),a=s&&n>0&&n<13?this.options.innerRadius:this.options.outerRadius,r=Math.sin(o)*a,l=-Math.cos(o)*a,h=this;e?(t(this.canvas).addClass("timepicker-canvas-out"),setTimeout(function(){t(h.canvas).removeClass("timepicker-canvas-out"),h.setHand(r,l)},e)):this.setHand(r,l)}},{key:"setHand",value:function(t,e,i){var s=this,o=Math.atan2(t,-e),a="hours"===this.currentView,r=Math.PI/(a||i?6:30),l=Math.sqrt(t*t+e*e),h=a&&l<(this.options.outerRadius+this.options.innerRadius)/2,d=h?this.options.innerRadius:this.options.outerRadius;this.options.twelveHour&&(d=this.options.outerRadius),o<0&&(o=2*Math.PI+o);var u=Math.round(o/r);o=u*r,this.options.twelveHour?a?0===u&&(u=12):(i&&(u*=5),60===u&&(u=0)):a?(12===u&&(u=0),u=h?0===u?12:u:0===u?0:u+12):(i&&(u*=5),60===u&&(u=0)),this[this.currentView]!==u&&this.vibrate&&this.options.vibrate&&(this.vibrateTimer||(navigator[this.vibrate](10),this.vibrateTimer=setTimeout(function(){s.vibrateTimer=null},100))),this[this.currentView]=u,a?this.spanHours.innerHTML=u:this.spanMinutes.innerHTML=n._addLeadingZero(u);var c=Math.sin(o)*(d-this.options.tickRadius),p=-Math.cos(o)*(d-this.options.tickRadius),v=Math.sin(o)*d,f=-Math.cos(o)*d;this.hand.setAttribute("x2",c),this.hand.setAttribute("y2",p),this.bg.setAttribute("cx",v),this.bg.setAttribute("cy",f)}},{key:"open",value:function(){this.isOpen||(this.isOpen=!0,this._updateTimeFromInput(),this.showView("hours"),this.modal.open())}},{key:"close",value:function(){this.isOpen&&(this.isOpen=!1,this.modal.close())}},{key:"done",value:function(t,e){var i=this.el.value,s=e?"":n._addLeadingZero(this.hours)+":"+n._addLeadingZero(this.minutes);this.time=s,!e&&this.options.twelveHour&&(s=s+" "+this.amOrPm),this.el.value=s,s!==i&&this.$el.trigger("change"),this.close(),this.el.focus()}},{key:"clear",value:function(){this.done(null,!0)}}],[{key:"init",value:function(t,e){return _get(n.__proto__||Object.getPrototypeOf(n),"init",this).call(this,this,t,e)}},{key:"_addLeadingZero",value:function(t){return(t<10?"0":"")+t}},{key:"_createSVGEl",value:function(t){return document.createElementNS("http://www.w3.org/2000/svg",t)}},{key:"_Pos",value:function(t){return t.targetTouches&&t.targetTouches.length>=1?{x:t.targetTouches[0].clientX,y:t.targetTouches[0].clientY}:{x:t.clientX,y:t.clientY}}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Timepicker}},{key:"defaults",get:function(){return e}}]),n}();i._template=['"].join(""),M.Timepicker=i,M.jQueryLoaded&&M.initializeJqueryWrapper(i,"timepicker","M_Timepicker")}(cash),function(t){"use strict";var e={},i=function(i){function n(e,i){_classCallCheck(this,n);var s=_possibleConstructorReturn(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,n,e,i));return s.el.M_CharacterCounter=s,s.options=t.extend({},n.defaults,i),s.isInvalid=!1,s.isValidLength=!1,s._setupCounter(),s._setupEventHandlers(),s}return _inherits(n,Component),_createClass(n,[{key:"destroy",value:function(){this._removeEventHandlers(),this.el.CharacterCounter=void 0,this._removeCounter()}},{key:"_setupEventHandlers",value:function(){this._handleUpdateCounterBound=this.updateCounter.bind(this),this.el.addEventListener("focus",this._handleUpdateCounterBound,!0),this.el.addEventListener("input",this._handleUpdateCounterBound,!0)}},{key:"_removeEventHandlers",value:function(){this.el.removeEventListener("focus",this._handleUpdateCounterBound,!0),this.el.removeEventListener("input",this._handleUpdateCounterBound,!0)}},{key:"_setupCounter",value:function(){this.counterEl=document.createElement("span"),t(this.counterEl).addClass("character-counter").css({float:"right","font-size":"12px",height:1}),this.$el.parent().append(this.counterEl)}},{key:"_removeCounter",value:function(){t(this.counterEl).remove()}},{key:"updateCounter",value:function(){var e=+this.$el.attr("data-length"),i=this.el.value.length;this.isValidLength=i<=e;var n=i;e&&(n+="/"+e,this._validateInput()),t(this.counterEl).html(n)}},{key:"_validateInput",value:function(){this.isValidLength&&this.isInvalid?(this.isInvalid=!1,this.$el.removeClass("invalid")):this.isValidLength||this.isInvalid||(this.isInvalid=!0,this.$el.removeClass("valid"),this.$el.addClass("invalid"))}}],[{key:"init",value:function(t,e){return _get(n.__proto__||Object.getPrototypeOf(n),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_CharacterCounter}},{key:"defaults",get:function(){return e}}]),n}();M.CharacterCounter=i,M.jQueryLoaded&&M.initializeJqueryWrapper(i,"characterCounter","M_CharacterCounter")}(cash),function(t){"use strict";var e={duration:200,dist:-100,shift:0,padding:0,numVisible:5,fullWidth:!1,indicators:!1,noWrap:!1,onCycleTo:null},i=function(i){function n(e,i){_classCallCheck(this,n);var s=_possibleConstructorReturn(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,n,e,i));return s.el.M_Carousel=s,s.options=t.extend({},n.defaults,i),s.hasMultipleSlides=s.$el.find(".carousel-item").length>1,s.showIndicators=s.options.indicators&&s.hasMultipleSlides,s.noWrap=s.options.noWrap||!s.hasMultipleSlides,s.pressed=!1,s.dragged=!1,s.offset=s.target=0,s.images=[],s.itemWidth=s.$el.find(".carousel-item").first().innerWidth(),s.itemHeight=s.$el.find(".carousel-item").first().innerHeight(),s.dim=2*s.itemWidth+s.options.padding||1,s._autoScrollBound=s._autoScroll.bind(s),s._trackBound=s._track.bind(s),s.options.fullWidth&&(s.options.dist=0,s._setCarouselHeight(),s.showIndicators&&s.$el.find(".carousel-fixed-item").addClass("with-indicators")),s.$indicators=t('
      '),s.$el.find(".carousel-item").each(function(e,i){if(s.images.push(e),s.showIndicators){var n=t('
    • ');0===i&&n[0].classList.add("active"),s.$indicators.append(n)}}),s.showIndicators&&s.$el.append(s.$indicators),s.count=s.images.length,s.options.numVisible=Math.min(s.count,s.options.numVisible),s.xform="transform",["webkit","Moz","O","ms"].every(function(t){var e=t+"Transform";return void 0===document.body.style[e]||(s.xform=e,!1)}),s._setupEventHandlers(),s._scroll(s.offset),s}return _inherits(n,Component),_createClass(n,[{key:"destroy",value:function(){this._removeEventHandlers(),this.el.M_Carousel=void 0}},{key:"_setupEventHandlers",value:function(){var t=this;this._handleCarouselTapBound=this._handleCarouselTap.bind(this),this._handleCarouselDragBound=this._handleCarouselDrag.bind(this),this._handleCarouselReleaseBound=this._handleCarouselRelease.bind(this),this._handleCarouselClickBound=this._handleCarouselClick.bind(this),void 0!==window.ontouchstart&&(this.el.addEventListener("touchstart",this._handleCarouselTapBound),this.el.addEventListener("touchmove",this._handleCarouselDragBound),this.el.addEventListener("touchend",this._handleCarouselReleaseBound)),this.el.addEventListener("mousedown",this._handleCarouselTapBound),this.el.addEventListener("mousemove",this._handleCarouselDragBound),this.el.addEventListener("mouseup",this._handleCarouselReleaseBound),this.el.addEventListener("mouseleave",this._handleCarouselReleaseBound),this.el.addEventListener("click",this._handleCarouselClickBound),this.showIndicators&&this.$indicators&&(this._handleIndicatorClickBound=this._handleIndicatorClick.bind(this),this.$indicators.find(".indicator-item").each(function(e,i){e.addEventListener("click",t._handleIndicatorClickBound)}));var e=M.throttle(this._handleResize,200);this._handleThrottledResizeBound=e.bind(this),window.addEventListener("resize",this._handleThrottledResizeBound)}},{key:"_removeEventHandlers",value:function(){var t=this;void 0!==window.ontouchstart&&(this.el.removeEventListener("touchstart",this._handleCarouselTapBound),this.el.removeEventListener("touchmove",this._handleCarouselDragBound),this.el.removeEventListener("touchend",this._handleCarouselReleaseBound)),this.el.removeEventListener("mousedown",this._handleCarouselTapBound),this.el.removeEventListener("mousemove",this._handleCarouselDragBound),this.el.removeEventListener("mouseup",this._handleCarouselReleaseBound),this.el.removeEventListener("mouseleave",this._handleCarouselReleaseBound),this.el.removeEventListener("click",this._handleCarouselClickBound),this.showIndicators&&this.$indicators&&this.$indicators.find(".indicator-item").each(function(e,i){e.removeEventListener("click",t._handleIndicatorClickBound)}),window.removeEventListener("resize",this._handleThrottledResizeBound)}},{key:"_handleCarouselTap",value:function(e){"mousedown"===e.type&&t(e.target).is("img")&&e.preventDefault(),this.pressed=!0,this.dragged=!1,this.verticalDragged=!1,this.reference=this._xpos(e),this.referenceY=this._ypos(e),this.velocity=this.amplitude=0,this.frame=this.offset,this.timestamp=Date.now(),clearInterval(this.ticker),this.ticker=setInterval(this._trackBound,100)}},{key:"_handleCarouselDrag",value:function(t){var e=void 0,i=void 0,n=void 0;if(this.pressed)if(e=this._xpos(t),i=this._ypos(t),n=this.reference-e,Math.abs(this.referenceY-i)<30&&!this.verticalDragged)(n>2||n<-2)&&(this.dragged=!0,this.reference=e,this._scroll(this.offset+n));else{if(this.dragged)return t.preventDefault(),t.stopPropagation(),!1;this.verticalDragged=!0}if(this.dragged)return t.preventDefault(),t.stopPropagation(),!1}},{key:"_handleCarouselRelease",value:function(t){if(this.pressed)return this.pressed=!1,clearInterval(this.ticker),this.target=this.offset,(this.velocity>10||this.velocity<-10)&&(this.amplitude=.9*this.velocity,this.target=this.offset+this.amplitude),this.target=Math.round(this.target/this.dim)*this.dim,this.noWrap&&(this.target>=this.dim*(this.count-1)?this.target=this.dim*(this.count-1):this.target<0&&(this.target=0)),this.amplitude=this.target-this.offset,this.timestamp=Date.now(),requestAnimationFrame(this._autoScrollBound),this.dragged&&(t.preventDefault(),t.stopPropagation()),!1}},{key:"_handleCarouselClick",value:function(e){if(this.dragged)return e.preventDefault(),e.stopPropagation(),!1;if(!this.options.fullWidth){var i=t(e.target).closest(".carousel-item").index();0!==this._wrap(this.center)-i&&(e.preventDefault(),e.stopPropagation()),this._cycleTo(i)}}},{key:"_handleIndicatorClick",value:function(e){e.stopPropagation();var i=t(e.target).closest(".indicator-item");i.length&&this._cycleTo(i.index())}},{key:"_handleResize",value:function(t){this.options.fullWidth?(this.itemWidth=this.$el.find(".carousel-item").first().innerWidth(),this.imageHeight=this.$el.find(".carousel-item.active").height(),this.dim=2*this.itemWidth+this.options.padding,this.offset=2*this.center*this.itemWidth,this.target=this.offset,this._setCarouselHeight(!0)):this._scroll()}},{key:"_setCarouselHeight",value:function(t){var e=this,i=this.$el.find(".carousel-item.active").length?this.$el.find(".carousel-item.active").first():this.$el.find(".carousel-item").first(),n=i.find("img").first();if(n.length)if(n[0].complete){var s=n.height();if(s>0)this.$el.css("height",s+"px");else{var o=n[0].naturalWidth,a=n[0].naturalHeight,r=this.$el.width()/o*a;this.$el.css("height",r+"px")}}else n.one("load",function(t,i){e.$el.css("height",t.offsetHeight+"px")});else if(!t){var l=i.height();this.$el.css("height",l+"px")}}},{key:"_xpos",value:function(t){return t.targetTouches&&t.targetTouches.length>=1?t.targetTouches[0].clientX:t.clientX}},{key:"_ypos",value:function(t){return t.targetTouches&&t.targetTouches.length>=1?t.targetTouches[0].clientY:t.clientY}},{key:"_wrap",value:function(t){return t>=this.count?t%this.count:t<0?this._wrap(this.count+t%this.count):t}},{key:"_track",value:function(){var t=void 0,e=void 0,i=void 0,n=void 0;e=(t=Date.now())-this.timestamp,this.timestamp=t,i=this.offset-this.frame,this.frame=this.offset,n=1e3*i/(1+e),this.velocity=.8*n+.2*this.velocity}},{key:"_autoScroll",value:function(){var t=void 0,e=void 0;this.amplitude&&(t=Date.now()-this.timestamp,(e=this.amplitude*Math.exp(-t/this.options.duration))>2||e<-2?(this._scroll(this.target-e),requestAnimationFrame(this._autoScrollBound)):this._scroll(this.target))}},{key:"_scroll",value:function(e){var i=this;this.$el.hasClass("scrolling")||this.el.classList.add("scrolling"),null!=this.scrollingTimeout&&window.clearTimeout(this.scrollingTimeout),this.scrollingTimeout=window.setTimeout(function(){i.$el.removeClass("scrolling")},this.options.duration);var n=void 0,s=void 0,o=void 0,a=void 0,r=void 0,l=void 0,h=void 0,d=void 0,u=void 0,c=void 0,p=this.center,v=1/this.options.numVisible;if(this.offset="number"==typeof e?e:this.offset,this.center=Math.floor((this.offset+this.dim/2)/this.dim),o=this.offset-this.center*this.dim,a=o<0?1:-1,r=-a*o*2/this.dim,s=this.count>>1,this.options.fullWidth?(h="translateX(0)",c=1):(h="translateX("+(this.el.clientWidth-this.itemWidth)/2+"px) ",h+="translateY("+(this.el.clientHeight-this.itemHeight)/2+"px)",c=1-v*r),this.showIndicators){var f=this.center%this.count,m=this.$indicators.find(".indicator-item.active");m.index()!==f&&(m.removeClass("active"),this.$indicators.find(".indicator-item").eq(f)[0].classList.add("active"))}if(!this.noWrap||this.center>=0&&this.center0?1-r:1):(d=this.options.dist*(2*n-r*a),u=1-v*(2*n-r*a)),!this.noWrap||this.center-n>=0){l=this.images[this._wrap(this.center-n)];var y=h+" translateX("+(-this.options.shift+(-this.dim*n-o)/2)+"px) translateZ("+d+"px)";this._updateItemStyle(l,u,-n,y)}}if(!this.noWrap||this.center>=0&&this.center0&&Math.abs(i-this.count)0&&(this.target-=this.dim*i),"function"==typeof e&&(this.oneTimeCallback=e),this.offset!==this.target&&(this.amplitude=this.target-this.offset,this.timestamp=Date.now(),requestAnimationFrame(this._autoScrollBound))}},{key:"next",value:function(t){(void 0===t||isNaN(t))&&(t=1);var e=this.center+t;if(e>this.count||e<0){if(this.noWrap)return;e=this._wrap(e)}this._cycleTo(e)}},{key:"prev",value:function(t){(void 0===t||isNaN(t))&&(t=1);var e=this.center-t;if(e>this.count||e<0){if(this.noWrap)return;e=this._wrap(e)}this._cycleTo(e)}},{key:"set",value:function(t,e){if((void 0===t||isNaN(t))&&(t=0),t>this.count||t<0){if(this.noWrap)return;t=this._wrap(t)}this._cycleTo(t,e)}}],[{key:"init",value:function(t,e){return _get(n.__proto__||Object.getPrototypeOf(n),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Carousel}},{key:"defaults",get:function(){return e}}]),n}();M.Carousel=i,M.jQueryLoaded&&M.initializeJqueryWrapper(i,"carousel","M_Carousel")}(cash),function(t){"use strict";var e={onOpen:void 0,onClose:void 0},i=function(i){function n(e,i){_classCallCheck(this,n);var s=_possibleConstructorReturn(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,n,e,i));return s.el.M_TapTarget=s,s.options=t.extend({},n.defaults,i),s.isOpen=!1,s.$origin=t("#"+s.$el.attr("data-target")),s._setup(),s._calculatePositioning(),s._setupEventHandlers(),s}return _inherits(n,Component),_createClass(n,[{key:"destroy",value:function(){this._removeEventHandlers(),this.el.TapTarget=void 0}},{key:"_setupEventHandlers",value:function(){this._handleDocumentClickBound=this._handleDocumentClick.bind(this),this._handleTargetClickBound=this._handleTargetClick.bind(this),this._handleOriginClickBound=this._handleOriginClick.bind(this),this.el.addEventListener("click",this._handleTargetClickBound),this.originEl.addEventListener("click",this._handleOriginClickBound);var t=M.throttle(this._handleResize,200);this._handleThrottledResizeBound=t.bind(this),window.addEventListener("resize",this._handleThrottledResizeBound)}},{key:"_removeEventHandlers",value:function(){this.el.removeEventListener("click",this._handleTargetClickBound),this.originEl.removeEventListener("click",this._handleOriginClickBound),window.removeEventListener("resize",this._handleThrottledResizeBound)}},{key:"_handleTargetClick",value:function(t){this.open()}},{key:"_handleOriginClick",value:function(t){this.close()}},{key:"_handleResize",value:function(t){this._calculatePositioning()}},{key:"_handleDocumentClick",value:function(e){t(e.target).closest(".tap-target-wrapper").length||(this.close(),e.preventDefault(),e.stopPropagation())}},{key:"_setup",value:function(){this.wrapper=this.$el.parent()[0],this.waveEl=t(this.wrapper).find(".tap-target-wave")[0],this.originEl=t(this.wrapper).find(".tap-target-origin")[0],this.contentEl=this.$el.find(".tap-target-content")[0],t(this.wrapper).hasClass(".tap-target-wrapper")||(this.wrapper=document.createElement("div"),this.wrapper.classList.add("tap-target-wrapper"),this.$el.before(t(this.wrapper)),this.wrapper.append(this.el)),this.contentEl||(this.contentEl=document.createElement("div"),this.contentEl.classList.add("tap-target-content"),this.$el.append(this.contentEl)),this.waveEl||(this.waveEl=document.createElement("div"),this.waveEl.classList.add("tap-target-wave"),this.originEl||(this.originEl=this.$origin.clone(!0,!0),this.originEl.addClass("tap-target-origin"),this.originEl.removeAttr("id"),this.originEl.removeAttr("style"),this.originEl=this.originEl[0],this.waveEl.append(this.originEl)),this.wrapper.append(this.waveEl))}},{key:"_calculatePositioning",value:function(){var e="fixed"===this.$origin.css("position");if(!e)for(var i=this.$origin.parents(),n=0;nd,v=a<=u,f=a>u,m=r>=.25*l&&r<=.75*l,g=this.$el.outerWidth(),_=this.$el.outerHeight(),y=a+o/2-_/2,k=r+s/2-g/2,b=e?"fixed":"absolute",w=m?g:g/2+s,C=_/2,E=v?_/2:0,x=c&&!m?g/2-s:0,O=s,T=f?"bottom":"top",L=2*s,$=L,B=_/2-$/2,D=g/2-L/2,S={};S.top=v?y+"px":"",S.right=p?l-k-g+"px":"",S.bottom=f?h-y-_+"px":"",S.left=c?k+"px":"",S.position=b,t(this.wrapper).css(S),t(this.contentEl).css({width:w+"px",height:C+"px",top:E+"px",right:"0px",bottom:"0px",left:x+"px",padding:O+"px",verticalAlign:T}),t(this.waveEl).css({top:B+"px",left:D+"px",width:L+"px",height:$+"px"})}},{key:"open",value:function(){this.isOpen||("function"==typeof this.options.onOpen&&this.options.onOpen.call(this,this.$origin[0]),this.isOpen=!0,this.wrapper.classList.add("open"),document.body.addEventListener("click",this._handleDocumentClickBound,!0),document.body.addEventListener("touchend",this._handleDocumentClickBound))}},{key:"close",value:function(){this.isOpen&&("function"==typeof this.options.onClose&&this.options.onClose.call(this,this.$origin[0]),this.isOpen=!1,this.wrapper.classList.remove("open"),document.body.removeEventListener("click",this._handleDocumentClickBound,!0),document.body.removeEventListener("touchend",this._handleDocumentClickBound))}}],[{key:"init",value:function(t,e){return _get(n.__proto__||Object.getPrototypeOf(n),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_TapTarget}},{key:"defaults",get:function(){return e}}]),n}();M.TapTarget=i,M.jQueryLoaded&&M.initializeJqueryWrapper(i,"tapTarget","M_TapTarget")}(cash),function(t){"use strict";var e={classes:"",dropdownOptions:{}},i=function(i){function n(e,i){_classCallCheck(this,n);var s=_possibleConstructorReturn(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,n,e,i));return s.$el.hasClass("browser-default")?_possibleConstructorReturn(s):(s.el.M_FormSelect=s,s.options=t.extend({},n.defaults,i),s.isMultiple=s.$el.prop("multiple"),s.el.tabIndex=-1,s._keysSelected={},s._valueDict={},s._setupDropdown(),s._setupEventHandlers(),s)}return _inherits(n,Component),_createClass(n,[{key:"destroy",value:function(){this._removeEventHandlers(),this._removeDropdown(),this.el.M_FormSelect=void 0}},{key:"_setupEventHandlers",value:function(){var e=this;this._handleSelectChangeBound=this._handleSelectChange.bind(this),this._handleOptionClickBound=this._handleOptionClick.bind(this),this._handleInputClickBound=this._handleInputClick.bind(this),t(this.dropdownOptions).find("li:not(.optgroup)").each(function(t){t.addEventListener("click",e._handleOptionClickBound)}),this.el.addEventListener("change",this._handleSelectChangeBound),this.input.addEventListener("click",this._handleInputClickBound)}},{key:"_removeEventHandlers",value:function(){var e=this;t(this.dropdownOptions).find("li:not(.optgroup)").each(function(t){t.removeEventListener("click",e._handleOptionClickBound)}),this.el.removeEventListener("change",this._handleSelectChangeBound),this.input.removeEventListener("click",this._handleInputClickBound)}},{key:"_handleSelectChange",value:function(t){this._setValueToInput()}},{key:"_handleOptionClick",value:function(e){e.preventDefault();var i=t(e.target).closest("li")[0],n=i.id;if(!t(i).hasClass("disabled")&&!t(i).hasClass("optgroup")&&n.length){var s=!0;if(this.isMultiple){var o=t(this.dropdownOptions).find("li.disabled.selected");o.length&&(o.removeClass("selected"),o.find('input[type="checkbox"]').prop("checked",!1),this._toggleEntryFromArray(o[0].id));var a=t(i).find('input[type="checkbox"]');a.prop("checked",!a.prop("checked")),s=this._toggleEntryFromArray(n)}else t(this.dropdownOptions).find("li").removeClass("active"),t(i).toggleClass("active"),this.input.value=i.textContent;this._activateOption(t(this.dropdownOptions),i),t(this._valueDict[n].el).prop("selected",s),this.$el.trigger("change")}e.stopPropagation()}},{key:"_handleInputClick",value:function(){this.dropdown&&this.dropdown.isOpen&&(this._setValueToInput(),this._setSelectedStates())}},{key:"_setupDropdown",value:function(){var e=this;this.wrapper=document.createElement("div"),t(this.wrapper).addClass("select-wrapper "+this.options.classes),this.$el.before(t(this.wrapper)),this.wrapper.appendChild(this.el),this.el.disabled&&this.wrapper.classList.add("disabled"),this.$selectOptions=this.$el.children("option, optgroup"),this.dropdownOptions=document.createElement("ul"),this.dropdownOptions.id="select-options-"+M.guid(),t(this.dropdownOptions).addClass("dropdown-content select-dropdown "+(this.isMultiple?"multiple-select-dropdown":"")),this.$selectOptions.length&&this.$selectOptions.each(function(i){if(t(i).is("option")){var n=void 0;n=e.isMultiple?e._appendOptionWithIcon(e.$el,i,"multiple"):e._appendOptionWithIcon(e.$el,i),e._addOptionToValueDict(i,n)}else if(t(i).is("optgroup")){var s=t(i).children("option");t(e.dropdownOptions).append(t('
    • '+i.getAttribute("label")+"
    • ")[0]),s.each(function(t){var i=e._appendOptionWithIcon(e.$el,t,"optgroup-option");e._addOptionToValueDict(t,i)})}}),this.$el.after(this.dropdownOptions),this.input=document.createElement("input"),t(this.input).addClass("select-dropdown dropdown-trigger"),this.input.setAttribute("type","text"),this.input.setAttribute("readonly","true"),this.input.setAttribute("data-target",this.dropdownOptions.id),this.el.disabled&&t(this.input).prop("disabled","true"),this.$el.before(this.input),this._setValueToInput();var i=t('');if(this.$el.before(i[0]),!this.el.disabled){var n=t.extend({},this.options.dropdownOptions);n.onOpenEnd=function(i){var n=t(e.dropdownOptions).find(".selected").first();if(e.dropdown.isScrollable&&n.length){var s=n[0].getBoundingClientRect().top-e.dropdownOptions.getBoundingClientRect().top;s-=e.dropdownOptions.clientHeight/2,e.dropdownOptions.scrollTop=s}},this.isMultiple&&(n.closeOnClick=!1),this.dropdown=M.Dropdown.init(this.input,n)}this._setSelectedStates()}},{key:"_addOptionToValueDict",value:function(t,e){var i=Object.keys(this._valueDict).length,n=this.dropdownOptions.id+i,s={};e.id=n,s.el=t,s.optionEl=e,this._valueDict[n]=s}},{key:"_removeDropdown",value:function(){t(this.wrapper).find(".caret").remove(),t(this.input).remove(),t(this.dropdownOptions).remove(),t(this.wrapper).before(this.$el),t(this.wrapper).remove()}},{key:"_appendOptionWithIcon",value:function(e,i,n){var s=i.disabled?"disabled ":"",o="optgroup-option"===n?"optgroup-option ":"",a=this.isMultiple?'":i.innerHTML,r=t("
    • "),l=t("");l.html(a),r.addClass(s+" "+o),r.append(l);var h=i.getAttribute("data-icon");i.getAttribute("class");if(h){var d=t('');r.prepend(d)}return t(this.dropdownOptions).append(r[0]),r[0]}},{key:"_toggleEntryFromArray",value:function(e){var i=!this._keysSelected.hasOwnProperty(e);return i?this._keysSelected[e]=!0:delete this._keysSelected[e],t(this._valueDict[e].optionEl).toggleClass("active"),t(this._valueDict[e].el).prop("selected",i),i}},{key:"_setValueToInput",value:function(){var e="";if(this.$el.find("option").each(function(i){if(t(i).prop("selected")){var n=t(i).text();e+=""===e?n:", "+n}}),""===e){var i=this.$el.find("option:disabled").eq(0);i.length&&(e=i.text())}this.input.value=e}},{key:"_setSelectedStates",value:function(){this._keysSelected={};for(var e in this._valueDict){var i=this._valueDict[e];t(i.el).prop("selected")?(t(i.optionEl).find('input[type="checkbox"]').prop("checked",!0),this._activateOption(t(this.dropdownOptions),t(i.optionEl)),this._keysSelected[e]=!0):(t(i.optionEl).find('input[type="checkbox"]').prop("checked",!1),t(i.optionEl).removeClass("selected"))}}},{key:"_activateOption",value:function(e,i){i&&(this.isMultiple||e.find("li.selected").removeClass("selected"),t(i).addClass("selected"))}},{key:"getSelectedValues",value:function(){var t=[];for(var e in this._keysSelected)t.push(this._valueDict[e].el.value);return t}}],[{key:"init",value:function(t,e){return _get(n.__proto__||Object.getPrototypeOf(n),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_FormSelect}},{key:"defaults",get:function(){return e}}]),n}();M.FormSelect=i,M.jQueryLoaded&&M.initializeJqueryWrapper(i,"formSelect","M_FormSelect")}(cash),function(t,e){"use strict";var i={},n=function(n){function s(e,i){_classCallCheck(this,s);var n=_possibleConstructorReturn(this,(s.__proto__||Object.getPrototypeOf(s)).call(this,s,e,i));return n.el.M_Range=n,n.options=t.extend({},s.defaults,i),n._mousedown=!1,n._setupThumb(),n._setupEventHandlers(),n}return _inherits(s,Component),_createClass(s,[{key:"destroy",value:function(){this._removeEventHandlers(),this._removeThumb(),this.el.M_Range=void 0}},{key:"_setupEventHandlers",value:function(){this._handleRangeChangeBound=this._handleRangeChange.bind(this),this._handleRangeFocusBound=this._handleRangeFocus.bind(this),this._handleRangeMousedownTouchstartBound=this._handleRangeMousedownTouchstart.bind(this),this._handleRangeInputMousemoveTouchmoveBound=this._handleRangeInputMousemoveTouchmove.bind(this),this._handleRangeMouseupTouchendBound=this._handleRangeMouseupTouchend.bind(this),this._handleRangeBlurMouseoutTouchleaveBound=this._handleRangeBlurMouseoutTouchleave.bind(this),this.el.addEventListener("change",this._handleRangeChangeBound),this.el.addEventListener("focus",this._handleRangeFocusBound),this.el.addEventListener("mousedown",this._handleRangeMousedownTouchstartBound),this.el.addEventListener("touchstart",this._handleRangeMousedownTouchstartBound),this.el.addEventListener("input",this._handleRangeInputMousemoveTouchmoveBound),this.el.addEventListener("mousemove",this._handleRangeInputMousemoveTouchmoveBound),this.el.addEventListener("touchmove",this._handleRangeInputMousemoveTouchmoveBound),this.el.addEventListener("mouseup",this._handleRangeMouseupTouchendBound),this.el.addEventListener("touchend",this._handleRangeMouseupTouchendBound),this.el.addEventListener("blur",this._handleRangeBlurMouseoutTouchleaveBound),this.el.addEventListener("mouseout",this._handleRangeBlurMouseoutTouchleaveBound),this.el.addEventListener("touchleave",this._handleRangeBlurMouseoutTouchleaveBound)}},{key:"_removeEventHandlers",value:function(){this.el.removeEventListener("change",this._handleRangeChangeBound),this.el.removeEventListener("focus",this._handleRangeFocusBound),this.el.removeEventListener("mousedown",this._handleRangeMousedownTouchstartBound),this.el.removeEventListener("touchstart",this._handleRangeMousedownTouchstartBound),this.el.removeEventListener("input",this._handleRangeInputMousemoveTouchmoveBound),this.el.removeEventListener("mousemove",this._handleRangeInputMousemoveTouchmoveBound),this.el.removeEventListener("touchmove",this._handleRangeInputMousemoveTouchmoveBound),this.el.removeEventListener("mouseup",this._handleRangeMouseupTouchendBound),this.el.removeEventListener("touchend",this._handleRangeMouseupTouchendBound),this.el.removeEventListener("blur",this._handleRangeBlurMouseoutTouchleaveBound),this.el.removeEventListener("mouseout",this._handleRangeBlurMouseoutTouchleaveBound),this.el.removeEventListener("touchleave",this._handleRangeBlurMouseoutTouchleaveBound)}},{key:"_handleRangeChange",value:function(){t(this.value).html(this.$el.val()),t(this.thumb).hasClass("active")||this._showRangeBubble();var e=this._calcRangeOffset();t(this.thumb).addClass("active").css("left",e+"px")}},{key:"_handleRangeFocus",value:function(){M.tabPressed&&this.$el.addClass("focused")}},{key:"_handleRangeMousedownTouchstart",value:function(e){if(t(this.value).html(this.$el.val()),this._mousedown=!0,this.$el.addClass("active"),t(this.thumb).hasClass("active")||this._showRangeBubble(),"input"!==e.type){var i=this._calcRangeOffset();t(this.thumb).addClass("active").css("left",i+"px")}}},{key:"_handleRangeInputMousemoveTouchmove",value:function(){if(this._mousedown){t(this.thumb).hasClass("active")||this._showRangeBubble();var e=this._calcRangeOffset();t(this.thumb).addClass("active").css("left",e+"px"),t(this.value).html(this.$el.val())}}},{key:"_handleRangeMouseupTouchend",value:function(){this._mousedown=!1,this.$el.removeClass("active")}},{key:"_handleRangeBlurMouseoutTouchleave",value:function(){if(!this._mousedown){this.$el.removeClass("focused");var i=7+parseInt(this.$el.css("padding-left"))+"px";t(this.thumb).hasClass("active")&&(e.remove(this.thumb),e({targets:this.thumb,height:0,width:0,top:10,easing:"easeOutQuad",marginLeft:i,duration:100})),t(this.thumb).removeClass("active")}}},{key:"_setupThumb",value:function(){this.thumb=document.createElement("span"),this.value=document.createElement("span"),t(this.thumb).addClass("thumb"),t(this.value).addClass("value"),t(this.thumb).append(this.value),this.$el.after(this.thumb)}},{key:"_removeThumb",value:function(){t(this.thumb).remove()}},{key:"_showRangeBubble",value:function(){var i=-7+parseInt(t(this.thumb).parent().css("padding-left"))+"px";e.remove(this.thumb),e({targets:this.thumb,height:30,width:30,top:-30,marginLeft:i,duration:300,easing:"easeOutQuint"})}},{key:"_calcRangeOffset",value:function(){var t=this.$el.width()-15,e=parseFloat(this.$el.attr("max")),i=parseFloat(this.$el.attr("min"));return(parseFloat(this.$el.val())-i)/(e-i)*t}}],[{key:"init",value:function(t,e){return _get(s.__proto__||Object.getPrototypeOf(s),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Range}},{key:"defaults",get:function(){return i}}]),s}();M.Range=n,M.jQueryLoaded&&M.initializeJqueryWrapper(n,"range","M_Range"),n.init(t("input[type=range]"))}(cash,M.anime); \ No newline at end of file diff --git a/src/main.js b/src/main.js new file mode 100644 index 0000000..f7eb9da --- /dev/null +++ b/src/main.js @@ -0,0 +1,583 @@ +/* +Application entry point and main JS file +Author: Mark Duske +*/ + +//Import +const electron = require("electron"); +const url = require("url"); +const path = require("path"); + +const { app, BrowserWindow, Menu, ipcMain } = electron; + +const colonyClient = require("./colonyClient"); + +//Local data Storage +const Store = require('./store.js'); + +/** + * Connector to interact with the colony curently open + */ +let currentColonyConnector; + +//Initialize Storage +// First instantiate the class +const dataStore = new Store({ + // We'll call our data file 'user-preferences' + configName: 'ddsc-user-preferences', + defaults: { //Predefined data + "recentColony": {} + } +}); + +//Global variables +let mainWindow; +let researchWindow; //Currently Open Research Window + +let currentAccount = {}; //The account curently in use + +let accountSelectWindow; //Currently open Account Selection Window +let accountSelectCallback; + +let colonySelectWindow; //Currently open Colony Selection Window +let colonySelectCallback; + +let createColonyWindow; + +//Already loaded colony information +let existingColonies = []; + +//Uncomment line below before releasing for fnial users +//process.env.NODE_ENV = 'prod'; + +//Initialization +app.on("ready", initMainWindow); + +//Functions + +/** + * Open the Main Window + */ +function initMainWindow() { + mainWindow = new BrowserWindow({ + "minHeight": 700, + "minWidth": 800, + "backgroundColor": '#FFFFFF', + show: false + }); + + mainWindow.loadURL( + url.format( + { + pathname: path.join(__dirname, "mainWindow.html"), + protocol: "file", + slashes: true + } + ) + ); + + //Set Window Menu + const menuTemplate = Menu.buildFromTemplate(mainWindowMenu); + Menu.setApplicationMenu(menuTemplate); + + //Close App when Main Window Closes + mainWindow.on("close", function () { + app.quit(); + }); + + //Ask for an Account to use + mainWindow.once("ready-to-show", function () { + console.log("Select Account!"); + mainWindow.show(); + selectAccount(setCurrentAccount, "You must first select the Ethereum account"); + }); + +} + +/** + * Set the number and other data for the currently selected account + * @param {*} _accountNumber + * @param {*} _accountAddress + */ +function setCurrentAccount(_accountNumber, _accountAddress) { + currentAccount = { + "number": _accountNumber, + "adress": _accountAddress + }; + console.log("Account Selected: " + _accountNumber, _accountAddress); + + mainWindow.webContents.send('account:change', _accountNumber, _accountAddress); +} + +/** + * Open a Research Window + */ +function openResearchWindow(_researchId) { + //Close currently open Research, if any is open + if (researchWindow != null) { + researchWindow.close(); + researchWindow = null; + } + + researchWindow = new BrowserWindow({ + /*"parent": mainWindow,*/ + "minHeight": 700, + "minWidth": 800 + }); + + researchWindow.loadURL( + url.format( + { + pathname: path.join(__dirname, "researchWindow.html"), + protocol: "file", + slashes: true + } + ) + ); + + researchWindow.on("close", function () { + researchWindow = null; + }); + + if (_researchId > 0) { + //Retrieve Domain data from Colony + let researchData; + + //TODO: Load Data + + //Load research information + researchWindow.webContents.send("research:loadData", researchData); + } +} + +/** + * Open a Task Window + */ +function openTaskWindow(_taskId) { + let taskWindow = new BrowserWindow({ + "parent": researchWindow, + "height": 500, + "width": 600, + resizable: false + }); + + taskWindow.loadURL( + url.format( + { + pathname: path.join(__dirname, "taskWindow.html"), + protocol: "file", + slashes: true + } + ) + ); + + if (_taskId > 0) { + //Retrieve Task data from Colony + let taskData; + + //TODO: Load Data + + //Load task information + taskWindow.webContents.send("task:loadData", taskData); + } +} + +function openCreateColonyWindow() { + //Close currently open Research, if any is open + if (createColonyWindow != null) { + createColonyWindow.close(); + createColonyWindow = null; + } + + createColonyWindow = new BrowserWindow({ + "parent": mainWindow, + "height": 475, + "width": 600, + resizable: false, + modal: true, + show: true, + autoHideMenuBar: true + }); + + createColonyWindow.loadURL( + url.format( + { + pathname: path.join(__dirname, "createColonyWindow.html"), + protocol: "file", + slashes: true + } + ) + ); + + //Close App when Main Window Closes + createColonyWindow.on("close", function () { + createColonyWindow = null; + }); +} + +/** + * Create a brand new colony + */ +function createColony(_colonyTokenSymbol, _colonyTokenName) { + const accountNumber = currentAccount.number; + + if (_colonyTokenSymbol == null || _colonyTokenSymbol === "") { + //Show window for inputs + openCreateColonyWindow(); + + return; + } + + mainWindow.webContents.send("colony:close"); + mainWindow.webContents.send("toast:show", "Creating new Colony " + _colonyTokenName + " , this can take up to a minute!", { displayLength: 30000 }); + + let clientCreation = colonyClient.createColony(accountNumber, _colonyTokenName, _colonyTokenSymbol); + clientCreation.then(function (colonyConnector) { + console.log("Colony CREATED!"); + colonyConnectorClient = colonyConnector["colonyClient"]; + colonyData = colonyConnector["colonyData"]; + + //Set current colony connector + currentColonyConnector = colonyConnectorClient; + + existingColonies.push(colonyData); + + //Store Colony Information in "recentColony" + storeRecentColony(colonyData.id, colonyData); + + //Update information on screen + mainWindow.webContents.send("colony:change", colonyData); + }, function (reason) { + console.log("Colony Error! " + reason); + }).catch(err => console.error(err)); +} + +/** + * Store information on a recently openned Colony + * @param {*} _colonyId + * @param {*} _colonyData + */ +function storeRecentColony(_colonyId, _colonyData) { + //Store Colony Information in "recentColony" + console.log("Storing Recent Colony: " + _colonyId + " / " + _colonyData); + try { + let recentColony = dataStore.get("recentColony"); + if (recentColony == null) { + recentColony = {}; + } + recentColony[_colonyId] = _colonyData; + + dataStore.set("recentColony", recentColony); + } catch (e) { + console.error(e); + } +} + +/** + * Open an existing Colony + */ +openColony = async function (_colonyId, _colonyAddress) { + const accountNumber = currentAccount.number; + + if (accountNumber == null) { + console.log("Error: No Account selected"); + + //Force account Selection + selectAccount(openColony); + } + + if (_colonyId > 0) { + console.log("Open Colony " + _colonyId + " using Account: " + accountNumber); + console.log("existingColonies.length " + existingColonies.length); + let colonyData; + + mainWindow.webContents.send("colony:close"); + mainWindow.webContents.send("toast:show", "Openning Colony " + _colonyId + " / " + _colonyAddress + ", this can take up to a minute!", { displayLength: 10000 }); + + //Generate new Connector + let openColonyClient = await colonyClient.openColony(accountNumber, _colonyId, _colonyAddress); + console.log("Colony OPEN! " + _colonyId); + colonyConnectorClient = openColonyClient["colonyClient"]; + colonyData = openColonyClient["colonyData"]; + + console.log("colonyData " + colonyData); + + //Set current colony connector + currentColonyConnector = colonyConnectorClient; + + //Store Colony Information in "recentColony" + storeRecentColony(colonyData.id, colonyData); + + mainWindow.webContents.send("colony:change", colonyData); + } else { + //Show Colony Selection window + try { + await selecColony(openColony); + } catch (e) { + console.error(e); + } + } +} + +/** + * Shows selector to pick a single Account + */ +selectAccount = async function (_callBack, _toastMessage) { + if (accountSelectWindow != null) { + accountSelectWindow.close(); + accountSelectWindow = null; + accountSelectCallback = null; + } + + mainWindow.webContents.send("colony:close"); + + //Show window to select Account + accountSelectWindow = new BrowserWindow({ + "parent": mainWindow, + "height": 150, + "width": 500, + resizable: false, + modal: true, + show: false, + autoHideMenuBar: true + }); + + accountSelectWindow.loadURL( + url.format( + { + pathname: path.join(__dirname, "selectAccountWindow.html"), + protocol: "file", + slashes: true + } + ) + ); + + accountSelectWindow.on("close", function () { + accountSelectWindow = null; + accountSelectCallback = null; + }); + + //Retrieve existing accounts + const accountList = await colonyClient.listAccounts(); + //console.log("Listed Accounts: " + accountList.length); + + //Set Callback fucntion + accountSelectCallback = _callBack; + + //accountSelectWindow.webContents.toggleDevTools(); + + accountSelectWindow.once("ready-to-show", function () { + //console.log("Show Account Window with " + accountList.length + " accounts!"); + accountSelectWindow.show(); + accountSelectWindow.webContents.send('account:list', accountList, _toastMessage); + }); +} + +/** + * Shows selector to pick a single Account + */ +selecColony = async function (_callBack) { + const accountNumber = currentAccount.number; + + if (colonySelectWindow != null) { + try { + colonySelectWindow.close(); + colonySelectWindow = null; + colonySelectCallback = null; + } catch (e) { } + } + + if (existingColonies.length == 0) { + //Warn of slowness in processing all this data + mainWindow.webContents.send("toast:show", "This operation can take a up to few minutes the first time, please be patient!", { displayLength: 60000 }); + } + + //Retrieve existing accounts + const colonyList = (existingColonies.length == 0) ? await colonyClient.listColonies(accountNumber) : existingColonies; + existingColonies = colonyList; + console.log("Loaded Colonies: " + colonyList.length); + + //Set Callback function + colonySelectCallback = _callBack; + + //Show window to select Account + colonySelectWindow = new BrowserWindow({ + "parent": mainWindow, + "height": 400, + "width": 700, + resizable: false, + modal: true, + show: false, + autoHideMenuBar: true + }); + + colonySelectWindow.loadURL( + url.format( + { + pathname: path.join(__dirname, "selectColonyWindow.html"), + protocol: "file", + slashes: true + } + ) + ); + + colonySelectWindow.on("close", function () { + colonySelectWindow = null; + colonySelectCallback = null; + }); + + //accountSelectWindow.webContents.toggleDevTools(); + + colonySelectWindow.once("ready-to-show", function () { + //console.log("Show Account Window with " + accountList.length + " accounts!"); + colonySelectWindow.show(); + colonySelectWindow.webContents.send("colony:list", colonyList, "Select existing DDS Colony to open"); + }); +} + +//Menu Definition +let menuRecentColonies = []; +try { + let recentColony = dataStore.get("recentColony"); + if (recentColony != null) { + console.log("Loading Recent Colonies"); + + for (colonyId in recentColony) { + const colonyData = recentColony[colonyId]; + + console.log(colonyId + " : " + colonyData); + + const labelValue = colonyData.id + " / " + colonyData.token.symbol + " / " + colonyData.token.name; + const id = colonyData.id; + const address = colonyData.address; + + menuRecentColonies.push({ + label: labelValue, + click() { + console.log(id, address); + openColony(id, address).then(function () { + console.error("Recent Colony Open: " + id); + }, function (reason) { + console.error("Error opening Recent Colony: " + reason); + }).catch(err => console.error(err)); + } + }); + } + } +} catch (e) { + console.error(e); +} + +const mainWindowMenu = [ + { + label: "Colony", + submenu: [ + { + label: "New", + click() { + createColony() + } + }, + { + label: "Open", + click() { + openColony() + } + }, + { + label: "Open Recent...", + submenu: menuRecentColonies + }, + { + label: "Change Account", + click() { + selectAccount(setCurrentAccount); + } + }, + { + label: "Quit", + accelerator: (process.platform == "darwin") ? "Command+Q" : "Ctrl+Q", + click() { + app.quit(); + } + } + ] + }, + { + label: "Research", + submenu: [ + { + label: "New", + click() { + openResearchWindow(); + } + } + ] + } +]; + +//Adjust Menu for Macs only +if (process.platform == "darwin") { + mainWindowMenu.unshift({}); +} + +//Enable Dev Tools +if (process.env.NODE_ENV !== 'prod') { + mainWindowMenu.push({ + label: "Debug", + submenu: [ + { + label: "Toggle Dev Tools", + accelerator: (process.platform == "darwin") ? "Command+I" : "Ctrl+I", + click(item, focusedWindow) { + focusedWindow.toggleDevTools(); + } + }, + { + role: "reload" + } + ] + }); +} + +//Events +ipcMain.on("task:open", function (e, _taskId) { + openTaskWindow(_taskId); +}); + +ipcMain.on("research:open", function (e, _researchId) { + openResearchWindow(_researchId); +}); + +ipcMain.on("colony:new", function (e, _researchId) { + createColony(); +}); + +ipcMain.on("account:selected", function (e, _accountNumber, _accountAddress) { + console.log("Etherium Account Selected " + _accountNumber + " / " + _accountAddress); + + if (accountSelectCallback != null) { + console.log("Triggering Account Select Callback"); + accountSelectCallback(_accountNumber, _accountAddress); + } +}); + +ipcMain.on("colony:selected", function (e, _colonyId, _colonyAddress) { + console.log("DDS Colony Selected " + _colonyId + " / " + _colonyAddress); + + if (colonySelectCallback != null) { + console.log("Triggering Colony Select Callback"); + colonySelectCallback(_colonyId, _colonyAddress); + } +}); + +ipcMain.on("colony:create", function (e, _tokenSymbol, _tokenName) { + console.log("DDS Colony Create " + _tokenSymbol + " / " + _tokenName); + + createColony(_tokenSymbol, _tokenName); +}); + +//Export functions that can be used from pages directly +module.exports = { + createColony +} \ No newline at end of file diff --git a/src/mainWindow.html b/src/mainWindow.html new file mode 100644 index 0000000..51da7b7 --- /dev/null +++ b/src/mainWindow.html @@ -0,0 +1,283 @@ + + + + + DDSC - Decentralized Data Science Colony + + + + + + + + + + + + +
      + +
      +
      +
      +
      + + Colony Information + + + Funding +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Pot NameFunds Available
      Rewards123
      Working Capital234
      Pot ABC1234
      Pot ABC11234
      Pot ABC21234
      +
      +
      +
      + + Current Research + add_box + +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      NameFundingStatus
      + Research 1 + 123EDA
      + Research 2 + 234Question
      Research 3123Communication
      Research 1123EDA
      Research 2234Question
      Research 3123Communication
      Research 1123EDA
      Research 2234Question
      Research 3123Communication
      Research 1123EDA
      Research 2234Question
      Research 3123Communication
      Research 1123EDA
      Research 2234Question
      Research 3123Communication
      +
      +
      +
      +
      +
      + +
      + + +
      + + + + + + + + + + \ No newline at end of file diff --git a/src/researchWindow.html b/src/researchWindow.html new file mode 100644 index 0000000..d1678b9 --- /dev/null +++ b/src/researchWindow.html @@ -0,0 +1,145 @@ + + + + + DDSC - Decentralized Data Science Colony + + + + + + + + + + + + +
      + +
      + +
      +
      +
      +
      + + Research Information +
      +
        +
      • Name: General Research Colony
      • +
      • Funding: 999 Tokens
      • +
      • Description: loren lipsum, ec...
      • +
      +
      + + Documents +
      + + + + + + + + + + + + + + + +
      PhaseTaskDocument
      Question2 - Question refined + This is an extremely long title that will be truncated +
      +
      +
      +
      + + Tasks + add_box + +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      PhaseNameFunding
      + done + Question2 - Something22
      + directions_run + EDA3 - Something25
      + flag + EDA4 - Something12
      + close + Model5 - Something2
      +
      +
      +
      +
      +
      + +
      + +
      + + + + + + + + \ No newline at end of file diff --git a/src/selectAccountWindow.html b/src/selectAccountWindow.html new file mode 100644 index 0000000..30ecef4 --- /dev/null +++ b/src/selectAccountWindow.html @@ -0,0 +1,78 @@ + + + + + DDSC - Select Account to Use + + + + + + + + + + + + +
      +
      + +
      +
      +
      +
      +
      + OK +
      +
      +
      + + + + + + + + \ No newline at end of file diff --git a/src/selectColonyWindow.html b/src/selectColonyWindow.html new file mode 100644 index 0000000..e7c46be --- /dev/null +++ b/src/selectColonyWindow.html @@ -0,0 +1,80 @@ + + + + + DDSC - Select Colony to Use + + + + + + + + + + + + +
      +
      + +
      +
      +
      +
      +
      + OK +
      +
      +
      + + + + + + + + \ No newline at end of file diff --git a/src/store.js b/src/store.js new file mode 100644 index 0000000..ae9886c --- /dev/null +++ b/src/store.js @@ -0,0 +1,52 @@ +/* + +References: +Article: https://codeburst.io/how-to-store-user-data-in-electron-3ba6bf66bc1e +Code: https://gist.github.com/ccnokes/95cb454860dbf8577e88d734c3f31e08#file-store-js + +*/ + +const electron = require('electron'); +const path = require('path'); +const fs = require('fs'); + +class Store { + constructor(opts) { + // Renderer process has to get `app` module via `remote`, whereas the main process can get it directly + // app.getPath('userData') will return a string of the user's app data directory path. + const userDataPath = (electron.app || electron.remote.app).getPath('userData'); + // We'll use the `configName` property to set the file name and path.join to bring it all together as a string + this.path = path.join(userDataPath, opts.configName + '.json'); + + this.data = parseDataFile(this.path, opts.defaults); + } + + // This will just return the property on the `data` object + get(key) { + return this.data[key]; + } + + // ...and this will set it + set(key, val) { + this.data[key] = val; + // Wait, I thought using the node.js' synchronous APIs was bad form? + // We're not writing a server so there's not nearly the same IO demand on the process + // Also if we used an async API and our app was quit before the asynchronous write had a chance to complete, + // we might lose that data. Note that in a real app, we would try/catch this. + fs.writeFileSync(this.path, JSON.stringify(this.data)); + } +} + +function parseDataFile(filePath, defaults) { + // We'll try/catch it in case the file doesn't exist yet, which will be the case on the first application run. + // `fs.readFileSync` will return a JSON string which we then parse into a Javascript object + try { + return JSON.parse(fs.readFileSync(filePath)); + } catch(error) { + // if there was some kind of error, return the passed in defaults instead. + return defaults; + } +} + +// expose the class +module.exports = Store; diff --git a/src/taskWindow.html b/src/taskWindow.html new file mode 100644 index 0000000..91ad54d --- /dev/null +++ b/src/taskWindow.html @@ -0,0 +1,86 @@ + + + + + DDSC - Decentralized Data Science Colony + + + + + + + + + + + + +
      +
      +
      +
      +
      +
      + + +
      +
      + + +
      +
      +
      +
      +
      + + +
      +
      + + +
      +
      +
      +
      + + +
      +
      +
      +
      +
      + +
      + + + + + + + + \ No newline at end of file From 8e1430d271cffa59459a6a12d28052412b9de71f Mon Sep 17 00:00:00 2001 From: mduske Date: Sun, 24 Jun 2018 19:47:04 -0400 Subject: [PATCH 2/3] changes --- CODE_OF_CONDUCT.md | 73 ---------------------------------------------- colonyHackathon | 1 + 2 files changed, 1 insertion(+), 73 deletions(-) delete mode 100644 CODE_OF_CONDUCT.md create mode 160000 colonyHackathon diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index 257cb32..0000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,73 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, gender identity and expression, level of experience, -nationality, personal appearance, race, religion, or sexual identity and -orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment -include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or - advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at [developers@colony.io](mailto:developers@colony.io). All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html - -[homepage]: https://www.contributor-covenant.org diff --git a/colonyHackathon b/colonyHackathon new file mode 160000 index 0000000..a4bfe4a --- /dev/null +++ b/colonyHackathon @@ -0,0 +1 @@ +Subproject commit a4bfe4a670518532ee485b55b7793983e3224992 From 3190cdb2934a7303ae838bfa17f8ab9bbaf9114a Mon Sep 17 00:00:00 2001 From: mduske Date: Sun, 24 Jun 2018 19:53:23 -0400 Subject: [PATCH 3/3] Update README.md --- README.md | 98 ++----------------------------------------------------- 1 file changed, 2 insertions(+), 96 deletions(-) diff --git a/README.md b/README.md index 0ee3c46..fcdb473 100644 --- a/README.md +++ b/README.md @@ -1,97 +1,3 @@ -![Hackathon](docs/hackathon_banner.png) -Welcome to the submission repository for the Colony Hackathon. +https://github.com/mduske/colonyHackathon -You can read more about the Colony Network and the colonyJS library on the [Docs site](https://joincolony.github.io/colonyjs/docs-overview/). - -## Gitter - -To meet potential team members, chat about projects, or get help with your code and the ColonyJS library, head over to the [the colonyHackathon Gitter](https://gitter.im/ColonyHackathon/Lobby). - - -# Submission Guidelines - -Participating in the hackathon is as easy as contributing to an open source project on GitHub. Exactly so, because you will register your project by creating an issue in this repository, and submit it by creating a pull request. - -Here’s how it works: - -## The Submission Process - -### 1) Create an issue -Your first step is to create an issue in the `colonyHackathon` repository. This issue acts as a "soft" registration for the hackathon, and can help you to coordinate your ideas with other participants. An issue is a good place to talk openly about your project ideas with others before you decide on its exact scope. - -Use your issue to talk with collaborators, brainstorm, and organize. Check out the other issues to see if there are participants who want to work on the same things. - -Members of the colony team will be able to point other participants to your issue (if it looks like they can help), help you with technical questions, or just offer support :) - -Issue events will also be pulled into the Gitter feed [Gitter](https://gitter.im/ColonyHackathon/Lobby) which is a better place for more general discussion and chatting. - -### 2) Build with Colony -Work on your project as you like. How you work is up to you; We recommend creating a new GitHub repo for your team. Remember to only begin working on your project after the hackathon begins on June 5th! - -Use the issue you created in step 1 to let others know where your project lives. You might want discuss any technical challenges or attract additional teammembers. - -Wherever you work, remember that your project should include an **Open Source License** of [some form](https://opensource.org/licenses), and should be accessible to everyone after the submission deadline. - -### 3) Fork and PR -When you feel ready to submit, create a new fork of the colonyHackathon repo, and add your project as a markdown file inside `colonyHackathon/submissions/`. - -You can use `submissions/exampleProject.md` as a template if you like. - -Be sure that your project's folder links to the repo you've been working in, and contains any other supporting materials that you want evaluated by judges (such as links to a pitch deck or demo video). - -Once ready, submit via a new [pull request](https://github.com/JoinColony/colonyHackathon/pulls). - -*Opening a Pull Request establishes your project as an "official" submission* - -You can open a PR before the submission deadline and continue to work, but all materials must be finalized *before* the end of the hackathon. Any commits to your project submission after the deadline will not be considered. - -We'd also recommend referencing the issue you created in step 1 [using keywords](https://help.github.com/articles/closing-issues-using-keywords/) in your PR. - -**Submit your pull request before the submission deadline: _June 24, 23:59 GMT_** - -### 4) Congratulate your team (and yourself) on a job well-done -Whether or not you get a prize, you deserve to be proud of your work. Thanks for participating in the hackathon! - - -## Dates - -**June 5th** -Registration begins - -**June 24th** -Submission deadline - -**June 25th** -Judging begins - -**June 29th** -Winners Announced - - -## Judges and Scoring - -Submissions will be graded across the following equally-weighted criteria: - -1. Functionality -2. Creativity -3. Difficulty -4. Design - -Info about our super-awesome judges panel can be found on [the hackathon website](https://colony.io/hackathon). - -## Prizes - -**Grand Prize:** -10,000 DAI - -**2nd Prize:** -5,000 DAI - -**3rd Prize:** -2,000 DAI - -Runners up: - -3 winners: 1,000 DAI - -10 winners: 500 DAI +fixes #112
      + +