Contract 0xc04Ad234E01327b24a831e3718DBFcbE245904CC 4

Txn Hash
Method
Block
From
To
Value
0x4f5b091f301282b0d0a363eb52ab9528cbb831a18202672ddbc6c47eb1e779a5Create Stream257481702021-06-27 7:17:20459 days 8 hrs ago0x1031a1c7cc8edc64cae561dcea4285f8ab97e02f IN  0xc04ad234e01327b24a831e3718dbfcbe245904cc0 Ether0.0023670610
0x4e20d1a6c0053a1dc2e2d8a7a202c4aa41cb3753d034f4f4dc216f4f6ec0154dWithdraw From St...256679482021-06-23 14:08:36463 days 1 hr ago0x1031a1c7cc8edc64cae561dcea4285f8ab97e02f IN  0xc04ad234e01327b24a831e3718dbfcbe245904cc0 Ether0.000564466
0x7bcefcabdc80e1d81e181a81058e39154fcff86124ca6c5fc5421067d722f27cCreate Stream256677722021-06-23 13:56:52463 days 1 hr ago0x1031a1c7cc8edc64cae561dcea4285f8ab97e02f IN  0xc04ad234e01327b24a831e3718dbfcbe245904cc0 Ether0.001522986
0x175c8f3e89f747edb7005aa0bfbb29f0dc7f3df2d3102d79a450c6d2e810a465Create Stream256677392021-06-23 13:54:40463 days 1 hr ago0x1031a1c7cc8edc64cae561dcea4285f8ab97e02f IN  0xc04ad234e01327b24a831e3718dbfcbe245904cc0 Ether0.001472416
0x79c1ea88faa2627554114f6d55f6205b10e2ac0c1d55d0bc7f227e858c14fac5Create Stream256677252021-06-23 13:53:44463 days 1 hr ago0x1031a1c7cc8edc64cae561dcea4285f8ab97e02f IN  0xc04ad234e01327b24a831e3718dbfcbe245904cc0 Ether0.000153346
0x38db90b307491c7fb50368841eda47c0780aada84714c43e13e685d96295f200Create Stream256677042021-06-23 13:52:20463 days 1 hr ago0x1031a1c7cc8edc64cae561dcea4285f8ab97e02f IN  0xc04ad234e01327b24a831e3718dbfcbe245904cc0 Ether0.000150576
0x1e68ff914888f05466289816ab9b9bdf2dc3a5ea809e1167d2f4afed8ed22014Create Stream256676842021-06-23 13:51:00463 days 1 hr ago0x1031a1c7cc8edc64cae561dcea4285f8ab97e02f IN  0xc04ad234e01327b24a831e3718dbfcbe245904cc0 Ether0.000150156
0xddf44cca3c3d4dfe2833442dbaf41213c84c4d0deb05cd7f543a0fbe45312142Withdraw From St...255862832021-06-19 19:23:16466 days 20 hrs ago0x38797fe73d5d442cded05bb03236904e94187220 IN  0xc04ad234e01327b24a831e3718dbfcbe245904cc0 Ether0.000460646
0x73c64bde6cc5fc1acd5aeeeefff1e73f428f3755a0e29eabe7cb7b7e87464390Withdraw From St...255860902021-06-19 19:10:24466 days 20 hrs ago0x38797fe73d5d442cded05bb03236904e94187220 IN  0xc04ad234e01327b24a831e3718dbfcbe245904cc0 Ether0.000460646
0x5baa1d14c3c9d87d0159cb2776c28a4f14eda10d1c9b0e888ac1160f171e4d08Withdraw From St...255857322021-06-19 18:46:32466 days 20 hrs ago0x38797fe73d5d442cded05bb03236904e94187220 IN  0xc04ad234e01327b24a831e3718dbfcbe245904cc0 Ether0.000460646
0xf7b339ac64a63ea612a49865474cc74adf9640914bf3b36e71e4d3bd0fd54e1dWithdraw From St...254009522021-06-11 5:05:52475 days 10 hrs ago0x38797fe73d5d442cded05bb03236904e94187220 IN  0xc04ad234e01327b24a831e3718dbfcbe245904cc0 Ether0.000153542
0x6a958c90c7eaa7b6cc818e671f04bafdecb4a16470e9c2f1a4f5e8999131c992Withdraw From St...254009312021-06-11 5:04:28475 days 10 hrs ago0x38797fe73d5d442cded05bb03236904e94187220 IN  0xc04ad234e01327b24a831e3718dbfcbe245904cc0 Ether0.000153542
0x07a2b31f74fa44953383bf97c26c0b0e227238ea60e64ae83f7bb9d511e9999eWithdraw From St...254009152021-06-11 5:03:24475 days 10 hrs ago0x38797fe73d5d442cded05bb03236904e94187220 IN  0xc04ad234e01327b24a831e3718dbfcbe245904cc0 Ether0.000153542
0xc7dad3dbf0da85d5a10816d709379dfc91b283328fa5d5c42ce9eb7ffe6554e2Withdraw From St...254009032021-06-11 5:02:36475 days 10 hrs ago0x38797fe73d5d442cded05bb03236904e94187220 IN  0xc04ad234e01327b24a831e3718dbfcbe245904cc0 Ether0.000153542
0x89c17cc30694462f82a4014de8ac79d6d66fe9f7425ede1a1afd7fae5bc56e41Withdraw From St...254008612021-06-11 4:59:48475 days 10 hrs ago0x38797fe73d5d442cded05bb03236904e94187220 IN  0xc04ad234e01327b24a831e3718dbfcbe245904cc0 Ether0.000153542
0xdcee78c737b0837d2bd7e918b94341e49ed59fc6b9839b7e24ff47b858b45625Withdraw From St...254008422021-06-11 4:58:32475 days 10 hrs ago0x38797fe73d5d442cded05bb03236904e94187220 IN  0xc04ad234e01327b24a831e3718dbfcbe245904cc0 Ether0.000153542
0x54384eaf54d2ffe01701b4e6bae76e3ec67614e348cb36aebad8aab364601708Withdraw From St...254008242021-06-11 4:57:20475 days 10 hrs ago0x38797fe73d5d442cded05bb03236904e94187220 IN  0xc04ad234e01327b24a831e3718dbfcbe245904cc0 Ether0.000153542
0xab585af33b0180a59e143785ee2cc702e9edd025e7c12287a6bf7ab057cad524Withdraw From St...254008072021-06-11 4:56:12475 days 10 hrs ago0x38797fe73d5d442cded05bb03236904e94187220 IN  0xc04ad234e01327b24a831e3718dbfcbe245904cc0 Ether0.000153542
0xe950fe0ba94159495bb7cc4cb60a6580c00f9759327d890073a79c001a124ed9Withdraw From St...254007652021-06-11 4:53:24475 days 10 hrs ago0x38797fe73d5d442cded05bb03236904e94187220 IN  0xc04ad234e01327b24a831e3718dbfcbe245904cc0 Ether0.000153542
0x412467c9fb3ec0d672417fa8f28542001357a5075402d4cf4aa031b6fb376eefWithdraw From St...254007442021-06-11 4:52:00475 days 10 hrs ago0x38797fe73d5d442cded05bb03236904e94187220 IN  0xc04ad234e01327b24a831e3718dbfcbe245904cc0 Ether0.000153542
0xe993d2599235eacfaa7ed954e5c9dbba7a6f605c5bdce1e525240a655966f385Withdraw From St...254007322021-06-11 4:51:12475 days 10 hrs ago0x38797fe73d5d442cded05bb03236904e94187220 IN  0xc04ad234e01327b24a831e3718dbfcbe245904cc0 Ether0.000153542
0xc49f3d473aa5a5156c64f0c7b6e71f19c3d63732efc716fbf683cd6b98a01451Withdraw From St...254007162021-06-11 4:50:08475 days 10 hrs ago0x38797fe73d5d442cded05bb03236904e94187220 IN  0xc04ad234e01327b24a831e3718dbfcbe245904cc0 Ether0.000153542
0x19c23ec910a33724f22762d2c4511061455476b3e0462df4b0afd889e3a946b5Withdraw From St...254006812021-06-11 4:47:48475 days 10 hrs ago0x38797fe73d5d442cded05bb03236904e94187220 IN  0xc04ad234e01327b24a831e3718dbfcbe245904cc0 Ether0.000153542
0x64376ff86f9d32eaef9deaa72d43f858142cad6093f9e11a825c1e1edcf5c123Withdraw From St...254006612021-06-11 4:46:28475 days 10 hrs ago0x38797fe73d5d442cded05bb03236904e94187220 IN  0xc04ad234e01327b24a831e3718dbfcbe245904cc0 Ether0.000153542
0x2aa40a92c20f711d7d4218244bb7d023c0f9ef20d92a537bde80340365021584Withdraw From St...254006532021-06-11 4:45:56475 days 10 hrs ago0x38797fe73d5d442cded05bb03236904e94187220 IN  0xc04ad234e01327b24a831e3718dbfcbe245904cc0 Ether0.000153542
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0xae4261eff94febf185c34bc95fa166a317c90f1b2062c4b9305c7401ce839e46259432652021-07-06 8:07:52450 days 7 hrs ago 0xc04ad234e01327b24a831e3718dbfcbe245904cc 0x7d669a64deb8a4a51eea755bb0e19fd39ce25ae90 Ether
0xae4261eff94febf185c34bc95fa166a317c90f1b2062c4b9305c7401ce839e46259432652021-07-06 8:07:52450 days 7 hrs ago 0x7ee114c3628ca90119fc699f03665bf9db8f5faf 0xc04ad234e01327b24a831e3718dbfcbe245904cc0 Ether
0xae4261eff94febf185c34bc95fa166a317c90f1b2062c4b9305c7401ce839e46259432652021-07-06 8:07:52450 days 7 hrs ago 0x7ee114c3628ca90119fc699f03665bf9db8f5faf 0xc04ad234e01327b24a831e3718dbfcbe245904cc0 Ether
0x31c85570c93c7b50863c1a997ff4271f934a6cc9c5339254193272f5cfb675a1259103942021-07-04 19:36:12451 days 19 hrs ago 0xc04ad234e01327b24a831e3718dbfcbe245904cc 0x79dfab686ef87cd2c871d5182f085385892341890 Ether
0x31c85570c93c7b50863c1a997ff4271f934a6cc9c5339254193272f5cfb675a1259103942021-07-04 19:36:12451 days 19 hrs ago 0x7ee114c3628ca90119fc699f03665bf9db8f5faf 0xc04ad234e01327b24a831e3718dbfcbe245904cc0 Ether
0xeef8111c682964d67e8deef6c027e499ba41b51eb5e67735117f63b71973fa17258132822021-06-30 7:41:16456 days 7 hrs ago 0xc04ad234e01327b24a831e3718dbfcbe245904cc 0x79dfab686ef87cd2c871d5182f085385892341890 Ether
0xeef8111c682964d67e8deef6c027e499ba41b51eb5e67735117f63b71973fa17258132822021-06-30 7:41:16456 days 7 hrs ago 0x7ee114c3628ca90119fc699f03665bf9db8f5faf 0xc04ad234e01327b24a831e3718dbfcbe245904cc0 Ether
0x4f5b091f301282b0d0a363eb52ab9528cbb831a18202672ddbc6c47eb1e779a5257481702021-06-27 7:17:20459 days 8 hrs ago 0xc04ad234e01327b24a831e3718dbfcbe245904cc 0xcc930994cf5b438dd9dcdfe18d56c15629bed38c0 Ether
0x4e20d1a6c0053a1dc2e2d8a7a202c4aa41cb3753d034f4f4dc216f4f6ec0154d256679482021-06-23 14:08:36463 days 1 hr ago 0xc04ad234e01327b24a831e3718dbfcbe245904cc 0xcc930994cf5b438dd9dcdfe18d56c15629bed38c0 Ether
0x7bcefcabdc80e1d81e181a81058e39154fcff86124ca6c5fc5421067d722f27c256677722021-06-23 13:56:52463 days 1 hr ago 0xc04ad234e01327b24a831e3718dbfcbe245904cc 0xcc930994cf5b438dd9dcdfe18d56c15629bed38c0 Ether
0x175c8f3e89f747edb7005aa0bfbb29f0dc7f3df2d3102d79a450c6d2e810a465256677392021-06-23 13:54:40463 days 1 hr ago 0xc04ad234e01327b24a831e3718dbfcbe245904cc 0xcc930994cf5b438dd9dcdfe18d56c15629bed38c0 Ether
0xddf44cca3c3d4dfe2833442dbaf41213c84c4d0deb05cd7f543a0fbe45312142255862832021-06-19 19:23:16466 days 20 hrs ago 0xc04ad234e01327b24a831e3718dbfcbe245904cc 0x79dfab686ef87cd2c871d5182f085385892341890 Ether
0x73c64bde6cc5fc1acd5aeeeefff1e73f428f3755a0e29eabe7cb7b7e87464390255860902021-06-19 19:10:24466 days 20 hrs ago 0xc04ad234e01327b24a831e3718dbfcbe245904cc 0x79dfab686ef87cd2c871d5182f085385892341890 Ether
0x5baa1d14c3c9d87d0159cb2776c28a4f14eda10d1c9b0e888ac1160f171e4d08255857322021-06-19 18:46:32466 days 20 hrs ago 0xc04ad234e01327b24a831e3718dbfcbe245904cc 0x79dfab686ef87cd2c871d5182f085385892341890 Ether
0xf7b339ac64a63ea612a49865474cc74adf9640914bf3b36e71e4d3bd0fd54e1d254009522021-06-11 5:05:52475 days 10 hrs ago 0xc04ad234e01327b24a831e3718dbfcbe245904cc 0x79dfab686ef87cd2c871d5182f085385892341890 Ether
0x6a958c90c7eaa7b6cc818e671f04bafdecb4a16470e9c2f1a4f5e8999131c992254009312021-06-11 5:04:28475 days 10 hrs ago 0xc04ad234e01327b24a831e3718dbfcbe245904cc 0x79dfab686ef87cd2c871d5182f085385892341890 Ether
0x07a2b31f74fa44953383bf97c26c0b0e227238ea60e64ae83f7bb9d511e9999e254009152021-06-11 5:03:24475 days 10 hrs ago 0xc04ad234e01327b24a831e3718dbfcbe245904cc 0x79dfab686ef87cd2c871d5182f085385892341890 Ether
0xc7dad3dbf0da85d5a10816d709379dfc91b283328fa5d5c42ce9eb7ffe6554e2254009032021-06-11 5:02:36475 days 10 hrs ago 0xc04ad234e01327b24a831e3718dbfcbe245904cc 0x79dfab686ef87cd2c871d5182f085385892341890 Ether
0x89c17cc30694462f82a4014de8ac79d6d66fe9f7425ede1a1afd7fae5bc56e41254008612021-06-11 4:59:48475 days 10 hrs ago 0xc04ad234e01327b24a831e3718dbfcbe245904cc 0x79dfab686ef87cd2c871d5182f085385892341890 Ether
0xdcee78c737b0837d2bd7e918b94341e49ed59fc6b9839b7e24ff47b858b45625254008422021-06-11 4:58:32475 days 10 hrs ago 0xc04ad234e01327b24a831e3718dbfcbe245904cc 0x79dfab686ef87cd2c871d5182f085385892341890 Ether
0x54384eaf54d2ffe01701b4e6bae76e3ec67614e348cb36aebad8aab364601708254008242021-06-11 4:57:20475 days 10 hrs ago 0xc04ad234e01327b24a831e3718dbfcbe245904cc 0x79dfab686ef87cd2c871d5182f085385892341890 Ether
0xab585af33b0180a59e143785ee2cc702e9edd025e7c12287a6bf7ab057cad524254008072021-06-11 4:56:12475 days 10 hrs ago 0xc04ad234e01327b24a831e3718dbfcbe245904cc 0x79dfab686ef87cd2c871d5182f085385892341890 Ether
0xe950fe0ba94159495bb7cc4cb60a6580c00f9759327d890073a79c001a124ed9254007652021-06-11 4:53:24475 days 10 hrs ago 0xc04ad234e01327b24a831e3718dbfcbe245904cc 0x79dfab686ef87cd2c871d5182f085385892341890 Ether
0x412467c9fb3ec0d672417fa8f28542001357a5075402d4cf4aa031b6fb376eef254007442021-06-11 4:52:00475 days 10 hrs ago 0xc04ad234e01327b24a831e3718dbfcbe245904cc 0x79dfab686ef87cd2c871d5182f085385892341890 Ether
0xe993d2599235eacfaa7ed954e5c9dbba7a6f605c5bdce1e525240a655966f385254007322021-06-11 4:51:12475 days 10 hrs ago 0xc04ad234e01327b24a831e3718dbfcbe245904cc 0x79dfab686ef87cd2c871d5182f085385892341890 Ether
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Sablier

Compiler Version
v0.5.11+commit.c082d0b4

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, GNU LGPLv3 license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2019-11-12
*/

// File: @openzeppelin/upgrades/contracts/Initializable.sol

pragma solidity >=0.4.24 <0.6.0;


/**
 * @title Initializable
 *
 * @dev Helper contract to support initializer functions. To use it, replace
 * the constructor with a function that has the `initializer` modifier.
 * WARNING: Unlike constructors, initializer functions must be manually
 * invoked. This applies both to deploying an Initializable contract, as well
 * as extending an Initializable contract via inheritance.
 * WARNING: When used with inheritance, manual care must be taken to not invoke
 * a parent initializer twice, or ensure that all initializers are idempotent,
 * because this is not dealt with automatically as with constructors.
 */
contract Initializable {

  /**
   * @dev Indicates that the contract has been initialized.
   */
  bool private initialized;

  /**
   * @dev Indicates that the contract is in the process of being initialized.
   */
  bool private initializing;

  /**
   * @dev Modifier to use in the initializer function of a contract.
   */
  modifier initializer() {
    require(initializing || isConstructor() || !initialized, "Contract instance has already been initialized");

    bool isTopLevelCall = !initializing;
    if (isTopLevelCall) {
      initializing = true;
      initialized = true;
    }

    _;

    if (isTopLevelCall) {
      initializing = false;
    }
  }

  /// @dev Returns true if and only if the function is running in the constructor
  function isConstructor() private view returns (bool) {
    // extcodesize checks the size of the code stored in an address, and
    // address returns the current address. Since the code is still not
    // deployed when running a constructor, any checks on its code size will
    // yield zero, making it an effective way to detect if a contract is
    // under construction or not.
    uint256 cs;
    assembly { cs := extcodesize(address) }
    return cs == 0;
  }

  // Reserved storage space to allow for layout changes in the future.
  uint256[50] private ______gap;
}

// File: @openzeppelin/contracts-ethereum-package/contracts/GSN/IRelayRecipient.sol

pragma solidity ^0.5.0;

/*
 * @dev Interface for a contract that will be called via the GSN from RelayHub.
 */
contract IRelayRecipient {
    /**
     * @dev Returns the address of the RelayHub instance this recipient interacts with.
     */
    function getHubAddr() public view returns (address);

    function acceptRelayedCall(
        address relay,
        address from,
        bytes calldata encodedFunction,
        uint256 transactionFee,
        uint256 gasPrice,
        uint256 gasLimit,
        uint256 nonce,
        bytes calldata approvalData,
        uint256 maxPossibleCharge
    )
        external
        view
        returns (uint256, bytes memory);

    function preRelayedCall(bytes calldata context) external returns (bytes32);

    function postRelayedCall(bytes calldata context, bool success, uint actualCharge, bytes32 preRetVal) external;
}

// File: @openzeppelin/contracts-ethereum-package/contracts/GSN/bouncers/GSNBouncerBase.sol

pragma solidity ^0.5.0;


/*
 * @dev Base contract used to implement GSNBouncers.
 *
 * > This contract does not perform all required tasks to implement a GSN
 * recipient contract: end users should use `GSNRecipient` instead.
 */
contract GSNBouncerBase is IRelayRecipient {
    uint256 constant private RELAYED_CALL_ACCEPTED = 0;
    uint256 constant private RELAYED_CALL_REJECTED = 11;

    // How much gas is forwarded to postRelayedCall
    uint256 constant internal POST_RELAYED_CALL_MAX_GAS = 100000;

    // Base implementations for pre and post relayedCall: only RelayHub can invoke them, and data is forwarded to the
    // internal hook.

    /**
     * @dev See `IRelayRecipient.preRelayedCall`.
     *
     * This function should not be overriden directly, use `_preRelayedCall` instead.
     *
     * * Requirements:
     *
     * - the caller must be the `RelayHub` contract.
     */
    function preRelayedCall(bytes calldata context) external returns (bytes32) {
        require(msg.sender == getHubAddr(), "GSNBouncerBase: caller is not RelayHub");
        return _preRelayedCall(context);
    }

    /**
     * @dev See `IRelayRecipient.postRelayedCall`.
     *
     * This function should not be overriden directly, use `_postRelayedCall` instead.
     *
     * * Requirements:
     *
     * - the caller must be the `RelayHub` contract.
     */
    function postRelayedCall(bytes calldata context, bool success, uint256 actualCharge, bytes32 preRetVal) external {
        require(msg.sender == getHubAddr(), "GSNBouncerBase: caller is not RelayHub");
        _postRelayedCall(context, success, actualCharge, preRetVal);
    }

    /**
     * @dev Return this in acceptRelayedCall to proceed with the execution of a relayed call. Note that this contract
     * will be charged a fee by RelayHub
     */
    function _approveRelayedCall() internal pure returns (uint256, bytes memory) {
        return _approveRelayedCall("");
    }

    /**
     * @dev See `GSNBouncerBase._approveRelayedCall`.
     *
     * This overload forwards `context` to _preRelayedCall and _postRelayedCall.
     */
    function _approveRelayedCall(bytes memory context) internal pure returns (uint256, bytes memory) {
        return (RELAYED_CALL_ACCEPTED, context);
    }

    /**
     * @dev Return this in acceptRelayedCall to impede execution of a relayed call. No fees will be charged.
     */
    function _rejectRelayedCall(uint256 errorCode) internal pure returns (uint256, bytes memory) {
        return (RELAYED_CALL_REJECTED + errorCode, "");
    }

    // Empty hooks for pre and post relayed call: users only have to define these if they actually use them.

    function _preRelayedCall(bytes memory) internal returns (bytes32) {
        // solhint-disable-previous-line no-empty-blocks
    }

    function _postRelayedCall(bytes memory, bool, uint256, bytes32) internal {
        // solhint-disable-previous-line no-empty-blocks
    }

    /*
     * @dev Calculates how much RelaHub will charge a recipient for using `gas` at a `gasPrice`, given a relayer's
     * `serviceFee`.
     */
    function _computeCharge(uint256 gas, uint256 gasPrice, uint256 serviceFee) internal pure returns (uint256) {
        // The fee is expressed as a percentage. E.g. a value of 40 stands for a 40% fee, so the recipient will be
        // charged for 1.4 times the spent amount.
        return (gas * gasPrice * (100 + serviceFee)) / 100;
    }
}

// File: @openzeppelin/contracts-ethereum-package/contracts/cryptography/ECDSA.sol

pragma solidity ^0.5.2;

/**
 * @title Elliptic curve signature operations
 * @dev Based on https://gist.github.com/axic/5b33912c6f61ae6fd96d6c4a47afde6d
 * TODO Remove this library once solidity supports passing a signature to ecrecover.
 * See https://github.com/ethereum/solidity/issues/864
 */

library ECDSA {
    /**
     * @dev Recover signer address from a message by using their signature
     * @param hash bytes32 message, the hash is the signed message. What is recovered is the signer address.
     * @param signature bytes signature, the signature is generated using web3.eth.sign()
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        // Check the signature length
        if (signature.length != 65) {
            return (address(0));
        }

        // Divide the signature in r, s and v variables
        bytes32 r;
        bytes32 s;
        uint8 v;

        // ecrecover takes the signature parameters, and the only way to get them
        // currently is to use assembly.
        // solhint-disable-next-line no-inline-assembly
        assembly {
            r := mload(add(signature, 0x20))
            s := mload(add(signature, 0x40))
            v := byte(0, mload(add(signature, 0x60)))
        }

        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return address(0);
        }

        if (v != 27 && v != 28) {
            return address(0);
        }

        // If the signature is valid (and not malleable), return the signer address
        return ecrecover(hash, v, r, s);
    }

    /**
     * toEthSignedMessageHash
     * @dev prefix a bytes32 value with "\x19Ethereum Signed Message:"
     * and hash the result
     */
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
    }
}

// File: @openzeppelin/contracts-ethereum-package/contracts/GSN/bouncers/GSNBouncerSignature.sol

pragma solidity ^0.5.0;




contract GSNBouncerSignature is Initializable, GSNBouncerBase {
    using ECDSA for bytes32;

    // We use a random storage slot to allow proxy contracts to enable GSN support in an upgrade without changing their
    // storage layout. This value is calculated as: keccak256('gsn.bouncer.signature.trustedSigner'), minus 1.
    bytes32 constant private TRUSTED_SIGNER_STORAGE_SLOT = 0xe7b237a4017a399d277819456dce32c2356236bbc518a6d84a9a8d1cfdf1e9c5;

    enum GSNBouncerSignatureErrorCodes {
        INVALID_SIGNER
    }

    function initialize(address trustedSigner) public initializer {
        _setTrustedSigner(trustedSigner);
    }

    function acceptRelayedCall(
        address relay,
        address from,
        bytes calldata encodedFunction,
        uint256 transactionFee,
        uint256 gasPrice,
        uint256 gasLimit,
        uint256 nonce,
        bytes calldata approvalData,
        uint256
    )
        external
        view
        returns (uint256, bytes memory)
    {
        bytes memory blob = abi.encodePacked(
            relay,
            from,
            encodedFunction,
            transactionFee,
            gasPrice,
            gasLimit,
            nonce, // Prevents replays on RelayHub
            getHubAddr(), // Prevents replays in multiple RelayHubs
            address(this) // Prevents replays in multiple recipients
        );
        if (keccak256(blob).toEthSignedMessageHash().recover(approvalData) == _getTrustedSigner()) {
            return _approveRelayedCall();
        } else {
            return _rejectRelayedCall(uint256(GSNBouncerSignatureErrorCodes.INVALID_SIGNER));
        }
    }

    function _getTrustedSigner() private view returns (address trustedSigner) {
      bytes32 slot = TRUSTED_SIGNER_STORAGE_SLOT;
      // solhint-disable-next-line no-inline-assembly
      assembly {
        trustedSigner := sload(slot)
      }
    }

    function _setTrustedSigner(address trustedSigner) private {
      bytes32 slot = TRUSTED_SIGNER_STORAGE_SLOT;
      // solhint-disable-next-line no-inline-assembly
      assembly {
        sstore(slot, trustedSigner)
      }
    }
}

// File: @openzeppelin/contracts-ethereum-package/contracts/GSN/Context.sol

pragma solidity ^0.5.0;

/*
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they not should not be accessed in such a direct
 * manner, since when dealing with GSN meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
contract Context {
    // Empty internal constructor, to prevent people from mistakenly deploying
    // an instance of this contract, with should be used via inheritance.
    constructor () internal { }
    // solhint-disable-previous-line no-empty-blocks

    function _msgSender() internal view returns (address) {
        return msg.sender;
    }

    function _msgData() internal view returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

// File: @openzeppelin/contracts-ethereum-package/contracts/GSN/GSNContext.sol

pragma solidity ^0.5.0;



/*
 * @dev Enables GSN support on `Context` contracts by recognizing calls from
 * RelayHub and extracting the actual sender and call data from the received
 * calldata.
 *
 * > This contract does not perform all required tasks to implement a GSN
 * recipient contract: end users should use `GSNRecipient` instead.
 */
contract GSNContext is Initializable, Context {
    // We use a random storage slot to allow proxy contracts to enable GSN support in an upgrade without changing their
    // storage layout. This value is calculated as: keccak256('gsn.relayhub.address'), minus 1.
    bytes32 private constant RELAY_HUB_ADDRESS_STORAGE_SLOT = 0x06b7792c761dcc05af1761f0315ce8b01ac39c16cc934eb0b2f7a8e71414f262;

    event RelayHubChanged(address indexed oldRelayHub, address indexed newRelayHub);

    function initialize() public initializer {
        _upgradeRelayHub(0xD216153c06E857cD7f72665E0aF1d7D82172F494);
    }

    function _getRelayHub() internal view returns (address relayHub) {
        bytes32 slot = RELAY_HUB_ADDRESS_STORAGE_SLOT;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            relayHub := sload(slot)
        }
    }

    function _upgradeRelayHub(address newRelayHub) internal {
        address currentRelayHub = _getRelayHub();
        require(newRelayHub != address(0), "GSNContext: new RelayHub is the zero address");
        require(newRelayHub != currentRelayHub, "GSNContext: new RelayHub is the current one");

        emit RelayHubChanged(currentRelayHub, newRelayHub);

        bytes32 slot = RELAY_HUB_ADDRESS_STORAGE_SLOT;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            sstore(slot, newRelayHub)
        }
    }

    // Overrides for Context's functions: when called from RelayHub, sender and
    // data require some pre-processing: the actual sender is stored at the end
    // of the call data, which in turns means it needs to be removed from it
    // when handling said data.

    function _msgSender() internal view returns (address) {
        if (msg.sender != _getRelayHub()) {
            return msg.sender;
        } else {
            return _getRelayedCallSender();
        }
    }

    function _msgData() internal view returns (bytes memory) {
        if (msg.sender != _getRelayHub()) {
            return msg.data;
        } else {
            return _getRelayedCallData();
        }
    }

    function _getRelayedCallSender() private pure returns (address result) {
        // We need to read 20 bytes (an address) located at array index msg.data.length - 20. In memory, the array
        // is prefixed with a 32-byte length value, so we first add 32 to get the memory read index. However, doing
        // so would leave the address in the upper 20 bytes of the 32-byte word, which is inconvenient and would
        // require bit shifting. We therefore subtract 12 from the read index so the address lands on the lower 20
        // bytes. This can always be done due to the 32-byte prefix.

        // The final memory read index is msg.data.length - 20 + 32 - 12 = msg.data.length. Using inline assembly is the
        // easiest/most-efficient way to perform this operation.

        // These fields are not accessible from assembly
        bytes memory array = msg.data;
        uint256 index = msg.data.length;

        // solhint-disable-next-line no-inline-assembly
        assembly {
            // Load the 32 bytes word from memory with the address on the lower 20 bytes, and mask those.
            result := and(mload(add(array, index)), 0xffffffffffffffffffffffffffffffffffffffff)
        }
        return result;
    }

    function _getRelayedCallData() private pure returns (bytes memory) {
        // RelayHub appends the sender address at the end of the calldata, so in order to retrieve the actual msg.data,
        // we must strip the last 20 bytes (length of an address type) from it.

        uint256 actualDataLength = msg.data.length - 20;
        bytes memory actualData = new bytes(actualDataLength);

        for (uint256 i = 0; i < actualDataLength; ++i) {
            actualData[i] = msg.data[i];
        }

        return actualData;
    }
}

// File: @openzeppelin/contracts-ethereum-package/contracts/GSN/IRelayHub.sol

pragma solidity ^0.5.0;

contract IRelayHub {
    // Relay management

    // Add stake to a relay and sets its unstakeDelay.
    // If the relay does not exist, it is created, and the caller
    // of this function becomes its owner. If the relay already exists, only the owner can call this function. A relay
    // cannot be its own owner.
    // All Ether in this function call will be added to the relay's stake.
    // Its unstake delay will be assigned to unstakeDelay, but the new value must be greater or equal to the current one.
    // Emits a Staked event.
    function stake(address relayaddr, uint256 unstakeDelay) external payable;

    // Emited when a relay's stake or unstakeDelay are increased
    event Staked(address indexed relay, uint256 stake, uint256 unstakeDelay);

    // Registers the caller as a relay.
    // The relay must be staked for, and not be a contract (i.e. this function must be called directly from an EOA).
    // Emits a RelayAdded event.
    // This function can be called multiple times, emitting new RelayAdded events. Note that the received transactionFee
    // is not enforced by relayCall.
    function registerRelay(uint256 transactionFee, string memory url) public;

    // Emitted when a relay is registered or re-registerd. Looking at these events (and filtering out RelayRemoved
    // events) lets a client discover the list of available relays.
    event RelayAdded(address indexed relay, address indexed owner, uint256 transactionFee, uint256 stake, uint256 unstakeDelay, string url);

    // Removes (deregisters) a relay. Unregistered (but staked for) relays can also be removed. Can only be called by
    // the owner of the relay. After the relay's unstakeDelay has elapsed, unstake will be callable.
    // Emits a RelayRemoved event.
    function removeRelayByOwner(address relay) public;

    // Emitted when a relay is removed (deregistered). unstakeTime is the time when unstake will be callable.
    event RelayRemoved(address indexed relay, uint256 unstakeTime);

    // Deletes the relay from the system, and gives back its stake to the owner. Can only be called by the relay owner,
    // after unstakeDelay has elapsed since removeRelayByOwner was called.
    // Emits an Unstaked event.
    function unstake(address relay) public;

    // Emitted when a relay is unstaked for, including the returned stake.
    event Unstaked(address indexed relay, uint256 stake);

    // States a relay can be in
    enum RelayState {
        Unknown, // The relay is unknown to the system: it has never been staked for
        Staked, // The relay has been staked for, but it is not yet active
        Registered, // The relay has registered itself, and is active (can relay calls)
        Removed    // The relay has been removed by its owner and can no longer relay calls. It must wait for its unstakeDelay to elapse before it can unstake
    }

    // Returns a relay's status. Note that relays can be deleted when unstaked or penalized.
    function getRelay(address relay) external view returns (uint256 totalStake, uint256 unstakeDelay, uint256 unstakeTime, address payable owner, RelayState state);

    // Balance management

    // Deposits ether for a contract, so that it can receive (and pay for) relayed transactions. Unused balance can only
    // be withdrawn by the contract itself, by callingn withdraw.
    // Emits a Deposited event.
    function depositFor(address target) public payable;

    // Emitted when depositFor is called, including the amount and account that was funded.
    event Deposited(address indexed recipient, address indexed from, uint256 amount);

    // Returns an account's deposits. These can be either a contnract's funds, or a relay owner's revenue.
    function balanceOf(address target) external view returns (uint256);

    // Withdraws from an account's balance, sending it back to it. Relay owners call this to retrieve their revenue, and
    // contracts can also use it to reduce their funding.
    // Emits a Withdrawn event.
    function withdraw(uint256 amount, address payable dest) public;

    // Emitted when an account withdraws funds from RelayHub.
    event Withdrawn(address indexed account, address indexed dest, uint256 amount);

    // Relaying

    // Check if the RelayHub will accept a relayed operation. Multiple things must be true for this to happen:
    //  - all arguments must be signed for by the sender (from)
    //  - the sender's nonce must be the current one
    //  - the recipient must accept this transaction (via acceptRelayedCall)
    // Returns a PreconditionCheck value (OK when the transaction can be relayed), or a recipient-specific error code if
    // it returns one in acceptRelayedCall.
    function canRelay(
        address relay,
        address from,
        address to,
        bytes memory encodedFunction,
        uint256 transactionFee,
        uint256 gasPrice,
        uint256 gasLimit,
        uint256 nonce,
        bytes memory signature,
        bytes memory approvalData
    ) public view returns (uint256 status, bytes memory recipientContext);

    // Preconditions for relaying, checked by canRelay and returned as the corresponding numeric values.
    enum PreconditionCheck {
        OK,                         // All checks passed, the call can be relayed
        WrongSignature,             // The transaction to relay is not signed by requested sender
        WrongNonce,                 // The provided nonce has already been used by the sender
        AcceptRelayedCallReverted,  // The recipient rejected this call via acceptRelayedCall
        InvalidRecipientStatusCode  // The recipient returned an invalid (reserved) status code
    }

    // Relays a transaction. For this to suceed, multiple conditions must be met:
    //  - canRelay must return PreconditionCheck.OK
    //  - the sender must be a registered relay
    //  - the transaction's gas price must be larger or equal to the one that was requested by the sender
    //  - the transaction must have enough gas to not run out of gas if all internal transactions (calls to the
    // recipient) use all gas available to them
    //  - the recipient must have enough balance to pay the relay for the worst-case scenario (i.e. when all gas is
    // spent)
    //
    // If all conditions are met, the call will be relayed and the recipient charged. preRelayedCall, the encoded
    // function and postRelayedCall will be called in order.
    //
    // Arguments:
    //  - from: the client originating the request
    //  - recipient: the target IRelayRecipient contract
    //  - encodedFunction: the function call to relay, including data
    //  - transactionFee: fee (%) the relay takes over actual gas cost
    //  - gasPrice: gas price the client is willing to pay
    //  - gasLimit: gas to forward when calling the encoded function
    //  - nonce: client's nonce
    //  - signature: client's signature over all previous params, plus the relay and RelayHub addresses
    //  - approvalData: dapp-specific data forwared to acceptRelayedCall. This value is *not* verified by the Hub, but
    //    it still can be used for e.g. a signature.
    //
    // Emits a TransactionRelayed event.
    function relayCall(
        address from,
        address to,
        bytes memory encodedFunction,
        uint256 transactionFee,
        uint256 gasPrice,
        uint256 gasLimit,
        uint256 nonce,
        bytes memory signature,
        bytes memory approvalData
    ) public;

    // Emitted when an attempt to relay a call failed. This can happen due to incorrect relayCall arguments, or the
    // recipient not accepting the relayed call. The actual relayed call was not executed, and the recipient not charged.
    // The reason field contains an error code: values 1-10 correspond to PreconditionCheck entries, and values over 10
    // are custom recipient error codes returned from acceptRelayedCall.
    event CanRelayFailed(address indexed relay, address indexed from, address indexed to, bytes4 selector, uint256 reason);

    // Emitted when a transaction is relayed. Note that the actual encoded function might be reverted: this will be
    // indicated in the status field.
    // Useful when monitoring a relay's operation and relayed calls to a contract.
    // Charge is the ether value deducted from the recipient's balance, paid to the relay's owner.
    event TransactionRelayed(address indexed relay, address indexed from, address indexed to, bytes4 selector, RelayCallStatus status, uint256 charge);

    // Reason error codes for the TransactionRelayed event
    enum RelayCallStatus {
        OK,                      // The transaction was successfully relayed and execution successful - never included in the event
        RelayedCallFailed,       // The transaction was relayed, but the relayed call failed
        PreRelayedFailed,        // The transaction was not relayed due to preRelatedCall reverting
        PostRelayedFailed,       // The transaction was relayed and reverted due to postRelatedCall reverting
        RecipientBalanceChanged  // The transaction was relayed and reverted due to the recipient's balance changing
    }

    // Returns how much gas should be forwarded to a call to relayCall, in order to relay a transaction that will spend
    // up to relayedCallStipend gas.
    function requiredGas(uint256 relayedCallStipend) public view returns (uint256);

    // Returns the maximum recipient charge, given the amount of gas forwarded, gas price and relay fee.
    function maxPossibleCharge(uint256 relayedCallStipend, uint256 gasPrice, uint256 transactionFee) public view returns (uint256);

    // Relay penalization. Any account can penalize relays, removing them from the system immediately, and rewarding the
    // reporter with half of the relay's stake. The other half is burned so that, even if the relay penalizes itself, it
    // still loses half of its stake.

    // Penalize a relay that signed two transactions using the same nonce (making only the first one valid) and
    // different data (gas price, gas limit, etc. may be different). The (unsigned) transaction data and signature for
    // both transactions must be provided.
    function penalizeRepeatedNonce(bytes memory unsignedTx1, bytes memory signature1, bytes memory unsignedTx2, bytes memory signature2) public;

    // Penalize a relay that sent a transaction that didn't target RelayHub's registerRelay or relayCall.
    function penalizeIllegalTransaction(bytes memory unsignedTx, bytes memory signature) public;

    event Penalized(address indexed relay, address sender, uint256 amount);

    function getNonce(address from) external view returns (uint256);
}

// File: @openzeppelin/contracts-ethereum-package/contracts/GSN/GSNRecipient.sol

pragma solidity ^0.5.0;






/*
 * @dev Base GSN recipient contract, adding the recipient interface and enabling
 * GSN support. Not all interface methods are implemented, derived contracts
 * must do so themselves.
 */
contract GSNRecipient is Initializable, IRelayRecipient, GSNContext, GSNBouncerBase {
    function initialize() public initializer {
        GSNContext.initialize();
    }

    function getHubAddr() public view returns (address) {
        return _getRelayHub();
    }

    // This function is view for future-proofing, it may require reading from
    // storage in the future.
    function relayHubVersion() public view returns (string memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return "1.0.0";
    }

    function _withdrawDeposits(uint256 amount, address payable payee) internal {
        IRelayHub(_getRelayHub()).withdraw(amount, payee);
    }
}

// File: @openzeppelin/contracts-ethereum-package/contracts/token/ERC20/IERC20.sol

pragma solidity ^0.5.2;

/**
 * @title ERC20 interface
 * @dev see https://eips.ethereum.org/EIPS/eip-20
 */
interface IERC20 {
    function transfer(address to, uint256 value) external returns (bool);

    function approve(address spender, uint256 value) external returns (bool);

    function transferFrom(address from, address to, uint256 value) external returns (bool);

    function totalSupply() external view returns (uint256);

    function balanceOf(address who) external view returns (uint256);

    function allowance(address owner, address spender) external view returns (uint256);

    event Transfer(address indexed from, address indexed to, uint256 value);

    event Approval(address indexed owner, address indexed spender, uint256 value);
}

// File: @openzeppelin/contracts-ethereum-package/contracts/utils/ReentrancyGuard.sol

pragma solidity ^0.5.2;


/**
 * @title Helps contracts guard against reentrancy attacks.
 * @author Remco Bloemen <[email protected]π.com>, Eenae <[email protected]>
 * @dev If you mark a function `nonReentrant`, you should also
 * mark it `external`.
 */
contract ReentrancyGuard is Initializable {
    /// @dev counter to allow mutex lock with only one SSTORE operation
    uint256 private _guardCounter;

    function initialize() public initializer {
        // The counter starts at one to prevent changing it from zero to a non-zero
        // value, which is a more expensive operation.
        _guardCounter = 1;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _guardCounter += 1;
        uint256 localCounter = _guardCounter;
        _;
        require(localCounter == _guardCounter);
    }

    uint256[50] private ______gap;
}

// File: @sablier/shared-contracts/compound/CarefulMath.sol

pragma solidity ^0.5.8;

/**
  * @title Careful Math
  * @author Compound
  * @notice Derived from OpenZeppelin's SafeMath library
  *         https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol
  */
contract CarefulMath {

    /**
     * @dev Possible error codes that we can return
     */
    enum MathError {
        NO_ERROR,
        DIVISION_BY_ZERO,
        INTEGER_OVERFLOW,
        INTEGER_UNDERFLOW
    }

    /**
    * @dev Multiplies two numbers, returns an error on overflow.
    */
    function mulUInt(uint a, uint b) internal pure returns (MathError, uint) {
        if (a == 0) {
            return (MathError.NO_ERROR, 0);
        }

        uint c = a * b;

        if (c / a != b) {
            return (MathError.INTEGER_OVERFLOW, 0);
        } else {
            return (MathError.NO_ERROR, c);
        }
    }

    /**
    * @dev Integer division of two numbers, truncating the quotient.
    */
    function divUInt(uint a, uint b) internal pure returns (MathError, uint) {
        if (b == 0) {
            return (MathError.DIVISION_BY_ZERO, 0);
        }

        return (MathError.NO_ERROR, a / b);
    }

    /**
    * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend).
    */
    function subUInt(uint a, uint b) internal pure returns (MathError, uint) {
        if (b <= a) {
            return (MathError.NO_ERROR, a - b);
        } else {
            return (MathError.INTEGER_UNDERFLOW, 0);
        }
    }

    /**
    * @dev Adds two numbers, returns an error on overflow.
    */
    function addUInt(uint a, uint b) internal pure returns (MathError, uint) {
        uint c = a + b;

        if (c >= a) {
            return (MathError.NO_ERROR, c);
        } else {
            return (MathError.INTEGER_OVERFLOW, 0);
        }
    }

    /**
    * @dev add a and b and then subtract c
    */
    function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) {
        (MathError err0, uint sum) = addUInt(a, b);

        if (err0 != MathError.NO_ERROR) {
            return (err0, 0);
        }

        return subUInt(sum, c);
    }
}

// File: @sablier/shared-contracts/compound/Exponential.sol

pragma solidity ^0.5.8;


/**
 * @title Exponential module for storing fixed-decision decimals
 * @author Compound
 * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places.
 *         Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is:
 *         `Exp({mantissa: 5100000000000000000})`.
 */
contract Exponential is CarefulMath {
    uint constant expScale = 1e18;
    uint constant halfExpScale = expScale/2;
    uint constant mantissaOne = expScale;

    struct Exp {
        uint mantissa;
    }

    /**
     * @dev Creates an exponential from numerator and denominator values.
     *      Note: Returns an error if (`num` * 10e18) > MAX_INT,
     *            or if `denom` is zero.
     */
    function getExp(uint num, uint denom) pure internal returns (MathError, Exp memory) {
        (MathError err0, uint scaledNumerator) = mulUInt(num, expScale);
        if (err0 != MathError.NO_ERROR) {
            return (err0, Exp({mantissa: 0}));
        }

        (MathError err1, uint rational) = divUInt(scaledNumerator, denom);
        if (err1 != MathError.NO_ERROR) {
            return (err1, Exp({mantissa: 0}));
        }

        return (MathError.NO_ERROR, Exp({mantissa: rational}));
    }

    /**
     * @dev Adds two exponentials, returning a new exponential.
     */
    function addExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {
        (MathError error, uint result) = addUInt(a.mantissa, b.mantissa);

        return (error, Exp({mantissa: result}));
    }

    /**
     * @dev Subtracts two exponentials, returning a new exponential.
     */
    function subExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {
        (MathError error, uint result) = subUInt(a.mantissa, b.mantissa);

        return (error, Exp({mantissa: result}));
    }

    /**
     * @dev Multiply an Exp by a scalar, returning a new Exp.
     */
    function mulScalar(Exp memory a, uint scalar) pure internal returns (MathError, Exp memory) {
        (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar);
        if (err0 != MathError.NO_ERROR) {
            return (err0, Exp({mantissa: 0}));
        }

        return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa}));
    }

    /**
     * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer.
     */
    function mulScalarTruncate(Exp memory a, uint scalar) pure internal returns (MathError, uint) {
        (MathError err, Exp memory product) = mulScalar(a, scalar);
        if (err != MathError.NO_ERROR) {
            return (err, 0);
        }

        return (MathError.NO_ERROR, truncate(product));
    }

    /**
     * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer.
     */
    function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (MathError, uint) {
        (MathError err, Exp memory product) = mulScalar(a, scalar);
        if (err != MathError.NO_ERROR) {
            return (err, 0);
        }

        return addUInt(truncate(product), addend);
    }

    /**
     * @dev Divide an Exp by a scalar, returning a new Exp.
     */
    function divScalar(Exp memory a, uint scalar) pure internal returns (MathError, Exp memory) {
        (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar);
        if (err0 != MathError.NO_ERROR) {
            return (err0, Exp({mantissa: 0}));
        }

        return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa}));
    }

    /**
     * @dev Divide a scalar by an Exp, returning a new Exp.
     */
    function divScalarByExp(uint scalar, Exp memory divisor) pure internal returns (MathError, Exp memory) {
        /*
          We are doing this as:
          getExp(mulUInt(expScale, scalar), divisor.mantissa)

          How it works:
          Exp = a / b;
          Scalar = s;
          `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale`
        */
        (MathError err0, uint numerator) = mulUInt(expScale, scalar);
        if (err0 != MathError.NO_ERROR) {
            return (err0, Exp({mantissa: 0}));
        }
        return getExp(numerator, divisor.mantissa);
    }

    /**
     * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer.
     */
    function divScalarByExpTruncate(uint scalar, Exp memory divisor) pure internal returns (MathError, uint) {
        (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor);
        if (err != MathError.NO_ERROR) {
            return (err, 0);
        }

        return (MathError.NO_ERROR, truncate(fraction));
    }

    /**
     * @dev Multiplies two exponentials, returning a new exponential.
     */
    function mulExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {

        (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa);
        if (err0 != MathError.NO_ERROR) {
            return (err0, Exp({mantissa: 0}));
        }

        // We add half the scale before dividing so that we get rounding instead of truncation.
        //  See "Listing 6" and text above it at https://accu.org/index.php/journals/1717
        // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18.
        (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct);
        if (err1 != MathError.NO_ERROR) {
            return (err1, Exp({mantissa: 0}));
        }

        (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale);
        // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero.
        assert(err2 == MathError.NO_ERROR);

        return (MathError.NO_ERROR, Exp({mantissa: product}));
    }

    /**
     * @dev Multiplies two exponentials given their mantissas, returning a new exponential.
     */
    function mulExp(uint a, uint b) pure internal returns (MathError, Exp memory) {
        return mulExp(Exp({mantissa: a}), Exp({mantissa: b}));
    }

    /**
     * @dev Multiplies three exponentials, returning a new exponential.
     */
    function mulExp3(Exp memory a, Exp memory b, Exp memory c) pure internal returns (MathError, Exp memory) {
        (MathError err, Exp memory ab) = mulExp(a, b);
        if (err != MathError.NO_ERROR) {
            return (err, ab);
        }
        return mulExp(ab, c);
    }

    /**
     * @dev Divides two exponentials, returning a new exponential.
     *     (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b,
     *  which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa)
     */
    function divExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) {
        return getExp(a.mantissa, b.mantissa);
    }

    /**
     * @dev Truncates the given exp to a whole number value.
     *      For example, truncate(Exp{mantissa: 15 * expScale}) = 15
     */
    function truncate(Exp memory exp) pure internal returns (uint) {
        // Note: We are not using careful math here as we're performing a division that cannot fail
        return exp.mantissa / expScale;
    }

    /**
     * @dev Checks if first Exp is less than second Exp.
     */
    function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {
        return left.mantissa < right.mantissa; //TODO: Add some simple tests and this in another PR yo.
    }

    /**
     * @dev Checks if left Exp <= right Exp.
     */
    function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) {
        return left.mantissa <= right.mantissa;
    }

    /**
     * @dev Checks if left Exp > right Exp.
     */
    function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {
        return left.mantissa > right.mantissa;
    }

    /**
     * @dev returns true if Exp is exactly zero
     */
    function isZeroExp(Exp memory value) pure internal returns (bool) {
        return value.mantissa == 0;
    }
}

// File: @sablier/shared-contracts/interfaces/ICERC20.sol

pragma solidity 0.5.11;

/**
 * @title CERC20 interface
 * @author Sablier
 * @dev See https://compound.finance/developers
 */
interface ICERC20 {
    function balanceOf(address who) external view returns (uint256);

    function isCToken() external view returns (bool);

    function approve(address spender, uint256 value) external returns (bool);

    function balanceOfUnderlying(address account) external returns (uint256);

    function exchangeRateCurrent() external returns (uint256);

    function mint(uint256 mintAmount) external returns (uint256);

    function redeem(uint256 redeemTokens) external returns (uint256);

    function redeemUnderlying(uint256 redeemAmount) external returns (uint256);

    function transfer(address recipient, uint256 amount) external returns (bool);

    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
}

// File: @sablier/shared-contracts/lifecycle/OwnableWithoutRenounce.sol

pragma solidity 0.5.11;



/**
 * @title OwnableWithoutRenounce
 * @author Sablier
 * @dev Fork of OpenZeppelin's Ownable contract, which provides basic authorization control, but with
 *  the `renounceOwnership` function removed to avoid fat-finger errors.
 *  We inherit from `Context` to keep this contract compatible with the Gas Station Network.
 * See https://github.com/OpenZeppelin/openzeppelin-contracts-ethereum-package/blob/master/contracts/ownership/Ownable.sol
 * See https://forum.openzeppelin.com/t/contract-request-ownable-without-renounceownership/1400
 * See https://docs.openzeppelin.com/contracts/2.x/gsn#_msg_sender_and_msg_data
 */
contract OwnableWithoutRenounce is Initializable, Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev The Ownable constructor sets the original `owner` of the contract to the sender
     * account.
     */
    function initialize(address sender) public initializer {
        _owner = sender;
        emit OwnershipTransferred(address(0), _owner);
    }

    /**
     * @return the address of the owner.
     */
    function owner() public view returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(isOwner());
        _;
    }

    /**
     * @return true if `msg.sender` is the owner of the contract.
     */
    function isOwner() public view returns (bool) {
        return _msgSender() == _owner;
    }

    /**
     * @dev Allows the current owner to transfer control of the contract to a newOwner.
     * @param newOwner The address to transfer ownership to.
     */
    function transferOwnership(address newOwner) public onlyOwner {
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers control of the contract to a newOwner.
     * @param newOwner The address to transfer ownership to.
     */
    function _transferOwnership(address newOwner) internal {
        require(newOwner != address(0));
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }

    uint256[50] private ______gap;
}

// File: @openzeppelin/contracts-ethereum-package/contracts/access/Roles.sol

pragma solidity ^0.5.2;

/**
 * @title Roles
 * @dev Library for managing addresses assigned to a Role.
 */
library Roles {
    struct Role {
        mapping (address => bool) bearer;
    }

    /**
     * @dev give an account access to this role
     */
    function add(Role storage role, address account) internal {
        require(account != address(0));
        require(!has(role, account));

        role.bearer[account] = true;
    }

    /**
     * @dev remove an account's access to this role
     */
    function remove(Role storage role, address account) internal {
        require(account != address(0));
        require(has(role, account));

        role.bearer[account] = false;
    }

    /**
     * @dev check if an account has this role
     * @return bool
     */
    function has(Role storage role, address account) internal view returns (bool) {
        require(account != address(0));
        return role.bearer[account];
    }
}

// File: @sablier/shared-contracts/lifecycle/PauserRoleWithoutRenounce.sol

pragma solidity ^0.5.0;




/**
 * @title PauserRoleWithoutRenounce
 * @author Sablier
 * @notice Fork of OpenZeppelin's PauserRole, but with the `renouncePauser` function removed to avoid fat-finger errors.
 *  We inherit from `Context` to keep this contract compatible with the Gas Station Network.
 * See https://github.com/OpenZeppelin/openzeppelin-contracts-ethereum-package/blob/master/contracts/access/roles/PauserRole.sol
 */

contract PauserRoleWithoutRenounce is Initializable, Context {
    using Roles for Roles.Role;

    event PauserAdded(address indexed account);
    event PauserRemoved(address indexed account);

    Roles.Role private _pausers;

    function initialize(address sender) public initializer {
        if (!isPauser(sender)) {
            _addPauser(sender);
        }
    }

    modifier onlyPauser() {
        require(isPauser(_msgSender()), "PauserRole: caller does not have the Pauser role");
        _;
    }

    function isPauser(address account) public view returns (bool) {
        return _pausers.has(account);
    }

    function addPauser(address account) public onlyPauser {
        _addPauser(account);
    }

    function _addPauser(address account) internal {
        _pausers.add(account);
        emit PauserAdded(account);
    }

    function _removePauser(address account) internal {
        _pausers.remove(account);
        emit PauserRemoved(account);
    }

    uint256[50] private ______gap;
}

// File: @sablier/shared-contracts/lifecycle/PausableWithoutRenounce.sol

pragma solidity 0.5.11;




/**
 * @title PausableWithoutRenounce
 * @author Sablier
 * @notice Fork of OpenZeppelin's Pausable, a contract module which allows children to implement an
 *  emergency stop mechanism that can be triggered by an authorized account, but with the `renouncePauser`
 *  function removed to avoid fat-finger errors.
 *  We inherit from `Context` to keep this contract compatible with the Gas Station Network.
 * See https://github.com/OpenZeppelin/openzeppelin-contracts-ethereum-package/blob/master/contracts/lifecycle/Pausable.sol
 * See https://docs.openzeppelin.com/contracts/2.x/gsn#_msg_sender_and_msg_data
 */
contract PausableWithoutRenounce is Initializable, Context, PauserRoleWithoutRenounce {
    /**
     * @dev Emitted when the pause is triggered by a pauser (`account`).
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by a pauser (`account`).
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state. Assigns the Pauser role
     * to the deployer.
     */
    function initialize(address sender) public initializer {
        PauserRoleWithoutRenounce.initialize(sender);
        _paused = false;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view returns (bool) {
        return _paused;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     */
    modifier whenNotPaused() {
        require(!_paused, "Pausable: paused");
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     */
    modifier whenPaused() {
        require(_paused, "Pausable: not paused");
        _;
    }

    /**
     * @dev Called by a pauser to pause, triggers stopped state.
     */
    function pause() public onlyPauser whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Called by a pauser to unpause, returns to normal state.
     */
    function unpause() public onlyPauser whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}

// File: @sablier/protocol/contracts/interfaces/ICTokenManager.sol

pragma solidity 0.5.11;

/**
 * @title CTokenManager Interface
 * @author Sablier
 */
interface ICTokenManager {
    /**
     * @notice Emits when the owner discards a cToken.
     */
    event DiscardCToken(address indexed tokenAddress);

    /**
     * @notice Emits when the owner whitelists a cToken.
     */
    event WhitelistCToken(address indexed tokenAddress);

    function whitelistCToken(address tokenAddress) external;

    function discardCToken(address tokenAddress) external;

    function isCToken(address tokenAddress) external view returns (bool);
}

// File: @sablier/protocol/contracts/interfaces/IERC1620.sol

pragma solidity 0.5.11;

/**
 * @title ERC-1620 Money Streaming Standard
 * @author Paul Razvan Berg - <[email protected]>
 * @dev See https://eips.ethereum.org/EIPS/eip-1620
 */
interface IERC1620 {
    /**
     * @notice Emits when a stream is successfully created.
     */
    event CreateStream(
        uint256 indexed streamId,
        address indexed sender,
        address indexed recipient,
        uint256 deposit,
        address tokenAddress,
        uint256 startTime,
        uint256 stopTime
    );

    /**
     * @notice Emits when the recipient of a stream withdraws a portion or all their pro rata share of the stream.
     */
    event WithdrawFromStream(uint256 indexed streamId, address indexed recipient, uint256 amount);

    /**
     * @notice Emits when a stream is successfully cancelled and tokens are transferred back on a pro rata basis.
     */
    event CancelStream(
        uint256 indexed streamId,
        address indexed sender,
        address indexed recipient,
        uint256 senderBalance,
        uint256 recipientBalance
    );

    function balanceOf(uint256 streamId, address who) external view returns (uint256 balance);

    function getStream(uint256 streamId)
        external
        view
        returns (
            address sender,
            address recipient,
            uint256 deposit,
            address token,
            uint256 startTime,
            uint256 stopTime,
            uint256 balance,
            uint256 rate
        );

    function createStream(address recipient, uint256 deposit, address tokenAddress, uint256 startTime, uint256 stopTime)
        external
        returns (uint256 streamId);

    function withdrawFromStream(uint256 streamId, uint256 funds) external returns (bool);

    function cancelStream(uint256 streamId) external returns (bool);
}

// File: @sablier/protocol/contracts/Types.sol

pragma solidity 0.5.11;


/**
 * @title Sablier Types
 * @author Sablier
 */
library Types {
    struct Stream {
        uint256 deposit;
        uint256 ratePerSecond;
        uint256 remainingBalance;
        uint256 startTime;
        uint256 stopTime;
        address recipient;
        address sender;
        address tokenAddress;
        bool isEntity;
    }

    struct CompoundingStreamVars {
        Exponential.Exp exchangeRateInitial;
        Exponential.Exp senderShare;
        Exponential.Exp recipientShare;
        bool isEntity;
    }
}

// File: @sablier/protocol/contracts/Sablier.sol

pragma solidity 0.5.11;










/**
 * @title Sablier's Money Streaming
 * @author Sablier
 */
contract Sablier is IERC1620, OwnableWithoutRenounce, PausableWithoutRenounce, Exponential, ReentrancyGuard {
    /*** Storage Properties ***/

    /**
     * @notice In Exp terms, 1e18 is 1, or 100%
     */
    uint256 constant hundredPercent = 1e18;

    /**
     * @notice In Exp terms, 1e16 is 0.01, or 1%
     */
    uint256 constant onePercent = 1e16;

    /**
     * @notice Stores information about the initial state of the underlying of the cToken.
     */
    mapping(uint256 => Types.CompoundingStreamVars) private compoundingStreamsVars;

    /**
     * @notice An instance of CTokenManager, responsible for whitelisting and discarding cTokens.
     */
    ICTokenManager public cTokenManager;

    /**
     * @notice The amount of interest has been accrued per token address.
     */
    mapping(address => uint256) private earnings;

    /**
     * @notice The percentage fee charged by the contract on the accrued interest.
     */
    Exp public fee;

    /**
     * @notice Counter for new stream ids.
     */
    uint256 public nextStreamId;

    /**
     * @notice The stream objects identifiable by their unsigned integer ids.
     */
    mapping(uint256 => Types.Stream) private streams;

    /*** Events ***/

    /**
     * @notice Emits when a compounding stream is successfully created.
     */
    event CreateCompoundingStream(
        uint256 indexed streamId,
        uint256 exchangeRate,
        uint256 senderSharePercentage,
        uint256 recipientSharePercentage
    );

    /**
     * @notice Emits when the owner discards a cToken.
     */
    event PayInterest(
        uint256 indexed streamId,
        uint256 senderInterest,
        uint256 recipientInterest,
        uint256 sablierInterest
    );

    /**
     * @notice Emits when the owner takes the earnings.
     */
    event TakeEarnings(address indexed tokenAddress, uint256 indexed amount);

    /**
     * @notice Emits when the owner updates the percentage fee.
     */
    event UpdateFee(uint256 indexed fee);

    /*** Modifiers ***/

    /**
     * @dev Throws if the caller is not the sender of the recipient of the stream.
     */
    modifier onlySenderOrRecipient(uint256 streamId) {
        require(
            msg.sender == streams[streamId].sender || msg.sender == streams[streamId].recipient,
            "caller is not the sender or the recipient of the stream"
        );
        _;
    }

    /**
     * @dev Throws if the id does not point to a valid stream.
     */
    modifier streamExists(uint256 streamId) {
        require(streams[streamId].isEntity, "stream does not exist");
        _;
    }

    /**
     * @dev Throws if the id does not point to a valid compounding stream.
     */
    modifier compoundingStreamExists(uint256 streamId) {
        require(compoundingStreamsVars[streamId].isEntity, "compounding stream does not exist");
        _;
    }

    /*** Contract Logic Starts Here */

    constructor(address cTokenManagerAddress) public {
        require(cTokenManagerAddress != address(0x00), "cTokenManager contract is the zero address");
        OwnableWithoutRenounce.initialize(msg.sender);
        PausableWithoutRenounce.initialize(msg.sender);
        cTokenManager = ICTokenManager(cTokenManagerAddress);
        nextStreamId = 1;
    }

    /*** Owner Functions ***/

    struct UpdateFeeLocalVars {
        MathError mathErr;
        uint256 feeMantissa;
    }

    /**
     * @notice Updates the Sablier fee.
     * @dev Throws if the caller is not the owner of the contract.
     *  Throws if `feePercentage` is not lower or equal to 100.
     * @param feePercentage The new fee as a percentage.
     */
    function updateFee(uint256 feePercentage) external onlyOwner {
        require(feePercentage <= 100, "fee percentage higher than 100%");
        UpdateFeeLocalVars memory vars;

        /* `feePercentage` will be stored as a mantissa, so we scale it up by one percent in Exp terms. */
        (vars.mathErr, vars.feeMantissa) = mulUInt(feePercentage, onePercent);
        /*
         * `mulUInt` can only return MathError.INTEGER_OVERFLOW but we control `onePercent`
         * and we know `feePercentage` is maximum 100.
         */
        assert(vars.mathErr == MathError.NO_ERROR);

        fee = Exp({ mantissa: vars.feeMantissa });
        emit UpdateFee(feePercentage);
    }

    struct TakeEarningsLocalVars {
        MathError mathErr;
    }

    /**
     * @notice Withdraws the earnings for the given token address.
     * @dev Throws if `amount` exceeds the available balance.
     * @param tokenAddress The address of the token to withdraw earnings for.
     * @param amount The amount of tokens to withdraw.
     */
    function takeEarnings(address tokenAddress, uint256 amount) external onlyOwner nonReentrant {
        require(cTokenManager.isCToken(tokenAddress), "cToken is not whitelisted");
        require(amount > 0, "amount is zero");
        require(earnings[tokenAddress] >= amount, "amount exceeds the available balance");

        TakeEarningsLocalVars memory vars;
        (vars.mathErr, earnings[tokenAddress]) = subUInt(earnings[tokenAddress], amount);
        /*
         * `subUInt` can only return MathError.INTEGER_UNDERFLOW but we know `earnings[tokenAddress]`
         * is at least as big as `amount`.
         */
        assert(vars.mathErr == MathError.NO_ERROR);

        emit TakeEarnings(tokenAddress, amount);
        require(IERC20(tokenAddress).transfer(msg.sender, amount), "token transfer failure");
    }

    /*** View Functions ***/

    /**
     * @notice Returns the compounding stream with all its properties.
     * @dev Throws if the id does not point to a valid stream.
     * @param streamId The id of the stream to query.
     * @return The stream object.
     */
    function getStream(uint256 streamId)
        external
        view
        streamExists(streamId)
        returns (
            address sender,
            address recipient,
            uint256 deposit,
            address tokenAddress,
            uint256 startTime,
            uint256 stopTime,
            uint256 remainingBalance,
            uint256 ratePerSecond
        )
    {
        sender = streams[streamId].sender;
        recipient = streams[streamId].recipient;
        deposit = streams[streamId].deposit;
        tokenAddress = streams[streamId].tokenAddress;
        startTime = streams[streamId].startTime;
        stopTime = streams[streamId].stopTime;
        remainingBalance = streams[streamId].remainingBalance;
        ratePerSecond = streams[streamId].ratePerSecond;
    }

    /**
     * @notice Returns either the delta in seconds between `block.timestamp` and `startTime` or
     *  between `stopTime` and `startTime, whichever is smaller. If `block.timestamp` is before
     *  `startTime`, it returns 0.
     * @dev Throws if the id does not point to a valid stream.
     * @param streamId The id of the stream for whom to query the delta.
     * @return The time delta in seconds.
     */
    function deltaOf(uint256 streamId) public view streamExists(streamId) returns (uint256 delta) {
        Types.Stream memory stream = streams[streamId];
        if (block.timestamp <= stream.startTime) return 0;
        if (block.timestamp < stream.stopTime) return block.timestamp - stream.startTime;
        return stream.stopTime - stream.startTime;
    }

    struct BalanceOfLocalVars {
        MathError mathErr;
        uint256 recipientBalance;
        uint256 withdrawalAmount;
        uint256 senderBalance;
    }

    /**
     * @notice Returns the available funds for the given stream id and address.
     * @dev Throws if the id does not point to a valid stream.
     * @param streamId The id of the stream for whom to query the balance.
     * @param who The address for whom to query the balance.
     * @return The total funds allocated to `who` as uint256.
     */
    function balanceOf(uint256 streamId, address who) public view streamExists(streamId) returns (uint256 balance) {
        Types.Stream memory stream = streams[streamId];
        BalanceOfLocalVars memory vars;

        uint256 delta = deltaOf(streamId);
        (vars.mathErr, vars.recipientBalance) = mulUInt(delta, stream.ratePerSecond);
        require(vars.mathErr == MathError.NO_ERROR, "recipient balance calculation error");

        /*
         * If the stream `balance` does not equal `deposit`, it means there have been withdrawals.
         * We have to subtract the total amount withdrawn from the amount of money that has been
         * streamed until now.
         */
        if (stream.deposit > stream.remainingBalance) {
            (vars.mathErr, vars.withdrawalAmount) = subUInt(stream.deposit, stream.remainingBalance);
            assert(vars.mathErr == MathError.NO_ERROR);
            (vars.mathErr, vars.recipientBalance) = subUInt(vars.recipientBalance, vars.withdrawalAmount);
            /* `withdrawalAmount` cannot and should not be bigger than `recipientBalance`. */
            assert(vars.mathErr == MathError.NO_ERROR);
        }

        if (who == stream.recipient) return vars.recipientBalance;
        if (who == stream.sender) {
            (vars.mathErr, vars.senderBalance) = subUInt(stream.remainingBalance, vars.recipientBalance);
            /* `recipientBalance` cannot and should not be bigger than `remainingBalance`. */
            assert(vars.mathErr == MathError.NO_ERROR);
            return vars.senderBalance;
        }
        return 0;
    }

    /**
     * @notice Checks if the given id points to a compounding stream.
     * @param streamId The id of the compounding stream to check.
     * @return bool true=it is compounding stream, otherwise false.
     */
    function isCompoundingStream(uint256 streamId) public view returns (bool) {
        return compoundingStreamsVars[streamId].isEntity;
    }

    /**
     * @notice Returns the compounding stream object with all its properties.
     * @dev Throws if the id does not point to a valid compounding stream.
     * @param streamId The id of the compounding stream to query.
     * @return The compounding stream object.
     */
    function getCompoundingStream(uint256 streamId)
        external
        view
        streamExists(streamId)
        compoundingStreamExists(streamId)
        returns (
            address sender,
            address recipient,
            uint256 deposit,
            address tokenAddress,
            uint256 startTime,
            uint256 stopTime,
            uint256 remainingBalance,
            uint256 ratePerSecond,
            uint256 exchangeRateInitial,
            uint256 senderSharePercentage,
            uint256 recipientSharePercentage
        )
    {
        sender = streams[streamId].sender;
        recipient = streams[streamId].recipient;
        deposit = streams[streamId].deposit;
        tokenAddress = streams[streamId].tokenAddress;
        startTime = streams[streamId].startTime;
        stopTime = streams[streamId].stopTime;
        remainingBalance = streams[streamId].remainingBalance;
        ratePerSecond = streams[streamId].ratePerSecond;
        exchangeRateInitial = compoundingStreamsVars[streamId].exchangeRateInitial.mantissa;
        senderSharePercentage = compoundingStreamsVars[streamId].senderShare.mantissa;
        recipientSharePercentage = compoundingStreamsVars[streamId].recipientShare.mantissa;
    }

    struct InterestOfLocalVars {
        MathError mathErr;
        Exp exchangeRateDelta;
        Exp underlyingInterest;
        Exp netUnderlyingInterest;
        Exp senderUnderlyingInterest;
        Exp recipientUnderlyingInterest;
        Exp sablierUnderlyingInterest;
        Exp senderInterest;
        Exp recipientInterest;
        Exp sablierInterest;
    }

    /**
     * @notice Computes the interest accrued by keeping the amount of tokens in the contract. Returns (0, 0, 0) if
     *  the stream is not a compounding stream.
     * @dev Throws if there is a math error. We do not assert the calculations which involve the current
     *  exchange rate, because we can't know what value we'll get back from the cToken contract.
     * @return The interest accrued by the sender, the recipient and sablier, respectively, as uint256s.
     */
    function interestOf(uint256 streamId, uint256 amount)
        public
        streamExists(streamId)
        returns (uint256 senderInterest, uint256 recipientInterest, uint256 sablierInterest)
    {
        if (!compoundingStreamsVars[streamId].isEntity) {
            return (0, 0, 0);
        }
        Types.Stream memory stream = streams[streamId];
        Types.CompoundingStreamVars memory compoundingStreamVars = compoundingStreamsVars[streamId];
        InterestOfLocalVars memory vars;

        /*
         * The exchange rate delta is a key variable, since it leads us to how much interest has been earned
         * since the compounding stream was created.
         */
        Exp memory exchangeRateCurrent = Exp({ mantissa: ICERC20(stream.tokenAddress).exchangeRateCurrent() });
        if (exchangeRateCurrent.mantissa <= compoundingStreamVars.exchangeRateInitial.mantissa) {
            return (0, 0, 0);
        }
        (vars.mathErr, vars.exchangeRateDelta) = subExp(exchangeRateCurrent, compoundingStreamVars.exchangeRateInitial);
        assert(vars.mathErr == MathError.NO_ERROR);

        /* Calculate how much interest has been earned by holding `amount` in the smart contract. */
        (vars.mathErr, vars.underlyingInterest) = mulScalar(vars.exchangeRateDelta, amount);
        require(vars.mathErr == MathError.NO_ERROR, "interest calculation error");

        /* Calculate our share from that interest. */
        if (fee.mantissa == hundredPercent) {
            (vars.mathErr, vars.sablierInterest) = divExp(vars.underlyingInterest, exchangeRateCurrent);
            require(vars.mathErr == MathError.NO_ERROR, "sablier interest conversion error");
            return (0, 0, truncate(vars.sablierInterest));
        } else if (fee.mantissa == 0) {
            vars.sablierUnderlyingInterest = Exp({ mantissa: 0 });
            vars.netUnderlyingInterest = vars.underlyingInterest;
        } else {
            (vars.mathErr, vars.sablierUnderlyingInterest) = mulExp(vars.underlyingInterest, fee);
            require(vars.mathErr == MathError.NO_ERROR, "sablier interest calculation error");

            /* Calculate how much interest is left for the sender and the recipient. */
            (vars.mathErr, vars.netUnderlyingInterest) = subExp(
                vars.underlyingInterest,
                vars.sablierUnderlyingInterest
            );
            /*
             * `subUInt` can only return MathError.INTEGER_UNDERFLOW but we know that `sablierUnderlyingInterest`
             * is less or equal than `underlyingInterest`, because we control the value of `fee`.
             */
            assert(vars.mathErr == MathError.NO_ERROR);
        }

        /* Calculate the sender's share of the interest. */
        (vars.mathErr, vars.senderUnderlyingInterest) = mulExp(
            vars.netUnderlyingInterest,
            compoundingStreamVars.senderShare
        );
        require(vars.mathErr == MathError.NO_ERROR, "sender interest calculation error");

        /* Calculate the recipient's share of the interest. */
        (vars.mathErr, vars.recipientUnderlyingInterest) = subExp(
            vars.netUnderlyingInterest,
            vars.senderUnderlyingInterest
        );
        /*
         * `subUInt` can only return MathError.INTEGER_UNDERFLOW but we know that `senderUnderlyingInterest`
         * is less or equal than `netUnderlyingInterest`, because `senderShare` is bounded between 1e16 and 1e18.
         */
        assert(vars.mathErr == MathError.NO_ERROR);

        /* Convert the interest to the equivalent cToken denomination. */
        (vars.mathErr, vars.senderInterest) = divExp(vars.senderUnderlyingInterest, exchangeRateCurrent);
        require(vars.mathErr == MathError.NO_ERROR, "sender interest conversion error");

        (vars.mathErr, vars.recipientInterest) = divExp(vars.recipientUnderlyingInterest, exchangeRateCurrent);
        require(vars.mathErr == MathError.NO_ERROR, "recipient interest conversion error");

        (vars.mathErr, vars.sablierInterest) = divExp(vars.sablierUnderlyingInterest, exchangeRateCurrent);
        require(vars.mathErr == MathError.NO_ERROR, "sablier interest conversion error");

        /* Truncating the results means losing everything on the last 1e18 positions of the mantissa */
        return (truncate(vars.senderInterest), truncate(vars.recipientInterest), truncate(vars.sablierInterest));
    }

    /**
     * @notice Returns the amount of interest that has been accrued for the given token address.
     * @param tokenAddress The address of the token to get the earnings for.
     * @return The amount of interest as uint256.
     */
    function getEarnings(address tokenAddress) external view returns (uint256) {
        require(cTokenManager.isCToken(tokenAddress), "token is not cToken");
        return earnings[tokenAddress];
    }

    /*** Public Effects & Interactions Functions ***/

    struct CreateStreamLocalVars {
        MathError mathErr;
        uint256 duration;
        uint256 ratePerSecond;
    }

    /**
     * @notice Creates a new stream funded by `msg.sender` and paid towards `recipient`.
     * @dev Throws if paused.
     *  Throws if the recipient is the zero address, the contract itself or the caller.
     *  Throws if the deposit is 0.
     *  Throws if the start time is before `block.timestamp`.
     *  Throws if the stop time is before the start time.
     *  Throws if the duration calculation has a math error.
     *  Throws if the deposit is smaller than the duration.
     *  Throws if the deposit is not a multiple of the duration.
     *  Throws if the rate calculation has a math error.
     *  Throws if the next stream id calculation has a math error.
     *  Throws if the contract is not allowed to transfer enough tokens.
     *  Throws if there is a token transfer failure.
     * @param recipient The address towards which the money is streamed.
     * @param deposit The amount of money to be streamed.
     * @param tokenAddress The ERC20 token to use as streaming currency.
     * @param startTime The unix timestamp for when the stream starts.
     * @param stopTime The unix timestamp for when the stream stops.
     * @return The uint256 id of the newly created stream.
     */
    function createStream(address recipient, uint256 deposit, address tokenAddress, uint256 startTime, uint256 stopTime)
        public
        whenNotPaused
        returns (uint256)
    {
        require(recipient != address(0x00), "stream to the zero address");
        require(recipient != address(this), "stream to the contract itself");
        require(recipient != msg.sender, "stream to the caller");
        require(deposit > 0, "deposit is zero");
        require(startTime >= block.timestamp, "start time before block.timestamp");
        require(stopTime > startTime, "stop time before the start time");

        CreateStreamLocalVars memory vars;
        (vars.mathErr, vars.duration) = subUInt(stopTime, startTime);
        /* `subUInt` can only return MathError.INTEGER_UNDERFLOW but we know `stopTime` is higher than `startTime`. */
        assert(vars.mathErr == MathError.NO_ERROR);

        /* Without this, the rate per second would be zero. */
        require(deposit >= vars.duration, "deposit smaller than time delta");

        /* This condition avoids dealing with remainders */
        require(deposit % vars.duration == 0, "deposit not multiple of time delta");

        (vars.mathErr, vars.ratePerSecond) = divUInt(deposit, vars.duration);
        /* `divUInt` can only return MathError.DIVISION_BY_ZERO but we know `duration` is not zero. */
        assert(vars.mathErr == MathError.NO_ERROR);

        /* Create and store the stream object. */
        uint256 streamId = nextStreamId;
        streams[streamId] = Types.Stream({
            remainingBalance: deposit,
            deposit: deposit,
            isEntity: true,
            ratePerSecond: vars.ratePerSecond,
            recipient: recipient,
            sender: msg.sender,
            startTime: startTime,
            stopTime: stopTime,
            tokenAddress: tokenAddress
        });

        /* Increment the next stream id. */
        (vars.mathErr, nextStreamId) = addUInt(nextStreamId, uint256(1));
        require(vars.mathErr == MathError.NO_ERROR, "next stream id calculation error");

        require(IERC20(tokenAddress).transferFrom(msg.sender, address(this), deposit), "token transfer failure");
        emit CreateStream(streamId, msg.sender, recipient, deposit, tokenAddress, startTime, stopTime);
        return streamId;
    }

    struct CreateCompoundingStreamLocalVars {
        MathError mathErr;
        uint256 shareSum;
        uint256 underlyingBalance;
        uint256 senderShareMantissa;
        uint256 recipientShareMantissa;
    }

    /**
     * @notice Creates a new compounding stream funded by `msg.sender` and paid towards `recipient`.
     * @dev Inherits all security checks from `createStream`.
     *  Throws if the cToken is not whitelisted.
     *  Throws if the sender share percentage and the recipient share percentage do not sum up to 100.
     *  Throws if the the sender share mantissa calculation has a math error.
     *  Throws if the the recipient share mantissa calculation has a math error.
     * @param recipient The address towards which the money is streamed.
     * @param deposit The amount of money to be streamed.
     * @param tokenAddress The ERC20 token to use as streaming currency.
     * @param startTime The unix timestamp for when the stream starts.
     * @param stopTime The unix timestamp for when the stream stops.
     * @param senderSharePercentage The sender's share of the interest, as a percentage.
     * @param recipientSharePercentage The recipient's share of the interest, as a percentage.
     * @return The uint256 id of the newly created compounding stream.
     */
    function createCompoundingStream(
        address recipient,
        uint256 deposit,
        address tokenAddress,
        uint256 startTime,
        uint256 stopTime,
        uint256 senderSharePercentage,
        uint256 recipientSharePercentage
    ) external whenNotPaused returns (uint256) {
        require(cTokenManager.isCToken(tokenAddress), "cToken is not whitelisted");
        CreateCompoundingStreamLocalVars memory vars;

        /* Ensure that the interest shares sum up to 100%. */
        (vars.mathErr, vars.shareSum) = addUInt(senderSharePercentage, recipientSharePercentage);
        require(vars.mathErr == MathError.NO_ERROR, "share sum calculation error");
        require(vars.shareSum == 100, "shares do not sum up to 100");

        uint256 streamId = createStream(recipient, deposit, tokenAddress, startTime, stopTime);

        /*
         * `senderSharePercentage` and `recipientSharePercentage` will be stored as mantissas, so we scale them up
         * by one percent in Exp terms.
         */
        (vars.mathErr, vars.senderShareMantissa) = mulUInt(senderSharePercentage, onePercent);
        /*
         * `mulUInt` can only return MathError.INTEGER_OVERFLOW but we control `onePercent` and
         * we know `senderSharePercentage` is maximum 100.
         */
        assert(vars.mathErr == MathError.NO_ERROR);

        (vars.mathErr, vars.recipientShareMantissa) = mulUInt(recipientSharePercentage, onePercent);
        /*
         * `mulUInt` can only return MathError.INTEGER_OVERFLOW but we control `onePercent` and
         * we know `recipientSharePercentage` is maximum 100.
         */
        assert(vars.mathErr == MathError.NO_ERROR);

        /* Create and store the compounding stream vars. */
        uint256 exchangeRateCurrent = ICERC20(tokenAddress).exchangeRateCurrent();
        compoundingStreamsVars[streamId] = Types.CompoundingStreamVars({
            exchangeRateInitial: Exp({ mantissa: exchangeRateCurrent }),
            isEntity: true,
            recipientShare: Exp({ mantissa: vars.recipientShareMantissa }),
            senderShare: Exp({ mantissa: vars.senderShareMantissa })
        });

        emit CreateCompoundingStream(streamId, exchangeRateCurrent, senderSharePercentage, recipientSharePercentage);
        return streamId;
    }

    /**
     * @notice Withdraws from the contract to the recipient's account.
     * @dev Throws if the id does not point to a valid stream.
     *  Throws if the caller is not the sender or the recipient of the stream.
     *  Throws if the amount exceeds the available balance.
     *  Throws if there is a token transfer failure.
     * @param streamId The id of the stream to withdraw tokens from.
     * @param amount The amount of tokens to withdraw.
     * @return bool true=success, otherwise false.
     */
    function withdrawFromStream(uint256 streamId, uint256 amount)
        external
        whenNotPaused
        nonReentrant
        streamExists(streamId)
        onlySenderOrRecipient(streamId)
        returns (bool)
    {
        require(amount > 0, "amount is zero");
        Types.Stream memory stream = streams[streamId];
        uint256 balance = balanceOf(streamId, stream.recipient);
        require(balance >= amount, "amount exceeds the available balance");

        if (!compoundingStreamsVars[streamId].isEntity) {
            withdrawFromStreamInternal(streamId, amount);
        } else {
            withdrawFromCompoundingStreamInternal(streamId, amount);
        }
        return true;
    }

    /**
     * @notice Cancels the stream and transfers the tokens back on a pro rata basis.
     * @dev Throws if the id does not point to a valid stream.
     *  Throws if the caller is not the sender or the recipient of the stream.
     *  Throws if there is a token transfer failure.
     * @param streamId The id of the stream to cancel.
     * @return bool true=success, otherwise false.
     */
    function cancelStream(uint256 streamId)
        external
        nonReentrant
        streamExists(streamId)
        onlySenderOrRecipient(streamId)
        returns (bool)
    {
        if (!compoundingStreamsVars[streamId].isEntity) {
            cancelStreamInternal(streamId);
        } else {
            cancelCompoundingStreamInternal(streamId);
        }
        return true;
    }

    /*** Internal Effects & Interactions Functions ***/

    struct WithdrawFromStreamInternalLocalVars {
        MathError mathErr;
    }

    /**
     * @notice Makes the withdrawal to the recipient of the stream.
     * @dev If the stream balance has been depleted to 0, the stream object is deleted
     *  to save gas and optimise contract storage.
     *  Throws if the stream balance calculation has a math error.
     *  Throws if there is a token transfer failure.
     */
    function withdrawFromStreamInternal(uint256 streamId, uint256 amount) internal {
        Types.Stream memory stream = streams[streamId];
        WithdrawFromStreamInternalLocalVars memory vars;
        (vars.mathErr, streams[streamId].remainingBalance) = subUInt(stream.remainingBalance, amount);
        /**
         * `subUInt` can only return MathError.INTEGER_UNDERFLOW but we know that `remainingBalance` is at least
         * as big as `amount`. See the `require` check in `withdrawFromInternal`.
         */
        assert(vars.mathErr == MathError.NO_ERROR);

        if (streams[streamId].remainingBalance == 0) delete streams[streamId];

        require(IERC20(stream.tokenAddress).transfer(stream.recipient, amount), "token transfer failure");
        emit WithdrawFromStream(streamId, stream.recipient, amount);
    }

    struct WithdrawFromCompoundingStreamInternalLocalVars {
        MathError mathErr;
        uint256 amountWithoutSenderInterest;
        uint256 netWithdrawalAmount;
    }

    /**
     * @notice Withdraws to the recipient's account and pays the accrued interest to all parties.
     * @dev If the stream balance has been depleted to 0, the stream object to save gas and optimise
     *  contract storage.
     *  Throws if there is a math error.
     *  Throws if there is a token transfer failure.
     */
    function withdrawFromCompoundingStreamInternal(uint256 streamId, uint256 amount) internal {
        Types.Stream memory stream = streams[streamId];
        WithdrawFromCompoundingStreamInternalLocalVars memory vars;

        /* Calculate the interest earned by each party for keeping `stream.balance` in the smart contract. */
        (uint256 senderInterest, uint256 recipientInterest, uint256 sablierInterest) = interestOf(streamId, amount);

        /*
         * Calculate the net withdrawal amount by subtracting `senderInterest` and `sablierInterest`.
         * Because the decimal points are lost when we truncate Exponentials, the recipient will implicitly earn
         * `recipientInterest` plus a tiny-weeny amount of interest, max 2e-8 in cToken denomination.
         */
        (vars.mathErr, vars.amountWithoutSenderInterest) = subUInt(amount, senderInterest);
        require(vars.mathErr == MathError.NO_ERROR, "amount without sender interest calculation error");
        (vars.mathErr, vars.netWithdrawalAmount) = subUInt(vars.amountWithoutSenderInterest, sablierInterest);
        require(vars.mathErr == MathError.NO_ERROR, "net withdrawal amount calculation error");

        /* Subtract `amount` from the remaining balance of the stream. */
        (vars.mathErr, streams[streamId].remainingBalance) = subUInt(stream.remainingBalance, amount);
        require(vars.mathErr == MathError.NO_ERROR, "balance subtraction calculation error");

        /* Delete the objects from storage if the remaining balance has been depleted to 0. */
        if (streams[streamId].remainingBalance == 0) {
            delete streams[streamId];
            delete compoundingStreamsVars[streamId];
        }

        /* Add the sablier interest to the earnings for this cToken. */
        (vars.mathErr, earnings[stream.tokenAddress]) = addUInt(earnings[stream.tokenAddress], sablierInterest);
        require(vars.mathErr == MathError.NO_ERROR, "earnings addition calculation error");

        /* Transfer the tokens to the sender and the recipient. */
        ICERC20 cToken = ICERC20(stream.tokenAddress);
        if (senderInterest > 0)
            require(cToken.transfer(stream.sender, senderInterest), "sender token transfer failure");
        require(cToken.transfer(stream.recipient, vars.netWithdrawalAmount), "recipient token transfer failure");

        emit WithdrawFromStream(streamId, stream.recipient, vars.netWithdrawalAmount);
        emit PayInterest(streamId, senderInterest, recipientInterest, sablierInterest);
    }

    /**
     * @notice Cancels the stream and transfers the tokens back on a pro rata basis.
     * @dev The stream and compounding stream vars objects get deleted to save gas
     *  and optimise contract storage.
     *  Throws if there is a token transfer failure.
     */
    function cancelStreamInternal(uint256 streamId) internal {
        Types.Stream memory stream = streams[streamId];
        uint256 senderBalance = balanceOf(streamId, stream.sender);
        uint256 recipientBalance = balanceOf(streamId, stream.recipient);

        delete streams[streamId];

        IERC20 token = IERC20(stream.tokenAddress);
        if (recipientBalance > 0)
            require(token.transfer(stream.recipient, recipientBalance), "recipient token transfer failure");
        if (senderBalance > 0) require(token.transfer(stream.sender, senderBalance), "sender token transfer failure");

        emit CancelStream(streamId, stream.sender, stream.recipient, senderBalance, recipientBalance);
    }

    struct CancelCompoundingStreamInternal {
        MathError mathErr;
        uint256 netSenderBalance;
        uint256 recipientBalanceWithoutSenderInterest;
        uint256 netRecipientBalance;
    }

    /**
     * @notice Cancels the stream, transfers the tokens back on a pro rata basis and pays the accrued
     * interest to all parties.
     * @dev Importantly, the money that has not been streamed yet is not considered chargeable.
     *  All the interest generated by that underlying will be returned to the sender.
     *  Throws if there is a math error.
     *  Throws if there is a token transfer failure.
     */
    function cancelCompoundingStreamInternal(uint256 streamId) internal {
        Types.Stream memory stream = streams[streamId];
        CancelCompoundingStreamInternal memory vars;

        /*
         * The sender gets back all the money that has not been streamed so far. By that, we mean both
         * the underlying amount and the interest generated by it.
         */
        uint256 senderBalance = balanceOf(streamId, stream.sender);
        uint256 recipientBalance = balanceOf(streamId, stream.recipient);

        /* Calculate the interest earned by each party for keeping `recipientBalance` in the smart contract. */
        (uint256 senderInterest, uint256 recipientInterest, uint256 sablierInterest) = interestOf(
            streamId,
            recipientBalance
        );

        /*
         * We add `senderInterest` to `senderBalance` to compute the net balance for the sender.
         * After this, the rest of the function is similar to `withdrawFromCompoundingStreamInternal`, except
         * we add the sender's share of the interest generated by `recipientBalance` to `senderBalance`.
         */
        (vars.mathErr, vars.netSenderBalance) = addUInt(senderBalance, senderInterest);
        require(vars.mathErr == MathError.NO_ERROR, "net sender balance calculation error");

        /*
         * Calculate the net withdrawal amount by subtracting `senderInterest` and `sablierInterest`.
         * Because the decimal points are lost when we truncate Exponentials, the recipient will implicitly earn
         * `recipientInterest` plus a tiny-weeny amount of interest, max 2e-8 in cToken denomination.
         */
        (vars.mathErr, vars.recipientBalanceWithoutSenderInterest) = subUInt(recipientBalance, senderInterest);
        require(vars.mathErr == MathError.NO_ERROR, "recipient balance without sender interest calculation error");
        (vars.mathErr, vars.netRecipientBalance) = subUInt(vars.recipientBalanceWithoutSenderInterest, sablierInterest);
        require(vars.mathErr == MathError.NO_ERROR, "net recipient balance calculation error");

        /* Add the sablier interest to the earnings attributed to this cToken. */
        (vars.mathErr, earnings[stream.tokenAddress]) = addUInt(earnings[stream.tokenAddress], sablierInterest);
        require(vars.mathErr == MathError.NO_ERROR, "earnings addition calculation error");

        /* Delete the objects from storage. */
        delete streams[streamId];
        delete compoundingStreamsVars[streamId];

        /* Transfer the tokens to the sender and the recipient. */
        IERC20 token = IERC20(stream.tokenAddress);
        if (vars.netSenderBalance > 0)
            require(token.transfer(stream.sender, vars.netSenderBalance), "sender token transfer failure");
        if (vars.netRecipientBalance > 0)
            require(token.transfer(stream.recipient, vars.netRecipientBalance), "recipient token transfer failure");

        emit CancelStream(streamId, stream.sender, stream.recipient, vars.netSenderBalance, vars.netRecipientBalance);
        emit PayInterest(streamId, senderInterest, recipientInterest, sablierInterest);
    }
}

// File: contracts/Payroll.sol

pragma solidity 0.5.11;










/**
 * @title Payroll Proxy
 * @author Sablier
 */
contract Payroll is Initializable, OwnableWithoutRenounce, Exponential, GSNRecipient, GSNBouncerSignature {
    /*** Storage Properties ***/

    /**
     * @notice Container for salary information
     * @member company The address of the company which funded this salary
     * @member isEntity bool true=object exists, otherwise false
     * @member streamId The id of the stream in the Sablier contract
     */
    struct Salary {
        address company;
        bool isEntity;
        uint256 streamId;
    }

    /**
     * @notice Counter for new salary ids.
     */
    uint256 public nextSalaryId;

    /**
     * @notice Whitelist of accounts able to call the withdrawal function for a given stream so
     *  employees don't have to pay gas.
     */
    mapping(address => mapping(uint256 => bool)) public relayers;

    /**
     * @notice An instance of Sablier, the contract responsible for creating, withdrawing from and cancelling streams.
     */
    Sablier public sablier;

    /**
     * @notice The salary objects identifiable by their unsigned integer ids.
     */
    mapping(uint256 => Salary) private salaries;

    /*** Events ***/

    /**
     * @notice Emits when a salary is successfully created.
     */
    event CreateSalary(uint256 indexed salaryId, uint256 indexed streamId, address indexed company);

    /**
     * @notice Emits when the employee withdraws a portion or all their pro rata share of the stream.
     */
    event WithdrawFromSalary(uint256 indexed salaryId, uint256 indexed streamId, address indexed company);

    /**
     * @notice Emits when a salary is successfully cancelled and both parties get their pro rata
     *  share of the available funds.
     */
    event CancelSalary(uint256 indexed salaryId, uint256 indexed streamId, address indexed company);

    /**
     * @dev Throws if the caller is not the company or the employee.
     */
    modifier onlyCompanyOrEmployee(uint256 salaryId) {
        Salary memory salary = salaries[salaryId];
        (, address employee, , , , , , ) = sablier.getStream(salary.streamId);
        require(
            _msgSender() == salary.company || _msgSender() == employee,
            "caller is not the company or the employee"
        );
        _;
    }

    /**
     * @dev Throws if the caller is not the employee or an approved relayer.
     */
    modifier onlyEmployeeOrRelayer(uint256 salaryId) {
        Salary memory salary = salaries[salaryId];
        (, address employee, , , , , , ) = sablier.getStream(salary.streamId);
        require(
            _msgSender() == employee || relayers[_msgSender()][salaryId],
            "caller is not the employee or a relayer"
        );
        _;
    }

    /**
     * @dev Throws if the id does not point to a valid salary.
     */
    modifier salaryExists(uint256 salaryId) {
        require(salaries[salaryId].isEntity, "salary does not exist");
        _;
    }

    /*** Contract Logic Starts Here ***/

    /**
     * @notice Only called once after the contract is deployed. We ask for the owner and the signer address
     *  to be specified as parameters to avoid handling `msg.sender` directly.
     * @dev The `initializer` modifier ensures that the function can only be called once.
     * @param ownerAddress The address of the contract owner.
     * @param signerAddress The address of the account able to authorise relayed transactions.
     * @param sablierAddress The address of the Sablier contract.
     */
    function initialize(address ownerAddress, address signerAddress, address sablierAddress) public initializer {
        require(ownerAddress != address(0x00), "owner is the zero address");
        require(signerAddress != address(0x00), "signer is the zero address");
        require(sablierAddress != address(0x00), "sablier contract is the zero address");
        OwnableWithoutRenounce.initialize(ownerAddress);
        GSNRecipient.initialize();
        GSNBouncerSignature.initialize(signerAddress);
        sablier = Sablier(sablierAddress);
        nextSalaryId = 1;
    }

    /*** Admin ***/

    /**
     * @notice Whitelists a relayer to process withdrawals so the employee doesn't have to pay gas.
     * @dev Throws if the caller is not the owner of the contract.
     *  Throws if the id does not point to a valid salary.
     *  Throws if the relayer is whitelisted.
     * @param relayer The address of the relayer account.
     * @param salaryId The id of the salary to whitelist the relayer for.
     */
    function whitelistRelayer(address relayer, uint256 salaryId) external onlyOwner salaryExists(salaryId) {
        require(!relayers[relayer][salaryId], "relayer is whitelisted");
        relayers[relayer][salaryId] = true;
    }

    /**
     * @notice Discard a previously whitelisted relayer to prevent them from processing withdrawals.
     * @dev Throws if the caller is not the owner of the contract.
     *  Throws if the relayer is not whitelisted.
     * @param relayer The address of the relayer account.
     * @param salaryId The id of the salary to discard the relayer for.
     */
    function discardRelayer(address relayer, uint256 salaryId) external onlyOwner {
        require(relayers[relayer][salaryId], "relayer is not whitelisted");
        relayers[relayer][salaryId] = false;
    }

    /*** View Functions ***/

    /**
     * @dev Called by {IRelayHub} to validate if this recipient accepts being charged for a relayed call. Note that the
     * recipient will be charged regardless of the execution result of the relayed call (i.e. if it reverts or not).
     *
     * The relay request was originated by `from` and will be served by `relay`. `encodedFunction` is the relayed call
     * calldata, so its first four bytes are the function selector. The relayed call will be forwarded `gasLimit` gas,
     * and the transaction executed with a gas price of at least `gasPrice`. `relay`'s fee is `transactionFee`, and the
     * recipient will be charged at most `maxPossibleCharge` (in wei). `nonce` is the sender's (`from`) nonce for
     * replay attack protection in {IRelayHub}, and `approvalData` is a optional parameter that can be used to hold
     * a signature over all or some of the previous values.
     *
     * Returns a tuple, where the first value is used to indicate approval (0) or rejection (custom non-zero error code,
     * values 1 to 10 are reserved) and the second one is data to be passed to the other {IRelayRecipient} functions.
     *
     * {acceptRelayedCall} is called with 50k gas: if it runs out during execution, the request will be considered
     * rejected. A regular revert will also trigger a rejection.
     */
    function acceptRelayedCall(
        address relay,
        address from,
        bytes calldata encodedFunction,
        uint256 transactionFee,
        uint256 gasPrice,
        uint256 gasLimit,
        uint256 nonce,
        bytes calldata approvalData,
        uint256
    ) external view returns (uint256, bytes memory) {
        /**
         * `nonce` prevents replays on RelayHub
         * `getHubAddr` prevents replays in multiple RelayHubs
         * `address(this)` prevents replays in multiple recipients
         */
        bytes memory blob = abi.encodePacked(
            relay,
            from,
            encodedFunction,
            transactionFee,
            gasPrice,
            gasLimit,
            nonce,
            getHubAddr(),
            address(this)
        );
        if (keccak256(blob).toEthSignedMessageHash().recover(approvalData) == owner()) {
            return _approveRelayedCall();
        } else {
            return _rejectRelayedCall(uint256(GSNBouncerSignatureErrorCodes.INVALID_SIGNER));
        }
    }

    /**
     * @notice Returns the salary object with all its properties.
     * @dev Throws if the id does not point to a valid salary.
     * @param salaryId The id of the salary to query.
     * @return The salary object.
     */
    function getSalary(uint256 salaryId)
        public
        view
        salaryExists(salaryId)
        returns (
            address company,
            address employee,
            uint256 salary,
            address tokenAddress,
            uint256 startTime,
            uint256 stopTime,
            uint256 remainingBalance,
            uint256 rate
        )
    {
        company = salaries[salaryId].company;
        (, employee, salary, tokenAddress, startTime, stopTime, remainingBalance, rate) = sablier.getStream(
            salaries[salaryId].streamId
        );
    }

    /*** Public Effects & Interactions Functions ***/

    struct CreateSalaryLocalVars {
        MathError mathErr;
    }

    /**
     * @notice Creates a new salary funded by `msg.sender` and paid towards `employee`.
     * @dev Throws if there is a math error.
     *  Throws if there is a token transfer failure.
     * @param employee The address of the employee who receives the salary.
     * @param salary The amount of tokens to be streamed.
     * @param tokenAddress The ERC20 token to use as streaming currency.
     * @param startTime The unix timestamp for when the stream starts.
     * @param stopTime The unix timestamp for when the stream stops.
     * @return The uint256 id of the newly created salary.
     */
    function createSalary(address employee, uint256 salary, address tokenAddress, uint256 startTime, uint256 stopTime)
        external
        returns (uint256 salaryId)
    {
        /* Transfer the tokens to this contract. */
        require(IERC20(tokenAddress).transferFrom(_msgSender(), address(this), salary), "token transfer failure");

        /* Approve the Sablier contract to spend from our tokens. */
        require(IERC20(tokenAddress).approve(address(sablier), salary), "token approval failure");

        /* Create the stream. */
        uint256 streamId = sablier.createStream(employee, salary, tokenAddress, startTime, stopTime);
        salaryId = nextSalaryId;
        salaries[nextSalaryId] = Salary({ company: _msgSender(), isEntity: true, streamId: streamId });

        /* Increment the next salary id. */
        CreateSalaryLocalVars memory vars;
        (vars.mathErr, nextSalaryId) = addUInt(nextSalaryId, uint256(1));
        require(vars.mathErr == MathError.NO_ERROR, "next stream id calculation error");

        emit CreateSalary(salaryId, streamId, _msgSender());
    }

    /**
     * @notice Creates a new compounding salary funded by `msg.sender` and paid towards `employee`.
     * @dev There's a bit of redundancy between `createSalary` and this function, but one has to
     *  call `sablier.createStream` and the other `sablier.createCompoundingStream`, so it's not
     *  worth it to run DRY code.
     *  Throws if there is a math error.
     *  Throws if there is a token transfer failure.
     * @param employee The address of the employee who receives the salary.
     * @param salary The amount of tokens to be streamed.
     * @param tokenAddress The ERC20 token to use as streaming currency.
     * @param startTime The unix timestamp for when the stream starts.
     * @param stopTime The unix timestamp for when the stream stops.
     * @param senderSharePercentage The sender's share of the interest, as a percentage.
     * @param recipientSharePercentage The sender's share of the interest, as a percentage.
     * @return The uint256 id of the newly created compounding salary.
     */
    function createCompoundingSalary(
        address employee,
        uint256 salary,
        address tokenAddress,
        uint256 startTime,
        uint256 stopTime,
        uint256 senderSharePercentage,
        uint256 recipientSharePercentage
    ) external returns (uint256 salaryId) {
        /* Transfer the tokens to this contract. */
        require(IERC20(tokenAddress).transferFrom(_msgSender(), address(this), salary), "token transfer failure");

        /* Approve the Sablier contract to spend from our tokens. */
        require(IERC20(tokenAddress).approve(address(sablier), salary), "token approval failure");

        /* Create the stream. */
        uint256 streamId = sablier.createCompoundingStream(
            employee,
            salary,
            tokenAddress,
            startTime,
            stopTime,
            senderSharePercentage,
            recipientSharePercentage
        );
        salaryId = nextSalaryId;
        salaries[nextSalaryId] = Salary({ company: _msgSender(), isEntity: true, streamId: streamId });

        /* Increment the next salary id. */
        CreateSalaryLocalVars memory vars;
        (vars.mathErr, nextSalaryId) = addUInt(nextSalaryId, uint256(1));
        require(vars.mathErr == MathError.NO_ERROR, "next stream id calculation error");

        /* We don't emit a different event for compounding salaries because we emit CreateCompoundingStream. */
        emit CreateSalary(salaryId, streamId, _msgSender());
    }

    struct CancelSalaryLocalVars {
        MathError mathErr;
        uint256 netCompanyBalance;
    }

    /**
     * @notice Withdraws from the contract to the employee's account.
     * @dev Throws if the id does not point to a valid salary.
     *  Throws if the caller is not the employee or a relayer.
     *  Throws if there is a token transfer failure.
     * @param salaryId The id of the salary to withdraw from.
     * @param amount The amount of tokens to withdraw.
     * @return bool true=success, false otherwise.
     */
    function withdrawFromSalary(uint256 salaryId, uint256 amount)
        external
        salaryExists(salaryId)
        onlyEmployeeOrRelayer(salaryId)
        returns (bool success)
    {
        Salary memory salary = salaries[salaryId];
        success = sablier.withdrawFromStream(salary.streamId, amount);
        emit WithdrawFromSalary(salaryId, salary.streamId, salary.company);
    }

    /**
     * @notice Cancels the salary and transfers the tokens back on a pro rata basis.
     * @dev Throws if the id does not point to a valid salary.
     *  Throws if the caller is not the company or the employee.
     *  Throws if there is a token transfer failure.
     * @param salaryId The id of the salary to cancel.
     * @return bool true=success, false otherwise.
     */
    function cancelSalary(uint256 salaryId)
        external
        salaryExists(salaryId)
        onlyCompanyOrEmployee(salaryId)
        returns (bool success)
    {
        Salary memory salary = salaries[salaryId];

        /* We avoid storing extraneous data twice, so we read the token address from Sablier. */
        (, address employee, , address tokenAddress, , , , ) = sablier.getStream(salary.streamId);
        uint256 companyBalance = sablier.balanceOf(salary.streamId, address(this));

        /**
         * The company gets all the money that has not been streamed yet, plus all the interest earned by what's left.
         * Not all streams are compounding and `companyBalance` coincides with `netCompanyBalance` then.
         */
        CancelSalaryLocalVars memory vars;
        if (!sablier.isCompoundingStream(salary.streamId)) {
            vars.netCompanyBalance = companyBalance;
        } else {
            uint256 employeeBalance = sablier.balanceOf(salary.streamId, employee);
            (uint256 companyInterest, , ) = sablier.interestOf(salary.streamId, employeeBalance);
            (vars.mathErr, vars.netCompanyBalance) = addUInt(companyBalance, companyInterest);
            require(vars.mathErr == MathError.NO_ERROR, "net company balance calculation error");
        }

        /* Delete the salary object to save gas. */
        delete salaries[salaryId];
        success = sablier.cancelStream(salary.streamId);

        /* Transfer the tokens to the company. */
        if (vars.netCompanyBalance > 0)
            require(
                IERC20(tokenAddress).transfer(salary.company, vars.netCompanyBalance),
                "company token transfer failure"
            );

        emit CancelSalary(salaryId, salary.streamId, salary.company);
    }
}

Contract ABI

[{"constant":true,"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"getEarnings","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"nextStreamId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"streamId","type":"uint256"}],"name":"getCompoundingStream","outputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"deposit","type":"uint256"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"stopTime","type":"uint256"},{"internalType":"uint256","name":"remainingBalance","type":"uint256"},{"internalType":"uint256","name":"ratePerSecond","type":"uint256"},{"internalType":"uint256","name":"exchangeRateInitial","type":"uint256"},{"internalType":"uint256","name":"senderSharePercentage","type":"uint256"},{"internalType":"uint256","name":"recipientSharePercentage","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"streamId","type":"uint256"},{"internalType":"address","name":"who","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"unpause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isPauser","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"streamId","type":"uint256"}],"name":"cancelStream","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"streamId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawFromStream","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"deposit","type":"uint256"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"stopTime","type":"uint256"},{"internalType":"uint256","name":"senderSharePercentage","type":"uint256"},{"internalType":"uint256","name":"recipientSharePercentage","type":"uint256"}],"name":"createCompoundingStream","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"addPauser","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"pause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"streamId","type":"uint256"}],"name":"getStream","outputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"deposit","type":"uint256"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"stopTime","type":"uint256"},{"internalType":"uint256","name":"remainingBalance","type":"uint256"},{"internalType":"uint256","name":"ratePerSecond","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"streamId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"interestOf","outputs":[{"internalType":"uint256","name":"senderInterest","type":"uint256"},{"internalType":"uint256","name":"recipientInterest","type":"uint256"},{"internalType":"uint256","name":"sablierInterest","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"feePercentage","type":"uint256"}],"name":"updateFee","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"streamId","type":"uint256"}],"name":"isCompoundingStream","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"streamId","type":"uint256"}],"name":"deltaOf","outputs":[{"internalType":"uint256","name":"delta","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"takeEarnings","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"deposit","type":"uint256"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"stopTime","type":"uint256"}],"name":"createStream","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"cTokenManager","outputs":[{"internalType":"contract ICTokenManager","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"fee","outputs":[{"internalType":"uint256","name":"mantissa","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cTokenManagerAddress","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"streamId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"exchangeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"senderSharePercentage","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"recipientSharePercentage","type":"uint256"}],"name":"CreateCompoundingStream","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"streamId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"senderInterest","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"recipientInterest","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sablierInterest","type":"uint256"}],"name":"PayInterest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TakeEarnings","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"UpdateFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"PauserAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"PauserRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"streamId","type":"uint256"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"deposit","type":"uint256"},{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"startTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"stopTime","type":"uint256"}],"name":"CreateStream","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"streamId","type":"uint256"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawFromStream","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"streamId","type":"uint256"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"senderBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"recipientBalance","type":"uint256"}],"name":"CancelStream","type":"event"}]

60806040523480156200001157600080fd5b5060405162004d7a38038062004d7a833981810160405260208110156200003757600080fd5b50516001600160a01b0381166200009a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602a81526020018062004d50602a913960400191505060405180910390fd5b620000b033620000f160201b620043e11760201c565b620000c6336200020e60201b6200239f1760201c565b60ce80546001600160a01b0319166001600160a01b0392909216919091179055600160d155620004ff565b600054610100900460ff1680620001165750620001166001600160e01b03620002fb16565b8062000125575060005460ff16155b6200017c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602e81526020018062004d22602e913960400191505060405180910390fd5b600054610100900460ff16158015620001a8576000805460ff1961ff0019909116610100171660011790555b603380546001600160a01b0319166001600160a01b0384811691909117918290556040519116906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a380156200020a576000805461ff00191690555b5050565b600054610100900460ff1680620002335750620002336001600160e01b03620002fb16565b8062000242575060005460ff16155b62000299576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602e81526020018062004d22602e913960400191505060405180910390fd5b600054610100900460ff16158015620002c5576000805460ff1961ff0019909116610100171660011790555b620002db826200030160201b62003faf1760201c565b6099805460ff1916905580156200020a576000805461ff00191690555050565b303b1590565b600054610100900460ff1680620003265750620003266001600160e01b03620002fb16565b8062000335575060005460ff16155b6200038c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602e81526020018062004d22602e913960400191505060405180910390fd5b600054610100900460ff16158015620003b8576000805460ff1961ff0019909116610100171660011790555b620003cc826001600160e01b03620003fb16565b620003e557620003e5826001600160e01b036200041e16565b80156200020a576000805461ff00191690555050565b6000620004188260666200047060201b62002b711790919060201c565b92915050565b62000439816066620004a660201b620041011790919060201c565b6040516001600160a01b038216907f6719d08c1888103bea251a4ed56406bd0c3e69723c8a1686e017e7bbe159b6f890600090a250565b60006001600160a01b0382166200048657600080fd5b506001600160a01b03166000908152602091909152604090205460ff1690565b6001600160a01b038116620004ba57600080fd5b620004cf82826001600160e01b036200047016565b15620004da57600080fd5b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b614813806200050f6000396000f3fe608060405234801561001057600080fd5b506004361061018e5760003560e01c8063894e9a0d116100de578063a82ccd4d11610097578063cc1b4bf611610071578063cc1b4bf614610518578063d2cba55c14610558578063ddca3f4314610560578063f2fde38b146105685761018e565b8063a82ccd4d146104a9578063c1eb9ee0146104c6578063c4d66de8146104f25761018e565b8063894e9a0d146103925780638c9a3252146104025780638da5cb5b146104435780638f32d59b146104675780639012c4a81461046f578063a734d51b1461048c5761018e565b80635c975abb1161014b5780638129fc1c116101255780638129fc1c146103105780638195aeaa1461031857806382dc1ec4146103645780638456cb591461038a5761018e565b80635c975abb146102c85780636db9241b146102d05780637a9b2c6c146102ed5761018e565b8063131b9c04146101935780631e99d569146101cb5780632b8a119d146101d35780633656eec2146102585780633f4ba83a1461028457806346fbf68e1461028e575b600080fd5b6101b9600480360360208110156101a957600080fd5b50356001600160a01b031661058e565b60408051918252519081900360200190f35b6101b961066e565b6101f0600480360360208110156101e957600080fd5b5035610674565b604080516001600160a01b039c8d1681529a8c1660208c01528a810199909952969099166060890152608088019490945260a087019290925260c086015260e08501526101008401526101208301939093526101408201929092529051908190036101600190f35b6101b96004803603604081101561026e57600080fd5b50803590602001356001600160a01b03166108a1565b61028c610b7e565b005b6102b4600480360360208110156102a457600080fd5b50356001600160a01b0316610c67565b604080519115158252519081900360200190f35b6102b4610c80565b6102b4600480360360208110156102e657600080fd5b5035610c89565b6102b46004803603604081101561030357600080fd5b5080359060200135610dbc565b61028c611063565b6101b9600480360360e081101561032e57600080fd5b506001600160a01b0381358116916020810135916040820135169060608101359060808101359060a08101359060c0013561110a565b61028c6004803603602081101561037a57600080fd5b50356001600160a01b03166114ec565b61028c61153b565b6103af600480360360208110156103a857600080fd5b5035611602565b604080516001600160a01b03998a168152978916602089015287810196909652939096166060860152608085019190915260a084015260c083019390935260e08201929092529051908190036101000190f35b6104256004803603604081101561041857600080fd5b50803590602001356116ce565b60408051938452602084019290925282820152519081900360600190f35b61044b611e1d565b604080516001600160a01b039092168252519081900360200190f35b6102b4611e2c565b61028c6004803603602081101561048557600080fd5b5035611e52565b6102b4600480360360208110156104a257600080fd5b5035611f4e565b6101b9600480360360208110156104bf57600080fd5b5035611f66565b61028c600480360360408110156104dc57600080fd5b506001600160a01b038135169060200135612098565b61028c6004803603602081101561050857600080fd5b50356001600160a01b031661239f565b6101b9600480360360a081101561052e57600080fd5b506001600160a01b0381358116916020810135916040820135169060608101359060800135612455565b61044b612ad9565b6101b9612ae8565b61028c6004803603602081101561057e57600080fd5b50356001600160a01b0316612aee565b60ce5460408051632f52e59560e01b81526001600160a01b03848116600483015291516000939290921691632f52e59591602480820192602092909190829003018186803b1580156105df57600080fd5b505afa1580156105f3573d6000803e3d6000fd5b505050506040513d602081101561060957600080fd5b5051610652576040805162461bcd60e51b81526020600482015260136024820152723a37b5b2b71034b9903737ba1031aa37b5b2b760691b604482015290519081900360640190fd5b506001600160a01b0316600090815260cf602052604090205490565b60d15481565b60008060008060008060008060008060008b60d2600082815260200190815260200160002060070160149054906101000a900460ff166106e9576040805162461bcd60e51b8152602060048201526015602482015260008051602061456e833981519152604482015290519081900360640190fd5b60008d815260cd60205260409020600301548d9060ff1661073b5760405162461bcd60e51b81526004018080602001828103825260218152602001806144d36021913960400191505060405180910390fd5b60d260008f815260200190815260200160002060060160009054906101000a90046001600160a01b03169c5060d260008f815260200190815260200160002060050160009054906101000a90046001600160a01b03169b5060d260008f8152602001908152602001600020600001549a5060d260008f815260200190815260200160002060070160009054906101000a90046001600160a01b0316995060d260008f815260200190815260200160002060030154985060d260008f815260200190815260200160002060040154975060d260008f815260200190815260200160002060020154965060d260008f815260200190815260200160002060010154955060cd60008f815260200190815260200160002060000160000154945060cd60008f815260200190815260200160002060010160000154935060cd60008f8152602001908152602001600020600201600001549250505091939597999b90929496989a50565b600082815260d260205260408120600701548390600160a01b900460ff166108fe576040805162461bcd60e51b8152602060048201526015602482015260008051602061456e833981519152604482015290519081900360640190fd5b6109066141fd565b50600084815260d2602090815260409182902082516101208101845281548152600182015492810192909252600281015492820192909252600382015460608201526004820154608082015260058201546001600160a01b0390811660a08301526006830154811660c083015260079092015491821660e0820152600160a01b90910460ff16151561010082015261099c614266565b60006109a787611f66565b90506109b7818460200151612b08565b60208401819052838260038111156109cb57fe5b60038111156109d657fe5b90525060009050825160038111156109ea57fe5b14610a265760405162461bcd60e51b81526004018080602001828103825260238152602001806147856023913960400191505060405180910390fd5b604083015183511115610acb57610a4583600001518460400151612b4a565b6040840181905283826003811115610a5957fe5b6003811115610a6457fe5b9052506000905082516003811115610a7857fe5b14610a7f57fe5b610a9182602001518360400151612b4a565b6020840181905283826003811115610aa557fe5b6003811115610ab057fe5b9052506000905082516003811115610ac457fe5b14610acb57fe5b8260a001516001600160a01b0316866001600160a01b03161415610af75750602001519250610b779050565b8260c001516001600160a01b0316866001600160a01b03161415610b6f57610b2783604001518360200151612b4a565b6060840181905283826003811115610b3b57fe5b6003811115610b4657fe5b9052506000905082516003811115610b5a57fe5b14610b6157fe5b50606001519250610b779050565b600094505050505b5092915050565b610b8e610b89612b6d565b610c67565b610bc95760405162461bcd60e51b81526004018080602001828103825260308152602001806145176030913960400191505060405180910390fd5b60995460ff16610c17576040805162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015290519081900360640190fd5b6099805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa610c4a612b6d565b604080516001600160a01b039092168252519081900360200190a1565b6000610c7a60668363ffffffff612b7116565b92915050565b60995460ff1690565b609a805460010190819055600082815260d260205260408120600701549091908390600160a01b900460ff16610cf4576040805162461bcd60e51b8152602060048201526015602482015260008051602061456e833981519152604482015290519081900360640190fd5b600084815260d2602052604090206006015484906001600160a01b0316331480610d375750600081815260d260205260409020600501546001600160a01b031633145b610d725760405162461bcd60e51b81526004018080602001828103825260378152602001806147a86037913960400191505060405180910390fd5b600085815260cd602052604090206003015460ff16610d9957610d9485612ba6565b610da2565b610da285612ef4565b600193505050609a548114610db657600080fd5b50919050565b60995460009060ff1615610e0a576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b609a805460010190819055600084815260d260205260409020600701548490600160a01b900460ff16610e72576040805162461bcd60e51b8152602060048201526015602482015260008051602061456e833981519152604482015290519081900360640190fd5b600085815260d2602052604090206006015485906001600160a01b0316331480610eb55750600081815260d260205260409020600501546001600160a01b031633145b610ef05760405162461bcd60e51b81526004018080602001828103825260378152602001806147a86037913960400191505060405180910390fd5b60008511610f36576040805162461bcd60e51b815260206004820152600e60248201526d616d6f756e74206973207a65726f60901b604482015290519081900360640190fd5b610f3e6141fd565b50600086815260d26020908152604080832081516101208101835281548152600182015493810193909352600281015491830191909152600381015460608301526004810154608083015260058101546001600160a01b0390811660a084018190526006830154821660c085015260079092015490811660e0840152600160a01b900460ff161515610100830152909190610fda9089906108a1565b90508681101561101b5760405162461bcd60e51b815260040180806020018281038252602481526020018061458e6024913960400191505060405180910390fd5b600088815260cd602052604090206003015460ff166110435761103e8888613504565b61104d565b61104d8888613797565b6001955050505050609a548114610b7757600080fd5b600054610100900460ff168061107c575061107c613d7e565b8061108a575060005460ff16155b6110c55760405162461bcd60e51b815260040180806020018281038252602e815260200180614712602e913960400191505060405180910390fd5b600054610100900460ff161580156110f0576000805460ff1961ff0019909116610100171660011790555b6001609a558015611107576000805461ff00191690555b50565b60995460009060ff1615611158576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b60ce5460408051632f52e59560e01b81526001600160a01b03898116600483015291519190921691632f52e595916024808301926020929190829003018186803b1580156111a557600080fd5b505afa1580156111b9573d6000803e3d6000fd5b505050506040513d60208110156111cf57600080fd5b505161121e576040805162461bcd60e51b815260206004820152601960248201527818d51bdad95b881a5cc81b9bdd081dda1a5d195b1a5cdd1959603a1b604482015290519081900360640190fd5b61122661428f565b6112308484613d84565b602083018190528282600381111561124457fe5b600381111561124f57fe5b905250600090508151600381111561126357fe5b146112b5576040805162461bcd60e51b815260206004820152601b60248201527f73686172652073756d2063616c63756c6174696f6e206572726f720000000000604482015290519081900360640190fd5b806020015160641461130e576040805162461bcd60e51b815260206004820152601b60248201527f73686172657320646f206e6f742073756d20757020746f203130300000000000604482015290519081900360640190fd5b600061131d8a8a8a8a8a612455565b905061133085662386f26fc10000612b08565b606084018190528382600381111561134457fe5b600381111561134f57fe5b905250600090508251600381111561136357fe5b1461136a57fe5b61137b84662386f26fc10000612b08565b608084018190528382600381111561138f57fe5b600381111561139a57fe5b90525060009050825160038111156113ae57fe5b146113b557fe5b6000886001600160a01b031663bd6d894d6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156113f257600080fd5b505af1158015611406573d6000803e3d6000fd5b505050506040513d602081101561141c57600080fd5b50516040805160a08101825260808082018481528252825160208082018552606089810151835281850192835285518083018752938a01518452848601938452600181860181815260008b815260cd8552889020965151875593515190860155925151600285015590516003909301805460ff19169315159390931790925582518481529182018a9052818301899052915192935084927fa9bbfc8562a8e1e6b889a428f128c90ed60c6204c37e4fb4354a202b4db59204929181900390910190a2509998505050505050505050565b6114f7610b89612b6d565b6115325760405162461bcd60e51b81526004018080602001828103825260308152602001806145176030913960400191505060405180910390fd5b61110781613daa565b611546610b89612b6d565b6115815760405162461bcd60e51b81526004018080602001828103825260308152602001806145176030913960400191505060405180910390fd5b60995460ff16156115cc576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b6099805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258610c4a612b6d565b6000806000806000806000808860d2600082815260200190815260200160002060070160149054906101000a900460ff16611672576040805162461bcd60e51b8152602060048201526015602482015260008051602061456e833981519152604482015290519081900360640190fd5b5050506000968752505060d26020525050604090922060068101546005820154825460078401546003850154600486015460028701546001909701546001600160a01b039687169a958716995093975091909416949092909190565b600082815260d26020526040812060070154819081908590600160a01b900460ff1661172f576040805162461bcd60e51b8152602060048201526015602482015260008051602061456e833981519152604482015290519081900360640190fd5b600086815260cd602052604090206003015460ff166117575760009350839250829150611e15565b61175f6141fd565b50600086815260d2602090815260409182902082516101208101845281548152600182015492810192909252600281015492820192909252600382015460608201526004820154608082015260058201546001600160a01b0390811660a08301526006830154811660c083015260079092015491821660e0820152600160a01b90910460ff1615156101008201526117f56142bf565b50600087815260cd6020908152604091829020825160a08101845281546080820190815281528351808401855260018301548152818401528351928301845260028201548352928301919091526003015460ff16151560608201526118586142f9565b611860614382565b60405180602001604052808560e001516001600160a01b031663bd6d894d6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156118aa57600080fd5b505af11580156118be573d6000803e3d6000fd5b505050506040513d60208110156118d457600080fd5b505190528351518151919250106118f9575060009650869550859450611e1592505050565b611907818460000151613df2565b602084018190528382600381111561191b57fe5b600381111561192657fe5b905250600090508251600381111561193a57fe5b1461194157fe5b61194f82602001518a613e2c565b604084018190528382600381111561196357fe5b600381111561196e57fe5b905250600090508251600381111561198257fe5b146119d4576040805162461bcd60e51b815260206004820152601a60248201527f696e7465726573742063616c63756c6174696f6e206572726f72000000000000604482015290519081900360640190fd5b60d054670de0b6b3a76400001415611a86576119f4826040015182613e94565b610120840181905283826003811115611a0957fe5b6003811115611a1457fe5b9052506000905082516003811115611a2857fe5b14611a645760405162461bcd60e51b81526004018080602001828103825260218152602001806147646021913960400191505060405180910390fd5b600080611a75846101200151613eb7565b91995097509550611e159350505050565b60d054611aad57604080516020810182526000815260c08401528201516060830152611b85565b60408083015181516020810190925260d0548252611aca91613ec6565b60c0840181905283826003811115611ade57fe5b6003811115611ae957fe5b9052506000905082516003811115611afd57fe5b14611b395760405162461bcd60e51b81526004018080602001828103825260228152602001806146196022913960400191505060405180910390fd5b611b4b82604001518360c00151613df2565b6060840181905283826003811115611b5f57fe5b6003811115611b6a57fe5b9052506000905082516003811115611b7e57fe5b14611b8557fe5b611b9782606001518460200151613ec6565b6080840181905283826003811115611bab57fe5b6003811115611bb657fe5b9052506000905082516003811115611bca57fe5b14611c065760405162461bcd60e51b81526004018080602001828103825260218152602001806145d76021913960400191505060405180910390fd5b611c1882606001518360800151613df2565b60a0840181905283826003811115611c2c57fe5b6003811115611c3757fe5b9052506000905082516003811115611c4b57fe5b14611c5257fe5b611c60826080015182613e94565b60e0840181905283826003811115611c7457fe5b6003811115611c7f57fe5b9052506000905082516003811115611c9357fe5b14611ce5576040805162461bcd60e51b815260206004820181905260248201527f73656e64657220696e74657265737420636f6e76657273696f6e206572726f72604482015290519081900360640190fd5b611cf38260a0015182613e94565b610100840181905283826003811115611d0857fe5b6003811115611d1357fe5b9052506000905082516003811115611d2757fe5b14611d635760405162461bcd60e51b815260040180806020018281038252602381526020018061468d6023913960400191505060405180910390fd5b611d718260c0015182613e94565b610120840181905283826003811115611d8657fe5b6003811115611d9157fe5b9052506000905082516003811115611da557fe5b14611de15760405162461bcd60e51b81526004018080602001828103825260218152602001806147646021913960400191505060405180910390fd5b611dee8260e00151613eb7565b611dfc836101000151613eb7565b611e0a846101200151613eb7565b975097509750505050505b509250925092565b6033546001600160a01b031690565b6033546000906001600160a01b0316611e43612b6d565b6001600160a01b031614905090565b611e5a611e2c565b611e6357600080fd5b6064811115611eb9576040805162461bcd60e51b815260206004820152601f60248201527f6665652070657263656e7461676520686967686572207468616e203130302500604482015290519081900360640190fd5b611ec1614395565b611ed282662386f26fc10000612b08565b6020830181905282826003811115611ee657fe5b6003811115611ef157fe5b9052506000905081516003811115611f0557fe5b14611f0c57fe5b60408051602080820183528301519081905260d0555182907f38e229a7f3f9c329892d08eb37c4e91ccac6d12c798d394990ca4f56028ec26690600090a25050565b600090815260cd602052604090206003015460ff1690565b600081815260d260205260408120600701548290600160a01b900460ff16611fc3576040805162461bcd60e51b8152602060048201526015602482015260008051602061456e833981519152604482015290519081900360640190fd5b611fcb6141fd565b50600083815260d26020908152604091829020825161012081018452815481526001820154928101929092526002810154928201929092526003820154606082018190526004830154608083015260058301546001600160a01b0390811660a08401526006840154811660c084015260079093015492831660e0830152600160a01b90920460ff16151561010082015290421161206c576000925050610db6565b8060800151421015612085576060015142039150610db6565b6060810151608090910151039392505050565b6120a0611e2c565b6120a957600080fd5b609a80546001019081905560ce5460408051632f52e59560e01b81526001600160a01b03868116600483015291519190921691632f52e595916024808301926020929190829003018186803b15801561210157600080fd5b505afa158015612115573d6000803e3d6000fd5b505050506040513d602081101561212b57600080fd5b505161217a576040805162461bcd60e51b815260206004820152601960248201527818d51bdad95b881a5cc81b9bdd081dda1a5d195b1a5cdd1959603a1b604482015290519081900360640190fd5b600082116121c0576040805162461bcd60e51b815260206004820152600e60248201526d616d6f756e74206973207a65726f60901b604482015290519081900360640190fd5b6001600160a01b038316600090815260cf60205260409020548211156122175760405162461bcd60e51b815260040180806020018281038252602481526020018061458e6024913960400191505060405180910390fd5b61221f6143ac565b6001600160a01b038416600090815260cf60205260409020546122429084612b4a565b6001600160a01b038616600090815260cf602052604090208190558282600381111561226a57fe5b600381111561227557fe5b905250600090508151600381111561228957fe5b1461229057fe5b60405183906001600160a01b038616907f13e8af02ad3e36f8d82fc8b86dcd67b7ed11f718f0e52fb245d2038eb71856ba90600090a36040805163a9059cbb60e01b81523360048201526024810185905290516001600160a01b0386169163a9059cbb9160448083019260209291908290030181600087803b15801561231557600080fd5b505af1158015612329573d6000803e3d6000fd5b505050506040513d602081101561233f57600080fd5b505161238b576040805162461bcd60e51b8152602060048201526016602482015275746f6b656e207472616e73666572206661696c75726560501b604482015290519081900360640190fd5b50609a54811461239a57600080fd5b505050565b600054610100900460ff16806123b857506123b8613d7e565b806123c6575060005460ff16155b6124015760405162461bcd60e51b815260040180806020018281038252602e815260200180614712602e913960400191505060405180910390fd5b600054610100900460ff1615801561242c576000805460ff1961ff0019909116610100171660011790555b61243582613faf565b6099805460ff191690558015612451576000805461ff00191690555b5050565b60995460009060ff16156124a3576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b6001600160a01b0386166124fe576040805162461bcd60e51b815260206004820152601a60248201527f73747265616d20746f20746865207a65726f2061646472657373000000000000604482015290519081900360640190fd5b6001600160a01b03861630141561255c576040805162461bcd60e51b815260206004820152601d60248201527f73747265616d20746f2074686520636f6e747261637420697473656c66000000604482015290519081900360640190fd5b6001600160a01b0386163314156125b1576040805162461bcd60e51b815260206004820152601460248201527339ba3932b0b6903a37903a34329031b0b63632b960611b604482015290519081900360640190fd5b600085116125f8576040805162461bcd60e51b815260206004820152600f60248201526e6465706f736974206973207a65726f60881b604482015290519081900360640190fd5b428310156126375760405162461bcd60e51b81526004018080602001828103825260218152602001806145f86021913960400191505060405180910390fd5b82821161268b576040805162461bcd60e51b815260206004820152601f60248201527f73746f702074696d65206265666f7265207468652073746172742074696d6500604482015290519081900360640190fd5b6126936143bf565b61269d8385612b4a565b60208301819052828260038111156126b157fe5b60038111156126bc57fe5b90525060009050815160038111156126d057fe5b146126d757fe5b8060200151861015612730576040805162461bcd60e51b815260206004820152601f60248201527f6465706f73697420736d616c6c6572207468616e2074696d652064656c746100604482015290519081900360640190fd5b8060200151868161273d57fe5b061561277a5760405162461bcd60e51b815260040180806020018281038252602281526020018061463b6022913960400191505060405180910390fd5b612788868260200151614067565b604083018190528282600381111561279c57fe5b60038111156127a757fe5b90525060009050815160038111156127bb57fe5b146127c257fe5b600060d154905060405180610120016040528088815260200183604001518152602001888152602001868152602001858152602001896001600160a01b03168152602001336001600160a01b03168152602001876001600160a01b031681526020016001151581525060d26000838152602001908152602001600020600082015181600001556020820151816001015560408201518160020155606082015181600301556080820151816004015560a08201518160050160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060c08201518160060160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060e08201518160070160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506101008201518160070160146101000a81548160ff02191690831515021790555090505061292860d1546001613d84565b60d18190558382600381111561293a57fe5b600381111561294557fe5b905250600090508251600381111561295957fe5b146129ab576040805162461bcd60e51b815260206004820181905260248201527f6e6578742073747265616d2069642063616c63756c6174696f6e206572726f72604482015290519081900360640190fd5b604080516323b872dd60e01b81523360048201523060248201526044810189905290516001600160a01b038816916323b872dd9160648083019260209291908290030181600087803b158015612a0057600080fd5b505af1158015612a14573d6000803e3d6000fd5b505050506040513d6020811015612a2a57600080fd5b5051612a76576040805162461bcd60e51b8152602060048201526016602482015275746f6b656e207472616e73666572206661696c75726560501b604482015290519081900360640190fd5b604080518881526001600160a01b038881166020830152818301889052606082018790529151918a1691339184917f7b01d409597969366dc268d7f957a990d1ca3d3449baf8fb45db67351aecfe789181900360800190a4979650505050505050565b60ce546001600160a01b031681565b60d05481565b612af6611e2c565b612aff57600080fd5b61110781614092565b60008083612b1b57506000905080612b43565b83830283858281612b2857fe5b0414612b3c57506002915060009050612b43565b6000925090505b9250929050565b600080838311612b61575060009050818303612b43565b50600390506000612b43565b3390565b60006001600160a01b038216612b8657600080fd5b506001600160a01b03166000908152602091909152604090205460ff1690565b612bae6141fd565b50600081815260d26020908152604080832081516101208101835281548152600182015493810193909352600281015491830191909152600381015460608301526004810154608083015260058101546001600160a01b0390811660a08401526006820154811660c0840181905260079092015490811660e0840152600160a01b900460ff161515610100830152909190612c4a9084906108a1565b90506000612c5c848460a001516108a1565b600085815260d26020526040812081815560018101829055600281018290556003810182905560048101919091556005810180546001600160a01b0319908116909155600682018054909116905560070180546001600160a81b031916905560e08401519091508115612daa57806001600160a01b031663a9059cbb8560a00151846040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b158015612d2d57600080fd5b505af1158015612d41573d6000803e3d6000fd5b505050506040513d6020811015612d5757600080fd5b5051612daa576040805162461bcd60e51b815260206004820181905260248201527f726563697069656e7420746f6b656e207472616e73666572206661696c757265604482015290519081900360640190fd5b8215612e9157806001600160a01b031663a9059cbb8560c00151856040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b158015612e1457600080fd5b505af1158015612e28573d6000803e3d6000fd5b505050506040513d6020811015612e3e57600080fd5b5051612e91576040805162461bcd60e51b815260206004820152601d60248201527f73656e64657220746f6b656e207472616e73666572206661696c757265000000604482015290519081900360640190fd5b8360a001516001600160a01b03168460c001516001600160a01b0316867fca3e6079b726e7728802a0537949e2d1c7762304fa641fb06eb56daf2ba8c6b98686604051808381526020018281526020019250505060405180910390a45050505050565b612efc6141fd565b50600081815260d2602090815260409182902082516101208101845281548152600182015492810192909252600281015492820192909252600382015460608201526004820154608082015260058201546001600160a01b0390811660a08301526006830154811660c083015260079092015491821660e0820152600160a01b90910460ff161515610100820152612f92614266565b6000612fa2848460c001516108a1565b90506000612fb4858560a001516108a1565b90506000806000612fc588856116ce565b925092509250612fd58584613d84565b6020880181905287826003811115612fe957fe5b6003811115612ff457fe5b905250600090508651600381111561300857fe5b146130445760405162461bcd60e51b81526004018080602001828103825260248152602001806147406024913960400191505060405180910390fd5b61304e8484612b4a565b604088018190528782600381111561306257fe5b600381111561306d57fe5b905250600090508651600381111561308157fe5b146130bd5760405162461bcd60e51b815260040180806020018281038252603b8152602001806146b0603b913960400191505060405180910390fd5b6130cb866040015182612b4a565b60608801819052878260038111156130df57fe5b60038111156130ea57fe5b90525060009050865160038111156130fe57fe5b1461313a5760405162461bcd60e51b81526004018080602001828103825260278152602001806146eb6027913960400191505060405180910390fd5b60e08701516001600160a01b0316600090815260cf60205260409020546131619082613d84565b60e08901516001600160a01b0316600090815260cf602052604090208190558782600381111561318d57fe5b600381111561319857fe5b90525060009050865160038111156131ac57fe5b146131e85760405162461bcd60e51b81526004018080602001828103825260238152602001806144f46023913960400191505060405180910390fd5b600088815260d260209081526040808320838155600180820185905560028083018690556003808401879055600484018790556005840180546001600160a01b03199081169091556006850180549091169055600790930180546001600160a81b031916905560cd855292852085815590810185905591820193909355909101805460ff1916905560e0880151908701511561336357806001600160a01b031663a9059cbb8960c0015189602001516040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b1580156132e657600080fd5b505af11580156132fa573d6000803e3d6000fd5b505050506040513d602081101561331057600080fd5b5051613363576040805162461bcd60e51b815260206004820152601d60248201527f73656e64657220746f6b656e207472616e73666572206661696c757265000000604482015290519081900360640190fd5b60608701511561345257806001600160a01b031663a9059cbb8960a0015189606001516040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b1580156133d557600080fd5b505af11580156133e9573d6000803e3d6000fd5b505050506040513d60208110156133ff57600080fd5b5051613452576040805162461bcd60e51b815260206004820181905260248201527f726563697069656e7420746f6b656e207472616e73666572206661696c757265604482015290519081900360640190fd5b8760a001516001600160a01b03168860c001516001600160a01b03168a7fca3e6079b726e7728802a0537949e2d1c7762304fa641fb06eb56daf2ba8c6b98a602001518b60600151604051808381526020018281526020019250505060405180910390a4604080518581526020810185905280820184905290518a917f5a8a03e48302e0bd2e011a3a2b54d1f849c55497f462f404bf52dce4290456b5919081900360600190a2505050505050505050565b61350c6141fd565b50600082815260d2602090815260409182902082516101208101845281548152600182015492810192909252600281015492820192909252600382015460608201526004820154608082015260058201546001600160a01b0390811660a08301526006830154811660c083015260079092015491821660e0820152600160a01b90910460ff1615156101008201526135a26143ac565b6135b0826040015184612b4a565b600086815260d260205260409020600201819055828260038111156135d157fe5b60038111156135dc57fe5b90525060009050815160038111156135f057fe5b146135f757fe5b600084815260d2602052604090206002015461366d57600084815260d26020526040812081815560018101829055600281018290556003810182905560048101919091556005810180546001600160a01b0319908116909155600682018054909116905560070180546001600160a81b03191690555b8160e001516001600160a01b031663a9059cbb8360a00151856040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b1580156136d557600080fd5b505af11580156136e9573d6000803e3d6000fd5b505050506040513d60208110156136ff57600080fd5b505161374b576040805162461bcd60e51b8152602060048201526016602482015275746f6b656e207472616e73666572206661696c75726560501b604482015290519081900360640190fd5b8160a001516001600160a01b0316847f36c3ab437e6a424ed25dc4bfdeb62706aa06558660fab2dab229d2555adaf89c856040518082815260200191505060405180910390a350505050565b61379f6141fd565b50600082815260d2602090815260409182902082516101208101845281548152600182015492810192909252600281015492820192909252600382015460608201526004820154608082015260058201546001600160a01b0390811660a08301526006830154811660c083015260079092015491821660e0820152600160a01b90910460ff1615156101008201526138356143bf565b600080600061384487876116ce565b9250925092506138548684612b4a565b602086018190528582600381111561386857fe5b600381111561387357fe5b905250600090508451600381111561388757fe5b146138c35760405162461bcd60e51b815260040180806020018281038252603081526020018061465d6030913960400191505060405180910390fd5b6138d1846020015182612b4a565b60408601819052858260038111156138e557fe5b60038111156138f057fe5b905250600090508451600381111561390457fe5b146139405760405162461bcd60e51b81526004018080602001828103825260278152602001806145476027913960400191505060405180910390fd5b61394e856040015187612b4a565b600089815260d2602052604090206002018190558582600381111561396f57fe5b600381111561397a57fe5b905250600090508451600381111561398e57fe5b146139ca5760405162461bcd60e51b81526004018080602001828103825260258152602001806145b26025913960400191505060405180910390fd5b600087815260d26020526040902060020154613a6857600087815260d260209081526040808320838155600180820185905560028083018690556003808401879055600484018790556005840180546001600160a01b03199081169091556006850180549091169055600790930180546001600160a81b031916905560cd9094529184208481559182018490559181019290925501805460ff191690555b60e08501516001600160a01b0316600090815260cf6020526040902054613a8f9082613d84565b60e08701516001600160a01b0316600090815260cf6020526040902081905585826003811115613abb57fe5b6003811115613ac657fe5b9052506000905084516003811115613ada57fe5b14613b165760405162461bcd60e51b81526004018080602001828103825260238152602001806144f46023913960400191505060405180910390fd5b60e08501518315613c0257806001600160a01b031663a9059cbb8760c00151866040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b158015613b8557600080fd5b505af1158015613b99573d6000803e3d6000fd5b505050506040513d6020811015613baf57600080fd5b5051613c02576040805162461bcd60e51b815260206004820152601d60248201527f73656e64657220746f6b656e207472616e73666572206661696c757265000000604482015290519081900360640190fd5b806001600160a01b031663a9059cbb8760a0015187604001516040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b158015613c6a57600080fd5b505af1158015613c7e573d6000803e3d6000fd5b505050506040513d6020811015613c9457600080fd5b5051613ce7576040805162461bcd60e51b815260206004820181905260248201527f726563697069656e7420746f6b656e207472616e73666572206661696c757265604482015290519081900360640190fd5b8560a001516001600160a01b0316887f36c3ab437e6a424ed25dc4bfdeb62706aa06558660fab2dab229d2555adaf89c87604001516040518082815260200191505060405180910390a36040805185815260208101859052808201849052905189917f5a8a03e48302e0bd2e011a3a2b54d1f849c55497f462f404bf52dce4290456b5919081900360600190a25050505050505050565b303b1590565b600080838301848110613d9c57600092509050612b43565b506002915060009050612b43565b613dbb60668263ffffffff61410116565b6040516001600160a01b038216907f6719d08c1888103bea251a4ed56406bd0c3e69723c8a1686e017e7bbe159b6f890600090a250565b6000613dfc614382565b600080613e1186600001518660000151612b4a565b60408051602081019091529081529097909650945050505050565b6000613e36614382565b600080613e47866000015186612b08565b90925090506000826003811115613e5a57fe5b14613e7957506040805160208101909152600081529092509050612b43565b60408051602081019091529081526000969095509350505050565b6000613e9e614382565b83518351613eac919061414d565b915091509250929050565b51670de0b6b3a7640000900490565b6000613ed0614382565b600080613ee586600001518660000151612b08565b90925090506000826003811115613ef857fe5b14613f1757506040805160208101909152600081529092509050612b43565b600080613f2c6706f05b59d3b2000084613d84565b90925090506000826003811115613f3f57fe5b14613f6157506040805160208101909152600081529094509250612b43915050565b600080613f7683670de0b6b3a7640000614067565b90925090506000826003811115613f8957fe5b14613f9057fe5b604080516020810190915290815260009a909950975050505050505050565b600054610100900460ff1680613fc85750613fc8613d7e565b80613fd6575060005460ff16155b6140115760405162461bcd60e51b815260040180806020018281038252602e815260200180614712602e913960400191505060405180910390fd5b600054610100900460ff1615801561403c576000805460ff1961ff0019909116610100171660011790555b61404582610c67565b6140525761405282613daa565b8015612451576000805461ff00191690555050565b6000808261407b5750600190506000612b43565b600083858161408657fe5b04915091509250929050565b6001600160a01b0381166140a557600080fd5b6033546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3603380546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b03811661411457600080fd5b61411e8282612b71565b1561412857600080fd5b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b6000614157614382565b60008061416c86670de0b6b3a7640000612b08565b9092509050600082600381111561417f57fe5b1461419e57506040805160208101909152600081529092509050612b43565b6000806141ab8388614067565b909250905060008260038111156141be57fe5b146141e057506040805160208101909152600081529094509250612b43915050565b604080516020810190915290815260009890975095505050505050565b604051806101200160405280600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b031681526020016000151581525090565b604080516080810190915280600081526020016000815260200160008152602001600081525090565b6040805160a081019091528060008152602001600081526020016000815260200160008152602001600081525090565b60405180608001604052806142d2614382565b81526020016142df614382565b81526020016142ec614382565b8152600060209091015290565b6040805161014081019091528060008152602001614315614382565b8152602001614322614382565b815260200161432f614382565b815260200161433c614382565b8152602001614349614382565b8152602001614356614382565b8152602001614363614382565b8152602001614370614382565b815260200161437d614382565b905290565b6040518060200160405280600081525090565b604080518082019091526000808252602082015290565b604080516020810190915280600061437d565b6040805160608101909152806000815260200160008152602001600081525090565b600054610100900460ff16806143fa57506143fa613d7e565b80614408575060005460ff16155b6144435760405162461bcd60e51b815260040180806020018281038252602e815260200180614712602e913960400191505060405180910390fd5b600054610100900460ff1615801561446e576000805460ff1961ff0019909116610100171660011790555b603380546001600160a01b0319166001600160a01b0384811691909117918290556040519116906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a38015612451576000805461ff0019169055505056fe636f6d706f756e64696e672073747265616d20646f6573206e6f742065786973746561726e696e6773206164646974696f6e2063616c63756c6174696f6e206572726f72506175736572526f6c653a2063616c6c657220646f6573206e6f742068617665207468652050617573657220726f6c656e6574207769746864726177616c20616d6f756e742063616c63756c6174696f6e206572726f7273747265616d20646f6573206e6f742065786973740000000000000000000000616d6f756e7420657863656564732074686520617661696c61626c652062616c616e636562616c616e6365207375627472616374696f6e2063616c63756c6174696f6e206572726f7273656e64657220696e7465726573742063616c63756c6174696f6e206572726f7273746172742074696d65206265666f726520626c6f636b2e74696d657374616d707361626c69657220696e7465726573742063616c63756c6174696f6e206572726f726465706f736974206e6f74206d756c7469706c65206f662074696d652064656c7461616d6f756e7420776974686f75742073656e64657220696e7465726573742063616c63756c6174696f6e206572726f72726563697069656e7420696e74657265737420636f6e76657273696f6e206572726f72726563697069656e742062616c616e636520776974686f75742073656e64657220696e7465726573742063616c63756c6174696f6e206572726f726e657420726563697069656e742062616c616e63652063616c63756c6174696f6e206572726f72436f6e747261637420696e7374616e63652068617320616c7265616479206265656e20696e697469616c697a65646e65742073656e6465722062616c616e63652063616c63756c6174696f6e206572726f727361626c69657220696e74657265737420636f6e76657273696f6e206572726f72726563697069656e742062616c616e63652063616c63756c6174696f6e206572726f7263616c6c6572206973206e6f74207468652073656e646572206f722074686520726563697069656e74206f66207468652073747265616da265627a7a72315820d5ad0c39f51a54f8b3b77f6b8f02e3d034b5fabbacccfa1751ca957d1cd14a2d64736f6c634300050b0032436f6e747261637420696e7374616e63652068617320616c7265616479206265656e20696e697469616c697a656463546f6b656e4d616e6167657220636f6e747261637420697320746865207a65726f2061646472657373000000000000000000000000ee5dfdf2e98fdc572786b9e5649cb8cc93d47a19

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000ee5dfdf2e98fdc572786b9e5649cb8cc93d47a19

-----Decoded View---------------
Arg [0] : cTokenManagerAddress (address): 0xEE5dfDf2e98FdC572786b9E5649cB8Cc93D47a19

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000ee5dfdf2e98fdc572786b9e5649cb8cc93d47a19


Deployed ByteCode Sourcemap

54775:36493:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;54775:36493:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;72129:202;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;72129:202:0;-1:-1:-1;;;;;72129:202:0;;:::i;:::-;;;;;;;;;;;;;;;;55842:27;;;:::i;65201:1286::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;65201:1286:0;;:::i;:::-;;;;-1:-1:-1;;;;;65201:1286:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;62908:1624;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;62908:1624:0;;;;;;-1:-1:-1;;;;;62908:1624:0;;:::i;51222:120::-;;;:::i;:::-;;48425:109;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;48425:109:0;-1:-1:-1;;;;;48425:109:0;;:::i;:::-;;;;;;;;;;;;;;;;;;50429:78;;;:::i;81528:401::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;81528:401:0;;:::i;80386:724::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;80386:724:0;;;;;;;:::i;31285:218::-;;;:::i;77492:2359::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;77492:2359:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;48542:92::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;48542:92:0;-1:-1:-1;;;;;48542:92:0;;:::i;51009:118::-;;;:::i;60742:823::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;60742:823:0;;:::i;:::-;;;;-1:-1:-1;;;;;60742:823:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;67372:4504;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;67372:4504:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;45195:79;;;:::i;:::-;;;;-1:-1:-1;;;;;45195:79:0;;;;;;;;;;;;;;45530:94;;;:::i;58563:696::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;58563:696:0;;:::i;64765:141::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;64765:141:0;;:::i;62002:362::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;62002:362:0;;:::i;59624:834::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;59624:834:0;;;;;;;;:::i;50185:144::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;50185:144:0;-1:-1:-1;;;;;50185:144:0;;:::i;73767:2386::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;73767:2386:0;;;;;;;;;;;;;;;;;;;;;;;;;:::i;55465:35::-;;;:::i;55757:14::-;;;:::i;45801:109::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;45801:109:0;-1:-1:-1;;;;;45801:109:0;;:::i;72129:202::-;72223:13;;:36;;;-1:-1:-1;;;72223:36:0;;-1:-1:-1;;;;;72223:36:0;;;;;;;;;72195:7;;72223:13;;;;;:22;;:36;;;;;;;;;;;;;;;:13;:36;;;5:2:-1;;;;30:1;27;20:12;5:2;72223:36:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;72223:36:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;72223:36:0;72215:68;;;;;-1:-1:-1;;;72215:68:0;;;;;;;;;;;;-1:-1:-1;;;72215:68:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;;72301:22:0;;;;;:8;:22;;;;;;;72129:202::o;55842:27::-;;;;:::o;65201:1286::-;65388:14;65417:17;65449:15;65479:20;65514:17;65546:16;65577:24;65616:21;65652:27;65694:29;65738:32;65303:8;57416:7;:17;57424:8;57416:17;;;;;;;;;;;:26;;;;;;;;;;;;57408:60;;;;;-1:-1:-1;;;57408:60:0;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;57408:60:0;;;;;;;;;;;;;;;57660:32;;;;:22;:32;;;;;:41;;;65346:8;;57660:41;;57652:87;;;;-1:-1:-1;;;57652:87:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;65807:7;:17;65815:8;65807:17;;;;;;;;;;;:24;;;;;;;;;;-1:-1:-1;;;;;65807:24:0;65798:33;;65854:7;:17;65862:8;65854:17;;;;;;;;;;;:27;;;;;;;;;;-1:-1:-1;;;;;65854:27:0;65842:39;;65902:7;:17;65910:8;65902:17;;;;;;;;;;;:25;;;65892:35;;65953:7;:17;65961:8;65953:17;;;;;;;;;;;:30;;;;;;;;;;-1:-1:-1;;;;;65953:30:0;65938:45;;66006:7;:17;66014:8;66006:17;;;;;;;;;;;:27;;;65994:39;;66055:7;:17;66063:8;66055:17;;;;;;;;;;;:26;;;66044:37;;66111:7;:17;66119:8;66111:17;;;;;;;;;;;:34;;;66092:53;;66172:7;:17;66180:8;66172:17;;;;;;;;;;;:31;;;66156:47;;66236:22;:32;66259:8;66236:32;;;;;;;;;;;:52;;:61;;;66214:83;;66332:22;:32;66355:8;66332:32;;;;;;;;;;;:44;;:53;;;66308:77;;66423:22;:32;66446:8;66423:32;;;;;;;;;;;:47;;:56;;;66396:83;;57479:1;65201:1286;;;;;;;;;;;;;;:::o;62908:1624::-;63002:15;57416:17;;;:7;:17;;;;;:26;;;:17;;-1:-1:-1;;;57416:26:0;;;;57408:60;;;;;-1:-1:-1;;;57408:60:0;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;57408:60:0;;;;;;;;;;;;;;;63030:26;;:::i;:::-;-1:-1:-1;63059:17:0;;;;:7;:17;;;;;;;;;63030:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;63030:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;63030:46:0;;;;;;;;;;;63087:30;;:::i;:::-;63130:13;63146:17;63154:8;63146:7;:17::i;:::-;63130:33;;63214:36;63222:5;63229:6;:20;;;63214:7;:36::i;:::-;63189:21;;;63174:76;;;63175:4;63174:76;;;;;;;;;;;;;;;;;;;-1:-1:-1;63285:18:0;;-1:-1:-1;63269:12:0;;:34;;;;;;;;;63261:82;;;;-1:-1:-1;;;63261:82:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;63632:23;;;;63615:14;;:40;63611:478;;;63712:48;63720:6;:14;;;63736:6;:23;;;63712:7;:48::i;:::-;63687:21;;;63672:88;;;63673:4;63672:88;;;;;;;;;;;;;;;;;;;-1:-1:-1;63798:18:0;;-1:-1:-1;63782:12:0;;:34;;;;;;;;;63775:42;;;;63872:53;63880:4;:21;;;63903:4;:21;;;63872:7;:53::i;:::-;63847:21;;;63832:93;;;63833:4;63832:93;;;;;;;;;;;;;;;;;;;-1:-1:-1;64058:18:0;;-1:-1:-1;64042:12:0;;:34;;;;;;;;;64035:42;;;;64112:6;:16;;;-1:-1:-1;;;;;64105:23:0;:3;-1:-1:-1;;;;;64105:23:0;;64101:57;;;-1:-1:-1;64137:21:0;;;;-1:-1:-1;64130:28:0;;-1:-1:-1;64130:28:0;64101:57;64180:6;:13;;;-1:-1:-1;;;;;64173:20:0;:3;-1:-1:-1;;;;;64173:20:0;;64169:337;;;64247:55;64255:6;:23;;;64280:4;:21;;;64247:7;:55::i;:::-;64225:18;;;64210:92;;;64211:4;64210:92;;;;;;;;;;;;;;;;;;;-1:-1:-1;64435:18:0;;-1:-1:-1;64419:12:0;;:34;;;;;;;;;64412:42;;;;-1:-1:-1;64476:18:0;;;;-1:-1:-1;64469:25:0;;-1:-1:-1;64469:25:0;64169:337;64523:1;64516:8;;;;;57479:1;62908:1624;;;;;:::o;51222:120::-;48322:22;48331:12;:10;:12::i;:::-;48322:8;:22::i;:::-;48314:83;;;;-1:-1:-1;;;48314:83:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;50865:7;;;;50857:40;;;;;-1:-1:-1;;;50857:40:0;;;;;;;;;;;;-1:-1:-1;;;50857:40:0;;;;;;;;;;;;;;;51281:7;:15;;-1:-1:-1;;51281:15:0;;;51312:22;51321:12;:10;:12::i;:::-;51312:22;;;-1:-1:-1;;;;;51312:22:0;;;;;;;;;;;;;;51222:120::o;48425:109::-;48481:4;48505:21;:8;48518:7;48505:21;:12;:21;:::i;:::-;48498:28;48425:109;-1:-1:-1;;48425:109:0:o;50429:78::-;50492:7;;;;50429:78;:::o;81528:401::-;31922:13;:18;;31939:1;31922:18;;;;;-1:-1:-1;57416:17:0;;;:7;:17;;;;;:26;;;-1:-1:-1;;31922:18:0;57416:17;;-1:-1:-1;;;57416:26:0;;;;57408:60;;;;;-1:-1:-1;;;57408:60:0;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;57408:60:0;;;;;;;;;;;;;;;57095:17;;;;:7;:17;;;;;:24;;;:17;;-1:-1:-1;;;;;57095:24:0;57081:10;:38;;:83;;-1:-1:-1;57137:17:0;;;;:7;:17;;;;;:27;;;-1:-1:-1;;;;;57137:27:0;57123:10;:41;57081:83;57059:188;;;;-1:-1:-1;;;57059:188:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;81726:32;;;;:22;:32;;;;;:41;;;;;81721:179;;81784:30;81805:8;81784:20;:30::i;:::-;81721:179;;;81847:41;81879:8;81847:31;:41::i;:::-;81917:4;81910:11;;57479:1;31998;32034:13;;32018:12;:29;32010:38;;;;;;81528:401;;;;:::o;80386:724::-;50666:7;;80602:4;;50666:7;;50665:8;50657:37;;;;;-1:-1:-1;;;50657:37:0;;;;;;;;;;;;-1:-1:-1;;;50657:37:0;;;;;;;;;;;;;;;31922:13;:18;;31939:1;31922:18;;;;;-1:-1:-1;57416:17:0;;;:7;:17;;;;;:26;;;:17;;-1:-1:-1;;;57416:26:0;;;;57408:60;;;;;-1:-1:-1;;;57408:60:0;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;57408:60:0;;;;;;;;;;;;;;;57095:17;;;;:7;:17;;;;;:24;;;:17;;-1:-1:-1;;;;;57095:24:0;57081:10;:38;;:83;;-1:-1:-1;57137:17:0;;;;:7;:17;;;;;:27;;;-1:-1:-1;;;;;57137:27:0;57123:10;:41;57081:83;57059:188;;;;-1:-1:-1;;;57059:188:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;80641:1;80632:6;:10;80624:37;;;;;-1:-1:-1;;;80624:37:0;;;;;;;;;;;;-1:-1:-1;;;80624:37:0;;;;;;;;;;;;;;;80672:26;;:::i;:::-;-1:-1:-1;80701:17:0;;;;:7;:17;;;;;;;;80672:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;80672:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;80672:46:0;;;;;;;;;;;;80701:17;80747:37;;80701:17;;80747:9;:37::i;:::-;80729:55;;80814:6;80803:7;:17;;80795:66;;;;-1:-1:-1;;;80795:66:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;80879:32;;;;:22;:32;;;;;:41;;;;;80874:207;;80937:44;80964:8;80974:6;80937:26;:44::i;:::-;80874:207;;;81014:55;81052:8;81062:6;81014:37;:55::i;:::-;81098:4;81091:11;;;;57479:1;31998;32034:13;;32018:12;:29;32010:38;;;;;31285:218;1118:12;;;;;;;;:31;;;1134:15;:13;:15::i;:::-;1118:47;;;-1:-1:-1;1154:11:0;;;;1153:12;1118:47;1110:106;;;;-1:-1:-1;;;1110:106:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1225:19;1248:12;;;;;;1247:13;1267:83;;;;1296:12;:19;;-1:-1:-1;;;;1296:19:0;;;;;1324:18;1311:4;1324:18;;;1267:83;31494:1;31478:13;:17;1368:57;;;;1412:5;1397:20;;-1:-1:-1;;1397:20:0;;;1368:57;31285:218;:::o;77492:2359::-;50666:7;;77787;;50666;;50665:8;50657:37;;;;;-1:-1:-1;;;50657:37:0;;;;;;;;;;;;-1:-1:-1;;;50657:37:0;;;;;;;;;;;;;;;77815:13;;:36;;;-1:-1:-1;;;77815:36:0;;-1:-1:-1;;;;;77815:36:0;;;;;;;;;:13;;;;;:22;;:36;;;;;;;;;;;;;;:13;:36;;;5:2:-1;;;;30:1;27;20:12;5:2;77815:36:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;77815:36:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;77815:36:0;77807:74;;;;;-1:-1:-1;;;77807:74:0;;;;;;;;;;;;-1:-1:-1;;;77807:74:0;;;;;;;;;;;;;;;77892:44;;:::i;:::-;78044:56;78052:21;78075:24;78044:7;:56::i;:::-;78027:13;;;78012:88;;;78013:4;78012:88;;;;;;;;;;;;;;;;;;;-1:-1:-1;78135:18:0;;-1:-1:-1;78119:12:0;;:34;;;;;;;;;78111:74;;;;;-1:-1:-1;;;78111:74:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;78204:4;:13;;;78221:3;78204:20;78196:60;;;;;-1:-1:-1;;;78196:60:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;78269:16;78288:67;78301:9;78312:7;78321:12;78335:9;78346:8;78288:12;:67::i;:::-;78269:86;;78593:42;78601:21;55138:4;78593:7;:42::i;:::-;78565:24;;;78550:85;;;78551:4;78550:85;;;;;;;;;;;;;;;;;;;-1:-1:-1;78851:18:0;;-1:-1:-1;78835:12:0;;:34;;;;;;;;;78828:42;;;;78929:45;78937:24;55138:4;78929:7;:45::i;:::-;78898:27;;;78883:91;;;78884:4;78883:91;;;;;;;;;;;;;;;;;;;-1:-1:-1;79193:18:0;;-1:-1:-1;79177:12:0;;:34;;;;;;;;;79170:42;;;;79286:27;79324:12;-1:-1:-1;;;;;79316:41:0;;:43;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;79316:43:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;79316:43:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;79316:43:0;79405:291;;;79469:38;;;;;79405:291;;;;79469:38;;;79405:291;;79641:43;;79316;79641;;;;;79657:24;;;;;79641:43;;79405:291;;;;;;79567:46;;;;;;;79583:27;;;;79567:46;;-1:-1:-1;;;79405:291:0;;;79532:4;79405:291;;;;;;-1:-1:-1;79370:32:0;;;:22;:32;;;;;:326;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;79370:326:0;;;;;;;;;;;79714:103;;;;;;;;;;;;;;;;;;;79316:43;;-1:-1:-1;79370:32:0;;79714:103;;;;;;;;;;;-1:-1:-1;79835:8:0;77492:2359;-1:-1:-1;;;;;;;;;77492:2359:0:o;48542:92::-;48322:22;48331:12;:10;:12::i;48322:22::-;48314:83;;;;-1:-1:-1;;;48314:83:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;48607:19;48618:7;48607:10;:19::i;51009:118::-;48322:22;48331:12;:10;:12::i;48322:22::-;48314:83;;;;-1:-1:-1;;;48314:83:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;50666:7;;;;50665:8;50657:37;;;;;-1:-1:-1;;;50657:37:0;;;;;;;;;;;;-1:-1:-1;;;50657:37:0;;;;;;;;;;;;;;;51069:7;:14;;-1:-1:-1;;51069:14:0;51079:4;51069:14;;;51099:20;51106:12;:10;:12::i;60742:823::-;60875:14;60904:17;60936:15;60966:20;61001:17;61033:16;61064:24;61103:21;60833:8;57416:7;:17;57424:8;57416:17;;;;;;;;;;;:26;;;;;;;;;;;;57408:60;;;;;-1:-1:-1;;;57408:60:0;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;57408:60:0;;;;;;;;;;;;;;;-1:-1:-1;;;61161:17:0;;;;-1:-1:-1;;61161:7:0;:17;;-1:-1:-1;;61161:17:0;;;;:24;;;;61208:27;;;;61256:25;;61307:30;;;;61360:27;;;;61409:26;;;;61465:34;;;;61161:24;61526:31;;;;-1:-1:-1;;;;;61161:24:0;;;;61208:27;;;;-1:-1:-1;61256:25:0;;-1:-1:-1;61307:30:0;;;;;61409:26;;61465:34;;61526:31;60742:823::o;67372:4504::-;67492:22;57416:17;;;:7;:17;;;;;:26;;;67492:22;;;;57416:17;;-1:-1:-1;;;57416:26:0;;;;57408:60;;;;;-1:-1:-1;;;57408:60:0;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;57408:60:0;;;;;;;;;;;;;;;67589:32;;;;:22;:32;;;;;:41;;;;;67584:91;;67655:1;;-1:-1:-1;67655:1:0;;-1:-1:-1;67655:1:0;;-1:-1:-1;67647:16:0;;67584:91;67685:26;;:::i;:::-;-1:-1:-1;67714:17:0;;;;:7;:17;;;;;;;;;67685:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;67685:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;67685:46:0;;;;;;;;;;;67742:56;;:::i;:::-;-1:-1:-1;67801:32:0;;;;:22;:32;;;;;;;;;67742:91;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;67742:91:0;;;;;;;;;;;;;;;67844:31;;:::i;:::-;68077:30;;:::i;:::-;68110:69;;;;;;;;68134:6;:19;;;-1:-1:-1;;;;;68126:48:0;;:50;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;68126:50:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;68126:50:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;68126:50:0;68110:69;;68226:41;;:50;68194:28;;68077:102;;-1:-1:-1;;68190:131:0;;-1:-1:-1;68301:1:0;;-1:-1:-1;68301:1:0;;-1:-1:-1;68301:1:0;;-1:-1:-1;68293:16:0;;-1:-1:-1;;;68293:16:0;68190:131;68372:70;68379:19;68400:21;:41;;;68372:6;:70::i;:::-;68346:22;;;68331:111;;;68332:4;68331:111;;;;;;;;;;;;;;;;;;;-1:-1:-1;68476:18:0;;-1:-1:-1;68460:12:0;;:34;;;;;;;;;68453:42;;;;68652:41;68662:4;:22;;;68686:6;68652:9;:41::i;:::-;68625:23;;;68610:83;;;68611:4;68610:83;;;;;;;;;;;;;;;;;;;-1:-1:-1;68728:18:0;;-1:-1:-1;68712:12:0;;:34;;;;;;;;;68704:73;;;;;-1:-1:-1;;;68704:73:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;68849:3;:12;55027:4;68849:30;68845:1266;;;68935:52;68942:4;:23;;;68967:19;68935:6;:52::i;:::-;68911:20;;;68896:91;;;68897:4;68896:91;;;;;;;;;;;;;;;;;;;-1:-1:-1;69026:18:0;;-1:-1:-1;69010:12:0;;:34;;;;;;;;;69002:80;;;;-1:-1:-1;;;69002:80:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;69105:1;69108;69111:30;69120:4;:20;;;69111:8;:30::i;:::-;69097:45;;-1:-1:-1;69097:45:0;-1:-1:-1;69097:45:0;-1:-1:-1;69097:45:0;;-1:-1:-1;;;;69097:45:0;68845:1266;69164:3;:12;69160:951;;69231:20;;;;;;;;-1:-1:-1;69231:20:0;;69198:30;;;:53;69295:23;;;69266:26;;;:52;69160:951;;;69407:23;;;;;69400:36;;;;;;;;69432:3;69400:36;;;;;:6;:36::i;:::-;69366:30;;;69351:85;;;69352:4;69351:85;;;;;;;;;;;;;;;;;;;-1:-1:-1;69475:18:0;;-1:-1:-1;69459:12:0;;:34;;;;;;;;;69451:81;;;;-1:-1:-1;;;69451:81:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;69683:112;69708:4;:23;;;69750:4;:30;;;69683:6;:112::i;:::-;69653:26;;;69638:157;;;69639:4;69638:157;;;;;;;;;;;;;;;;;;;-1:-1:-1;70080:18:0;;-1:-1:-1;70064:12:0;;:34;;;;;;;;;70057:42;;;;70232:106;70253:4;:26;;;70294:21;:33;;;70232:6;:106::i;:::-;70199:29;;;70184:154;;;70185:4;70184:154;;;;;;;;;;;;;;;;;;;-1:-1:-1;70373:18:0;;-1:-1:-1;70357:12:0;;:34;;;;;;;;;70349:80;;;;-1:-1:-1;;;70349:80:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;70557:102;70578:4;:26;;;70619:4;:29;;;70557:6;:102::i;:::-;70521:32;;;70506:153;;;70507:4;70506:153;;;;;;;;;;;;;;;;;;;-1:-1:-1;70943:18:0;;-1:-1:-1;70927:12:0;;:34;;;;;;;;;70920:42;;;;71088:58;71095:4;:29;;;71126:19;71088:6;:58::i;:::-;71065:19;;;71050:96;;;71051:4;71050:96;;;;;;;;;;;;;;;;;;;-1:-1:-1;71181:18:0;;-1:-1:-1;71165:12:0;;:34;;;;;;;;;71157:79;;;;;-1:-1:-1;;;71157:79:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;71290:61;71297:4;:32;;;71331:19;71290:6;:61::i;:::-;71264:22;;;71249:102;;;71250:4;71249:102;;;;;;;;;;;;;;;;;;;-1:-1:-1;71386:18:0;;-1:-1:-1;71370:12:0;;:34;;;;;;;;;71362:82;;;;-1:-1:-1;;;71362:82:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;71496:59;71503:4;:30;;;71535:19;71496:6;:59::i;:::-;71472:20;;;71457:98;;;71458:4;71457:98;;;;;;;;;;;;;;;;;;;-1:-1:-1;71590:18:0;;-1:-1:-1;71574:12:0;;:34;;;;;;;;;71566:80;;;;-1:-1:-1;;;71566:80:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;71772:29;71781:4;:19;;;71772:8;:29::i;:::-;71803:32;71812:4;:22;;;71803:8;:32::i;:::-;71837:30;71846:4;:20;;;71837:8;:30::i;:::-;71764:104;;;;;;;;;;57479:1;67372:4504;;;;;;:::o;45195:79::-;45260:6;;-1:-1:-1;;;;;45260:6:0;45195:79;:::o;45530:94::-;45610:6;;45570:4;;-1:-1:-1;;;;;45610:6:0;45594:12;:10;:12::i;:::-;-1:-1:-1;;;;;45594:22:0;;45587:29;;45530:94;:::o;58563:696::-;45407:9;:7;:9::i;:::-;45399:18;;;;;;58660:3;58643:13;:20;;58635:64;;;;;-1:-1:-1;;;58635:64:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;58710:30;;:::i;:::-;58896:34;58904:13;55138:4;58896:7;:34::i;:::-;58876:16;;;58861:69;;;58862:4;58861:69;;;;;;;;;;;;;;;;;;;-1:-1:-1;59138:18:0;;-1:-1:-1;59122:12:0;;:34;;;;;;;;;59115:42;;;;59176:35;;;;;;;;;59192:16;;;59176:35;;;;59170:3;:41;59227:24;59237:13;;59227:24;;-1:-1:-1;;59227:24:0;45428:1;58563:696;:::o;64765:141::-;64833:4;64857:32;;;:22;:32;;;;;:41;;;;;;64765:141::o;62002:362::-;62081:13;57416:17;;;:7;:17;;;;;:26;;;:17;;-1:-1:-1;;;57416:26:0;;;;57408:60;;;;;-1:-1:-1;;;57408:60:0;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;57408:60:0;;;;;;;;;;;;;;;62107:26;;:::i;:::-;-1:-1:-1;62136:17:0;;;;:7;:17;;;;;;;;;62107:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;62107:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;62107:46:0;;;;;;;;;;;;62168:15;:35;62164:49;;62212:1;62205:8;;;;;62164:49;62246:6;:15;;;62228;:33;62224:80;;;62288:16;;;62270:15;:34;;-1:-1:-1;62263:41:0;;62224:80;62340:16;;;;62322:15;;;;;:34;;62002:362;-1:-1:-1;;;62002:362:0:o;59624:834::-;45407:9;:7;:9::i;:::-;45399:18;;;;;;31922:13;:18;;31939:1;31922:18;;;;;59735:13;;:36;;;-1:-1:-1;;;59735:36:0;;-1:-1:-1;;;;;59735:36:0;;;;;;;;;:13;;;;;:22;;:36;;;;;;;;;;;;;;:13;:36;;;5:2:-1;;;;30:1;27;20:12;5:2;59735:36:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;59735:36:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;59735:36:0;59727:74;;;;;-1:-1:-1;;;59727:74:0;;;;;;;;;;;;-1:-1:-1;;;59727:74:0;;;;;;;;;;;;;;;59829:1;59820:6;:10;59812:37;;;;;-1:-1:-1;;;59812:37:0;;;;;;;;;;;;-1:-1:-1;;;59812:37:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;59868:22:0;;;;;;:8;:22;;;;;;:32;-1:-1:-1;59868:32:0;59860:81;;;;-1:-1:-1;;;59860:81:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;59954:33;;:::i;:::-;-1:-1:-1;;;;;60047:22:0;;;;;;:8;:22;;;;;;60039:39;;60071:6;60039:7;:39::i;:::-;-1:-1:-1;;;;;60013:22:0;;59999:12;60013:22;;;:8;:22;;;;;59998:80;;;59999:4;59998:80;;;;;;;;;;;;;;;;;;;-1:-1:-1;60284:18:0;;-1:-1:-1;60268:12:0;;:34;;;;;;;;;60261:42;;;;60321:34;;60348:6;;-1:-1:-1;;;;;60321:34:0;;;;;;;;60374:49;;;-1:-1:-1;;;60374:49:0;;60404:10;60374:49;;;;;;;;;;;;-1:-1:-1;;;;;60374:29:0;;;;;:49;;;;;;;;;;;;;;-1:-1:-1;60374:29:0;:49;;;5:2:-1;;;;30:1;27;20:12;5:2;60374:49:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;60374:49:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;60374:49:0;60366:84;;;;;-1:-1:-1;;;60366:84:0;;;;;;;;;;;;-1:-1:-1;;;60366:84:0;;;;;;;;;;;;;;;31998:1;32034:13;;32018:12;:29;32010:38;;;;;;45428:1;59624:834;;:::o;50185:144::-;1118:12;;;;;;;;:31;;;1134:15;:13;:15::i;:::-;1118:47;;;-1:-1:-1;1154:11:0;;;;1153:12;1118:47;1110:106;;;;-1:-1:-1;;;1110:106:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1225:19;1248:12;;;;;;1247:13;1267:83;;;;1296:12;:19;;-1:-1:-1;;;;1296:19:0;;;;;1324:18;1311:4;1324:18;;;1267:83;50251:44;50288:6;50251:36;:44::i;:::-;50306:7;:15;;-1:-1:-1;;50306:15:0;;;1368:57;;;;1412:5;1397:20;;-1:-1:-1;;1397:20:0;;;1368:57;50185:144;;:::o;73767:2386::-;50666:7;;73941;;50666;;50665:8;50657:37;;;;;-1:-1:-1;;;50657:37:0;;;;;;;;;;;;-1:-1:-1;;;50657:37:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;73974:26:0;;73966:65;;;;;-1:-1:-1;;;73966:65:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;74050:26:0;;74071:4;74050:26;;74042:68;;;;;-1:-1:-1;;;74042:68:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;74129:23:0;;74142:10;74129:23;;74121:56;;;;;-1:-1:-1;;;74121:56:0;;;;;;;;;;;;-1:-1:-1;;;74121:56:0;;;;;;;;;;;;;;;74206:1;74196:7;:11;74188:39;;;;;-1:-1:-1;;;74188:39:0;;;;;;;;;;;;-1:-1:-1;;;74188:39:0;;;;;;;;;;;;;;;74259:15;74246:9;:28;;74238:74;;;;-1:-1:-1;;;74238:74:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;74342:9;74331:8;:20;74323:64;;;;;-1:-1:-1;;;74323:64:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;74400:33;;:::i;:::-;74476:28;74484:8;74494:9;74476:7;:28::i;:::-;74459:13;;;74444:60;;;74445:4;74444:60;;;;;;;;;;;;;;;;;;;-1:-1:-1;74658:18:0;;-1:-1:-1;74642:12:0;;:34;;;;;;;;;74635:42;;;;74773:4;:13;;;74762:7;:24;;74754:68;;;;;-1:-1:-1;;;74754:68:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;74914:4;:13;;;74904:7;:23;;;;;;:28;74896:75;;;;-1:-1:-1;;;74896:75:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;75021:31;75029:7;75038:4;:13;;;75021:7;:31::i;:::-;74999:18;;;74984:68;;;74985:4;74984:68;;;;;;;;;;;;;;;;;;;-1:-1:-1;75190:18:0;;-1:-1:-1;75174:12:0;;:34;;;;;;;;;75167:42;;;;75273:16;75292:12;;75273:31;;75335:350;;;;;;;;75412:7;75335:350;;;;75478:4;:18;;;75335:350;;;;75381:7;75335:350;;;;75590:9;75335:350;;;;75624:8;75335:350;;;;75522:9;-1:-1:-1;;;;;75335:350:0;;;;;75554:10;-1:-1:-1;;;;;75335:350:0;;;;;75661:12;-1:-1:-1;;;;;75335:350:0;;;;;75444:4;75335:350;;;;;75315:7;:17;75323:8;75315:17;;;;;;;;;;;:370;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;75315:370:0;;;;;-1:-1:-1;;;;;75315:370:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;75315:370:0;;;;;-1:-1:-1;;;;;75315:370:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;75315:370:0;;;;;-1:-1:-1;;;;;75315:370:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;75774:33;75782:12;;75804:1;75774:7;:33::i;:::-;75758:12;75743:64;;;75744:4;75743:64;;;;;;;;;;;;;;;;;;;-1:-1:-1;75842:18:0;;-1:-1:-1;75826:12:0;;:34;;;;;;;;;75818:79;;;;;-1:-1:-1;;;75818:79:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;75918:69;;;-1:-1:-1;;;75918:69:0;;75952:10;75918:69;;;;75972:4;75918:69;;;;;;;;;;;;-1:-1:-1;;;;;75918:33:0;;;;;:69;;;;;;;;;;;;;;-1:-1:-1;75918:33:0;:69;;;5:2:-1;;;;30:1;27;20:12;5:2;75918:69:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;75918:69:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;75918:69:0;75910:104;;;;;-1:-1:-1;;;75910:104:0;;;;;;;;;;;;-1:-1:-1;;;75910:104:0;;;;;;;;;;;;;;;76030:89;;;;;;-1:-1:-1;;;;;76030:89:0;;;;;;;;;;;;;;;;;;;;;;;;;76053:10;;76043:8;;76030:89;;;;;;;;;76137:8;73767:2386;-1:-1:-1;;;;;;;73767:2386:0:o;55465:35::-;;;-1:-1:-1;;;;;55465:35:0;;:::o;55757:14::-;;;;:::o;45801:109::-;45407:9;:7;:9::i;:::-;45399:18;;;;;;45874:28;45893:8;45874:18;:28::i;32729:343::-;32785:9;;32817:6;32813:69;;-1:-1:-1;32848:18:0;;-1:-1:-1;32848:18:0;32840:30;;32813:69;32903:5;;;32907:1;32903;:5;:1;32925:5;;;;;:10;32921:144;;-1:-1:-1;32960:26:0;;-1:-1:-1;32988:1:0;;-1:-1:-1;32952:38:0;;32921:144;33031:18;;-1:-1:-1;33051:1:0;-1:-1:-1;32729:343:0;;;;;;:::o;33517:236::-;33573:9;33584:4;33610:1;33605;:6;33601:145;;-1:-1:-1;33636:18:0;;-1:-1:-1;33656:5:0;;;33628:34;;33601:145;-1:-1:-1;33703:27:0;;-1:-1:-1;33732:1:0;33695:39;;13037:90;13109:10;13037:90;:::o;47193:165::-;47265:4;-1:-1:-1;;;;;47290:21:0;;47282:30;;;;;;-1:-1:-1;;;;;;47330:20:0;:11;:20;;;;;;;;;;;;;;;47193:165::o;86680:729::-;86748:26;;:::i;:::-;-1:-1:-1;86777:17:0;;;;:7;:17;;;;;;;;86748:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;86748:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;86748:46:0;;;;;;;;;;;;86777:17;86829:34;;86777:17;;86829:9;:34::i;:::-;86805:58;;86874:24;86901:37;86911:8;86921:6;:16;;;86901:9;:37::i;:::-;86958:17;;;;:7;:17;;;;;86951:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;86951:24:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;86951:24:0;;;87010:19;;;;86874:64;;-1:-1:-1;87045:20:0;;87041:134;;87088:5;-1:-1:-1;;;;;87088:14:0;;87103:6;:16;;;87121;87088:50;;;;;;;;;;;;;-1:-1:-1;;;;;87088:50:0;-1:-1:-1;;;;;87088:50:0;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;87088:50:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;87088:50:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;87088:50:0;87080:95;;;;;-1:-1:-1;;;87080:95:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;87190:17;;87186:109;;87217:5;-1:-1:-1;;;;;87217:14:0;;87232:6;:13;;;87247;87217:44;;;;;;;;;;;;;-1:-1:-1;;;;;87217:44:0;-1:-1:-1;;;;;87217:44:0;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;87217:44:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;87217:44:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;87217:44:0;87209:86;;;;;-1:-1:-1;;;87209:86:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;87351:6;:16;;;-1:-1:-1;;;;;87313:88:0;87336:6;:13;;;-1:-1:-1;;;;;87313:88:0;87326:8;87313:88;87369:13;87384:16;87313:88;;;;;;;;;;;;;;;;;;;;;;;;86680:729;;;;;:::o;88063:3202::-;88142:26;;:::i;:::-;-1:-1:-1;88171:17:0;;;;:7;:17;;;;;;;;;88142:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;88142:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;88142:46:0;;;;;;;;;;;88199:43;;:::i;:::-;88452:21;88476:34;88486:8;88496:6;:13;;;88476:9;:34::i;:::-;88452:58;;88521:24;88548:37;88558:8;88568:6;:16;;;88548:9;:37::i;:::-;88521:64;;88712:22;88736:25;88763:23;88790:75;88815:8;88838:16;88790:10;:75::i;:::-;88711:154;;;;;;89258:38;89266:13;89281:14;89258:7;:38::i;:::-;89233:21;;;89218:78;;;89219:4;89218:78;;;;;;;;;;;;;;;;;;;-1:-1:-1;89331:18:0;;-1:-1:-1;89315:12:0;;:34;;;;;;;;;89307:83;;;;-1:-1:-1;;;89307:83:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;89809:41;89817:16;89835:14;89809:7;:41::i;:::-;89763:42;;;89748:102;;;89749:4;89748:102;;;;;;;;;;;;;;;;;;;-1:-1:-1;89885:18:0;;-1:-1:-1;89869:12:0;;:34;;;;;;;;;89861:106;;;;-1:-1:-1;;;89861:106:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;90021:68;90029:4;:42;;;90073:15;90021:7;:68::i;:::-;89993:24;;;89978:111;;;89979:4;89978:111;;;;;;;;;;;;;;;;;;;-1:-1:-1;90124:18:0;;-1:-1:-1;90108:12:0;;:34;;;;;;;;;90100:86;;;;-1:-1:-1;;;90100:86:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;90347:19;;;;-1:-1:-1;;;;;90338:29:0;;;;;:8;:29;;;;;;90330:55;;90369:15;90330:7;:55::i;:::-;90306:19;;;;-1:-1:-1;;;;;90297:29:0;90283:12;90297:29;;;:8;:29;;;;;90282:103;;;90283:4;90282:103;;;;;;;;;;;;;;;;;;;-1:-1:-1;90420:18:0;;-1:-1:-1;90404:12:0;;:34;;;;;;;;;90396:82;;;;-1:-1:-1;;;90396:82:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;90546:17;;;;:7;:17;;;;;;;;90539:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;90539:24:0;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;90539:24:0;;;90581:22;:32;;;;;90574:39;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;90574:39:0;;;90716:19;;;;90751:21;;;;:25;90747:138;;90799:5;-1:-1:-1;;;;;90799:14:0;;90814:6;:13;;;90829:4;:21;;;90799:52;;;;;;;;;;;;;-1:-1:-1;;;;;90799:52:0;-1:-1:-1;;;;;90799:52:0;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;90799:52:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;90799:52:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;90799:52:0;90791:94;;;;;-1:-1:-1;;;90791:94:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;90900:24;;;;:28;90896:150;;90951:5;-1:-1:-1;;;;;90951:14:0;;90966:6;:16;;;90984:4;:24;;;90951:58;;;;;;;;;;;;;-1:-1:-1;;;;;90951:58:0;-1:-1:-1;;;;;90951:58:0;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;90951:58:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;90951:58:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;90951:58:0;90943:103;;;;;-1:-1:-1;;;90943:103:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;91102:6;:16;;;-1:-1:-1;;;;;91064:104:0;91087:6;:13;;;-1:-1:-1;;;;;91064:104:0;91077:8;91064:104;91120:4;:21;;;91143:4;:24;;;91064:104;;;;;;;;;;;;;;;;;;;;;;;;91184:73;;;;;;;;;;;;;;;;;;;;91196:8;;91184:73;;;;;;;;;;88063:3202;;;;;;;;;:::o;82432:844::-;82522:26;;:::i;:::-;-1:-1:-1;82551:17:0;;;;:7;:17;;;;;;;;;82522:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;82522:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;82522:46:0;;;;;;;;;;;82579:47;;:::i;:::-;82690:40;82698:6;:23;;;82723:6;82690:7;:40::i;:::-;82638:12;82652:17;;;:7;:17;;;;;:34;;82637:93;;;82638:4;82637:93;;;;;;;;;;;;;;;;;;;-1:-1:-1;82987:18:0;;-1:-1:-1;82971:12:0;;:34;;;;;;;;;82964:42;;;;83023:17;;;;:7;:17;;;;;:34;;;83019:69;;83071:17;;;;:7;:17;;;;;83064:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;83064:24:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;83064:24:0;;;83019:69;83116:6;:19;;;-1:-1:-1;;;;;83109:36:0;;83146:6;:16;;;83164:6;83109:62;;;;;;;;;;;;;-1:-1:-1;;;;;83109:62:0;-1:-1:-1;;;;;83109:62:0;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;83109:62:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;83109:62:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;83109:62:0;83101:97;;;;;-1:-1:-1;;;83101:97:0;;;;;;;;;;;;-1:-1:-1;;;83101:97:0;;;;;;;;;;;;;;;83243:6;:16;;;-1:-1:-1;;;;;83214:54:0;83233:8;83214:54;83261:6;83214:54;;;;;;;;;;;;;;;;;;82432:844;;;;:::o;83808:2582::-;83909:26;;:::i;:::-;-1:-1:-1;83938:17:0;;;;:7;:17;;;;;;;;;83909:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;83909:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;83909:46:0;;;;;;;;;;;83966:58;;:::i;:::-;84149:22;84173:25;84200:23;84227:28;84238:8;84248:6;84227:10;:28::i;:::-;84148:107;;;;;;84664:31;84672:6;84680:14;84664:7;:31::i;:::-;84628:32;;;84613:82;;;84614:4;84613:82;;;;;;;;;;;;;;;;;;;-1:-1:-1;84730:18:0;;-1:-1:-1;84714:12:0;;:34;;;;;;;;;84706:95;;;;-1:-1:-1;;;84706:95:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;84855:58;84863:4;:32;;;84897:15;84855:7;:58::i;:::-;84827:24;;;84812:101;;;84813:4;84812:101;;;;;;;;;;;;;;;;;;;-1:-1:-1;84948:18:0;;-1:-1:-1;84932:12:0;;:34;;;;;;;;;84924:86;;;;-1:-1:-1;;;84924:86:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;85151:40;85159:6;:23;;;85184:6;85151:7;:40::i;:::-;85099:12;85113:17;;;:7;:17;;;;;:34;;85098:93;;;85099:4;85098:93;;;;;;;;;;;;;;;;;;;-1:-1:-1;85226:18:0;;-1:-1:-1;85210:12:0;;:34;;;;;;;;;85202:84;;;;-1:-1:-1;;;85202:84:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;85399:17;;;;:7;:17;;;;;:34;;;85395:150;;85462:17;;;;:7;:17;;;;;;;;85455:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;85455:24:0;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;85455:24:0;;;85501:22;:32;;;;;;85494:39;;;;;;;;;;;;;;;;;;;-1:-1:-1;;85494:39:0;;;85395:150;85695:19;;;;-1:-1:-1;;;;;85686:29:0;;;;;:8;:29;;;;;;85678:55;;85717:15;85678:7;:55::i;:::-;85654:19;;;;-1:-1:-1;;;;;85645:29:0;85631:12;85645:29;;;:8;:29;;;;;85630:103;;;85631:4;85630:103;;;;;;;;;;;;;;;;;;;-1:-1:-1;85768:18:0;;-1:-1:-1;85752:12:0;;:34;;;;;;;;;85744:82;;;;-1:-1:-1;;;85744:82:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;85932:19;;;;85967:18;;85963:125;;86008:6;-1:-1:-1;;;;;86008:15:0;;86024:6;:13;;;86039:14;86008:46;;;;;;;;;;;;;-1:-1:-1;;;;;86008:46:0;-1:-1:-1;;;;;86008:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;86008:46:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;86008:46:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;86008:46:0;86000:88;;;;;-1:-1:-1;;;86000:88:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;86107:6;-1:-1:-1;;;;;86107:15:0;;86123:6;:16;;;86141:4;:24;;;86107:59;;;;;;;;;;;;;-1:-1:-1;;;;;86107:59:0;-1:-1:-1;;;;;86107:59:0;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;86107:59:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;86107:59:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;86107:59:0;86099:104;;;;;-1:-1:-1;;;86099:104:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;86250:6;:16;;;-1:-1:-1;;;;;86221:72:0;86240:8;86221:72;86268:4;:24;;;86221:72;;;;;;;;;;;;;;;;;;86309:73;;;;;;;;;;;;;;;;;;;;86321:8;;86309:73;;;;;;;;;;83808:2582;;;;;;;;:::o;1519:476::-;1959:7;1947:20;1982:7;1519:476;:::o;33838:258::-;33894:9;;33931:5;;;33953:6;;;33949:140;;33984:18;;-1:-1:-1;34004:1:0;-1:-1:-1;33976:30:0;;33949:140;-1:-1:-1;34047:26:0;;-1:-1:-1;34075:1:0;;-1:-1:-1;34039:38:0;;48642:122;48699:21;:8;48712:7;48699:21;:12;:21;:::i;:::-;48736:20;;-1:-1:-1;;;;;48736:20:0;;;;;;;;48642:122;:::o;36215:225::-;36282:9;36293:10;;:::i;:::-;36317:15;36334:11;36349:31;36357:1;:10;;;36369:1;:10;;;36349:7;:31::i;:::-;36408:23;;;;;;;;;;;;36316:64;;36408:23;;-1:-1:-1;36215:225:0;-1:-1:-1;;;;;36215:225:0:o;36529:353::-;36598:9;36609:10;;:::i;:::-;36633:14;36649:19;36672:27;36680:1;:10;;;36692:6;36672:7;:27::i;:::-;36632:67;;-1:-1:-1;36632:67:0;-1:-1:-1;36722:18:0;36714:4;:26;;;;;;;;;36710:92;;-1:-1:-1;36771:18:0;;;;;;;;;-1:-1:-1;36771:18:0;;36765:4;;-1:-1:-1;36771:18:0;-1:-1:-1;36757:33:0;;36710:92;36842:31;;;;;;;;;;;;-1:-1:-1;;36842:31:0;;-1:-1:-1;36529:353:0;-1:-1:-1;;;;36529:353:0:o;41504:146::-;41571:9;41582:10;;:::i;:::-;41619;;41631;;41612:30;;41619:10;41612:6;:30::i;:::-;41605:37;;;;41504:146;;;;;:::o;41808:213::-;41990:12;34934:4;41990:23;;;41808:213::o;39477:1136::-;39544:9;39555:10;;:::i;:::-;39581:14;39597:24;39625:31;39633:1;:10;;;39645:1;:10;;;39625:7;:31::i;:::-;39580:76;;-1:-1:-1;39580:76:0;-1:-1:-1;39679:18:0;39671:4;:26;;;;;;;;;39667:92;;-1:-1:-1;39728:18:0;;;;;;;;;-1:-1:-1;39728:18:0;;39722:4;;-1:-1:-1;39728:18:0;-1:-1:-1;39714:33:0;;39667:92;40076:14;;40133:42;34974:10;40155:19;40133:7;:42::i;:::-;40075:100;;-1:-1:-1;40075:100:0;-1:-1:-1;40198:18:0;40190:4;:26;;;;;;;;;40186:92;;-1:-1:-1;40247:18:0;;;;;;;;;-1:-1:-1;40247:18:0;;40241:4;;-1:-1:-1;40247:18:0;-1:-1:-1;40233:33:0;;-1:-1:-1;;40233:33:0;40186:92;40291:14;40307:12;40323:51;40331:32;34934:4;40323:7;:51::i;:::-;40290:84;;-1:-1:-1;40290:84:0;-1:-1:-1;40520:18:0;40512:4;:26;;;;;;;;;40505:34;;;;40580:24;;;;;;;;;;;;-1:-1:-1;;40580:24:0;;-1:-1:-1;39477:1136:0;-1:-1:-1;;;;;;;;39477:1136:0:o;48132:141::-;1118:12;;;;;;;;:31;;;1134:15;:13;:15::i;:::-;1118:47;;;-1:-1:-1;1154:11:0;;;;1153:12;1118:47;1110:106;;;;-1:-1:-1;;;1110:106:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1225:19;1248:12;;;;;;1247:13;1267:83;;;;1296:12;:19;;-1:-1:-1;;;;1296:19:0;;;;;1324:18;1311:4;1324:18;;;1267:83;48203:16;48212:6;48203:8;:16::i;:::-;48198:68;;48236:18;48247:6;48236:10;:18::i;:::-;1372:14;1368:57;;;1412:5;1397:20;;-1:-1:-1;;1397:20:0;;;48132:141;;:::o;33167:215::-;33223:9;;33255:6;33251:77;;-1:-1:-1;33286:26:0;;-1:-1:-1;33314:1:0;33278:38;;33251:77;33348:18;33372:1;33368;:5;;;;;;33340:34;;;;33167:215;;;;;:::o;46060:187::-;-1:-1:-1;;;;;46134:22:0;;46126:31;;;;;;46194:6;;46173:38;;-1:-1:-1;;;;;46173:38:0;;;;46194:6;;46173:38;;46194:6;;46173:38;46222:6;:17;;-1:-1:-1;;;;;;46222:17:0;-1:-1:-1;;;;;46222:17:0;;;;;;;;;;46060:187::o;46645:186::-;-1:-1:-1;;;;;46722:21:0;;46714:30;;;;;;46764:18;46768:4;46774:7;46764:3;:18::i;:::-;46763:19;46755:28;;;;;;-1:-1:-1;;;;;46796:20:0;:11;:20;;;;;;;;;;;:27;;-1:-1:-1;;46796:27:0;46819:4;46796:27;;;46645:186::o;35288:515::-;35349:9;35360:10;;:::i;:::-;35384:14;35400:20;35424:22;35432:3;34934:4;35424:7;:22::i;:::-;35383:63;;-1:-1:-1;35383:63:0;-1:-1:-1;35469:18:0;35461:4;:26;;;;;;;;;35457:92;;-1:-1:-1;35518:18:0;;;;;;;;;-1:-1:-1;35518:18:0;;35512:4;;-1:-1:-1;35518:18:0;-1:-1:-1;35504:33:0;;35457:92;35562:14;35578:13;35595:31;35603:15;35620:5;35595:7;:31::i;:::-;35561:65;;-1:-1:-1;35561:65:0;-1:-1:-1;35649:18:0;35641:4;:26;;;;;;;;;35637:92;;-1:-1:-1;35698:18:0;;;;;;;;;-1:-1:-1;35698:18:0;;35692:4;;-1:-1:-1;35698:18:0;-1:-1:-1;35684:33:0;;-1:-1:-1;;35684:33:0;35637:92;35769:25;;;;;;;;;;;;-1:-1:-1;;35769:25:0;;-1:-1:-1;35288:515:0;-1:-1:-1;;;;;;35288:515:0:o;54775:36493::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;54775:36493:0;;;;;;-1:-1:-1;;;;;54775:36493:0;;;;;;-1:-1:-1;;;;;54775:36493:0;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;-1:-1:-1;54775:36493:0;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;-1:-1:-1;54775:36493:0;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;;;:::o;:::-;;;;;;;;;;;-1:-1:-1;54775:36493:0;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;:::o;:::-;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;-1:-1:-1;54775:36493:0;;;;;;;;:::o;:::-;;;;;;;;;;;-1:-1:-1;54775:36493:0;;;;;;;;;;;;;-1:-1:-1;54775:36493:0;;;;;;;;;;;;;;:::o;44982:145::-;1118:12;;;;;;;;:31;;;1134:15;:13;:15::i;:::-;1118:47;;;-1:-1:-1;1154:11:0;;;;1153:12;1118:47;1110:106;;;;-1:-1:-1;;;1110:106:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1225:19;1248:12;;;;;;1247:13;1267:83;;;;1296:12;:19;;-1:-1:-1;;;;1296:19:0;;;;;1324:18;1311:4;1324:18;;;1267:83;45048:6;:15;;-1:-1:-1;;;;;;45048:15:0;-1:-1:-1;;;;;45048:15:0;;;;;;;;;;;45079:40;;45112:6;;;-1:-1:-1;;45079:40:0;;-1:-1:-1;;45079:40:0;1372:14;1368:57;;;1412:5;1397:20;;-1:-1:-1;;1397:20:0;;;44982:145;;:::o

Swarm Source

bzzr://d5ad0c39f51a54f8b3b77f6b8f02e3d034b5fabbacccfa1751ca957d1cd14a2d
Block Transaction Difficulty Gas Used Reward
Block Uncle Number Difficulty Gas Used Reward
Loading

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.