ETH Price: $3,059.78 (+2.61%)
Gas: 1 Gwei

Contract

0x5bF4fF5D8cbF2961896abC1f7499f361356808bb
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
0x60806040112648902020-11-15 21:21:381329 days ago1605475298IN
 Create: LoanMaintenance
0 ETH0.1064749122

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
LoanMaintenance

Compiler Version
v0.5.17+commit.d19bba13

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, Apache-2.0 license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2020-11-15
*/

/**
 * Copyright 2017-2020, bZeroX, LLC <https://bzx.network/>. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0.
 */

pragma solidity 0.5.17;
pragma experimental ABIEncoderV2;


interface IWeth {
    function deposit() external payable;
    function withdraw(uint256 wad) external;
}

contract IERC20 {
    string public name;
    uint8 public decimals;
    string public symbol;
    function totalSupply() public view returns (uint256);
    function balanceOf(address _who) public view returns (uint256);
    function allowance(address _owner, address _spender) public view returns (uint256);
    function approve(address _spender, uint256 _value) public returns (bool);
    function transfer(address _to, uint256 _value) public returns (bool);
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool);
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

contract IWethERC20 is IWeth, IERC20 {}

contract Constants {

    uint256 internal constant WEI_PRECISION = 10**18;
    uint256 internal constant WEI_PERCENT_PRECISION = 10**20;

    uint256 internal constant DAYS_IN_A_YEAR = 365;
    uint256 internal constant ONE_MONTH = 2628000; // approx. seconds in a month

    string internal constant UserRewardsID = "UserRewards";
    string internal constant LoanDepositValueID = "LoanDepositValue";

    IWethERC20 public constant wethToken = IWethERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
    address public constant bzrxTokenAddress = 0x56d811088235F11C8920698a204A5010a788f4b3;
    address public constant vbzrxTokenAddress = 0xB72B31907C1C95F3650b64b2469e08EdACeE5e8F;
}

/**
 * @dev Library for managing loan sets
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * Include with `using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set;`.
 *
 */
library EnumerableBytes32Set {

    struct Bytes32Set {
        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping (bytes32 => uint256) index;
        bytes32[] values;
    }

    /**
     * @dev Add an address value to a set. O(1).
     * Returns false if the value was already in the set.
     */
    function addAddress(Bytes32Set storage set, address addrvalue)
        internal
        returns (bool)
    {
        bytes32 value;
        assembly {
            value := addrvalue
        }
        return addBytes32(set, value);
    }

    /**
     * @dev Add a value to a set. O(1).
     * Returns false if the value was already in the set.
     */
    function addBytes32(Bytes32Set storage set, bytes32 value)
        internal
        returns (bool)
    {
        if (!contains(set, value)){
            set.index[value] = set.values.push(value);
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes an address value from a set. O(1).
     * Returns false if the value was not present in the set.
     */
    function removeAddress(Bytes32Set storage set, address addrvalue)
        internal
        returns (bool)
    {
        bytes32 value;
        assembly {
            value := addrvalue
        }
        return removeBytes32(set, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     * Returns false if the value was not present in the set.
     */
    function removeBytes32(Bytes32Set storage set, bytes32 value)
        internal
        returns (bool)
    {
        if (contains(set, value)){
            uint256 toDeleteIndex = set.index[value] - 1;
            uint256 lastIndex = set.values.length - 1;

            // If the element we're deleting is the last one, we can just remove it without doing a swap
            if (lastIndex != toDeleteIndex) {
                bytes32 lastValue = set.values[lastIndex];

                // Move the last value to the index where the deleted value is
                set.values[toDeleteIndex] = lastValue;
                // Update the index for the moved value
                set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based
            }

            // Delete the index entry for the deleted value
            delete set.index[value];

            // Delete the old entry for the moved value
            set.values.pop();

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value)
        internal
        view
        returns (bool)
    {
        return set.index[value] != 0;
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function containsAddress(Bytes32Set storage set, address addrvalue)
        internal
        view
        returns (bool)
    {
        bytes32 value;
        assembly {
            value := addrvalue
        }
        return set.index[value] != 0;
    }

    /**
     * @dev Returns an array with all values in the set. O(N).
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.

     * WARNING: This function may run out of gas on large sets: use {length} and
     * {get} instead in these cases.
     */
    function enumerate(Bytes32Set storage set, uint256 start, uint256 count)
        internal
        view
        returns (bytes32[] memory output)
    {
        uint256 end = start + count;
        require(end >= start, "addition overflow");
        end = set.values.length < end ? set.values.length : end;
        if (end == 0 || start >= end) {
            return output;
        }

        output = new bytes32[](end-start);
        for (uint256 i = start; i < end; i++) {
            output[i-start] = set.values[i];
        }
        return output;
    }

    /**
     * @dev Returns the number of elements on the set. O(1).
     */
    function length(Bytes32Set storage set)
        internal
        view
        returns (uint256)
    {
        return set.values.length;
    }

   /** @dev Returns the element stored at position `index` in the set. O(1).
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function get(Bytes32Set storage set, uint256 index)
        internal
        view
        returns (bytes32)
    {
        return set.values[index];
    }

   /** @dev Returns the element stored at position `index` in the set. O(1).
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function getAddress(Bytes32Set storage set, uint256 index)
        internal
        view
        returns (address)
    {
        bytes32 value = set.values[index];
        address addrvalue;
        assembly {
            addrvalue := value
        }
        return addrvalue;
    }
}

/**
 * @title Helps contracts guard against reentrancy attacks.
 * @author Remco Bloemen <remco@2π.com>, Eenae <[email protected]>
 * @dev If you mark a function `nonReentrant`, you should also
 * mark it `external`.
 */
contract ReentrancyGuard {

    /// @dev Constant for unlocked guard state - non-zero to prevent extra gas costs.
    /// See: https://github.com/OpenZeppelin/openzeppelin-solidity/issues/1056
    uint256 internal constant REENTRANCY_GUARD_FREE = 1;

    /// @dev Constant for locked guard state
    uint256 internal constant REENTRANCY_GUARD_LOCKED = 2;

    /**
    * @dev We use a single lock for the whole contract.
    */
    uint256 internal reentrancyLock = REENTRANCY_GUARD_FREE;

    /**
    * @dev Prevents a contract from calling itself, directly or indirectly.
    * If you mark a function `nonReentrant`, you should also
    * mark it `external`. Calling one `nonReentrant` function from
    * another is not supported. Instead, you can implement a
    * `private` function doing the actual work, and an `external`
    * wrapper marked as `nonReentrant`.
    */
    modifier nonReentrant() {
        require(reentrancyLock == REENTRANCY_GUARD_FREE, "nonReentrant");
        reentrancyLock = REENTRANCY_GUARD_LOCKED;
        _;
        reentrancyLock = REENTRANCY_GUARD_FREE;
    }
}

/*
 * @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 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, which should be used via inheritance.
    constructor () internal { }
    // solhint-disable-previous-line no-empty-blocks

    function _msgSender() internal view returns (address payable) {
        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;
    }
}

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
contract Ownable is Context {
    address private _owner;

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor () internal {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

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

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

    /**
     * @dev Returns true if the caller is the current owner.
     */
    function isOwner() public view returns (bool) {
        return _msgSender() == _owner;
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public onlyOwner {
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     */
    function _transferOwnership(address newOwner) internal {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     *
     * _Available since v2.4.0._
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     *
     * _Available since v2.4.0._
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b != 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
    * @dev Integer division of two numbers, rounding up and truncating the quotient
    */
    function divCeil(uint256 a, uint256 b) internal pure returns (uint256) {
        return divCeil(a, b, "SafeMath: division by zero");
    }

    /**
    * @dev Integer division of two numbers, rounding up and truncating the quotient
    */
    function divCeil(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b != 0, errorMessage);

        if (a == 0) {
            return 0;
        }
        uint256 c = ((a - 1) / b) + 1;

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     *
     * _Available since v2.4.0._
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }

    function min256(uint256 _a, uint256 _b) internal pure returns (uint256) {
        return _a < _b ? _a : _b;
    }
}

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following 
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
        // for accounts without code, i.e. `keccak256('')`
        bytes32 codehash;
        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
        // solhint-disable-next-line no-inline-assembly
        assembly { codehash := extcodehash(account) }
        return (codehash != accountHash && codehash != 0x0);
    }

    /**
     * @dev Converts an `address` into `address payable`. Note that this is
     * simply a type cast: the actual underlying value is not changed.
     *
     * _Available since v2.4.0._
     */
    function toPayable(address account) internal pure returns (address payable) {
        return address(uint160(account));
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     *
     * _Available since v2.4.0._
     */
    function sendValue(address recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        // solhint-disable-next-line avoid-call-value
        (bool success, ) = recipient.call.value(amount)("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }
}

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using SafeMath for uint256;
    using Address for address;

    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        // solhint-disable-next-line max-line-length
        require((value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).add(value);
        callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
        callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves.

        // A Solidity high level call has three parts:
        //  1. The target address is checked to verify it contains contract code
        //  2. The call itself is made, and success asserted
        //  3. The return value is decoded, which in turn checks the size of the returned data.
        // solhint-disable-next-line max-line-length
        require(address(token).isContract(), "SafeERC20: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = address(token).call(data);
        require(success, "SafeERC20: low-level call failed");

        if (returndata.length > 0) { // Return data is optional
            // solhint-disable-next-line max-line-length
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

contract LoanStruct {
    struct Loan {
        bytes32 id;                 // id of the loan
        bytes32 loanParamsId;       // the linked loan params id
        bytes32 pendingTradesId;    // the linked pending trades id
        uint256 principal;          // total borrowed amount outstanding
        uint256 collateral;         // total collateral escrowed for the loan
        uint256 startTimestamp;     // loan start time
        uint256 endTimestamp;       // for active loans, this is the expected loan end time, for in-active loans, is the actual (past) end time
        uint256 startMargin;        // initial margin when the loan opened
        uint256 startRate;          // reference rate when the loan opened for converting collateralToken to loanToken
        address borrower;           // borrower of this loan
        address lender;             // lender of this loan
        bool active;                // if false, the loan has been fully closed
    }
}

contract LoanParamsStruct {
    struct LoanParams {
        bytes32 id;                 // id of loan params object
        bool active;                // if false, this object has been disabled by the owner and can't be used for future loans
        address owner;              // owner of this object
        address loanToken;          // the token being loaned
        address collateralToken;    // the required collateral token
        uint256 minInitialMargin;   // the minimum allowed initial margin
        uint256 maintenanceMargin;  // an unhealthy loan when current margin is at or below this value
        uint256 maxLoanTerm;        // the maximum term for new loans (0 means there's no max term)
    }
}

contract OrderStruct {
    struct Order {
        uint256 lockedAmount;           // escrowed amount waiting for a counterparty
        uint256 interestRate;           // interest rate defined by the creator of this order
        uint256 minLoanTerm;            // minimum loan term allowed
        uint256 maxLoanTerm;            // maximum loan term allowed
        uint256 createdTimestamp;       // timestamp when this order was created
        uint256 expirationTimestamp;    // timestamp when this order expires
    }
}

contract LenderInterestStruct {
    struct LenderInterest {
        uint256 principalTotal;     // total borrowed amount outstanding of asset
        uint256 owedPerDay;         // interest owed per day for all loans of asset
        uint256 owedTotal;          // total interest owed for all loans of asset (assuming they go to full term)
        uint256 paidTotal;          // total interest paid so far for asset
        uint256 updatedTimestamp;   // last update
    }
}

contract LoanInterestStruct {
    struct LoanInterest {
        uint256 owedPerDay;         // interest owed per day for loan
        uint256 depositTotal;       // total escrowed interest for loan
        uint256 updatedTimestamp;   // last update
    }
}

contract Objects is
    LoanStruct,
    LoanParamsStruct,
    OrderStruct,
    LenderInterestStruct,
    LoanInterestStruct
{}

contract State is Constants, Objects, ReentrancyGuard, Ownable {
    using SafeMath for uint256;
    using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set;

    address public priceFeeds;                                                              // handles asset reference price lookups
    address public swapsImpl;                                                               // handles asset swaps using dex liquidity

    mapping (bytes4 => address) public logicTargets;                                        // implementations of protocol functions

    mapping (bytes32 => Loan) public loans;                                                 // loanId => Loan
    mapping (bytes32 => LoanParams) public loanParams;                                      // loanParamsId => LoanParams

    mapping (address => mapping (bytes32 => Order)) public lenderOrders;                    // lender => orderParamsId => Order
    mapping (address => mapping (bytes32 => Order)) public borrowerOrders;                  // borrower => orderParamsId => Order

    mapping (bytes32 => mapping (address => bool)) public delegatedManagers;                // loanId => delegated => approved

    // Interest
    mapping (address => mapping (address => LenderInterest)) public lenderInterest;         // lender => loanToken => LenderInterest object
    mapping (bytes32 => LoanInterest) public loanInterest;                                  // loanId => LoanInterest object

    // Internals
    EnumerableBytes32Set.Bytes32Set internal logicTargetsSet;                               // implementations set
    EnumerableBytes32Set.Bytes32Set internal activeLoansSet;                                // active loans set

    mapping (address => EnumerableBytes32Set.Bytes32Set) internal lenderLoanSets;           // lender loans set
    mapping (address => EnumerableBytes32Set.Bytes32Set) internal borrowerLoanSets;         // borrow loans set
    mapping (address => EnumerableBytes32Set.Bytes32Set) internal userLoanParamSets;        // user loan params set

    address public feesController;                                                          // address controlling fee withdrawals

    uint256 public lendingFeePercent = 10 ether; // 10% fee                                 // fee taken from lender interest payments
    mapping (address => uint256) public lendingFeeTokensHeld;                               // total interest fees received and not withdrawn per asset
    mapping (address => uint256) public lendingFeeTokensPaid;                               // total interest fees withdraw per asset (lifetime fees = lendingFeeTokensHeld + lendingFeeTokensPaid)

    uint256 public tradingFeePercent = 0.15 ether; // 0.15% fee                             // fee paid for each trade
    mapping (address => uint256) public tradingFeeTokensHeld;                               // total trading fees received and not withdrawn per asset
    mapping (address => uint256) public tradingFeeTokensPaid;                               // total trading fees withdraw per asset (lifetime fees = tradingFeeTokensHeld + tradingFeeTokensPaid)

    uint256 public borrowingFeePercent = 0.09 ether; // 0.09% fee                           // origination fee paid for each loan
    mapping (address => uint256) public borrowingFeeTokensHeld;                             // total borrowing fees received and not withdrawn per asset
    mapping (address => uint256) public borrowingFeeTokensPaid;                             // total borrowing fees withdraw per asset (lifetime fees = borrowingFeeTokensHeld + borrowingFeeTokensPaid)

    uint256 public protocolTokenHeld;                                                       // current protocol token deposit balance
    uint256 public protocolTokenPaid;                                                       // lifetime total payout of protocol token

    uint256 public affiliateFeePercent = 30 ether; // 30% fee share                         // fee share for affiliate program

    mapping (address => mapping (address => uint256)) public liquidationIncentivePercent;   // percent discount on collateral for liquidators per loanToken and collateralToken

    mapping (address => address) public loanPoolToUnderlying;                               // loanPool => underlying
    mapping (address => address) public underlyingToLoanPool;                               // underlying => loanPool
    EnumerableBytes32Set.Bytes32Set internal loanPoolsSet;                                  // loan pools set

    mapping (address => bool) public supportedTokens;                                       // supported tokens for swaps

    uint256 public maxDisagreement = 5 ether;                                               // % disagreement between swap rate and reference rate

    uint256 public sourceBufferPercent = 5 ether;                                           // used to estimate kyber swap source amount

    uint256 public maxSwapSize = 1500 ether;                                                // maximum supported swap size in ETH


    function _setTarget(
        bytes4 sig,
        address target)
        internal
    {
        logicTargets[sig] = target;

        if (target != address(0)) {
            logicTargetsSet.addBytes32(bytes32(sig));
        } else {
            logicTargetsSet.removeBytes32(bytes32(sig));
        }
    }
}

interface IPriceFeeds {
    function queryRate(
        address sourceToken,
        address destToken)
        external
        view
        returns (uint256 rate, uint256 precision);

    function queryPrecision(
        address sourceToken,
        address destToken)
        external
        view
        returns (uint256 precision);

    function queryReturn(
        address sourceToken,
        address destToken,
        uint256 sourceAmount)
        external
        view
        returns (uint256 destAmount);

    function checkPriceDisagreement(
        address sourceToken,
        address destToken,
        uint256 sourceAmount,
        uint256 destAmount,
        uint256 maxSlippage)
        external
        view
        returns (uint256 sourceToDestSwapRate);

    function amountInEth(
        address Token,
        uint256 amount)
        external
        view
        returns (uint256 ethAmount);

    function getMaxDrawdown(
        address loanToken,
        address collateralToken,
        uint256 loanAmount,
        uint256 collateralAmount,
        uint256 maintenanceMargin)
        external
        view
        returns (uint256);

    function getCurrentMarginAndCollateralSize(
        address loanToken,
        address collateralToken,
        uint256 loanAmount,
        uint256 collateralAmount)
        external
        view
        returns (uint256 currentMargin, uint256 collateralInEthAmount);

    function getCurrentMargin(
        address loanToken,
        address collateralToken,
        uint256 loanAmount,
        uint256 collateralAmount)
        external
        view
        returns (uint256 currentMargin, uint256 collateralToLoanRate);

    function shouldLiquidate(
        address loanToken,
        address collateralToken,
        uint256 loanAmount,
        uint256 collateralAmount,
        uint256 maintenanceMargin)
        external
        view
        returns (bool);

    function getFastGasPrice(
        address payToken)
        external
        view
        returns (uint256);
}

contract FeesEvents {

    enum FeeType {
        Lending,
        Trading,
        Borrowing,
        SettleInterest
    }

    event PayLendingFee(
        address indexed payer,
        address indexed token,
        uint256 amount
    );

    event SettleFeeRewardForInterestExpense(
        address indexed payer,
        address indexed token,
        bytes32 indexed loanId,
        uint256 amount
    );

    event PayTradingFee(
        address indexed payer,
        address indexed token,
        bytes32 indexed loanId,
        uint256 amount
    );

    event PayBorrowingFee(
        address indexed payer,
        address indexed token,
        bytes32 indexed loanId,
        uint256 amount
    );

    event EarnReward(
        address indexed receiver,
        bytes32 indexed loanId,
        FeeType indexed feeType,
        address token,
        uint256 amount
    );
}

contract FeesHelper is State, FeesEvents {
    using SafeERC20 for IERC20;

    // calculate trading fee
    function _getTradingFee(
        uint256 feeTokenAmount)
        internal
        view
        returns (uint256)
    {
        return feeTokenAmount
            .mul(tradingFeePercent)
            .divCeil(WEI_PERCENT_PRECISION);
    }

    // calculate loan origination fee
    function _getBorrowingFee(
        uint256 feeTokenAmount)
        internal
        view
        returns (uint256)
    {
        return feeTokenAmount
            .mul(borrowingFeePercent)
            .divCeil(WEI_PERCENT_PRECISION);
    }

    // settle trading fee
    function _payTradingFee(
        address user,
        bytes32 loanId,
        address feeToken,
        uint256 tradingFee)
        internal
    {
        if (tradingFee != 0) {
            tradingFeeTokensHeld[feeToken] = tradingFeeTokensHeld[feeToken]
                .add(tradingFee);

            emit PayTradingFee(
                user,
                feeToken,
                loanId,
                tradingFee
            );

            _payFeeReward(
                user,
                loanId,
                feeToken,
                tradingFee,
                FeeType.Trading
            );
        }
    }

    // settle loan origination fee
    function _payBorrowingFee(
        address user,
        bytes32 loanId,
        address feeToken,
        uint256 borrowingFee)
        internal
    {
        if (borrowingFee != 0) {
            borrowingFeeTokensHeld[feeToken] = borrowingFeeTokensHeld[feeToken]
                .add(borrowingFee);

            emit PayBorrowingFee(
                user,
                feeToken,
                loanId,
                borrowingFee
            );

            _payFeeReward(
                user,
                loanId,
                feeToken,
                borrowingFee,
                FeeType.Borrowing
            );
        }
    }

    // settle lender (interest) fee
    function _payLendingFee(
        address user,
        address feeToken,
        uint256 lendingFee)
        internal
    {
        if (lendingFee != 0) {
            lendingFeeTokensHeld[feeToken] = lendingFeeTokensHeld[feeToken]
                .add(lendingFee);

            emit PayLendingFee(
                user,
                feeToken,
                lendingFee
            );

             //// NOTE: Lenders do not receive a fee reward ////
        }
    }

    // settles and pays borrowers based on the fees generated by their interest payments
    function _settleFeeRewardForInterestExpense(
        LoanInterest storage loanInterestLocal,
        bytes32 loanId,
        address feeToken,
        address user,
        uint256 interestTime)
        internal
    {
        uint256 updatedTimestamp = loanInterestLocal.updatedTimestamp;

        uint256 interestExpenseFee;
        if (updatedTimestamp != 0) {
            // this represents the fee generated by a borrower's interest payment
            interestExpenseFee = interestTime
                .sub(updatedTimestamp)
                .mul(loanInterestLocal.owedPerDay)
                .mul(lendingFeePercent)
                .div(1 days * WEI_PERCENT_PRECISION);
        }

        loanInterestLocal.updatedTimestamp = interestTime;

        if (interestExpenseFee != 0) {
            emit SettleFeeRewardForInterestExpense(
                user,
                feeToken,
                loanId,
                interestExpenseFee
            );

            _payFeeReward(
                user,
                loanId,
                feeToken,
                interestExpenseFee,
                FeeType.SettleInterest
            );
        }
    }

    // pay protocolToken reward to user
    function _payFeeReward(
        address user,
        bytes32 loanId,
        address feeToken,
        uint256 feeAmount,
        FeeType feeType)
        internal
    {
        // The protocol is designed to allow positions and loans to be closed, if for whatever reason
        // the price lookup is failing, returning 0, or is otherwise paused. Therefore, we allow this
        // call to fail silently, rather than revert, to allow the transaction to continue without a
        // BZRX token reward.
        uint256 rewardAmount;
        address _priceFeeds = priceFeeds;
        (bool success, bytes memory data) = _priceFeeds.staticcall(
            abi.encodeWithSelector(
                IPriceFeeds(_priceFeeds).queryReturn.selector,
                feeToken,
                bzrxTokenAddress, // price rewards using BZRX price rather than vesting token price
                feeAmount / 2  // 50% of fee value
            )
        );
        assembly {
            if eq(success, 1) {
                rewardAmount := mload(add(data, 32))
            }
        }

        if (rewardAmount != 0) {
            uint256 tokenBalance = protocolTokenHeld;
            if (rewardAmount > tokenBalance) {
                rewardAmount = tokenBalance;
            }
            if (rewardAmount != 0) {
                protocolTokenHeld = tokenBalance
                    .sub(rewardAmount);

                bytes32 slot = keccak256(abi.encodePacked(user, UserRewardsID));
                assembly {
                    sstore(slot, add(sload(slot), rewardAmount))
                }

                emit EarnReward(
                    user,
                    loanId,
                    feeType,
                    vbzrxTokenAddress, // rewardToken
                    rewardAmount
                );
            }
        }
    }
}

contract VaultController is Constants {
    using SafeERC20 for IERC20;

    event VaultDeposit(
        address indexed asset,
        address indexed from,
        uint256 amount
    );
    event VaultWithdraw(
        address indexed asset,
        address indexed to,
        uint256 amount
    );

    function vaultEtherDeposit(
        address from,
        uint256 value)
        internal
    {
        IWethERC20 _wethToken = wethToken;
        _wethToken.deposit.value(value)();

        emit VaultDeposit(
            address(_wethToken),
            from,
            value
        );
    }

    function vaultEtherWithdraw(
        address to,
        uint256 value)
        internal
    {
        if (value != 0) {
            IWethERC20 _wethToken = wethToken;
            uint256 balance = address(this).balance;
            if (value > balance) {
                _wethToken.withdraw(value - balance);
            }
            Address.sendValue(to, value);

            emit VaultWithdraw(
                address(_wethToken),
                to,
                value
            );
        }
    }

    function vaultDeposit(
        address token,
        address from,
        uint256 value)
        internal
    {
        if (value != 0) {
            IERC20(token).safeTransferFrom(
                from,
                address(this),
                value
            );

            emit VaultDeposit(
                token,
                from,
                value
            );
        }
    }

    function vaultWithdraw(
        address token,
        address to,
        uint256 value)
        internal
    {
        if (value != 0) {
            IERC20(token).safeTransfer(
                to,
                value
            );

            emit VaultWithdraw(
                token,
                to,
                value
            );
        }
    }

    function vaultTransfer(
        address token,
        address from,
        address to,
        uint256 value)
        internal
    {
        if (value != 0) {
            if (from == address(this)) {
                IERC20(token).safeTransfer(
                    to,
                    value
                );
            } else {
                IERC20(token).safeTransferFrom(
                    from,
                    to,
                    value
                );
            }
        }
    }

    function vaultApprove(
        address token,
        address to,
        uint256 value)
        internal
    {
        if (value != 0 && IERC20(token).allowance(address(this), to) != 0) {
            IERC20(token).safeApprove(to, 0);
        }
        IERC20(token).safeApprove(to, value);
    }
}

contract InterestUser is State, VaultController, FeesHelper {
    using SafeERC20 for IERC20;

    function _payInterest(
        address lender,
        address interestToken)
        internal
    {
        LenderInterest storage lenderInterestLocal = lenderInterest[lender][interestToken];

        uint256 interestOwedNow = 0;
        if (lenderInterestLocal.owedPerDay != 0 && lenderInterestLocal.updatedTimestamp != 0) {
            interestOwedNow = block.timestamp
                .sub(lenderInterestLocal.updatedTimestamp)
                .mul(lenderInterestLocal.owedPerDay)
                .div(1 days);

            lenderInterestLocal.updatedTimestamp = block.timestamp;

            if (interestOwedNow > lenderInterestLocal.owedTotal)
	            interestOwedNow = lenderInterestLocal.owedTotal;

            if (interestOwedNow != 0) {
                lenderInterestLocal.paidTotal = lenderInterestLocal.paidTotal
                    .add(interestOwedNow);
                lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal
                    .sub(interestOwedNow);

                _payInterestTransfer(
                    lender,
                    interestToken,
                    interestOwedNow
                );
            }
        } else {
            lenderInterestLocal.updatedTimestamp = block.timestamp;
        }
    }

    function _payInterestTransfer(
        address lender,
        address interestToken,
        uint256 interestOwedNow)
        internal
    {
        uint256 lendingFee = interestOwedNow
            .mul(lendingFeePercent)
            .divCeil(WEI_PERCENT_PRECISION);

        _payLendingFee(
            lender,
            interestToken,
            lendingFee
        );

        // transfers the interest to the lender, less the interest fee
        vaultWithdraw(
            interestToken,
            lender,
            interestOwedNow
                .sub(lendingFee)
        );
    }
}

contract LiquidationHelper is State {

    function _getLiquidationAmounts(
        uint256 principal,
        uint256 collateral,
        uint256 currentMargin,
        uint256 maintenanceMargin,
        uint256 collateralToLoanRate,
        uint256 incentivePercent)
        internal
        view
        returns (uint256 maxLiquidatable, uint256 maxSeizable)
    {
        if (currentMargin > maintenanceMargin || collateralToLoanRate == 0) {
            return (maxLiquidatable, maxSeizable);
        } else if (currentMargin <= incentivePercent) {
            return (principal, collateral);
        }

        uint256 desiredMargin = maintenanceMargin
            .add(5 ether); // 5 percentage points above maintenance

        // maxLiquidatable = ((1 + desiredMargin)*principal - collateralToLoanRate*collateral) / (desiredMargin - incentivePercent)
        maxLiquidatable = desiredMargin
            .add(WEI_PERCENT_PRECISION)
            .mul(principal)
            .div(WEI_PERCENT_PRECISION);
        maxLiquidatable = maxLiquidatable
            .sub(
                collateral
                    .mul(collateralToLoanRate)
                    .div(WEI_PRECISION)
            );
        maxLiquidatable = maxLiquidatable
            .mul(WEI_PERCENT_PRECISION)
            .div(
                desiredMargin
                    .sub(incentivePercent)
            );
        if (maxLiquidatable > principal) {
            maxLiquidatable = principal;
        }

        // maxSeizable = maxLiquidatable * (1 + incentivePercent) / collateralToLoanRate
        maxSeizable = maxLiquidatable
            .mul(
                incentivePercent
                    .add(WEI_PERCENT_PRECISION)
            );
        maxSeizable = maxSeizable
            .div(collateralToLoanRate)
            .div(100);
        if (maxSeizable > collateral) {
            maxSeizable = collateral;
        }

        return (maxLiquidatable, maxSeizable);
    }
}

contract SwapsEvents {

    event LoanSwap(
        bytes32 indexed loanId,
        address indexed sourceToken,
        address indexed destToken,
        address borrower,
        uint256 sourceAmount,
        uint256 destAmount
    );

    event ExternalSwap(
        address indexed user,
        address indexed sourceToken,
        address indexed destToken,
        uint256 sourceAmount,
        uint256 destAmount
    );
}

interface ISwapsImpl {
    function dexSwap(
        address sourceTokenAddress,
        address destTokenAddress,
        address receiverAddress,
        address returnToSenderAddress,
        uint256 minSourceTokenAmount,
        uint256 maxSourceTokenAmount,
        uint256 requiredDestTokenAmount)
        external
        returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed);

    function dexExpectedRate(
        address sourceTokenAddress,
        address destTokenAddress,
        uint256 sourceTokenAmount)
        external
        view
        returns (uint256);
}

contract SwapsUser is State, SwapsEvents, FeesHelper {

    function _loanSwap(
        bytes32 loanId,
        address sourceToken,
        address destToken,
        address user,
        uint256 minSourceTokenAmount,
        uint256 maxSourceTokenAmount,
        uint256 requiredDestTokenAmount,
        bool bypassFee,
        bytes memory loanDataBytes)
        internal
        returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed, uint256 sourceToDestSwapRate)
    {
        (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall(
            [
                sourceToken,
                destToken,
                address(this), // receiver
                address(this), // returnToSender
                user
            ],
            [
                minSourceTokenAmount,
                maxSourceTokenAmount,
                requiredDestTokenAmount
            ],
            loanId,
            bypassFee,
            loanDataBytes
        );

        // will revert if swap size too large
        _checkSwapSize(sourceToken, sourceTokenAmountUsed);

        // will revert if disagreement found
        sourceToDestSwapRate = IPriceFeeds(priceFeeds).checkPriceDisagreement(
            sourceToken,
            destToken,
            sourceTokenAmountUsed,
            destTokenAmountReceived,
            maxDisagreement
        );

        emit LoanSwap(
            loanId,
            sourceToken,
            destToken,
            user,
            sourceTokenAmountUsed,
            destTokenAmountReceived
        );
    }

    function _swapsCall(
        address[5] memory addrs,
        uint256[3] memory vals,
        bytes32 loanId,
        bool miscBool, // bypassFee
        bytes memory loanDataBytes)
        internal
        returns (uint256, uint256)
    {
        //addrs[0]: sourceToken
        //addrs[1]: destToken
        //addrs[2]: receiver
        //addrs[3]: returnToSender
        //addrs[4]: user
        //vals[0]:  minSourceTokenAmount
        //vals[1]:  maxSourceTokenAmount
        //vals[2]:  requiredDestTokenAmount

        require(vals[0] != 0, "sourceAmount == 0");

        uint256 destTokenAmountReceived;
        uint256 sourceTokenAmountUsed;

        uint256 tradingFee;
        if (!miscBool) { // bypassFee
            if (vals[2] == 0) {
                // condition: vals[0] will always be used as sourceAmount

                tradingFee = _getTradingFee(vals[0]);
                if (tradingFee != 0) {
                    _payTradingFee(
                        addrs[4], // user
                        loanId,
                        addrs[0], // sourceToken
                        tradingFee
                    );

                    vals[0] = vals[0]
                        .sub(tradingFee);
                }
            } else {
                // condition: unknown sourceAmount will be used

                tradingFee = _getTradingFee(vals[2]);

                if (tradingFee != 0) {
                    vals[2] = vals[2]
                        .add(tradingFee);
                }
            }
        }

        if (vals[1] == 0) {
            vals[1] = vals[0];
        } else {
            require(vals[0] <= vals[1], "min greater than max");
        }

        require(loanDataBytes.length == 0, "invalid state");
        (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall_internal(
            addrs,
            vals
        );

        if (vals[2] == 0) {
            // there's no minimum destTokenAmount, but all of vals[0] (minSourceTokenAmount) must be spent, and amount spent can't exceed vals[0]
            require(sourceTokenAmountUsed == vals[0], "swap too large to fill");

            if (tradingFee != 0) {
                sourceTokenAmountUsed = sourceTokenAmountUsed + tradingFee; // will never overflow
            }
        } else {
            // there's a minimum destTokenAmount required, but sourceTokenAmountUsed won't be greater than vals[1] (maxSourceTokenAmount)
            require(sourceTokenAmountUsed <= vals[1], "swap fill too large");
            require(destTokenAmountReceived >= vals[2], "insufficient swap liquidity");

            if (tradingFee != 0) {
                _payTradingFee(
                    addrs[4], // user
                    loanId, // loanId,
                    addrs[1], // destToken
                    tradingFee
                );

                destTokenAmountReceived = destTokenAmountReceived - tradingFee; // will never overflow
            }
        }

        return (destTokenAmountReceived, sourceTokenAmountUsed);
    }

    function _swapsCall_internal(
        address[5] memory addrs,
        uint256[3] memory vals)
        internal
        returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)
    {
        bytes memory data = abi.encodeWithSelector(
            ISwapsImpl(swapsImpl).dexSwap.selector,
            addrs[0], // sourceToken
            addrs[1], // destToken
            addrs[2], // receiverAddress
            addrs[3], // returnToSenderAddress
            vals[0],  // minSourceTokenAmount
            vals[1],  // maxSourceTokenAmount
            vals[2]   // requiredDestTokenAmount
        );

        bool success;
        (success, data) = swapsImpl.delegatecall(data);
        require(success, "swap failed");

        (destTokenAmountReceived, sourceTokenAmountUsed) = abi.decode(data, (uint256, uint256));
    }

    function _swapsExpectedReturn(
        address sourceToken,
        address destToken,
        uint256 sourceTokenAmount)
        internal
        view
        returns (uint256)
    {
        uint256 tradingFee = _getTradingFee(sourceTokenAmount);
        if (tradingFee != 0) {
            sourceTokenAmount = sourceTokenAmount
                .sub(tradingFee);
        }

        uint256 sourceToDestRate = ISwapsImpl(swapsImpl).dexExpectedRate(
            sourceToken,
            destToken,
            sourceTokenAmount
        );
        uint256 sourceToDestPrecision = IPriceFeeds(priceFeeds).queryPrecision(
            sourceToken,
            destToken
        );

        return sourceTokenAmount
            .mul(sourceToDestRate)
            .div(sourceToDestPrecision);
    }

    function _checkSwapSize(
        address tokenAddress,
        uint256 amount)
        internal
        view
    {
        uint256 _maxSwapSize = maxSwapSize;
        if (_maxSwapSize != 0) {
            uint256 amountInEth;
            if (tokenAddress == address(wethToken)) {
                amountInEth = amount;
            } else {
                amountInEth = IPriceFeeds(priceFeeds).amountInEth(tokenAddress, amount);
            }
            require(amountInEth <= _maxSwapSize, "swap too large");
        }
    }
}

contract LoanMaintenanceEvents {

    event DepositCollateral(
        address indexed user,
        address indexed depositToken,
        bytes32 indexed loanId,
        uint256 depositAmount
    );

    event WithdrawCollateral(
        address indexed user,
        address indexed withdrawToken,
        bytes32 indexed loanId,
        uint256 withdrawAmount
    );

    event ExtendLoanDuration(
        address indexed user,
        address indexed depositToken,
        bytes32 indexed loanId,
        uint256 depositAmount,
        uint256 collateralUsedAmount,
        uint256 newEndTimestamp
    );

    event ReduceLoanDuration(
        address indexed user,
        address indexed withdrawToken,
        bytes32 indexed loanId,
        uint256 withdrawAmount,
        uint256 newEndTimestamp
    );

    event LoanDeposit(
        bytes32 indexed loanId,
        uint256 depositValueAsLoanToken,
        uint256 depositValueAsCollateralToken
    );

    event ClaimReward(
        address indexed user,
        address indexed receiver,
        address indexed token,
        uint256 amount
    );

    enum LoanType {
        All,
        Margin,
        NonMargin
    }

    struct LoanReturnData {
        bytes32 loanId; // id of the loan
        uint96 endTimestamp; // loan end timestamp
        address loanToken; // loan token address
        address collateralToken; // collateral token address
        uint256 principal; // principal amount of the loan
        uint256 collateral; // collateral amount of the loan
        uint256 interestOwedPerDay; // interest owned per day
        uint256 interestDepositRemaining; // remaining unspent interest
        uint256 startRate; // collateralToLoanRate
        uint256 startMargin; // margin with which loan was open
        uint256 maintenanceMargin; // maintenance margin
        uint256 currentMargin; /// current margin
        uint256 maxLoanTerm; // maximum term of the loan
        uint256 maxLiquidatable; // current max liquidatable
        uint256 maxSeizable; // current max seizable
        uint256 depositValueAsLoanToken; // net value of deposit denominated as loanToken
        uint256 depositValueAsCollateralToken; // net value of deposit denominated as collateralToken
    }
}

contract LoanMaintenance is State, LoanMaintenanceEvents, VaultController, InterestUser, SwapsUser, LiquidationHelper {

    function initialize(
        address target)
        external
        onlyOwner
    {
        _setTarget(this.depositCollateral.selector, target);
        _setTarget(this.withdrawCollateral.selector, target);
        _setTarget(this.withdrawAccruedInterest.selector, target);
        _setTarget(this.extendLoanDuration.selector, target);
        _setTarget(this.reduceLoanDuration.selector, target);
        _setTarget(this.setDepositAmount.selector, target);
        _setTarget(this.claimRewards.selector, target);
        _setTarget(this.rewardsBalanceOf.selector, target);
        _setTarget(this.getLenderInterestData.selector, target);
        _setTarget(this.getLoanInterestData.selector, target);
        _setTarget(this.getUserLoans.selector, target);
        _setTarget(this.getUserLoansCount.selector, target);
        _setTarget(this.getLoan.selector, target);
        _setTarget(this.getActiveLoans.selector, target);
        _setTarget(this.getActiveLoansCount.selector, target);
    }

    function depositCollateral(
        bytes32 loanId,
        uint256 depositAmount) // must match msg.value if ether is sent
        external
        payable
        nonReentrant
    {
        require(depositAmount != 0, "depositAmount is 0");

        Loan storage loanLocal = loans[loanId];
        require(loanLocal.active, "loan is closed");

        LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];

        address collateralToken = loanParamsLocal.collateralToken;
        uint256 collateral = loanLocal.collateral;

        require(msg.value == 0 || collateralToken == address(wethToken), "wrong asset sent");

        collateral = collateral
            .add(depositAmount);
        loanLocal.collateral = collateral;

        if (msg.value == 0) {
            vaultDeposit(
                collateralToken,
                msg.sender,
                depositAmount
            );
        } else {
            require(msg.value == depositAmount, "ether deposit mismatch");
            vaultEtherDeposit(
                msg.sender,
                msg.value
            );
        }

        // update deposit amount
        (uint256 collateralToLoanRate, uint256 collateralToLoanPrecision) = IPriceFeeds(priceFeeds).queryRate(
            collateralToken,
            loanParamsLocal.loanToken
        );
        if (collateralToLoanRate != 0) {
            _setDepositAmount(
                loanId,
                depositAmount
                    .mul(collateralToLoanRate)
                    .div(collateralToLoanPrecision),
                depositAmount,
                false // isSubtraction
            );
        }

        emit DepositCollateral(
            loanLocal.borrower,
            collateralToken,
            loanId,
            depositAmount
        );
    }

    function withdrawCollateral(
        bytes32 loanId,
        address receiver,
        uint256 withdrawAmount)
        external
        nonReentrant
        returns (uint256 actualWithdrawAmount)
    {
        require(withdrawAmount != 0, "withdrawAmount is 0");
        Loan storage loanLocal = loans[loanId];
        LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];

        require(loanLocal.active, "loan is closed");
        require(
            msg.sender == loanLocal.borrower ||
            delegatedManagers[loanLocal.id][msg.sender],
            "unauthorized"
        );

        address collateralToken = loanParamsLocal.collateralToken;
        uint256 collateral = loanLocal.collateral;

        uint256 maxDrawdown = IPriceFeeds(priceFeeds).getMaxDrawdown(
            loanParamsLocal.loanToken,
            collateralToken,
            loanLocal.principal,
            collateral,
            loanParamsLocal.maintenanceMargin
        );

        if (withdrawAmount > maxDrawdown) {
            actualWithdrawAmount = maxDrawdown;
        } else {
            actualWithdrawAmount = withdrawAmount;
        }

        collateral = collateral
            .sub(actualWithdrawAmount, "withdrawAmount too high");
        loanLocal.collateral = collateral;

        if (collateralToken == address(wethToken)) {
            vaultEtherWithdraw(
                receiver,
                actualWithdrawAmount
            );
        } else {
            vaultWithdraw(
                collateralToken,
                receiver,
                actualWithdrawAmount
            );
        }

        // update deposit amount
        (uint256 collateralToLoanRate, uint256 collateralToLoanPrecision) = IPriceFeeds(priceFeeds).queryRate(
            collateralToken,
            loanParamsLocal.loanToken
        );
        if (collateralToLoanRate != 0) {
            _setDepositAmount(
                loanId,
                actualWithdrawAmount
                    .mul(collateralToLoanRate)
                    .div(collateralToLoanPrecision),
                actualWithdrawAmount,
                true // isSubtraction
            );
        }

        emit WithdrawCollateral(
            loanLocal.borrower,
            collateralToken,
            loanId,
            actualWithdrawAmount
        );
    }

    function withdrawAccruedInterest(
        address loanToken)
        external
    {
        // pay outstanding interest to lender
        _payInterest(
            msg.sender, // lender
            loanToken
        );
    }

    function extendLoanDuration(
        bytes32 loanId,
        uint256 depositAmount,
        bool useCollateral,
        bytes calldata /*loanDataBytes*/) // for future use
        external
        payable
        nonReentrant
        returns (uint256 secondsExtended)
    {
        require(depositAmount != 0, "depositAmount is 0");
        Loan storage loanLocal = loans[loanId];
        LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];

        require(loanLocal.active, "loan is closed");
        require(
            !useCollateral ||
            msg.sender == loanLocal.borrower ||
            delegatedManagers[loanLocal.id][msg.sender],
            "unauthorized"
        );
        require(loanParamsLocal.maxLoanTerm == 0, "indefinite-term only");
        require(msg.value == 0 || (!useCollateral && loanParamsLocal.loanToken == address(wethToken)), "wrong asset sent");

        // pay outstanding interest to lender
        _payInterest(
            loanLocal.lender,
            loanParamsLocal.loanToken
        );

        LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];

        _settleFeeRewardForInterestExpense(
            loanInterestLocal,
            loanLocal.id,
            loanParamsLocal.loanToken,
            loanLocal.borrower,
            block.timestamp
        );

        // Handle back interest: calculates interest owned since the loan endtime passed but the loan remained open
        uint256 backInterestOwed;
        if (block.timestamp > loanLocal.endTimestamp) {
            backInterestOwed = block.timestamp
                .sub(loanLocal.endTimestamp);
            backInterestOwed = backInterestOwed
                .mul(loanInterestLocal.owedPerDay);
            backInterestOwed = backInterestOwed
                .div(1 days);

            require(depositAmount > backInterestOwed, "deposit cannot cover back interest");
        }

        // deposit interest
        uint256 collateralUsed;
        if (useCollateral) {
            collateralUsed = _doSwapWithCollateral(
                loanLocal,
                loanParamsLocal,
                depositAmount
            );
        } else {
            if (msg.value == 0) {
                vaultDeposit(
                    loanParamsLocal.loanToken,
                    msg.sender,
                    depositAmount
                );
            } else {
                require(msg.value == depositAmount, "ether deposit mismatch");
                vaultEtherDeposit(
                    msg.sender,
                    msg.value
                );
            }
        }

        if (backInterestOwed != 0) {
            depositAmount = depositAmount
                .sub(backInterestOwed);

            // pay out backInterestOwed
            _payInterestTransfer(
                loanLocal.lender,
                loanParamsLocal.loanToken,
                backInterestOwed
            );
        }

        secondsExtended = depositAmount
            .mul(1 days)
            .div(loanInterestLocal.owedPerDay);

        loanLocal.endTimestamp = loanLocal.endTimestamp
            .add(secondsExtended);

        require(loanLocal.endTimestamp > block.timestamp &&
               (loanLocal.endTimestamp - block.timestamp) > 1 hours,
            "loan too short"
        );

        loanInterestLocal.depositTotal = loanInterestLocal.depositTotal
            .add(depositAmount);

        lenderInterest[loanLocal.lender][loanParamsLocal.loanToken].owedTotal = lenderInterest[loanLocal.lender][loanParamsLocal.loanToken].owedTotal
            .add(depositAmount);

        emit ExtendLoanDuration(
            loanLocal.borrower,
            loanParamsLocal.loanToken,
            loanId,
            depositAmount,
            collateralUsed,
            loanLocal.endTimestamp
        );
    }

    function reduceLoanDuration(
        bytes32 loanId,
        address receiver,
        uint256 withdrawAmount)
        external
        nonReentrant
        returns (uint256 secondsReduced)
    {
        require(withdrawAmount != 0, "withdrawAmount is 0");
        Loan storage loanLocal = loans[loanId];
        LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];

        require(loanLocal.active, "loan is closed");
        require(
            msg.sender == loanLocal.borrower ||
            delegatedManagers[loanLocal.id][msg.sender],
            "unauthorized"
        );
        require(loanParamsLocal.maxLoanTerm == 0, "indefinite-term only");
        require(loanLocal.endTimestamp > block.timestamp, "loan term has ended");

        // pay outstanding interest to lender
        _payInterest(
            loanLocal.lender,
            loanParamsLocal.loanToken
        );

        LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];

        _settleFeeRewardForInterestExpense(
            loanInterestLocal,
            loanLocal.id,
            loanParamsLocal.loanToken,
            loanLocal.borrower,
            block.timestamp
        );

        uint256 interestDepositRemaining = loanLocal.endTimestamp
            .sub(block.timestamp)
            .mul(loanInterestLocal.owedPerDay)
            .div(1 days);
        require(withdrawAmount < interestDepositRemaining, "withdraw amount too high");

        // withdraw interest
        if (loanParamsLocal.loanToken == address(wethToken)) {
            vaultEtherWithdraw(
                receiver,
                withdrawAmount
            );
        } else {
            vaultWithdraw(
                loanParamsLocal.loanToken,
                receiver,
                withdrawAmount
            );
        }

        secondsReduced = withdrawAmount
            .mul(1 days)
            .div(loanInterestLocal.owedPerDay);

        require (loanLocal.endTimestamp > secondsReduced, "loan too short");

        loanLocal.endTimestamp = loanLocal.endTimestamp
            .sub(secondsReduced);

        require(loanLocal.endTimestamp > block.timestamp &&
               (loanLocal.endTimestamp - block.timestamp) > 1 hours,
            "loan too short"
        );

        loanInterestLocal.depositTotal = loanInterestLocal.depositTotal
            .sub(withdrawAmount);

        lenderInterest[loanLocal.lender][loanParamsLocal.loanToken].owedTotal = lenderInterest[loanLocal.lender][loanParamsLocal.loanToken].owedTotal
            .sub(withdrawAmount);

        emit ReduceLoanDuration(
            loanLocal.borrower,
            loanParamsLocal.loanToken,
            loanId,
            withdrawAmount,
            loanLocal.endTimestamp
        );
    }

    function setDepositAmount(
        bytes32 loanId,
        uint256 depositValueAsLoanToken,
        uint256 depositValueAsCollateralToken)
        external
    {
        // only callable by loan pools
        require(loanPoolToUnderlying[msg.sender] != address(0), "not authorized");

        _setDepositAmount(
            loanId,
            depositValueAsLoanToken,
            depositValueAsCollateralToken,
            false // isSubtraction
        );
    }

    function claimRewards(
        address receiver)
        external
        returns (uint256 claimAmount)
    {
        bytes32 slot = keccak256(abi.encodePacked(msg.sender, UserRewardsID));
        assembly {
            claimAmount := sload(slot)
        }

        if (claimAmount != 0) {
            assembly {
                sstore(slot, 0)
            }

            protocolTokenPaid = protocolTokenPaid
                .add(claimAmount);

            IERC20(vbzrxTokenAddress).transfer(
                receiver,
                claimAmount
            );

            emit ClaimReward(
                msg.sender,
                receiver,
                vbzrxTokenAddress,
                claimAmount
            );
        }
    }

    function rewardsBalanceOf(
        address user)
        external
        view
        returns (uint256 rewardsBalance)
    {
        bytes32 slot = keccak256(abi.encodePacked(user, UserRewardsID));
        assembly {
            rewardsBalance := sload(slot)
        }
    }

    /// @dev Gets current lender interest data totals for all loans with a specific oracle and interest token
    /// @param lender The lender address
    /// @param loanToken The loan token address
    /// @return interestPaid The total amount of interest that has been paid to a lender so far
    /// @return interestPaidDate The date of the last interest pay out, or 0 if no interest has been withdrawn yet
    /// @return interestOwedPerDay The amount of interest the lender is earning per day
    /// @return interestUnPaid The total amount of interest the lender is owned and not yet withdrawn
    /// @return interestFeePercent The fee retained by the protocol before interest is paid to the lender
    /// @return principalTotal The total amount of outstading principal the lender has loaned
    function getLenderInterestData(
        address lender,
        address loanToken)
        external
        view
        returns (
            uint256 interestPaid,
            uint256 interestPaidDate,
            uint256 interestOwedPerDay,
            uint256 interestUnPaid,
            uint256 interestFeePercent,
            uint256 principalTotal)
    {
        LenderInterest memory lenderInterestLocal = lenderInterest[lender][loanToken];

        interestUnPaid = block.timestamp.sub(lenderInterestLocal.updatedTimestamp).mul(lenderInterestLocal.owedPerDay).div(1 days);
        if (interestUnPaid > lenderInterestLocal.owedTotal)
            interestUnPaid = lenderInterestLocal.owedTotal;

        return (
            lenderInterestLocal.paidTotal,
            lenderInterestLocal.paidTotal != 0 ? lenderInterestLocal.updatedTimestamp : 0,
            lenderInterestLocal.owedPerDay,
            lenderInterestLocal.updatedTimestamp != 0 ? interestUnPaid : 0,
            lendingFeePercent,
            lenderInterestLocal.principalTotal
        );
    }

    /// @dev Gets current interest data for a loan
    /// @param loanId A unique id representing the loan
    /// @return loanToken The loan token that interest is paid in
    /// @return interestOwedPerDay The amount of interest the borrower is paying per day
    /// @return interestDepositTotal The total amount of interest the borrower has deposited
    /// @return interestDepositRemaining The amount of deposited interest that is not yet owed to a lender
    function getLoanInterestData(
        bytes32 loanId)
        external
        view
        returns (
            address loanToken,
            uint256 interestOwedPerDay,
            uint256 interestDepositTotal,
            uint256 interestDepositRemaining)
    {
        loanToken = loanParams[loans[loanId].loanParamsId].loanToken;
        interestOwedPerDay = loanInterest[loanId].owedPerDay;
        interestDepositTotal = loanInterest[loanId].depositTotal;

        uint256 endTimestamp = loans[loanId].endTimestamp;
        uint256 interestTime = block.timestamp > endTimestamp ?
            endTimestamp :
            block.timestamp;
        interestDepositRemaining = endTimestamp > interestTime ?
            endTimestamp
                .sub(interestTime)
                .mul(interestOwedPerDay)
                .div(1 days) :
                0;
    }

    // Only returns data for loans that are active
    // All(0): all loans
    // Margin(1): margin trade loans
    // NonMargin(2): non-margin trade loans
    // only active loans are returned
    function getUserLoans(
        address user,
        uint256 start,
        uint256 count,
        LoanType loanType,
        bool isLender,
        bool unsafeOnly)
        external
        view
        returns (LoanReturnData[] memory loansData)
    {
        EnumerableBytes32Set.Bytes32Set storage set = isLender ?
            lenderLoanSets[user] :
            borrowerLoanSets[user];

        uint256 end = start.add(count).min256(set.length());
        if (start >= end) {
            return loansData;
        }
        count = end-start;

        uint256 idx = count;
        LoanReturnData memory loanData;
        loansData = new LoanReturnData[](idx);
        for (uint256 i = --end; i >= start; i--) {
            loanData = _getLoan(
                set.get(i), // loanId
                loanType,
                unsafeOnly
            );
            if (loanData.loanId == 0) {
                if (i == 0) {
                    break;
                } else {
                    continue;
                }
            }

            loansData[count-(idx--)] = loanData;

            if (i == 0) {
                break;
            }
        }

        if (idx != 0) {
            count -= idx;
            assembly {
                mstore(loansData, count)
            }
        }
    }

    function getUserLoansCount(
        address user,
        bool isLender)
        external
        view
        returns (uint256)
    {
        return isLender ?
            lenderLoanSets[user].length() :
            borrowerLoanSets[user].length();
    }

    function getLoan(
        bytes32 loanId)
        external
        view
        returns (LoanReturnData memory loanData)
    {
        return _getLoan(
            loanId,
            LoanType.All,
            false // unsafeOnly
        );
    }

    function getActiveLoans(
        uint256 start,
        uint256 count,
        bool unsafeOnly)
        external
        view
        returns (LoanReturnData[] memory loansData)
    {
        uint256 end = start.add(count).min256(activeLoansSet.length());
        if (start >= end) {
            return loansData;
        }
        count = end-start;

        uint256 idx = count;
        LoanReturnData memory loanData;
        loansData = new LoanReturnData[](idx);
        for (uint256 i = --end; i >= start; i--) {
            loanData = _getLoan(
                activeLoansSet.get(i), // loanId
                LoanType.All,
                unsafeOnly
            );
            if (loanData.loanId == 0) {
                if (i == 0) {
                    break;
                } else {
                    continue;
                }
            }

            loansData[count-(idx--)] = loanData;

            if (i == 0) {
                break;
            }
        }

        if (idx != 0) {
            count -= idx;
            assembly {
                mstore(loansData, count)
            }
        }
    }

    function getActiveLoansCount()
        external
        view
        returns (uint256)
    {
        return activeLoansSet.length();
    }

    function _getLoan(
        bytes32 loanId,
        LoanType loanType,
        bool unsafeOnly)
        internal
        view
        returns (LoanReturnData memory loanData)
    {
        Loan memory loanLocal = loans[loanId];
        LoanParams memory loanParamsLocal = loanParams[loanLocal.loanParamsId];

        if ((loanType == LoanType.Margin && loanParamsLocal.maxLoanTerm == 0) ||
            (loanType == LoanType.NonMargin && loanParamsLocal.maxLoanTerm != 0)) {
            return loanData;
        }

        LoanInterest memory loanInterestLocal = loanInterest[loanId];

        (uint256 currentMargin, uint256 value) = IPriceFeeds(priceFeeds).getCurrentMargin( // currentMargin, collateralToLoanRate
            loanParamsLocal.loanToken,
            loanParamsLocal.collateralToken,
            loanLocal.principal,
            loanLocal.collateral
        );

        uint256 maxLiquidatable;
        uint256 maxSeizable;
        if (currentMargin <= loanParamsLocal.maintenanceMargin) {
            (maxLiquidatable, maxSeizable) = _getLiquidationAmounts(
                loanLocal.principal,
                loanLocal.collateral,
                currentMargin,
                loanParamsLocal.maintenanceMargin,
                value, // collateralToLoanRate
                liquidationIncentivePercent[loanParamsLocal.loanToken][loanParamsLocal.collateralToken]
            );
        } else if (unsafeOnly) {
            return loanData;
        }

        uint256 depositValueAsLoanToken;
        uint256 depositValueAsCollateralToken;
        bytes32 slot = keccak256(abi.encode(loanId, LoanDepositValueID));
        assembly {
            depositValueAsLoanToken := sload(slot)
            depositValueAsCollateralToken := sload(add(slot, 1))
        }

        if (loanLocal.endTimestamp > block.timestamp) {
            value = loanLocal.endTimestamp
                .sub(block.timestamp)
                .mul(loanInterestLocal.owedPerDay)
                .div(1 days);
        } else {
            value = 0;
        }

        return LoanReturnData({
            loanId: loanId,
            endTimestamp: uint96(loanLocal.endTimestamp),
            loanToken: loanParamsLocal.loanToken,
            collateralToken: loanParamsLocal.collateralToken,
            principal: loanLocal.principal,
            collateral: loanLocal.collateral,
            interestOwedPerDay: loanInterestLocal.owedPerDay,
            interestDepositRemaining: value,
            startRate: loanLocal.startRate,
            startMargin: loanLocal.startMargin,
            maintenanceMargin: loanParamsLocal.maintenanceMargin,
            currentMargin: currentMargin,
            maxLoanTerm: loanParamsLocal.maxLoanTerm,
            maxLiquidatable: maxLiquidatable,
            maxSeizable: maxSeizable,
            depositValueAsLoanToken: depositValueAsLoanToken,
            depositValueAsCollateralToken: depositValueAsCollateralToken
        });
    }

    function _doSwapWithCollateral(
        Loan storage loanLocal,
        LoanParams memory loanParamsLocal,
        uint256 depositAmount)
        internal
        returns (uint256)
    {
        // reverts in _loanSwap if amountNeeded can't be bought
        (,uint256 sourceTokenAmountUsed,) = _loanSwap(
            loanLocal.id,
            loanParamsLocal.collateralToken,
            loanParamsLocal.loanToken,
            loanLocal.borrower,
            loanLocal.collateral, // minSourceTokenAmount
            0, // maxSourceTokenAmount (0 means minSourceTokenAmount)
            depositAmount, // requiredDestTokenAmount (partial spend of loanLocal.collateral to fill this amount)
            true, // bypassFee
            "" // loanDataBytes
        );
        loanLocal.collateral = loanLocal.collateral
            .sub(sourceTokenAmountUsed);

        // ensure the loan is still healthy
        (uint256 currentMargin, uint256 collateralToLoanRate) = IPriceFeeds(priceFeeds).getCurrentMargin(
            loanParamsLocal.loanToken,
            loanParamsLocal.collateralToken,
            loanLocal.principal,
            loanLocal.collateral
        );
        require(
            currentMargin > loanParamsLocal.maintenanceMargin,
            "unhealthy position"
        );

        // update deposit amount
        if (sourceTokenAmountUsed != 0 && collateralToLoanRate != 0) {
            _setDepositAmount(
                loanLocal.id,
                sourceTokenAmountUsed
                    .mul(collateralToLoanRate)
                    .div(WEI_PRECISION),
                sourceTokenAmountUsed,
                true // isSubtraction
            );
        }

        return sourceTokenAmountUsed;
    }

    function _setDepositAmount(
        bytes32 loanId,
        uint256 depositValueAsLoanToken,
        uint256 depositValueAsCollateralToken,
        bool isSubtraction)
        internal
    {
        bytes32 slot = keccak256(abi.encode(loanId, LoanDepositValueID));
        assembly {
            let val := sload(slot)
            switch isSubtraction
            case 0 {
                sstore(slot, add(val, depositValueAsLoanToken))
            }
            default {
                switch gt(val, depositValueAsLoanToken)
                case 1 {
                    sstore(slot, sub(val, depositValueAsLoanToken))
                }
                default {
                    sstore(slot, 0)
                }
            }

            slot := add(slot, 1)
            val := sload(slot)
            switch isSubtraction
            case 0 {
                sstore(slot, add(val, depositValueAsCollateralToken))
            }
            default {
                switch gt(val, depositValueAsCollateralToken)
                case 1 {
                    sstore(slot, sub(val, depositValueAsCollateralToken))
                }
                default {
                    sstore(slot, 0)
                }
            }
        }

        emit LoanDeposit(
            loanId,
            depositValueAsLoanToken,
            depositValueAsCollateralToken
        );
    }
}

Contract Security Audit

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ClaimReward","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"depositToken","type":"address"},{"indexed":true,"internalType":"bytes32","name":"loanId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"depositAmount","type":"uint256"}],"name":"DepositCollateral","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"bytes32","name":"loanId","type":"bytes32"},{"indexed":true,"internalType":"enum FeesEvents.FeeType","name":"feeType","type":"uint8"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"EarnReward","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"depositToken","type":"address"},{"indexed":true,"internalType":"bytes32","name":"loanId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"depositAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"collateralUsedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newEndTimestamp","type":"uint256"}],"name":"ExtendLoanDuration","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"sourceToken","type":"address"},{"indexed":true,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"sourceAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"}],"name":"ExternalSwap","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"loanId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"depositValueAsLoanToken","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"depositValueAsCollateralToken","type":"uint256"}],"name":"LoanDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"loanId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sourceToken","type":"address"},{"indexed":true,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"sourceAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"}],"name":"LoanSwap","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":"address","name":"payer","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"bytes32","name":"loanId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PayBorrowingFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"payer","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PayLendingFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"payer","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"bytes32","name":"loanId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PayTradingFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"withdrawToken","type":"address"},{"indexed":true,"internalType":"bytes32","name":"loanId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"withdrawAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newEndTimestamp","type":"uint256"}],"name":"ReduceLoanDuration","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"payer","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"bytes32","name":"loanId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"SettleFeeRewardForInterestExpense","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"VaultDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"VaultWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"withdrawToken","type":"address"},{"indexed":true,"internalType":"bytes32","name":"loanId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"withdrawAmount","type":"uint256"}],"name":"WithdrawCollateral","type":"event"},{"constant":true,"inputs":[],"name":"affiliateFeePercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"borrowerOrders","outputs":[{"internalType":"uint256","name":"lockedAmount","type":"uint256"},{"internalType":"uint256","name":"interestRate","type":"uint256"},{"internalType":"uint256","name":"minLoanTerm","type":"uint256"},{"internalType":"uint256","name":"maxLoanTerm","type":"uint256"},{"internalType":"uint256","name":"createdTimestamp","type":"uint256"},{"internalType":"uint256","name":"expirationTimestamp","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"borrowingFeePercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"borrowingFeeTokensHeld","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"borrowingFeeTokensPaid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"bzrxTokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"claimRewards","outputs":[{"internalType":"uint256","name":"claimAmount","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"}],"name":"delegatedManagers","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"loanId","type":"bytes32"},{"internalType":"uint256","name":"depositAmount","type":"uint256"}],"name":"depositCollateral","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"loanId","type":"bytes32"},{"internalType":"uint256","name":"depositAmount","type":"uint256"},{"internalType":"bool","name":"useCollateral","type":"bool"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"extendLoanDuration","outputs":[{"internalType":"uint256","name":"secondsExtended","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"feesController","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"count","type":"uint256"},{"internalType":"bool","name":"unsafeOnly","type":"bool"}],"name":"getActiveLoans","outputs":[{"components":[{"internalType":"bytes32","name":"loanId","type":"bytes32"},{"internalType":"uint96","name":"endTimestamp","type":"uint96"},{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"uint256","name":"principal","type":"uint256"},{"internalType":"uint256","name":"collateral","type":"uint256"},{"internalType":"uint256","name":"interestOwedPerDay","type":"uint256"},{"internalType":"uint256","name":"interestDepositRemaining","type":"uint256"},{"internalType":"uint256","name":"startRate","type":"uint256"},{"internalType":"uint256","name":"startMargin","type":"uint256"},{"internalType":"uint256","name":"maintenanceMargin","type":"uint256"},{"internalType":"uint256","name":"currentMargin","type":"uint256"},{"internalType":"uint256","name":"maxLoanTerm","type":"uint256"},{"internalType":"uint256","name":"maxLiquidatable","type":"uint256"},{"internalType":"uint256","name":"maxSeizable","type":"uint256"},{"internalType":"uint256","name":"depositValueAsLoanToken","type":"uint256"},{"internalType":"uint256","name":"depositValueAsCollateralToken","type":"uint256"}],"internalType":"struct LoanMaintenanceEvents.LoanReturnData[]","name":"loansData","type":"tuple[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getActiveLoansCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"lender","type":"address"},{"internalType":"address","name":"loanToken","type":"address"}],"name":"getLenderInterestData","outputs":[{"internalType":"uint256","name":"interestPaid","type":"uint256"},{"internalType":"uint256","name":"interestPaidDate","type":"uint256"},{"internalType":"uint256","name":"interestOwedPerDay","type":"uint256"},{"internalType":"uint256","name":"interestUnPaid","type":"uint256"},{"internalType":"uint256","name":"interestFeePercent","type":"uint256"},{"internalType":"uint256","name":"principalTotal","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"loanId","type":"bytes32"}],"name":"getLoan","outputs":[{"components":[{"internalType":"bytes32","name":"loanId","type":"bytes32"},{"internalType":"uint96","name":"endTimestamp","type":"uint96"},{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"uint256","name":"principal","type":"uint256"},{"internalType":"uint256","name":"collateral","type":"uint256"},{"internalType":"uint256","name":"interestOwedPerDay","type":"uint256"},{"internalType":"uint256","name":"interestDepositRemaining","type":"uint256"},{"internalType":"uint256","name":"startRate","type":"uint256"},{"internalType":"uint256","name":"startMargin","type":"uint256"},{"internalType":"uint256","name":"maintenanceMargin","type":"uint256"},{"internalType":"uint256","name":"currentMargin","type":"uint256"},{"internalType":"uint256","name":"maxLoanTerm","type":"uint256"},{"internalType":"uint256","name":"maxLiquidatable","type":"uint256"},{"internalType":"uint256","name":"maxSeizable","type":"uint256"},{"internalType":"uint256","name":"depositValueAsLoanToken","type":"uint256"},{"internalType":"uint256","name":"depositValueAsCollateralToken","type":"uint256"}],"internalType":"struct LoanMaintenanceEvents.LoanReturnData","name":"loanData","type":"tuple"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"loanId","type":"bytes32"}],"name":"getLoanInterestData","outputs":[{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"uint256","name":"interestOwedPerDay","type":"uint256"},{"internalType":"uint256","name":"interestDepositTotal","type":"uint256"},{"internalType":"uint256","name":"interestDepositRemaining","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"count","type":"uint256"},{"internalType":"enum LoanMaintenanceEvents.LoanType","name":"loanType","type":"uint8"},{"internalType":"bool","name":"isLender","type":"bool"},{"internalType":"bool","name":"unsafeOnly","type":"bool"}],"name":"getUserLoans","outputs":[{"components":[{"internalType":"bytes32","name":"loanId","type":"bytes32"},{"internalType":"uint96","name":"endTimestamp","type":"uint96"},{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"uint256","name":"principal","type":"uint256"},{"internalType":"uint256","name":"collateral","type":"uint256"},{"internalType":"uint256","name":"interestOwedPerDay","type":"uint256"},{"internalType":"uint256","name":"interestDepositRemaining","type":"uint256"},{"internalType":"uint256","name":"startRate","type":"uint256"},{"internalType":"uint256","name":"startMargin","type":"uint256"},{"internalType":"uint256","name":"maintenanceMargin","type":"uint256"},{"internalType":"uint256","name":"currentMargin","type":"uint256"},{"internalType":"uint256","name":"maxLoanTerm","type":"uint256"},{"internalType":"uint256","name":"maxLiquidatable","type":"uint256"},{"internalType":"uint256","name":"maxSeizable","type":"uint256"},{"internalType":"uint256","name":"depositValueAsLoanToken","type":"uint256"},{"internalType":"uint256","name":"depositValueAsCollateralToken","type":"uint256"}],"internalType":"struct LoanMaintenanceEvents.LoanReturnData[]","name":"loansData","type":"tuple[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"bool","name":"isLender","type":"bool"}],"name":"getUserLoansCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"lenderInterest","outputs":[{"internalType":"uint256","name":"principalTotal","type":"uint256"},{"internalType":"uint256","name":"owedPerDay","type":"uint256"},{"internalType":"uint256","name":"owedTotal","type":"uint256"},{"internalType":"uint256","name":"paidTotal","type":"uint256"},{"internalType":"uint256","name":"updatedTimestamp","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"lenderOrders","outputs":[{"internalType":"uint256","name":"lockedAmount","type":"uint256"},{"internalType":"uint256","name":"interestRate","type":"uint256"},{"internalType":"uint256","name":"minLoanTerm","type":"uint256"},{"internalType":"uint256","name":"maxLoanTerm","type":"uint256"},{"internalType":"uint256","name":"createdTimestamp","type":"uint256"},{"internalType":"uint256","name":"expirationTimestamp","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"lendingFeePercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lendingFeeTokensHeld","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lendingFeeTokensPaid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"liquidationIncentivePercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"loanInterest","outputs":[{"internalType":"uint256","name":"owedPerDay","type":"uint256"},{"internalType":"uint256","name":"depositTotal","type":"uint256"},{"internalType":"uint256","name":"updatedTimestamp","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"loanParams","outputs":[{"internalType":"bytes32","name":"id","type":"bytes32"},{"internalType":"bool","name":"active","type":"bool"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"uint256","name":"minInitialMargin","type":"uint256"},{"internalType":"uint256","name":"maintenanceMargin","type":"uint256"},{"internalType":"uint256","name":"maxLoanTerm","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"loanPoolToUnderlying","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"loans","outputs":[{"internalType":"bytes32","name":"id","type":"bytes32"},{"internalType":"bytes32","name":"loanParamsId","type":"bytes32"},{"internalType":"bytes32","name":"pendingTradesId","type":"bytes32"},{"internalType":"uint256","name":"principal","type":"uint256"},{"internalType":"uint256","name":"collateral","type":"uint256"},{"internalType":"uint256","name":"startTimestamp","type":"uint256"},{"internalType":"uint256","name":"endTimestamp","type":"uint256"},{"internalType":"uint256","name":"startMargin","type":"uint256"},{"internalType":"uint256","name":"startRate","type":"uint256"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"lender","type":"address"},{"internalType":"bool","name":"active","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"name":"logicTargets","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"maxDisagreement","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"maxSwapSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"priceFeeds","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"protocolTokenHeld","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"protocolTokenPaid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"loanId","type":"bytes32"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"withdrawAmount","type":"uint256"}],"name":"reduceLoanDuration","outputs":[{"internalType":"uint256","name":"secondsReduced","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"rewardsBalanceOf","outputs":[{"internalType":"uint256","name":"rewardsBalance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"loanId","type":"bytes32"},{"internalType":"uint256","name":"depositValueAsLoanToken","type":"uint256"},{"internalType":"uint256","name":"depositValueAsCollateralToken","type":"uint256"}],"name":"setDepositAmount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"sourceBufferPercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"supportedTokens","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"swapsImpl","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"tradingFeePercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"tradingFeeTokensHeld","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"tradingFeeTokensPaid","outputs":[{"internalType":"uint256","name":"","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"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"underlyingToLoanPool","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"vbzrxTokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"wethToken","outputs":[{"internalType":"contract IWethERC20","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"loanToken","type":"address"}],"name":"withdrawAccruedInterest","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"loanId","type":"bytes32"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"withdrawAmount","type":"uint256"}],"name":"withdrawCollateral","outputs":[{"internalType":"uint256","name":"actualWithdrawAmount","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]

60806040526001600055678ac7230489e80000601455670214e8348c4f000060175567013fbe85edc90000601a556801a055690d9db80000601f55674563918244f40000602655674563918244f40000602755685150ae84a8cdf00000602855600062000071620000c560201b60201c565b600180546001600160a01b0319166001600160a01b038316908117909155604051919250906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350620000c9565b3390565b61533b80620000d96000396000f3fe6080604052600436106102ff5760003560e01c80638da5cb5b11610190578063cb6eacd1116100dc578063dea9b46411610095578063edab119f1161006f578063edab119f146108f6578063ef5cfb8c1461090b578063f27451ac1461092b578063f2fde38b1461094b576102ff565b8063dea9b464146108ae578063e81fefa0146108c1578063e8f62764146108e1576102ff565b8063cb6eacd1146107f2578063cfc85c0614610826578063d1979fb014610839578063d473c2da14610859578063d485045e1461086e578063db35400d1461088e576102ff565b8063ab3bd42811610149578063b30643d911610123578063b30643d91461075a578063b7e152411461077a578063c4a908151461079a578063c4d66de8146107d2576102ff565b8063ab3bd42814610703578063ae0a853014610723578063b1bb822514610738576102ff565b80638da5cb5b146106545780638dc48ba5146106695780638f32d59b1461068957806392d894f81461069e5780639b16cd87146106be578063ab2c9d75146106ee576102ff565b80634699f8461161024f57806362fff3f6116102085780637420ca3e116101e25780637420ca3e146105e857806378d849ed146105fd5780637a8faeb8146106125780638932f5f714610627576102ff565b806362fff3f61461058257806368c4ac26146105b3578063691bfee8146105d3576102ff565b80634699f846146104d25780634b57b0be146104e75780634f28cac21461050957806351c4e7b21461051e578063569fc1fb1461053357806360857c2c14610562576102ff565b806333dc41c7116102bc578063369ed07211610296578063369ed0721461044357806339cd381e146104705780634115a2b6146104855780634203e395146104b2576102ff565b806333dc41c7146103e35780633432423c146104035780633452d2d414610423576102ff565b8063065d810f14610304578063122f0e3a1461033f57806317548b791461036c578063218b39c6146103995780632a324027146103b95780632f470764146103ce575b600080fd5b34801561031057600080fd5b5061032461031f3660046140cc565b61096b565b604051610336969594939291906151ba565b60405180910390f35b34801561034b57600080fd5b5061035f61035a3660046141de565b6109ab565b6040516103369190615175565b34801561037857600080fd5b5061038c6103873660046142fa565b610d66565b6040516103369190614c74565b3480156103a557600080fd5b5061038c6103b4366004614044565b610d81565b3480156103c557600080fd5b5061035f610d9c565b3480156103da57600080fd5b5061035f610da2565b3480156103ef57600080fd5b5061035f6103fe366004614044565b610da8565b34801561040f57600080fd5b5061032461041e3660046140cc565b610e01565b34801561042f57600080fd5b5061035f61043e366004614044565b610e41565b34801561044f57600080fd5b5061046361045e3660046140fc565b610e53565b6040516103369190614dfe565b34801561047c57600080fd5b5061038c610fb3565b34801561049157600080fd5b506104a56104a03660046141bf565b610fcb565b6040516103369190614e0f565b3480156104be57600080fd5b5061035f6104cd366004614044565b610feb565b3480156104de57600080fd5b5061035f610ffd565b3480156104f357600080fd5b506104fc611003565b6040516103369190614f67565b34801561051557600080fd5b5061035f61101b565b34801561052a57600080fd5b5061035f611021565b34801561053f57600080fd5b5061055361054e3660046141a1565b611032565b60405161033693929190615191565b34801561056e57600080fd5b5061046361057d366004614366565b611053565b34801561058e57600080fd5b506105a261059d366004614062565b611165565b60405161033695949392919061519f565b3480156105bf57600080fd5b506104a56105ce366004614044565b61119f565b3480156105df57600080fd5b5061035f6111b4565b3480156105f457600080fd5b5061038c6111ba565b34801561060957600080fd5b5061038c6111c9565b34801561061e57600080fd5b5061035f6111d8565b34801561063357600080fd5b506106476106423660046141a1565b6111de565b6040516103369190615166565b34801561066057600080fd5b5061038c6111f8565b34801561067557600080fd5b5061038c610684366004614044565b611207565b34801561069557600080fd5b506104a5611222565b3480156106aa57600080fd5b5061035f6106b9366004614044565b611248565b3480156106ca57600080fd5b506106de6106d93660046141a1565b61125a565b6040516103369493929190614de3565b3480156106fa57600080fd5b5061038c6112eb565b34801561070f57600080fd5b5061035f61071e36600461409c565b611303565b34801561072f57600080fd5b5061035f611351565b34801561074457600080fd5b506107586107533660046142c8565b611357565b005b34801561076657600080fd5b5061035f610775366004614044565b61139e565b34801561078657600080fd5b5061035f610795366004614044565b6113b0565b3480156107a657600080fd5b506107ba6107b53660046141a1565b6113c2565b6040516103369c9b9a99989796959493929190614e94565b3480156107de57600080fd5b506107586107ed366004614044565b611435565b3480156107fe57600080fd5b5061081261080d3660046141a1565b61155b565b604051610336989796959493929190614e1d565b61035f61083436600461424a565b6115b2565b34801561084557600080fd5b50610324610854366004614062565b611abc565b34801561086557600080fd5b5061035f611bab565b34801561087a57600080fd5b5061035f610889366004614044565b611bb1565b34801561089a57600080fd5b5061035f6108a93660046141de565b611bc3565b6107586108bc36600461422b565b611f0d565b3480156108cd57600080fd5b506107586108dc366004614044565b612164565b3480156108ed57600080fd5b5061038c61216e565b34801561090257600080fd5b5061035f61217d565b34801561091757600080fd5b5061035f610926366004614044565b612183565b34801561093757600080fd5b5061035f610946366004614062565b6122f6565b34801561095757600080fd5b50610758610966366004614044565b612311565b6008602090815260009283526040808420909152908252902080546001820154600283015460038401546004850154600590950154939492939192909186565b60006001600054146109d85760405162461bcd60e51b81526004016109cf906150d6565b60405180910390fd5b6002600055816109fa5760405162461bcd60e51b81526004016109cf90614f86565b6000848152600560209081526040808320600181015484526006909252909120600a820154600160a01b900460ff16610a455760405162461bcd60e51b81526004016109cf906150c6565b60098201546001600160a01b0316331480610a7b57508154600090815260096020908152604080832033845290915290205460ff165b610a975760405162461bcd60e51b81526004016109cf90615096565b600681015415610ab95760405162461bcd60e51b81526004016109cf90614fb6565b42826006015411610adc5760405162461bcd60e51b81526004016109cf90615106565b600a8201546002820154610afc916001600160a01b03908116911661233e565b81546000818152600b60205260409020600283015460098501549192610b319284926001600160a01b0390811691164261241c565b6000610b7162015180610b658460000154610b594289600601546124c990919063ffffffff16565b9063ffffffff61250b16565b9063ffffffff61254516565b9050808610610b925760405162461bcd60e51b81526004016109cf90615056565b60028301546001600160a01b031673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21415610bca57610bc58787612587565b610be3565b6002830154610be3906001600160a01b03168888612668565b8154610bfc90610b65886201518063ffffffff61250b16565b945084846006015411610c215760405162461bcd60e51b81526004016109cf90614ff6565b6006840154610c36908663ffffffff6124c916565b6006850181905542108015610c525750610e1042856006015403115b610c6e5760405162461bcd60e51b81526004016109cf90614ff6565b6001820154610c83908763ffffffff6124c916565b6001830155600a848101546001600160a01b039081166000908152602092835260408082206002808901549094168352909352919091200154610ccc908763ffffffff6124c916565b600a858101546001600160a01b039081166000908152602092835260408082206002808a0180548616855291909552918190209093019390935591546009870154600688015492518c949283169391909216917f2ccf872a9a65a45661ce779b7bc6808ef3a167e50289371df14de6df2f817c7d91610d4d918c9190615183565b60405180910390a4505060016000555090949350505050565b6004602052600090815260409020546001600160a01b031681565b6022602052600090815260409020546001600160a01b031681565b60175481565b601e5481565b600080826040518060400160405280600b81526020016a557365725265776172647360a81b815250604051602001610de1929190614c41565b60408051601f198184030181529190528051602090910120549392505050565b6007602090815260009283526040808420909152908252902080546001820154600283015460038401546004850154600590950154939492939192909186565b60196020526000908152604090205481565b6060600083610e79576001600160a01b0388166000908152601160205260409020610e92565b6001600160a01b03881660009081526010602052604090205b90506000610ebe610ea2836126d8565b610eb28a8a63ffffffff6126df16565b9063ffffffff61270416565b9050808810610ecf5750610fa99050565b878103965086610edd613e14565b81604051908082528060200260200182016040528015610f1757816020015b610f04613e14565b815260200190600190039081610efc5790505b50945060001990920191825b8a8110610f9457610f44610f3d868363ffffffff61271a16565b8a8961273e565b8051909250610f5c5780610f5757610f94565b610f8b565b818684806001900395508c0381518110610f7257fe5b60200260200101819052508060001415610f8b57610f94565b60001901610f23565b508115610fa45781890398508885525b505050505b9695505050505050565b73b72b31907c1c95f3650b64b2469e08edacee5e8f81565b600960209081526000928352604080842090915290825290205460ff1681565b60156020526000908152604090205481565b60145481565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b60285481565b600061102d600e6126d8565b905090565b600b6020526000908152604090208054600182015460029092015490919083565b60606000611074611064600e6126d8565b610eb2878763ffffffff6126df16565b9050808510611083575061115e565b848103935083611091613e14565b816040519080825280602002602001820160405280156110cb57816020015b6110b8613e14565b8152602001906001900390816110b05790505b50935060001990920191825b87811061114a576110fa6110f2600e8363ffffffff61271a16565b60008861273e565b8051909250611112578061110d5761114a565b611141565b8185848060019003955089038151811061112857fe5b602002602001018190525080600014156111415761114a565b600019016110d7565b50811561115a5781860395508584525b5050505b9392505050565b600a602090815260009283526040808420909152908252902080546001820154600283015460038401546004909401549293919290919085565b60256020526000908152604090205460ff1681565b60275481565b6003546001600160a01b031681565b6002546001600160a01b031681565b601d5481565b6111e6613e14565b6111f28260008061273e565b92915050565b6001546001600160a01b031690565b6021602052600090815260409020546001600160a01b031681565b6001546000906001600160a01b0316611239612ba1565b6001600160a01b031614905090565b60166020526000908152604090205481565b60008181526005602081815260408084206001808201548652600680855283872060020154888852600b86529387208054920154959094529201546001600160a01b039091169391929190814282106112b357426112b5565b815b90508082116112c55760006112e0565b6112e062015180610b6587610b59868663ffffffff6124c916565b925050509193509193565b7356d811088235f11c8920698a204a5010a788f4b381565b600081611330576001600160a01b038316600090815260116020526040902061132b906126d8565b61115e565b6001600160a01b038316600090815260106020526040902061115e906126d8565b601f5481565b336000908152602160205260409020546001600160a01b031661138c5760405162461bcd60e51b81526004016109cf90615076565b6113998383836000612ba5565b505050565b601c6020526000908152604090205481565b601b6020526000908152604090205481565b600560208190526000918252604090912080546001820154600283015460038401546004850154958501546006860154600787015460088801546009890154600a9099015497999698959794969593949293919290916001600160a01b039081169190811690600160a01b900460ff168c565b61143d611222565b6114595760405162461bcd60e51b81526004016109cf90615096565b61146a6337aa6d1960e21b82612ca2565b61147b63db35400d60e01b82612ca2565b61148c630740ff7d60e51b82612ca2565b61149d6367e42e0360e11b82612ca2565b6114ae630917871d60e11b82612ca2565b6114bf63b1bb822560e01b82612ca2565b6114d0633bd73ee360e21b82612ca2565b6114e16333dc41c760e01b82612ca2565b6114f2630d1979fb60e41b82612ca2565b611503639b16cd8760e01b82612ca2565b611514631b4f683960e11b82612ca2565b6115256315677a8560e31b82612ca2565b611536638932f5f760e01b82612ca2565b6115476318215f0b60e21b82612ca2565b6115586328e273d960e11b82612ca2565b50565b60066020819052600091825260409091208054600182015460028301546003840154600485015460058601549590960154939560ff8416956101009094046001600160a01b03908116959381169492169290919088565b60006001600054146115d65760405162461bcd60e51b81526004016109cf906150d6565b6002600055846115f85760405162461bcd60e51b81526004016109cf906150a6565b6000868152600560209081526040808320600181015484526006909252909120600a820154600160a01b900460ff166116435760405162461bcd60e51b81526004016109cf906150c6565b85158061165c575060098201546001600160a01b031633145b8061168257508154600090815260096020908152604080832033845290915290205460ff165b61169e5760405162461bcd60e51b81526004016109cf90615096565b6006810154156116c05760405162461bcd60e51b81526004016109cf90614fb6565b3415806116f65750851580156116f6575060028101546001600160a01b031673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2145b6117125760405162461bcd60e51b81526004016109cf90614fe6565b600a8201546002820154611732916001600160a01b03908116911661233e565b81546000818152600b602052604090206002830154600985015491926117679284926001600160a01b0390811691164261241c565b600083600601544211156117d757600684015461178b90429063ffffffff6124c916565b82549091506117a190829063ffffffff61250b16565b90506117b6816201518063ffffffff61254516565b90508089116117d75760405162461bcd60e51b81526004016109cf90614fc6565b6000881561185c5760408051610100808201835286548252600187015460ff811615156020840152046001600160a01b039081169282019290925260028601548216606082015260038601549091166080820152600485015460a0820152600585015460c0820152600685015460e08201526118559086908c612d18565b90506118a8565b3461187f57600284015461187a906001600160a01b0316338c612e8b565b6118a8565b89341461189e5760405162461bcd60e51b81526004016109cf90615136565b6118a83334612eef565b81156118e2576118be8a8363ffffffff6124c916565b600a8601546002860154919b506118e2916001600160a01b03918216911684612f9f565b82546118fb90610b658c6201518063ffffffff61250b16565b6006860154909650611913908763ffffffff6126df16565b600686018190554210801561192f5750610e1042866006015403115b61194b5760405162461bcd60e51b81526004016109cf90614ff6565b6001830154611960908b63ffffffff6126df16565b6001840155600a858101546001600160a01b039081166000908152602092835260408082206002808a015490941683529093529190912001546119a9908b63ffffffff6126df16565b600a600087600a0160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060008660020160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b03168152602001908152602001600020600201819055508a8460020160009054906101000a90046001600160a01b03166001600160a01b03168660090160009054906101000a90046001600160a01b03166001600160a01b03167f1a82d5bf63a278f4fcb396bfc36eb7457ad565605dd62b6f0f80619f811279db8d858a60060154604051611aa093929190615191565b60405180910390a4505060016000555091979650505050505050565b600080600080600080611acd613eb6565b506001600160a01b038089166000908152600a60209081526040808320938b16835292815290829020825160a081018452815481526001820154928101839052600282015493810193909352600381015460608401526004015460808301819052611b4d916201518091610b659190610b5990429063ffffffff6124c916565b93508060400151841115611b6357806040015193505b606081015180611b74576000611b7a565b81608001515b60208301516080840151611b8f576000611b91565b865b6014549451939d929c50909a509850919650945092505050565b60265481565b60186020526000908152604090205481565b6000600160005414611be75760405162461bcd60e51b81526004016109cf906150d6565b600260005581611c095760405162461bcd60e51b81526004016109cf90614f86565b6000848152600560209081526040808320600181015484526006909252909120600a820154600160a01b900460ff16611c545760405162461bcd60e51b81526004016109cf906150c6565b60098201546001600160a01b0316331480611c8a57508154600090815260096020908152604080832033845290915290205460ff165b611ca65760405162461bcd60e51b81526004016109cf90615096565b600381810154600484810154600280549086015494870154600587015460405163f80b25fb60e01b81526001600160a01b039687169794966000969481169563f80b25fb95611cfe9592909116938a938a9201614d6b565b60206040518083038186803b158015611d1657600080fd5b505afa158015611d2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611d4e9190810190614318565b905080871115611d6057809550611d64565b8695505b60408051808201909152601781527f7769746864726177416d6f756e7420746f6f20686967680000000000000000006020820152611dab908390889063ffffffff612ff616565b6004860181905591506001600160a01b03831673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21415611de857611de38887612587565b611df3565b611df3838988612668565b6002805490850154604051630a7549df60e21b815260009283926001600160a01b03918216926329d5277c92611e30928a92911690600401614c82565b604080518083038186803b158015611e4757600080fd5b505afa158015611e5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611e7f9190810190614336565b9150915081600014611eab57611eab8b611ea383610b658c8763ffffffff61250b16565b8a6001612ba5565b60098701546040518c916001600160a01b03808916929116907f7b1bab051266a4a36232da9b4341daf225fa42f7202b0e7207b9b502644ff1bb90611ef1908d90615175565b60405180910390a4505060016000555093979650505050505050565b600160005414611f2f5760405162461bcd60e51b81526004016109cf906150d6565b600260005580611f515760405162461bcd60e51b81526004016109cf906150a6565b6000828152600560205260409020600a810154600160a01b900460ff16611f8a5760405162461bcd60e51b81526004016109cf906150c6565b60018101546000908152600660205260409020600381015460048301546001600160a01b0390911690341580611fdc57506001600160a01b03821673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2145b611ff85760405162461bcd60e51b81526004016109cf90614fe6565b612008818663ffffffff6126df16565b6004850181905590503461202657612021823387612e8b565b61204f565b8434146120455760405162461bcd60e51b81526004016109cf90615136565b61204f3334612eef565b6002805490840154604051630a7549df60e21b815260009283926001600160a01b03918216926329d5277c9261208c928992911690600401614c82565b604080518083038186803b1580156120a357600080fd5b505afa1580156120b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506120db9190810190614336565b915091508160001461210757612107886120ff83610b658b8763ffffffff61250b16565b896000612ba5565b600986015460405189916001600160a01b03808816929116907fa8a69faa6a38cc9c2beed79e034e1bd99f7eac877a5cee9f0118a8667b7ed93e9061214d908c90615175565b60405180910390a450506001600055505050505050565b611558338261233e565b6013546001600160a01b031681565b601a5481565b600080336040518060400160405280600b81526020016a557365725265776172647360a81b8152506040516020016121bc929190614c41565b60405160208183030381529060405280519060200120905080549150816000146122f05760008155601e546121f7908363ffffffff6126df16565b601e5560405163a9059cbb60e01b815273b72b31907c1c95f3650b64b2469e08edacee5e8f9063a9059cbb906122339086908690600401614dad565b602060405180830381600087803b15801561224d57600080fd5b505af1158015612261573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506122859190810190614183565b5073b72b31907c1c95f3650b64b2469e08edacee5e8f6001600160a01b0316836001600160a01b0316336001600160a01b03167ff9ce28130cf0ab6ae397696b8e3f3c22063af7b518a2d85c64520eadcb39155f856040516122e79190615175565b60405180910390a45b50919050565b60208080526000928352604080842090915290825290205481565b612319611222565b6123355760405162461bcd60e51b81526004016109cf90615096565b61155881613022565b6001600160a01b038083166000908152600a60209081526040808320938516835292905290812060018101549091901580159061237e5750600482015415155b1561240f576123a962015180610b658460010154610b598660040154426124c990919063ffffffff16565b42600484015560028301549091508111156123c5575060028101545b801561240a5760038201546123e0908263ffffffff6126df16565b600383015560028201546123fa908263ffffffff6124c916565b600283015561240a848483612f9f565b612416565b4260048301555b50505050565b600285015460008115612459576014548754612456916a07259756a8d6199800000091610b659190610b599081898963ffffffff6124c916565b90505b6002870183905580156124c05785856001600160a01b0316856001600160a01b03167fcf877e0841dcb21fb3fc42f1273a3ad3b8e956ec5d00b514bbd34a43b4cda2ee846040516124aa9190615175565b60405180910390a46124c08487878460036130a4565b50505050505050565b600061115e83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612ff6565b60008261251a575060006111f2565b8282028284828161252757fe5b041461115e5760405162461bcd60e51b81526004016109cf90615086565b600061115e83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613280565b80156126645773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2478083111561260c57604051632e1a7d4d60e01b81526001600160a01b03831690632e1a7d4d906125d99084870390600401615175565b600060405180830381600087803b1580156125f357600080fd5b505af1158015612607573d6000803e3d6000fd5b505050505b61261684846132b7565b836001600160a01b0316826001600160a01b03167fc44aeefa68e8b9c1ad5f7be4b0dd194580f81f5c362862e72196503a320eb7a1856040516126599190615175565b60405180910390a350505b5050565b8015611399576126886001600160a01b038416838363ffffffff61335316565b816001600160a01b0316836001600160a01b03167fc44aeefa68e8b9c1ad5f7be4b0dd194580f81f5c362862e72196503a320eb7a1836040516126cb9190615175565b60405180910390a3505050565b6001015490565b60008282018381101561115e5760405162461bcd60e51b81526004016109cf90614fd6565b6000818310612713578161115e565b5090919050565b600082600101828154811061272b57fe5b9060005260206000200154905092915050565b612746613e14565b61274e613ee5565b506000848152600560208181526040928390208351610180810185528154815260018201549281019290925260028101549382019390935260038301546060820152600483015460808201529082015460a0820152600682015460c0820152600782015460e0820152600882015461010082015260098201546001600160a01b03908116610120830152600a90920154918216610140820152600160a01b90910460ff161515610160820152612802613f49565b5060208181015160009081526006808352604091829020825161010080820185528254825260018084015460ff811615159784019790975295046001600160a01b039081169482019490945260028201548416606082015260038201549093166080840152600481015460a0840152600581015460c0840152015460e08201529085600281111561288f57fe5b14801561289e575060e0810151155b806128c2575060028560028111156128b257fe5b1480156128c2575060e081015115155b156128cf575061115e9050565b6128d7613f8d565b506000868152600b602090815260408083208151606080820184528254825260018301549482019490945260029182015481840152905485840151608080880151958901519089015194516317f8680960e11b815293969586956001600160a01b0390941694632ff0d01294612951949391600401614d2d565b604080518083038186803b15801561296857600080fd5b505afa15801561297c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506129a09190810190614336565b915091506000808560c001518411612a2657612a1c87606001518860800151868960c0015187602060008d606001516001600160a01b03166001600160a01b0316815260200190815260200160002060008d608001516001600160a01b03166001600160a01b03168152602001908152602001600020546133ac565b9092509050612a39565b8815612a39575061115e95505050505050565b60008060008d6040518060400160405280601081526020016f4c6f616e4465706f73697456616c756560801b815250604051602001612a79929190614f47565b6040516020818303038152906040528051906020012090508054925060018101549150428a60c001511115612ad557612ace62015180610b658a60000151610b59428f60c001516124c990919063ffffffff16565b9550612ada565b600095505b6040518061022001604052808f81526020018b60c001516001600160601b031681526020018a606001516001600160a01b031681526020018a608001516001600160a01b031681526020018b6060015181526020018b608001518152602001896000015181526020018781526020018b610100015181526020018b60e0015181526020018a60c0015181526020018881526020018a60e001518152602001868152602001858152602001848152602001838152509a50505050505050505050509392505050565b3390565b6000846040518060400160405280601081526020016f4c6f616e4465706f73697456616c756560801b815250604051602001612be2929190614f47565b60405160208183030381529060405280519060200120905080548260008114612c255785821160018114612c195760008455612c1f565b86830384555b50612c2b565b85820183555b50506001018054828015612c595784821160018114612c4d5760008455612c53565b85830384555b50612c5f565b84820183555b5050847f6fdb66f06832f41be9e4313f93e9b50685b11f2540d275342262997f35da88108585604051612c93929190615183565b60405180910390a25050505050565b6001600160e01b03198216600090815260046020526040902080546001600160a01b0319166001600160a01b03831690811790915515612cfd57612cf7600c6001600160e01b0319841663ffffffff6134d816565b50612664565b611399600c6001600160e01b0319841663ffffffff61352016565b600080612d648560000154856080015186606001518860090160009054906101000a90046001600160a01b031689600401546000896001604051806020016040528060008152506135e1565b506004870154909250612d7e91508263ffffffff6124c916565b60048087018290556002546060870151608088015160038a01546040516317f8680960e11b815260009687966001600160a01b0390961695632ff0d01295612dcd959094909390929101614d2d565b604080518083038186803b158015612de457600080fd5b505afa158015612df8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612e1c9190810190614336565b915091508560c001518211612e435760405162461bcd60e51b81526004016109cf906150b6565b8215801590612e5157508015155b15612e80578654612e8090612e78670de0b6b3a7640000610b65878663ffffffff61250b16565b856001612ba5565b509095945050505050565b801561139957612eac6001600160a01b03841683308463ffffffff61373e16565b816001600160a01b0316836001600160a01b03167f2790b90165fd3973ad7edde4eca71b4f8808dd4857a2a3a3e8ae5642a5cb196e836040516126cb9190615175565b600073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29050806001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b158015612f4357600080fd5b505af1158015612f57573d6000803e3d6000fd5b5050505050826001600160a01b0316816001600160a01b03167f2790b90165fd3973ad7edde4eca71b4f8808dd4857a2a3a3e8ae5642a5cb196e846040516126cb9190615175565b6000612fcf68056bc75e2d63100000612fc36014548561250b90919063ffffffff16565b9063ffffffff61376216565b9050612fdc8484836137a4565b6124168385612ff1858563ffffffff6124c916565b612668565b6000818484111561301a5760405162461bcd60e51b81526004016109cf9190614f75565b505050900390565b6001600160a01b0381166130485760405162461bcd60e51b81526004016109cf90614fa6565b6001546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b600280546040516000926001600160a01b03909216918391606091849163d138f9a160e01b916130f2918b917356d811088235f11c8920698a204a5010a788f4b391908c0490602401614d05565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516131309190614c5d565b600060405180830381855afa9150503d806000811461316b576040519150601f19603f3d011682016040523d82523d6000602084013e613170565b606091505b5091509150600182141561318657602081015193505b831561327557601d548085111561319b578094505b8415613273576131b1818663ffffffff6124c916565b601d8190555060008a6040518060400160405280600b81526020016a557365725265776172647360a81b8152506040516020016131ef929190614c41565b60405160208183030381529060405280519060200120905085815401815586600381111561321957fe5b8a8c6001600160a01b03167fe6c5d7a78caa3f3f24c92ef7f180efb19eb4cc6decff0d5b9cbc4d164b718d0973b72b31907c1c95f3650b64b2469e08edacee5e8f8a604051613269929190614dad565b60405180910390a4505b505b505050505050505050565b600081836132a15760405162461bcd60e51b81526004016109cf9190614f75565b5060008385816132ad57fe5b0495945050505050565b804710156132d75760405162461bcd60e51b81526004016109cf90615046565b6000826001600160a01b0316826040516132f090614c69565b60006040518083038185875af1925050503d806000811461332d576040519150601f19603f3d011682016040523d82523d6000602084013e613332565b606091505b50509050806113995760405162461bcd60e51b81526004016109cf90615036565b60405161139990849063a9059cbb60e01b906133759086908690602401614dad565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613825565b600080848611806133bb575083155b156133c5576134cd565b8286116133d65750869050856134cd565b60006133f086674563918244f4000063ffffffff6126df16565b905061341368056bc75e2d63100000610b658b610b59858463ffffffff6126df16565b9250613441613434670de0b6b3a7640000610b658b8963ffffffff61250b16565b849063ffffffff6124c916565b925061346f613456828663ffffffff6124c916565b610b658568056bc75e2d6310000063ffffffff61250b16565b92508883111561347d578892505b6134a66134998568056bc75e2d6310000063ffffffff6126df16565b849063ffffffff61250b16565b91506134bd6064610b65848863ffffffff61254516565b9150878211156134cb578791505b505b965096945050505050565b60006134e4838361390a565b61351857506001808301805480830180835560009283526020808420909201859055848352908590526040909120556111f2565b5060006111f2565b600061352c838361390a565b1561351857600082815260208490526040902054600184015460001991820191018082146135a457600085600101828154811061356557fe5b906000526020600020015490508086600101848154811061358257fe5b6000918252602080832090910192909255918252869052604090206001830190555b600084815260208690526040812055600185018054806135c057fe5b600190038181906000526020600020016000905590556001925050506111f2565b6040805160a0810182526001600160a01b03808b16825289811660208084019190915230838501819052606080850191909152918a1660808401528351918201845288825281018790529182018590526000918291829161364591908e888861391f565b90935091506136548b83613ad9565b600254602654604051631e2c62d360e01b81526001600160a01b0390921691631e2c62d39161368d918f918f9188918a91600401614d6b565b60206040518083038186803b1580156136a557600080fd5b505afa1580156136b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506136dd9190810190614318565b9050896001600160a01b03168b6001600160a01b03168d7fb4eb3c9b62efcce7021cba5fd9cd0c44df91c2272806ccc5e57df7c912e8d7168c868860405161372793929190614dc8565b60405180910390a499509950999650505050505050565b6040516124169085906323b872dd60e01b9061337590879087908790602401614d05565b600061115e83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613bb5565b8015611399576001600160a01b0382166000908152601560205260409020546137d3908263ffffffff6126df16565b6001600160a01b0380841660008181526015602052604090819020939093559151908516907f40a75ae5f7a5336e75f7c7977e12c4b46a9ac0f30de01a2d5b6c1a4f4af63587906126cb908590615175565b613837826001600160a01b0316613bff565b6138535760405162461bcd60e51b81526004016109cf90615146565b60006060836001600160a01b03168360405161386f9190614c5d565b6000604051808303816000865af19150503d80600081146138ac576040519150601f19603f3d011682016040523d82523d6000602084013e6138b1565b606091505b5091509150816138d35760405162461bcd60e51b81526004016109cf90615006565b80511561241657808060200190516138ee9190810190614183565b6124165760405162461bcd60e51b81526004016109cf906150f6565b60009081526020919091526040902054151590565b835160009081906139425760405162461bcd60e51b81526004016109cf90615026565b6000806000866139c357604089015161399b576139668960005b6020020151613c3b565b905080156139965760808a015161398790898c60005b602002015184613c5f565b885161399390826124c9565b89525b6139c3565b6139a689600261395c565b905080156139c35760408901516139bd90826126df565b60408a01525b60208901516139d857885160208a01526139fd565b6020890151895111156139fd5760405162461bcd60e51b81526004016109cf90615156565b855115613a1c5760405162461bcd60e51b81526004016109cf906150e6565b613a268a8a613cf8565b60408b01519194509250613a645788518214613a545760405162461bcd60e51b81526004016109cf90615126565b8015613a5f57908101905b613aca565b6020890151821115613a885760405162461bcd60e51b81526004016109cf90615016565b6040890151831015613aac5760405162461bcd60e51b81526004016109cf90614f96565b8015613aca5760808a0151613ac490898c600161397c565b80830392505b50909890975095505050505050565b60285480156113995760006001600160a01b03841673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21415613b10575081613b95565b600254604051635967aa7560e11b81526001600160a01b039091169063b2cf54ea90613b429087908790600401614dad565b60206040518083038186803b158015613b5a57600080fd5b505afa158015613b6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250613b929190810190614318565b90505b818111156124165760405162461bcd60e51b81526004016109cf90615066565b60008183613bd65760405162461bcd60e51b81526004016109cf9190614f75565b5083613be45750600061115e565b6000836001860381613bf257fe5b0460010195945050505050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590613c3357508115155b949350505050565b60006111f268056bc75e2d63100000612fc36017548561250b90919063ffffffff16565b8015612416576001600160a01b038216600090815260186020526040902054613c8e908263ffffffff6126df16565b6001600160a01b03808416600081815260186020526040908190209390935591518592918716907fb23479169712c443e6b00fb0cec3506a5f5926f541df4243d313e11c8c5c71ed90613ce2908690615175565b60405180910390a46124168484848460016130a4565b815160208084015160408086015160608781015187519588015188850151945160009889989497632bea876360e01b97613d3f979296919592949293919291602401614c9d565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925260035491519092506000916001600160a01b031690613d91908490614c5d565b600060405180830381855af49150503d8060008114613dcc576040519150601f19603f3d011682016040523d82523d6000602084013e613dd1565b606091505b509250905080613df35760405162461bcd60e51b81526004016109cf90615116565b81806020019051613e079190810190614336565b9097909650945050505050565b6040518061022001604052806000801916815260200160006001600160601b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810182905261016081019190915290565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915290565b60405180606001604052806000815260200160008152602001600081525090565b80356111f2816152bc565b80356111f2816152d0565b80516111f2816152d0565b80356111f2816152d9565b80356111f2816152e2565b60008083601f840112613ff757600080fd5b50813567ffffffffffffffff81111561400f57600080fd5b60208301915083600182028301111561402757600080fd5b9250929050565b80356111f2816152eb565b80516111f2816152d9565b60006020828403121561405657600080fd5b6000613c338484613fae565b6000806040838503121561407557600080fd5b60006140818585613fae565b925050602061409285828601613fae565b9150509250929050565b600080604083850312156140af57600080fd5b60006140bb8585613fae565b925050602061409285828601613fb9565b600080604083850312156140df57600080fd5b60006140eb8585613fae565b925050602061409285828601613fcf565b60008060008060008060c0878903121561411557600080fd5b60006141218989613fae565b965050602061413289828a01613fcf565b955050604061414389828a01613fcf565b945050606061415489828a0161402e565b935050608061416589828a01613fb9565b92505060a061417689828a01613fb9565b9150509295509295509295565b60006020828403121561419557600080fd5b6000613c338484613fc4565b6000602082840312156141b357600080fd5b6000613c338484613fcf565b600080604083850312156141d257600080fd5b60006140818585613fcf565b6000806000606084860312156141f357600080fd5b60006141ff8686613fcf565b935050602061421086828701613fae565b925050604061422186828701613fcf565b9150509250925092565b6000806040838503121561423e57600080fd5b60006140eb8585613fcf565b60008060008060006080868803121561426257600080fd5b600061426e8888613fcf565b955050602061427f88828901613fcf565b945050604061429088828901613fb9565b935050606086013567ffffffffffffffff8111156142ad57600080fd5b6142b988828901613fe5565b92509250509295509295909350565b6000806000606084860312156142dd57600080fd5b60006142e98686613fcf565b935050602061421086828701613fcf565b60006020828403121561430c57600080fd5b6000613c338484613fda565b60006020828403121561432a57600080fd5b6000613c338484614039565b6000806040838503121561434957600080fd5b60006143558585614039565b925050602061409285828601614039565b60008060006060848603121561437b57600080fd5b60006143878686613fcf565b935050602061439886828701613fcf565b925050604061422186828701613fb9565b60006143b58383614ae4565b50506102200190565b6143cf6143ca8261522c565b61529b565b82525050565b6143cf8161522c565b60006143e98261521a565b6143f3818561521e565b93506143fe83615214565b8060005b8381101561442c57815161441688826143a9565b975061442183615214565b925050600101614402565b509495945050505050565b6143cf81615237565b6143cf8161523c565b60006144548261521a565b61445e8185615227565b935061446e81856020860161526f565b9290920192915050565b6143cf81615264565b600061448c8261521a565b614496818561521e565b93506144a681856020860161526f565b6144af816152ac565b9093019392505050565b60006144c660138361521e565b7207769746864726177416d6f756e74206973203606c1b815260200192915050565b60006144f5601b8361521e565b7f696e73756666696369656e742073776170206c69717569646974790000000000815260200192915050565b600061452e60268361521e565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015260400192915050565b600061457660148361521e565b73696e646566696e6974652d7465726d206f6e6c7960601b815260200192915050565b60006145a660228361521e565b7f6465706f7369742063616e6e6f7420636f766572206261636b20696e746572658152611cdd60f21b602082015260400192915050565b60006145ea601b8361521e565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b600061462360108361521e565b6f1ddc9bdb99c8185cdcd95d081cd95b9d60821b815260200192915050565b600061464f600e8361521e565b6d1b1bd85b881d1bdbc81cda1bdc9d60921b815260200192915050565b600061467960208361521e565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b60006146b260138361521e565b72737761702066696c6c20746f6f206c6172676560681b815260200192915050565b60006146e160118361521e565b700736f75726365416d6f756e74203d3d203607c1b815260200192915050565b600061470e603a8361521e565b7f416464726573733a20756e61626c6520746f2073656e642076616c75652c207281527f6563697069656e74206d61792068617665207265766572746564000000000000602082015260400192915050565b600061476d601d8361521e565b7f416464726573733a20696e73756666696369656e742062616c616e6365000000815260200192915050565b60006147a660188361521e565b7f776974686472617720616d6f756e7420746f6f20686967680000000000000000815260200192915050565b60006147df600e8361521e565b6d7377617020746f6f206c6172676560901b815260200192915050565b6000614809600e8361521e565b6d1b9bdd08185d5d1a1bdc9a5e995960921b815260200192915050565b600061483360218361521e565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b6000614876600c8361521e565b6b1d5b985d5d1a1bdc9a5e995960a21b815260200192915050565b600061489e60128361521e565b7106465706f736974416d6f756e7420697320360741b815260200192915050565b60006148cc60128361521e565b713ab73432b0b63a343c903837b9b4ba34b7b760711b815260200192915050565b60006111f2600083615227565b6000614907600e8361521e565b6d1b1bd85b881a5cc818db1bdcd95960921b815260200192915050565b6000614931600c8361521e565b6b1b9bdb9499595b9d1c985b9d60a21b815260200192915050565b6000614959600d8361521e565b6c696e76616c696420737461746560981b815260200192915050565b6000614982602a8361521e565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b60006149ce60138361521e565b721b1bd85b881d195c9b481a185cc8195b991959606a1b815260200192915050565b60006149fd600b8361521e565b6a1cddd85c0819985a5b195960aa1b815260200192915050565b6000614a2460168361521e565b751cddd85c081d1bdbc81b185c99d9481d1bc8199a5b1b60521b815260200192915050565b6000614a5660168361521e565b750cae8d0cae440c8cae0dee6d2e840dad2e6dac2e8c6d60531b815260200192915050565b6000614a88601f8361521e565b7f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b6000614ac160148361521e565b730dad2dc40cee4cac2e8cae440e8d0c2dc40dac2f60631b815260200192915050565b8051610220830190614af68482614440565b506020820151614b096020850182614c38565b506040820151614b1c60408501826143d5565b506060820151614b2f60608501826143d5565b506080820151614b426080850182614440565b5060a0820151614b5560a0850182614440565b5060c0820151614b6860c0850182614440565b5060e0820151614b7b60e0850182614440565b50610100820151614b90610100850182614440565b50610120820151614ba5610120850182614440565b50610140820151614bba610140850182614440565b50610160820151614bcf610160850182614440565b50610180820151614be4610180850182614440565b506101a0820151614bf96101a0850182614440565b506101c0820151614c0e6101c0850182614440565b506101e0820151614c236101e0850182614440565b50610200820151612416610200850182614440565b6143cf81615258565b6000614c4d82856143be565b601482019150613c338284614449565b600061115e8284614449565b60006111f2826148ed565b602081016111f282846143d5565b60408101614c9082856143d5565b61115e60208301846143d5565b60e08101614cab828a6143d5565b614cb860208301896143d5565b614cc560408301886143d5565b614cd260608301876143d5565b614cdf6080830186614440565b614cec60a0830185614440565b614cf960c0830184614440565b98975050505050505050565b60608101614d1382866143d5565b614d2060208301856143d5565b613c336040830184614440565b60808101614d3b82876143d5565b614d4860208301866143d5565b614d556040830185614440565b614d626060830184614440565b95945050505050565b60a08101614d7982886143d5565b614d8660208301876143d5565b614d936040830186614440565b614da06060830185614440565b610fa96080830184614440565b60408101614dbb82856143d5565b61115e6020830184614440565b60608101614dd682866143d5565b614d206020830185614440565b60808101614df182876143d5565b614d486020830186614440565b6020808252810161115e81846143de565b602081016111f28284614437565b6101008101614e2c828b614440565b614e39602083018a614437565b614e4660408301896143d5565b614e5360608301886143d5565b614e6060808301876143d5565b614e6d60a0830186614440565b614e7a60c0830185614440565b614e8760e0830184614440565b9998505050505050505050565b6101808101614ea3828f614440565b614eb0602083018e614440565b614ebd604083018d614440565b614eca606083018c614440565b614ed7608083018b614440565b614ee460a083018a614440565b614ef160c0830189614440565b614efe60e0830188614440565b614f0c610100830187614440565b614f1a6101208301866143d5565b614f286101408301856143d5565b614f36610160830184614437565b9d9c50505050505050505050505050565b60408101614f558285614440565b8181036020830152613c338184614481565b602081016111f28284614478565b6020808252810161115e8184614481565b602080825281016111f2816144b9565b602080825281016111f2816144e8565b602080825281016111f281614521565b602080825281016111f281614569565b602080825281016111f281614599565b602080825281016111f2816145dd565b602080825281016111f281614616565b602080825281016111f281614642565b602080825281016111f28161466c565b602080825281016111f2816146a5565b602080825281016111f2816146d4565b602080825281016111f281614701565b602080825281016111f281614760565b602080825281016111f281614799565b602080825281016111f2816147d2565b602080825281016111f2816147fc565b602080825281016111f281614826565b602080825281016111f281614869565b602080825281016111f281614891565b602080825281016111f2816148bf565b602080825281016111f2816148fa565b602080825281016111f281614924565b602080825281016111f28161494c565b602080825281016111f281614975565b602080825281016111f2816149c1565b602080825281016111f2816149f0565b602080825281016111f281614a17565b602080825281016111f281614a49565b602080825281016111f281614a7b565b602080825281016111f281614ab4565b61022081016111f28284614ae4565b602081016111f28284614440565b60408101614dbb8285614440565b60608101614dd68286614440565b60a081016151ad8288614440565b614d866020830187614440565b60c081016151c88289614440565b6151d56020830188614440565b6151e26040830187614440565b6151ef6060830186614440565b6151fc6080830185614440565b61520960a0830184614440565b979650505050505050565b60200190565b5190565b90815260200190565b919050565b60006111f28261524c565b151590565b90565b6001600160e01b03191690565b6001600160a01b031690565b6001600160601b031690565b60006111f28261522c565b60005b8381101561528a578181015183820152602001615272565b838111156124165750506000910152565b60006111f28260006111f2826152b6565b601f01601f191690565b60601b90565b6152c58161522c565b811461155857600080fd5b6152c581615237565b6152c58161523c565b6152c58161523f565b6003811061155857600080fdfea365627a7a7231582054acbafafa6908356df4b14019a2815a4f242caed603fbe98f637bc9471c488f6c6578706572696d656e74616cf564736f6c63430005110040

Deployed Bytecode

0x6080604052600436106102ff5760003560e01c80638da5cb5b11610190578063cb6eacd1116100dc578063dea9b46411610095578063edab119f1161006f578063edab119f146108f6578063ef5cfb8c1461090b578063f27451ac1461092b578063f2fde38b1461094b576102ff565b8063dea9b464146108ae578063e81fefa0146108c1578063e8f62764146108e1576102ff565b8063cb6eacd1146107f2578063cfc85c0614610826578063d1979fb014610839578063d473c2da14610859578063d485045e1461086e578063db35400d1461088e576102ff565b8063ab3bd42811610149578063b30643d911610123578063b30643d91461075a578063b7e152411461077a578063c4a908151461079a578063c4d66de8146107d2576102ff565b8063ab3bd42814610703578063ae0a853014610723578063b1bb822514610738576102ff565b80638da5cb5b146106545780638dc48ba5146106695780638f32d59b1461068957806392d894f81461069e5780639b16cd87146106be578063ab2c9d75146106ee576102ff565b80634699f8461161024f57806362fff3f6116102085780637420ca3e116101e25780637420ca3e146105e857806378d849ed146105fd5780637a8faeb8146106125780638932f5f714610627576102ff565b806362fff3f61461058257806368c4ac26146105b3578063691bfee8146105d3576102ff565b80634699f846146104d25780634b57b0be146104e75780634f28cac21461050957806351c4e7b21461051e578063569fc1fb1461053357806360857c2c14610562576102ff565b806333dc41c7116102bc578063369ed07211610296578063369ed0721461044357806339cd381e146104705780634115a2b6146104855780634203e395146104b2576102ff565b806333dc41c7146103e35780633432423c146104035780633452d2d414610423576102ff565b8063065d810f14610304578063122f0e3a1461033f57806317548b791461036c578063218b39c6146103995780632a324027146103b95780632f470764146103ce575b600080fd5b34801561031057600080fd5b5061032461031f3660046140cc565b61096b565b604051610336969594939291906151ba565b60405180910390f35b34801561034b57600080fd5b5061035f61035a3660046141de565b6109ab565b6040516103369190615175565b34801561037857600080fd5b5061038c6103873660046142fa565b610d66565b6040516103369190614c74565b3480156103a557600080fd5b5061038c6103b4366004614044565b610d81565b3480156103c557600080fd5b5061035f610d9c565b3480156103da57600080fd5b5061035f610da2565b3480156103ef57600080fd5b5061035f6103fe366004614044565b610da8565b34801561040f57600080fd5b5061032461041e3660046140cc565b610e01565b34801561042f57600080fd5b5061035f61043e366004614044565b610e41565b34801561044f57600080fd5b5061046361045e3660046140fc565b610e53565b6040516103369190614dfe565b34801561047c57600080fd5b5061038c610fb3565b34801561049157600080fd5b506104a56104a03660046141bf565b610fcb565b6040516103369190614e0f565b3480156104be57600080fd5b5061035f6104cd366004614044565b610feb565b3480156104de57600080fd5b5061035f610ffd565b3480156104f357600080fd5b506104fc611003565b6040516103369190614f67565b34801561051557600080fd5b5061035f61101b565b34801561052a57600080fd5b5061035f611021565b34801561053f57600080fd5b5061055361054e3660046141a1565b611032565b60405161033693929190615191565b34801561056e57600080fd5b5061046361057d366004614366565b611053565b34801561058e57600080fd5b506105a261059d366004614062565b611165565b60405161033695949392919061519f565b3480156105bf57600080fd5b506104a56105ce366004614044565b61119f565b3480156105df57600080fd5b5061035f6111b4565b3480156105f457600080fd5b5061038c6111ba565b34801561060957600080fd5b5061038c6111c9565b34801561061e57600080fd5b5061035f6111d8565b34801561063357600080fd5b506106476106423660046141a1565b6111de565b6040516103369190615166565b34801561066057600080fd5b5061038c6111f8565b34801561067557600080fd5b5061038c610684366004614044565b611207565b34801561069557600080fd5b506104a5611222565b3480156106aa57600080fd5b5061035f6106b9366004614044565b611248565b3480156106ca57600080fd5b506106de6106d93660046141a1565b61125a565b6040516103369493929190614de3565b3480156106fa57600080fd5b5061038c6112eb565b34801561070f57600080fd5b5061035f61071e36600461409c565b611303565b34801561072f57600080fd5b5061035f611351565b34801561074457600080fd5b506107586107533660046142c8565b611357565b005b34801561076657600080fd5b5061035f610775366004614044565b61139e565b34801561078657600080fd5b5061035f610795366004614044565b6113b0565b3480156107a657600080fd5b506107ba6107b53660046141a1565b6113c2565b6040516103369c9b9a99989796959493929190614e94565b3480156107de57600080fd5b506107586107ed366004614044565b611435565b3480156107fe57600080fd5b5061081261080d3660046141a1565b61155b565b604051610336989796959493929190614e1d565b61035f61083436600461424a565b6115b2565b34801561084557600080fd5b50610324610854366004614062565b611abc565b34801561086557600080fd5b5061035f611bab565b34801561087a57600080fd5b5061035f610889366004614044565b611bb1565b34801561089a57600080fd5b5061035f6108a93660046141de565b611bc3565b6107586108bc36600461422b565b611f0d565b3480156108cd57600080fd5b506107586108dc366004614044565b612164565b3480156108ed57600080fd5b5061038c61216e565b34801561090257600080fd5b5061035f61217d565b34801561091757600080fd5b5061035f610926366004614044565b612183565b34801561093757600080fd5b5061035f610946366004614062565b6122f6565b34801561095757600080fd5b50610758610966366004614044565b612311565b6008602090815260009283526040808420909152908252902080546001820154600283015460038401546004850154600590950154939492939192909186565b60006001600054146109d85760405162461bcd60e51b81526004016109cf906150d6565b60405180910390fd5b6002600055816109fa5760405162461bcd60e51b81526004016109cf90614f86565b6000848152600560209081526040808320600181015484526006909252909120600a820154600160a01b900460ff16610a455760405162461bcd60e51b81526004016109cf906150c6565b60098201546001600160a01b0316331480610a7b57508154600090815260096020908152604080832033845290915290205460ff165b610a975760405162461bcd60e51b81526004016109cf90615096565b600681015415610ab95760405162461bcd60e51b81526004016109cf90614fb6565b42826006015411610adc5760405162461bcd60e51b81526004016109cf90615106565b600a8201546002820154610afc916001600160a01b03908116911661233e565b81546000818152600b60205260409020600283015460098501549192610b319284926001600160a01b0390811691164261241c565b6000610b7162015180610b658460000154610b594289600601546124c990919063ffffffff16565b9063ffffffff61250b16565b9063ffffffff61254516565b9050808610610b925760405162461bcd60e51b81526004016109cf90615056565b60028301546001600160a01b031673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21415610bca57610bc58787612587565b610be3565b6002830154610be3906001600160a01b03168888612668565b8154610bfc90610b65886201518063ffffffff61250b16565b945084846006015411610c215760405162461bcd60e51b81526004016109cf90614ff6565b6006840154610c36908663ffffffff6124c916565b6006850181905542108015610c525750610e1042856006015403115b610c6e5760405162461bcd60e51b81526004016109cf90614ff6565b6001820154610c83908763ffffffff6124c916565b6001830155600a848101546001600160a01b039081166000908152602092835260408082206002808901549094168352909352919091200154610ccc908763ffffffff6124c916565b600a858101546001600160a01b039081166000908152602092835260408082206002808a0180548616855291909552918190209093019390935591546009870154600688015492518c949283169391909216917f2ccf872a9a65a45661ce779b7bc6808ef3a167e50289371df14de6df2f817c7d91610d4d918c9190615183565b60405180910390a4505060016000555090949350505050565b6004602052600090815260409020546001600160a01b031681565b6022602052600090815260409020546001600160a01b031681565b60175481565b601e5481565b600080826040518060400160405280600b81526020016a557365725265776172647360a81b815250604051602001610de1929190614c41565b60408051601f198184030181529190528051602090910120549392505050565b6007602090815260009283526040808420909152908252902080546001820154600283015460038401546004850154600590950154939492939192909186565b60196020526000908152604090205481565b6060600083610e79576001600160a01b0388166000908152601160205260409020610e92565b6001600160a01b03881660009081526010602052604090205b90506000610ebe610ea2836126d8565b610eb28a8a63ffffffff6126df16565b9063ffffffff61270416565b9050808810610ecf5750610fa99050565b878103965086610edd613e14565b81604051908082528060200260200182016040528015610f1757816020015b610f04613e14565b815260200190600190039081610efc5790505b50945060001990920191825b8a8110610f9457610f44610f3d868363ffffffff61271a16565b8a8961273e565b8051909250610f5c5780610f5757610f94565b610f8b565b818684806001900395508c0381518110610f7257fe5b60200260200101819052508060001415610f8b57610f94565b60001901610f23565b508115610fa45781890398508885525b505050505b9695505050505050565b73b72b31907c1c95f3650b64b2469e08edacee5e8f81565b600960209081526000928352604080842090915290825290205460ff1681565b60156020526000908152604090205481565b60145481565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b60285481565b600061102d600e6126d8565b905090565b600b6020526000908152604090208054600182015460029092015490919083565b60606000611074611064600e6126d8565b610eb2878763ffffffff6126df16565b9050808510611083575061115e565b848103935083611091613e14565b816040519080825280602002602001820160405280156110cb57816020015b6110b8613e14565b8152602001906001900390816110b05790505b50935060001990920191825b87811061114a576110fa6110f2600e8363ffffffff61271a16565b60008861273e565b8051909250611112578061110d5761114a565b611141565b8185848060019003955089038151811061112857fe5b602002602001018190525080600014156111415761114a565b600019016110d7565b50811561115a5781860395508584525b5050505b9392505050565b600a602090815260009283526040808420909152908252902080546001820154600283015460038401546004909401549293919290919085565b60256020526000908152604090205460ff1681565b60275481565b6003546001600160a01b031681565b6002546001600160a01b031681565b601d5481565b6111e6613e14565b6111f28260008061273e565b92915050565b6001546001600160a01b031690565b6021602052600090815260409020546001600160a01b031681565b6001546000906001600160a01b0316611239612ba1565b6001600160a01b031614905090565b60166020526000908152604090205481565b60008181526005602081815260408084206001808201548652600680855283872060020154888852600b86529387208054920154959094529201546001600160a01b039091169391929190814282106112b357426112b5565b815b90508082116112c55760006112e0565b6112e062015180610b6587610b59868663ffffffff6124c916565b925050509193509193565b7356d811088235f11c8920698a204a5010a788f4b381565b600081611330576001600160a01b038316600090815260116020526040902061132b906126d8565b61115e565b6001600160a01b038316600090815260106020526040902061115e906126d8565b601f5481565b336000908152602160205260409020546001600160a01b031661138c5760405162461bcd60e51b81526004016109cf90615076565b6113998383836000612ba5565b505050565b601c6020526000908152604090205481565b601b6020526000908152604090205481565b600560208190526000918252604090912080546001820154600283015460038401546004850154958501546006860154600787015460088801546009890154600a9099015497999698959794969593949293919290916001600160a01b039081169190811690600160a01b900460ff168c565b61143d611222565b6114595760405162461bcd60e51b81526004016109cf90615096565b61146a6337aa6d1960e21b82612ca2565b61147b63db35400d60e01b82612ca2565b61148c630740ff7d60e51b82612ca2565b61149d6367e42e0360e11b82612ca2565b6114ae630917871d60e11b82612ca2565b6114bf63b1bb822560e01b82612ca2565b6114d0633bd73ee360e21b82612ca2565b6114e16333dc41c760e01b82612ca2565b6114f2630d1979fb60e41b82612ca2565b611503639b16cd8760e01b82612ca2565b611514631b4f683960e11b82612ca2565b6115256315677a8560e31b82612ca2565b611536638932f5f760e01b82612ca2565b6115476318215f0b60e21b82612ca2565b6115586328e273d960e11b82612ca2565b50565b60066020819052600091825260409091208054600182015460028301546003840154600485015460058601549590960154939560ff8416956101009094046001600160a01b03908116959381169492169290919088565b60006001600054146115d65760405162461bcd60e51b81526004016109cf906150d6565b6002600055846115f85760405162461bcd60e51b81526004016109cf906150a6565b6000868152600560209081526040808320600181015484526006909252909120600a820154600160a01b900460ff166116435760405162461bcd60e51b81526004016109cf906150c6565b85158061165c575060098201546001600160a01b031633145b8061168257508154600090815260096020908152604080832033845290915290205460ff165b61169e5760405162461bcd60e51b81526004016109cf90615096565b6006810154156116c05760405162461bcd60e51b81526004016109cf90614fb6565b3415806116f65750851580156116f6575060028101546001600160a01b031673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2145b6117125760405162461bcd60e51b81526004016109cf90614fe6565b600a8201546002820154611732916001600160a01b03908116911661233e565b81546000818152600b602052604090206002830154600985015491926117679284926001600160a01b0390811691164261241c565b600083600601544211156117d757600684015461178b90429063ffffffff6124c916565b82549091506117a190829063ffffffff61250b16565b90506117b6816201518063ffffffff61254516565b90508089116117d75760405162461bcd60e51b81526004016109cf90614fc6565b6000881561185c5760408051610100808201835286548252600187015460ff811615156020840152046001600160a01b039081169282019290925260028601548216606082015260038601549091166080820152600485015460a0820152600585015460c0820152600685015460e08201526118559086908c612d18565b90506118a8565b3461187f57600284015461187a906001600160a01b0316338c612e8b565b6118a8565b89341461189e5760405162461bcd60e51b81526004016109cf90615136565b6118a83334612eef565b81156118e2576118be8a8363ffffffff6124c916565b600a8601546002860154919b506118e2916001600160a01b03918216911684612f9f565b82546118fb90610b658c6201518063ffffffff61250b16565b6006860154909650611913908763ffffffff6126df16565b600686018190554210801561192f5750610e1042866006015403115b61194b5760405162461bcd60e51b81526004016109cf90614ff6565b6001830154611960908b63ffffffff6126df16565b6001840155600a858101546001600160a01b039081166000908152602092835260408082206002808a015490941683529093529190912001546119a9908b63ffffffff6126df16565b600a600087600a0160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060008660020160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b03168152602001908152602001600020600201819055508a8460020160009054906101000a90046001600160a01b03166001600160a01b03168660090160009054906101000a90046001600160a01b03166001600160a01b03167f1a82d5bf63a278f4fcb396bfc36eb7457ad565605dd62b6f0f80619f811279db8d858a60060154604051611aa093929190615191565b60405180910390a4505060016000555091979650505050505050565b600080600080600080611acd613eb6565b506001600160a01b038089166000908152600a60209081526040808320938b16835292815290829020825160a081018452815481526001820154928101839052600282015493810193909352600381015460608401526004015460808301819052611b4d916201518091610b659190610b5990429063ffffffff6124c916565b93508060400151841115611b6357806040015193505b606081015180611b74576000611b7a565b81608001515b60208301516080840151611b8f576000611b91565b865b6014549451939d929c50909a509850919650945092505050565b60265481565b60186020526000908152604090205481565b6000600160005414611be75760405162461bcd60e51b81526004016109cf906150d6565b600260005581611c095760405162461bcd60e51b81526004016109cf90614f86565b6000848152600560209081526040808320600181015484526006909252909120600a820154600160a01b900460ff16611c545760405162461bcd60e51b81526004016109cf906150c6565b60098201546001600160a01b0316331480611c8a57508154600090815260096020908152604080832033845290915290205460ff165b611ca65760405162461bcd60e51b81526004016109cf90615096565b600381810154600484810154600280549086015494870154600587015460405163f80b25fb60e01b81526001600160a01b039687169794966000969481169563f80b25fb95611cfe9592909116938a938a9201614d6b565b60206040518083038186803b158015611d1657600080fd5b505afa158015611d2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611d4e9190810190614318565b905080871115611d6057809550611d64565b8695505b60408051808201909152601781527f7769746864726177416d6f756e7420746f6f20686967680000000000000000006020820152611dab908390889063ffffffff612ff616565b6004860181905591506001600160a01b03831673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21415611de857611de38887612587565b611df3565b611df3838988612668565b6002805490850154604051630a7549df60e21b815260009283926001600160a01b03918216926329d5277c92611e30928a92911690600401614c82565b604080518083038186803b158015611e4757600080fd5b505afa158015611e5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611e7f9190810190614336565b9150915081600014611eab57611eab8b611ea383610b658c8763ffffffff61250b16565b8a6001612ba5565b60098701546040518c916001600160a01b03808916929116907f7b1bab051266a4a36232da9b4341daf225fa42f7202b0e7207b9b502644ff1bb90611ef1908d90615175565b60405180910390a4505060016000555093979650505050505050565b600160005414611f2f5760405162461bcd60e51b81526004016109cf906150d6565b600260005580611f515760405162461bcd60e51b81526004016109cf906150a6565b6000828152600560205260409020600a810154600160a01b900460ff16611f8a5760405162461bcd60e51b81526004016109cf906150c6565b60018101546000908152600660205260409020600381015460048301546001600160a01b0390911690341580611fdc57506001600160a01b03821673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2145b611ff85760405162461bcd60e51b81526004016109cf90614fe6565b612008818663ffffffff6126df16565b6004850181905590503461202657612021823387612e8b565b61204f565b8434146120455760405162461bcd60e51b81526004016109cf90615136565b61204f3334612eef565b6002805490840154604051630a7549df60e21b815260009283926001600160a01b03918216926329d5277c9261208c928992911690600401614c82565b604080518083038186803b1580156120a357600080fd5b505afa1580156120b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506120db9190810190614336565b915091508160001461210757612107886120ff83610b658b8763ffffffff61250b16565b896000612ba5565b600986015460405189916001600160a01b03808816929116907fa8a69faa6a38cc9c2beed79e034e1bd99f7eac877a5cee9f0118a8667b7ed93e9061214d908c90615175565b60405180910390a450506001600055505050505050565b611558338261233e565b6013546001600160a01b031681565b601a5481565b600080336040518060400160405280600b81526020016a557365725265776172647360a81b8152506040516020016121bc929190614c41565b60405160208183030381529060405280519060200120905080549150816000146122f05760008155601e546121f7908363ffffffff6126df16565b601e5560405163a9059cbb60e01b815273b72b31907c1c95f3650b64b2469e08edacee5e8f9063a9059cbb906122339086908690600401614dad565b602060405180830381600087803b15801561224d57600080fd5b505af1158015612261573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506122859190810190614183565b5073b72b31907c1c95f3650b64b2469e08edacee5e8f6001600160a01b0316836001600160a01b0316336001600160a01b03167ff9ce28130cf0ab6ae397696b8e3f3c22063af7b518a2d85c64520eadcb39155f856040516122e79190615175565b60405180910390a45b50919050565b60208080526000928352604080842090915290825290205481565b612319611222565b6123355760405162461bcd60e51b81526004016109cf90615096565b61155881613022565b6001600160a01b038083166000908152600a60209081526040808320938516835292905290812060018101549091901580159061237e5750600482015415155b1561240f576123a962015180610b658460010154610b598660040154426124c990919063ffffffff16565b42600484015560028301549091508111156123c5575060028101545b801561240a5760038201546123e0908263ffffffff6126df16565b600383015560028201546123fa908263ffffffff6124c916565b600283015561240a848483612f9f565b612416565b4260048301555b50505050565b600285015460008115612459576014548754612456916a07259756a8d6199800000091610b659190610b599081898963ffffffff6124c916565b90505b6002870183905580156124c05785856001600160a01b0316856001600160a01b03167fcf877e0841dcb21fb3fc42f1273a3ad3b8e956ec5d00b514bbd34a43b4cda2ee846040516124aa9190615175565b60405180910390a46124c08487878460036130a4565b50505050505050565b600061115e83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612ff6565b60008261251a575060006111f2565b8282028284828161252757fe5b041461115e5760405162461bcd60e51b81526004016109cf90615086565b600061115e83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613280565b80156126645773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2478083111561260c57604051632e1a7d4d60e01b81526001600160a01b03831690632e1a7d4d906125d99084870390600401615175565b600060405180830381600087803b1580156125f357600080fd5b505af1158015612607573d6000803e3d6000fd5b505050505b61261684846132b7565b836001600160a01b0316826001600160a01b03167fc44aeefa68e8b9c1ad5f7be4b0dd194580f81f5c362862e72196503a320eb7a1856040516126599190615175565b60405180910390a350505b5050565b8015611399576126886001600160a01b038416838363ffffffff61335316565b816001600160a01b0316836001600160a01b03167fc44aeefa68e8b9c1ad5f7be4b0dd194580f81f5c362862e72196503a320eb7a1836040516126cb9190615175565b60405180910390a3505050565b6001015490565b60008282018381101561115e5760405162461bcd60e51b81526004016109cf90614fd6565b6000818310612713578161115e565b5090919050565b600082600101828154811061272b57fe5b9060005260206000200154905092915050565b612746613e14565b61274e613ee5565b506000848152600560208181526040928390208351610180810185528154815260018201549281019290925260028101549382019390935260038301546060820152600483015460808201529082015460a0820152600682015460c0820152600782015460e0820152600882015461010082015260098201546001600160a01b03908116610120830152600a90920154918216610140820152600160a01b90910460ff161515610160820152612802613f49565b5060208181015160009081526006808352604091829020825161010080820185528254825260018084015460ff811615159784019790975295046001600160a01b039081169482019490945260028201548416606082015260038201549093166080840152600481015460a0840152600581015460c0840152015460e08201529085600281111561288f57fe5b14801561289e575060e0810151155b806128c2575060028560028111156128b257fe5b1480156128c2575060e081015115155b156128cf575061115e9050565b6128d7613f8d565b506000868152600b602090815260408083208151606080820184528254825260018301549482019490945260029182015481840152905485840151608080880151958901519089015194516317f8680960e11b815293969586956001600160a01b0390941694632ff0d01294612951949391600401614d2d565b604080518083038186803b15801561296857600080fd5b505afa15801561297c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506129a09190810190614336565b915091506000808560c001518411612a2657612a1c87606001518860800151868960c0015187602060008d606001516001600160a01b03166001600160a01b0316815260200190815260200160002060008d608001516001600160a01b03166001600160a01b03168152602001908152602001600020546133ac565b9092509050612a39565b8815612a39575061115e95505050505050565b60008060008d6040518060400160405280601081526020016f4c6f616e4465706f73697456616c756560801b815250604051602001612a79929190614f47565b6040516020818303038152906040528051906020012090508054925060018101549150428a60c001511115612ad557612ace62015180610b658a60000151610b59428f60c001516124c990919063ffffffff16565b9550612ada565b600095505b6040518061022001604052808f81526020018b60c001516001600160601b031681526020018a606001516001600160a01b031681526020018a608001516001600160a01b031681526020018b6060015181526020018b608001518152602001896000015181526020018781526020018b610100015181526020018b60e0015181526020018a60c0015181526020018881526020018a60e001518152602001868152602001858152602001848152602001838152509a50505050505050505050509392505050565b3390565b6000846040518060400160405280601081526020016f4c6f616e4465706f73697456616c756560801b815250604051602001612be2929190614f47565b60405160208183030381529060405280519060200120905080548260008114612c255785821160018114612c195760008455612c1f565b86830384555b50612c2b565b85820183555b50506001018054828015612c595784821160018114612c4d5760008455612c53565b85830384555b50612c5f565b84820183555b5050847f6fdb66f06832f41be9e4313f93e9b50685b11f2540d275342262997f35da88108585604051612c93929190615183565b60405180910390a25050505050565b6001600160e01b03198216600090815260046020526040902080546001600160a01b0319166001600160a01b03831690811790915515612cfd57612cf7600c6001600160e01b0319841663ffffffff6134d816565b50612664565b611399600c6001600160e01b0319841663ffffffff61352016565b600080612d648560000154856080015186606001518860090160009054906101000a90046001600160a01b031689600401546000896001604051806020016040528060008152506135e1565b506004870154909250612d7e91508263ffffffff6124c916565b60048087018290556002546060870151608088015160038a01546040516317f8680960e11b815260009687966001600160a01b0390961695632ff0d01295612dcd959094909390929101614d2d565b604080518083038186803b158015612de457600080fd5b505afa158015612df8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612e1c9190810190614336565b915091508560c001518211612e435760405162461bcd60e51b81526004016109cf906150b6565b8215801590612e5157508015155b15612e80578654612e8090612e78670de0b6b3a7640000610b65878663ffffffff61250b16565b856001612ba5565b509095945050505050565b801561139957612eac6001600160a01b03841683308463ffffffff61373e16565b816001600160a01b0316836001600160a01b03167f2790b90165fd3973ad7edde4eca71b4f8808dd4857a2a3a3e8ae5642a5cb196e836040516126cb9190615175565b600073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29050806001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b158015612f4357600080fd5b505af1158015612f57573d6000803e3d6000fd5b5050505050826001600160a01b0316816001600160a01b03167f2790b90165fd3973ad7edde4eca71b4f8808dd4857a2a3a3e8ae5642a5cb196e846040516126cb9190615175565b6000612fcf68056bc75e2d63100000612fc36014548561250b90919063ffffffff16565b9063ffffffff61376216565b9050612fdc8484836137a4565b6124168385612ff1858563ffffffff6124c916565b612668565b6000818484111561301a5760405162461bcd60e51b81526004016109cf9190614f75565b505050900390565b6001600160a01b0381166130485760405162461bcd60e51b81526004016109cf90614fa6565b6001546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b600280546040516000926001600160a01b03909216918391606091849163d138f9a160e01b916130f2918b917356d811088235f11c8920698a204a5010a788f4b391908c0490602401614d05565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516131309190614c5d565b600060405180830381855afa9150503d806000811461316b576040519150601f19603f3d011682016040523d82523d6000602084013e613170565b606091505b5091509150600182141561318657602081015193505b831561327557601d548085111561319b578094505b8415613273576131b1818663ffffffff6124c916565b601d8190555060008a6040518060400160405280600b81526020016a557365725265776172647360a81b8152506040516020016131ef929190614c41565b60405160208183030381529060405280519060200120905085815401815586600381111561321957fe5b8a8c6001600160a01b03167fe6c5d7a78caa3f3f24c92ef7f180efb19eb4cc6decff0d5b9cbc4d164b718d0973b72b31907c1c95f3650b64b2469e08edacee5e8f8a604051613269929190614dad565b60405180910390a4505b505b505050505050505050565b600081836132a15760405162461bcd60e51b81526004016109cf9190614f75565b5060008385816132ad57fe5b0495945050505050565b804710156132d75760405162461bcd60e51b81526004016109cf90615046565b6000826001600160a01b0316826040516132f090614c69565b60006040518083038185875af1925050503d806000811461332d576040519150601f19603f3d011682016040523d82523d6000602084013e613332565b606091505b50509050806113995760405162461bcd60e51b81526004016109cf90615036565b60405161139990849063a9059cbb60e01b906133759086908690602401614dad565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613825565b600080848611806133bb575083155b156133c5576134cd565b8286116133d65750869050856134cd565b60006133f086674563918244f4000063ffffffff6126df16565b905061341368056bc75e2d63100000610b658b610b59858463ffffffff6126df16565b9250613441613434670de0b6b3a7640000610b658b8963ffffffff61250b16565b849063ffffffff6124c916565b925061346f613456828663ffffffff6124c916565b610b658568056bc75e2d6310000063ffffffff61250b16565b92508883111561347d578892505b6134a66134998568056bc75e2d6310000063ffffffff6126df16565b849063ffffffff61250b16565b91506134bd6064610b65848863ffffffff61254516565b9150878211156134cb578791505b505b965096945050505050565b60006134e4838361390a565b61351857506001808301805480830180835560009283526020808420909201859055848352908590526040909120556111f2565b5060006111f2565b600061352c838361390a565b1561351857600082815260208490526040902054600184015460001991820191018082146135a457600085600101828154811061356557fe5b906000526020600020015490508086600101848154811061358257fe5b6000918252602080832090910192909255918252869052604090206001830190555b600084815260208690526040812055600185018054806135c057fe5b600190038181906000526020600020016000905590556001925050506111f2565b6040805160a0810182526001600160a01b03808b16825289811660208084019190915230838501819052606080850191909152918a1660808401528351918201845288825281018790529182018590526000918291829161364591908e888861391f565b90935091506136548b83613ad9565b600254602654604051631e2c62d360e01b81526001600160a01b0390921691631e2c62d39161368d918f918f9188918a91600401614d6b565b60206040518083038186803b1580156136a557600080fd5b505afa1580156136b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506136dd9190810190614318565b9050896001600160a01b03168b6001600160a01b03168d7fb4eb3c9b62efcce7021cba5fd9cd0c44df91c2272806ccc5e57df7c912e8d7168c868860405161372793929190614dc8565b60405180910390a499509950999650505050505050565b6040516124169085906323b872dd60e01b9061337590879087908790602401614d05565b600061115e83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613bb5565b8015611399576001600160a01b0382166000908152601560205260409020546137d3908263ffffffff6126df16565b6001600160a01b0380841660008181526015602052604090819020939093559151908516907f40a75ae5f7a5336e75f7c7977e12c4b46a9ac0f30de01a2d5b6c1a4f4af63587906126cb908590615175565b613837826001600160a01b0316613bff565b6138535760405162461bcd60e51b81526004016109cf90615146565b60006060836001600160a01b03168360405161386f9190614c5d565b6000604051808303816000865af19150503d80600081146138ac576040519150601f19603f3d011682016040523d82523d6000602084013e6138b1565b606091505b5091509150816138d35760405162461bcd60e51b81526004016109cf90615006565b80511561241657808060200190516138ee9190810190614183565b6124165760405162461bcd60e51b81526004016109cf906150f6565b60009081526020919091526040902054151590565b835160009081906139425760405162461bcd60e51b81526004016109cf90615026565b6000806000866139c357604089015161399b576139668960005b6020020151613c3b565b905080156139965760808a015161398790898c60005b602002015184613c5f565b885161399390826124c9565b89525b6139c3565b6139a689600261395c565b905080156139c35760408901516139bd90826126df565b60408a01525b60208901516139d857885160208a01526139fd565b6020890151895111156139fd5760405162461bcd60e51b81526004016109cf90615156565b855115613a1c5760405162461bcd60e51b81526004016109cf906150e6565b613a268a8a613cf8565b60408b01519194509250613a645788518214613a545760405162461bcd60e51b81526004016109cf90615126565b8015613a5f57908101905b613aca565b6020890151821115613a885760405162461bcd60e51b81526004016109cf90615016565b6040890151831015613aac5760405162461bcd60e51b81526004016109cf90614f96565b8015613aca5760808a0151613ac490898c600161397c565b80830392505b50909890975095505050505050565b60285480156113995760006001600160a01b03841673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21415613b10575081613b95565b600254604051635967aa7560e11b81526001600160a01b039091169063b2cf54ea90613b429087908790600401614dad565b60206040518083038186803b158015613b5a57600080fd5b505afa158015613b6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250613b929190810190614318565b90505b818111156124165760405162461bcd60e51b81526004016109cf90615066565b60008183613bd65760405162461bcd60e51b81526004016109cf9190614f75565b5083613be45750600061115e565b6000836001860381613bf257fe5b0460010195945050505050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590613c3357508115155b949350505050565b60006111f268056bc75e2d63100000612fc36017548561250b90919063ffffffff16565b8015612416576001600160a01b038216600090815260186020526040902054613c8e908263ffffffff6126df16565b6001600160a01b03808416600081815260186020526040908190209390935591518592918716907fb23479169712c443e6b00fb0cec3506a5f5926f541df4243d313e11c8c5c71ed90613ce2908690615175565b60405180910390a46124168484848460016130a4565b815160208084015160408086015160608781015187519588015188850151945160009889989497632bea876360e01b97613d3f979296919592949293919291602401614c9d565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925260035491519092506000916001600160a01b031690613d91908490614c5d565b600060405180830381855af49150503d8060008114613dcc576040519150601f19603f3d011682016040523d82523d6000602084013e613dd1565b606091505b509250905080613df35760405162461bcd60e51b81526004016109cf90615116565b81806020019051613e079190810190614336565b9097909650945050505050565b6040518061022001604052806000801916815260200160006001600160601b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810182905261016081019190915290565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915290565b60405180606001604052806000815260200160008152602001600081525090565b80356111f2816152bc565b80356111f2816152d0565b80516111f2816152d0565b80356111f2816152d9565b80356111f2816152e2565b60008083601f840112613ff757600080fd5b50813567ffffffffffffffff81111561400f57600080fd5b60208301915083600182028301111561402757600080fd5b9250929050565b80356111f2816152eb565b80516111f2816152d9565b60006020828403121561405657600080fd5b6000613c338484613fae565b6000806040838503121561407557600080fd5b60006140818585613fae565b925050602061409285828601613fae565b9150509250929050565b600080604083850312156140af57600080fd5b60006140bb8585613fae565b925050602061409285828601613fb9565b600080604083850312156140df57600080fd5b60006140eb8585613fae565b925050602061409285828601613fcf565b60008060008060008060c0878903121561411557600080fd5b60006141218989613fae565b965050602061413289828a01613fcf565b955050604061414389828a01613fcf565b945050606061415489828a0161402e565b935050608061416589828a01613fb9565b92505060a061417689828a01613fb9565b9150509295509295509295565b60006020828403121561419557600080fd5b6000613c338484613fc4565b6000602082840312156141b357600080fd5b6000613c338484613fcf565b600080604083850312156141d257600080fd5b60006140818585613fcf565b6000806000606084860312156141f357600080fd5b60006141ff8686613fcf565b935050602061421086828701613fae565b925050604061422186828701613fcf565b9150509250925092565b6000806040838503121561423e57600080fd5b60006140eb8585613fcf565b60008060008060006080868803121561426257600080fd5b600061426e8888613fcf565b955050602061427f88828901613fcf565b945050604061429088828901613fb9565b935050606086013567ffffffffffffffff8111156142ad57600080fd5b6142b988828901613fe5565b92509250509295509295909350565b6000806000606084860312156142dd57600080fd5b60006142e98686613fcf565b935050602061421086828701613fcf565b60006020828403121561430c57600080fd5b6000613c338484613fda565b60006020828403121561432a57600080fd5b6000613c338484614039565b6000806040838503121561434957600080fd5b60006143558585614039565b925050602061409285828601614039565b60008060006060848603121561437b57600080fd5b60006143878686613fcf565b935050602061439886828701613fcf565b925050604061422186828701613fb9565b60006143b58383614ae4565b50506102200190565b6143cf6143ca8261522c565b61529b565b82525050565b6143cf8161522c565b60006143e98261521a565b6143f3818561521e565b93506143fe83615214565b8060005b8381101561442c57815161441688826143a9565b975061442183615214565b925050600101614402565b509495945050505050565b6143cf81615237565b6143cf8161523c565b60006144548261521a565b61445e8185615227565b935061446e81856020860161526f565b9290920192915050565b6143cf81615264565b600061448c8261521a565b614496818561521e565b93506144a681856020860161526f565b6144af816152ac565b9093019392505050565b60006144c660138361521e565b7207769746864726177416d6f756e74206973203606c1b815260200192915050565b60006144f5601b8361521e565b7f696e73756666696369656e742073776170206c69717569646974790000000000815260200192915050565b600061452e60268361521e565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015260400192915050565b600061457660148361521e565b73696e646566696e6974652d7465726d206f6e6c7960601b815260200192915050565b60006145a660228361521e565b7f6465706f7369742063616e6e6f7420636f766572206261636b20696e746572658152611cdd60f21b602082015260400192915050565b60006145ea601b8361521e565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b600061462360108361521e565b6f1ddc9bdb99c8185cdcd95d081cd95b9d60821b815260200192915050565b600061464f600e8361521e565b6d1b1bd85b881d1bdbc81cda1bdc9d60921b815260200192915050565b600061467960208361521e565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b60006146b260138361521e565b72737761702066696c6c20746f6f206c6172676560681b815260200192915050565b60006146e160118361521e565b700736f75726365416d6f756e74203d3d203607c1b815260200192915050565b600061470e603a8361521e565b7f416464726573733a20756e61626c6520746f2073656e642076616c75652c207281527f6563697069656e74206d61792068617665207265766572746564000000000000602082015260400192915050565b600061476d601d8361521e565b7f416464726573733a20696e73756666696369656e742062616c616e6365000000815260200192915050565b60006147a660188361521e565b7f776974686472617720616d6f756e7420746f6f20686967680000000000000000815260200192915050565b60006147df600e8361521e565b6d7377617020746f6f206c6172676560901b815260200192915050565b6000614809600e8361521e565b6d1b9bdd08185d5d1a1bdc9a5e995960921b815260200192915050565b600061483360218361521e565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b6000614876600c8361521e565b6b1d5b985d5d1a1bdc9a5e995960a21b815260200192915050565b600061489e60128361521e565b7106465706f736974416d6f756e7420697320360741b815260200192915050565b60006148cc60128361521e565b713ab73432b0b63a343c903837b9b4ba34b7b760711b815260200192915050565b60006111f2600083615227565b6000614907600e8361521e565b6d1b1bd85b881a5cc818db1bdcd95960921b815260200192915050565b6000614931600c8361521e565b6b1b9bdb9499595b9d1c985b9d60a21b815260200192915050565b6000614959600d8361521e565b6c696e76616c696420737461746560981b815260200192915050565b6000614982602a8361521e565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b60006149ce60138361521e565b721b1bd85b881d195c9b481a185cc8195b991959606a1b815260200192915050565b60006149fd600b8361521e565b6a1cddd85c0819985a5b195960aa1b815260200192915050565b6000614a2460168361521e565b751cddd85c081d1bdbc81b185c99d9481d1bc8199a5b1b60521b815260200192915050565b6000614a5660168361521e565b750cae8d0cae440c8cae0dee6d2e840dad2e6dac2e8c6d60531b815260200192915050565b6000614a88601f8361521e565b7f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b6000614ac160148361521e565b730dad2dc40cee4cac2e8cae440e8d0c2dc40dac2f60631b815260200192915050565b8051610220830190614af68482614440565b506020820151614b096020850182614c38565b506040820151614b1c60408501826143d5565b506060820151614b2f60608501826143d5565b506080820151614b426080850182614440565b5060a0820151614b5560a0850182614440565b5060c0820151614b6860c0850182614440565b5060e0820151614b7b60e0850182614440565b50610100820151614b90610100850182614440565b50610120820151614ba5610120850182614440565b50610140820151614bba610140850182614440565b50610160820151614bcf610160850182614440565b50610180820151614be4610180850182614440565b506101a0820151614bf96101a0850182614440565b506101c0820151614c0e6101c0850182614440565b506101e0820151614c236101e0850182614440565b50610200820151612416610200850182614440565b6143cf81615258565b6000614c4d82856143be565b601482019150613c338284614449565b600061115e8284614449565b60006111f2826148ed565b602081016111f282846143d5565b60408101614c9082856143d5565b61115e60208301846143d5565b60e08101614cab828a6143d5565b614cb860208301896143d5565b614cc560408301886143d5565b614cd260608301876143d5565b614cdf6080830186614440565b614cec60a0830185614440565b614cf960c0830184614440565b98975050505050505050565b60608101614d1382866143d5565b614d2060208301856143d5565b613c336040830184614440565b60808101614d3b82876143d5565b614d4860208301866143d5565b614d556040830185614440565b614d626060830184614440565b95945050505050565b60a08101614d7982886143d5565b614d8660208301876143d5565b614d936040830186614440565b614da06060830185614440565b610fa96080830184614440565b60408101614dbb82856143d5565b61115e6020830184614440565b60608101614dd682866143d5565b614d206020830185614440565b60808101614df182876143d5565b614d486020830186614440565b6020808252810161115e81846143de565b602081016111f28284614437565b6101008101614e2c828b614440565b614e39602083018a614437565b614e4660408301896143d5565b614e5360608301886143d5565b614e6060808301876143d5565b614e6d60a0830186614440565b614e7a60c0830185614440565b614e8760e0830184614440565b9998505050505050505050565b6101808101614ea3828f614440565b614eb0602083018e614440565b614ebd604083018d614440565b614eca606083018c614440565b614ed7608083018b614440565b614ee460a083018a614440565b614ef160c0830189614440565b614efe60e0830188614440565b614f0c610100830187614440565b614f1a6101208301866143d5565b614f286101408301856143d5565b614f36610160830184614437565b9d9c50505050505050505050505050565b60408101614f558285614440565b8181036020830152613c338184614481565b602081016111f28284614478565b6020808252810161115e8184614481565b602080825281016111f2816144b9565b602080825281016111f2816144e8565b602080825281016111f281614521565b602080825281016111f281614569565b602080825281016111f281614599565b602080825281016111f2816145dd565b602080825281016111f281614616565b602080825281016111f281614642565b602080825281016111f28161466c565b602080825281016111f2816146a5565b602080825281016111f2816146d4565b602080825281016111f281614701565b602080825281016111f281614760565b602080825281016111f281614799565b602080825281016111f2816147d2565b602080825281016111f2816147fc565b602080825281016111f281614826565b602080825281016111f281614869565b602080825281016111f281614891565b602080825281016111f2816148bf565b602080825281016111f2816148fa565b602080825281016111f281614924565b602080825281016111f28161494c565b602080825281016111f281614975565b602080825281016111f2816149c1565b602080825281016111f2816149f0565b602080825281016111f281614a17565b602080825281016111f281614a49565b602080825281016111f281614a7b565b602080825281016111f281614ab4565b61022081016111f28284614ae4565b602081016111f28284614440565b60408101614dbb8285614440565b60608101614dd68286614440565b60a081016151ad8288614440565b614d866020830187614440565b60c081016151c88289614440565b6151d56020830188614440565b6151e26040830187614440565b6151ef6060830186614440565b6151fc6080830185614440565b61520960a0830184614440565b979650505050505050565b60200190565b5190565b90815260200190565b919050565b60006111f28261524c565b151590565b90565b6001600160e01b03191690565b6001600160a01b031690565b6001600160601b031690565b60006111f28261522c565b60005b8381101561528a578181015183820152602001615272565b838111156124165750506000910152565b60006111f28260006111f2826152b6565b601f01601f191690565b60601b90565b6152c58161522c565b811461155857600080fd5b6152c581615237565b6152c58161523c565b6152c58161523f565b6003811061155857600080fdfea365627a7a7231582054acbafafa6908356df4b14019a2815a4f242caed603fbe98f637bc9471c488f6c6578706572696d656e74616cf564736f6c63430005110040

Deployed Bytecode Sourcemap

59902:27073:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;29147:69;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;29147:69:0;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;69578:2856;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;69578:2856:0;;;;;;;;:::i;:::-;;;;;;;;28646:47;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;28646:47:0;;;;;;;;:::i;:::-;;;;;;;;32572:56;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;32572:56:0;;;;;;;;:::i;30912:45::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;30912:45:0;;;:::i;32006:32::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;32006:32:0;;;:::i;73707:285::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;73707:285:0;;;;;;;;:::i;29018:67::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;29018:67:0;;;;;;;;:::i;31184:56::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;31184:56:0;;;;;;;;:::i;77477:1357::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;77477:1357:0;;;;;;;;:::i;:::-;;;;;;;;1707:86;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1707:86:0;;;:::i;29280:71::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;29280:71:0;;;;;;;;:::i;:::-;;;;;;;;30560:56;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;30560:56:0;;;;;;;;:::i;30424:43::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;30424:43:0;;;:::i;1515:93::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1515:93:0;;;:::i;:::-;;;;;;;;33219:39;;8:9:-1;5:2;;;30:1;27;20:12;5:2;33219:39:0;;;:::i;80557:144::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;80557:144:0;;;:::i;29568:53::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;29568:53:0;;;;;;;;:::i;:::-;;;;;;;;;;79380:1169;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;79380:1169:0;;;;;;;;:::i;29427:78::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;29427:78:0;;;;;;;;:::i;:::-;;;;;;;;;;;;32804:48;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;32804:48:0;;;;;;;;:::i;33079:44::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;33079:44:0;;;:::i;28508:24::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;28508:24:0;;;:::i;28374:25::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;28374:25:0;;;:::i;31871:32::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;31871:32:0;;;:::i;79115:257::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;79115:257:0;;;;;;;;:::i;:::-;;;;;;;;11041:79;;8:9:-1;5:2;;;30:1;27;20:12;5:2;11041:79:0;;;:::i;32453:56::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;32453:56:0;;;;;;;;:::i;11387:94::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;11387:94:0;;;:::i;30713:56::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;30713:56:0;;;;;;;;:::i;76379:890::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;76379:890:0;;;;;;;;:::i;:::-;;;;;;;;;;;1615:85;;8:9:-1;5:2;;;30:1;27;20:12;5:2;1615:85:0;;;:::i;78842:265::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;78842:265:0;;;;;;;;:::i;32144:45::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;32144:45:0;;;:::i;72442:478::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;72442:478:0;;;;;;;;:::i;:::-;;31667:58;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;31667:58:0;;;;;;;;:::i;31513:::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;31513:58:0;;;;;;;;:::i;28782:38::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;28782:38:0;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;60029:1018;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;60029:1018:0;;;;;;;;:::i;28893:49::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;28893:49:0;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;65603:3967;;;;;;;;;:::i;74809:1094::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;74809:1094:0;;;;;;;;:::i;32929:40::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;32929:40:0;;;:::i;31032:56::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;31032:56:0;;;;;;;;:::i;62937:2417::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;62937:2417:0;;;;;;;;:::i;61055:1874::-;;;;;;;;;:::i;65362:233::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;65362:233:0;;;;;;;;:::i;30290:29::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;30290:29:0;;;:::i;31382:47::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;31382:47:0;;;:::i;72928:771::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;72928:771:0;;;;;;;;:::i;32274:84::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;32274:84:0;;;;;;;;:::i;11636:109::-;;8:9:-1;5:2;;;30:1;27;20:12;5:2;-1:-1;11636:109:0;;;;;;;;:::i;29147:69::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;69578:2856::-;69750:22;8177:1;8870:14;;:39;8862:64;;;;-1:-1:-1;;;8862:64:0;;;;;;;;;;;;;;;;;8285:1;8937:14;:40;69798:19;69790:51;;;;-1:-1:-1;;;69790:51:0;;;;;;;;;69852:22;69877:13;;;:5;:13;;;;;;;;69949:22;;;;69938:34;;:10;:34;;;;;;69993:16;;;;-1:-1:-1;;;69993:16:0;;;;69985:43;;;;-1:-1:-1;;;69985:43:0;;;;;;;;;70075:18;;;;-1:-1:-1;;;;;70075:18:0;70061:10;:32;;:92;;-1:-1:-1;70128:12:0;;70110:31;;;;:17;:31;;;;;;;;70142:10;70110:43;;;;;;;;;;70061:92;70039:154;;;;-1:-1:-1;;;70039:154:0;;;;;;;;;70212:27;;;;:32;70204:65;;;;-1:-1:-1;;;70204:65:0;;;;;;;;;70313:15;70288:9;:22;;;:40;70280:72;;;;-1:-1:-1;;;70280:72:0;;;;;;;;;70439:16;;;;70470:25;;;;70412:94;;-1:-1:-1;;;;;70439:16:0;;;;70470:25;70412:12;:94::i;:::-;70573:12;;70519:38;70560:26;;;:12;:26;;;;;70707:25;;;;70747:18;;;;70560:26;;70599:207;;70560:26;;-1:-1:-1;;;;;70707:25:0;;;;70747:18;70780:15;70599:34;:207::i;:::-;70819:32;70854:131;70978:6;70854:105;70930:17;:28;;;70854:57;70895:15;70854:9;:22;;;:40;;:57;;;;:::i;:::-;:75;:105;:75;:105;:::i;:::-;:123;:131;:123;:131;:::i;:::-;70819:166;;71021:24;71004:14;:41;70996:78;;;;-1:-1:-1;;;70996:78:0;;;;;;;;;71121:25;;;;-1:-1:-1;;;;;71121:25:0;1565:42;71121:47;71117:338;;;71185:93;71222:8;71249:14;71185:18;:93::i;:::-;71117:338;;;71343:25;;;;71311:132;;-1:-1:-1;;;;;71343:25:0;71387:8;71414:14;71311:13;:132::i;:::-;71543:28;;71484:88;;:40;:14;71517:6;71484:40;:32;:40;:::i;:88::-;71467:105;;71619:14;71594:9;:22;;;:39;71585:67;;;;-1:-1:-1;;;71585:67:0;;;;;;;;;71690:22;;;;:56;;71731:14;71690:56;:40;:56;:::i;:::-;71665:22;;;:81;;;71792:15;-1:-1:-1;71767:112:0;;;;;71872:7;71853:15;71828:9;:22;;;:40;71827:52;71767:112;71759:162;;;;-1:-1:-1;;;71759:162:0;;;;;;;;;71967:30;;;;:64;;72016:14;71967:64;:48;:64;:::i;:::-;71934:30;;;:97;72116:14;72131:16;;;;-1:-1:-1;;;;;72131:16:0;;;72116:32;;;;;;;;;;;;72149:25;;;;;;;;72116:59;;;;;;;;;:69;;:103;;72204:14;72116:103;:87;:103;:::i;:::-;72044:14;72059:16;;;;-1:-1:-1;;;;;72059:16:0;;;72044:32;;;;;;;;;;;;72077:25;;;;;;;;72044:59;;;;;;;;;;:69;;;:175;;;;72303:25;;72270:18;;;;72393:22;;;;72237:189;;72343:6;;72303:25;;;;72270:18;;;;;72237:189;;;;72364:14;;72393:22;72237:189;;;;;;;;;;-1:-1:-1;;8177:1:0;9000:14;:38;-1:-1:-1;69578:2856:0;;;-1:-1:-1;;;;69578:2856:0:o;28646:47::-;;;;;;;;;;;;-1:-1:-1;;;;;28646:47:0;;:::o;32572:56::-;;;;;;;;;;;;-1:-1:-1;;;;;32572:56:0;;:::o;30912:45::-;;;;:::o;32006:32::-;;;;:::o;73707:285::-;73807:22;73847:12;73889:4;73895:13;;;;;;;;;;;;;-1:-1:-1;;;73895:13:0;;;73872:37;;;;;;;;;;;;;;-1:-1:-1;;26:21;;;22:32;6:49;;73872:37:0;;;73862:48;;49:4:-1;73862:48:0;;;;73963:11;;73930:55;-1:-1:-1;;;73930:55:0:o;29018:67::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;31184:56::-;;;;;;;;;;;;;:::o;77477:1357::-;77699:33;77750:43;77796:8;:82;;-1:-1:-1;;;;;77856:22:0;;;;;;:16;:22;;;;;77796:82;;;-1:-1:-1;;;;;77820:20:0;;;;;;:14;:20;;;;;77796:82;77750:128;;77891:11;77905:37;77929:12;:3;:10;:12::i;:::-;77905:16;:5;77915;77905:16;:9;:16;:::i;:::-;:23;:37;:23;:37;:::i;:::-;77891:51;;77966:3;77957:5;:12;77953:61;;-1:-1:-1;77986:16:0;;-1:-1:-1;77986:16:0;77953:61;78032:9;;;;-1:-1:-1;78032:9:0;78084:30;;:::i;:::-;78158:3;78137:25;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;-1:-1:-1;78125:37:0;-1:-1:-1;;;78190:5:0;;;;;78173:508;78202:5;78197:1;:10;78173:508;;78240:118;78267:10;:3;78275:1;78267:10;:7;:10;:::i;:::-;78306:8;78333:10;78240:8;:118::i;:::-;78377:15;;78229:129;;-1:-1:-1;78373:177:0;;78422:6;78418:117;;78453:5;;78418:117;78507:8;;78418:117;78593:8;78566:9;78583:5;;;;;;;78576;:13;78566:24;;;;;;;;;;;;;:35;;;;78622:1;78627;78622:6;78618:52;;;78649:5;;78618:52;-1:-1:-1;;78209:3:0;78173:508;;;-1:-1:-1;78697:8:0;;78693:134;;78731:3;78722:12;;;;78795:5;78784:9;78777:24;78758:58;77477:1357;;;;;;;;;;;;;:::o;1707:86::-;1751:42;1707:86;:::o;29280:71::-;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;30560:56::-;;;;;;;;;;;;;:::o;30424:43::-;;;;:::o;1515:93::-;1565:42;1515:93;:::o;33219:39::-;;;;:::o;80557:144::-;80638:7;80670:23;:14;:21;:23::i;:::-;80663:30;;80557:144;:::o;29568:53::-;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;79380:1169::-;79529:33;79580:11;79594:48;79618:23;:14;:21;:23::i;:::-;79594:16;:5;79604;79594:16;:9;:16;:::i;:48::-;79580:62;;79666:3;79657:5;:12;79653:61;;-1:-1:-1;79686:16:0;;79653:61;79732:9;;;;-1:-1:-1;79732:9:0;79784:30;;:::i;:::-;79858:3;79837:25;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;-1:-1:-1;79825:37:0;-1:-1:-1;;;79890:5:0;;;;;79873:523;79902:5;79897:1;:10;79873:523;;79940:133;79967:21;:14;79986:1;79967:21;:18;:21;:::i;:::-;80017:12;80048:10;79940:8;:133::i;:::-;80092:15;;79929:144;;-1:-1:-1;80088:177:0;;80137:6;80133:117;;80168:5;;80133:117;80222:8;;80133:117;80308:8;80281:9;80298:5;;;;;;;80291;:13;80281:24;;;;;;;;;;;;;:35;;;;80337:1;80342;80337:6;80333:52;;;80364:5;;80333:52;-1:-1:-1;;79909:3:0;79873:523;;;-1:-1:-1;80412:8:0;;80408:134;;80446:3;80437:12;;;;80510:5;80499:9;80492:24;80473:58;79380:1169;;;;;;;;;:::o;29427:78::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;32804:48::-;;;;;;;;;;;;;;;:::o;33079:44::-;;;;:::o;28508:24::-;;;-1:-1:-1;;;;;28508:24:0;;:::o;28374:25::-;;;-1:-1:-1;;;;;28374:25:0;;:::o;31871:32::-;;;;:::o;79115:257::-;79208:30;;:::i;:::-;79263:101;79286:6;79307:12;79334:5;79263:8;:101::i;:::-;79256:108;79115:257;-1:-1:-1;;79115:257:0:o;11041:79::-;11106:6;;-1:-1:-1;;;;;11106:6:0;11041:79;:::o;32453:56::-;;;;;;;;;;;;-1:-1:-1;;;;;32453:56:0;;:::o;11387:94::-;11467:6;;11427:4;;-1:-1:-1;;;;;11467:6:0;11451:12;:10;:12::i;:::-;-1:-1:-1;;;;;11451:22:0;;11444:29;;11387:94;:::o;30713:56::-;;;;;;;;;;;;;:::o;76379:890::-;76498:17;76687:13;;;:5;:13;;;;;;;;:26;;;;;76676:38;;:10;:38;;;;;;:48;;;76756:20;;;:12;:20;;;;;:31;;76821:33;;;76890:13;;;;:26;;;-1:-1:-1;;;;;76676:48:0;;;;76756:31;;76821:33;76498:17;;76950:15;:30;-1:-1:-1;76950:89:0;;77024:15;76950:89;;;76996:12;76950:89;76927:112;;77092:12;77077;:27;:184;;77260:1;77077:184;;;77120:120;77233:6;77120:90;77191:18;77120:48;:12;77155;77120:48;:34;:48;:::i;:120::-;77050:211;;76379:890;;;;;;;:::o;1615:85::-;1658:42;1615:85;:::o;78842:265::-;78967:7;78999:8;:100;;-1:-1:-1;;;;;79068:22:0;;;;;;:16;:22;;;;;:31;;:29;:31::i;:::-;78999:100;;;-1:-1:-1;;;;;79023:20:0;;;;;;:14;:20;;;;;:29;;:27;:29::i;32144:45::-;;;;:::o;72442:478::-;72687:10;72710:1;72666:32;;;:20;:32;;;;;;-1:-1:-1;;;;;72666:32:0;72658:73;;;;-1:-1:-1;;;72658:73:0;;;;;;;;;72744:168;72776:6;72797:23;72835:29;72879:5;72744:17;:168::i;:::-;72442:478;;;:::o;31667:58::-;;;;;;;;;;;;;:::o;31513:::-;;;;;;;;;;;;;:::o;28782:38::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;28782:38:0;;;;;;;;-1:-1:-1;;;28782:38:0;;;;;:::o;60029:1018::-;11253:9;:7;:9::i;:::-;11245:34;;;;-1:-1:-1;;;11245:34:0;;;;;;;;;60128:51;-1:-1:-1;;;60172:6:0;60128:10;:51::i;:::-;60190:52;-1:-1:-1;;;60235:6:0;60190:10;:52::i;:::-;60253:57;-1:-1:-1;;;60303:6:0;60253:10;:57::i;:::-;60321:52;-1:-1:-1;;;60366:6:0;60321:10;:52::i;:::-;60384;-1:-1:-1;;;60429:6:0;60384:10;:52::i;:::-;60447:50;-1:-1:-1;;;60490:6:0;60447:10;:50::i;:::-;60508:46;-1:-1:-1;;;60547:6:0;60508:10;:46::i;:::-;60565:50;-1:-1:-1;;;60608:6:0;60565:10;:50::i;:::-;60626:55;-1:-1:-1;;;60674:6:0;60626:10;:55::i;:::-;60692:53;-1:-1:-1;;;60738:6:0;60692:10;:53::i;:::-;60756:46;-1:-1:-1;;;60795:6:0;60756:10;:46::i;:::-;60813:51;-1:-1:-1;;;60857:6:0;60813:10;:51::i;:::-;60875:41;-1:-1:-1;;;60909:6:0;60875:10;:41::i;:::-;60927:48;-1:-1:-1;;;60968:6:0;60927:10;:48::i;:::-;60986:53;-1:-1:-1;;;61032:6:0;60986:10;:53::i;:::-;60029:1018;:::o;28893:49::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;28893:49:0;;;;;;;;;;;;;;;:::o;65603:3967::-;65854:23;8177:1;8870:14;;:39;8862:64;;;;-1:-1:-1;;;8862:64:0;;;;;;;;;8285:1;8937:14;:40;65903:18;65895:49;;;;-1:-1:-1;;;65895:49:0;;;;;;;;;65955:22;65980:13;;;:5;:13;;;;;;;;66052:22;;;;66041:34;;:10;:34;;;;;;66096:16;;;;-1:-1:-1;;;66096:16:0;;;;66088:43;;;;-1:-1:-1;;;66088:43:0;;;;;;;;;66165:13;66164:14;:63;;;-1:-1:-1;66209:18:0;;;;-1:-1:-1;;;;;66209:18:0;66195:10;:32;66164:63;:123;;;-1:-1:-1;66262:12:0;;66244:31;;;;:17;:31;;;;;;;;66276:10;66244:43;;;;;;;;;;66164:123;66142:185;;;;-1:-1:-1;;;66142:185:0;;;;;;;;;66346:27;;;;:32;66338:65;;;;-1:-1:-1;;;66338:65:0;;;;;;;;;66422:9;:14;;:85;;;66442:13;66441:14;:65;;;;-1:-1:-1;66459:25:0;;;;-1:-1:-1;;;;;66459:25:0;1565:42;66459:47;66441:65;66414:114;;;;-1:-1:-1;;;66414:114:0;;;;;;;;;66615:16;;;;66646:25;;;;66588:94;;-1:-1:-1;;;;;66615:16:0;;;;66646:25;66588:12;:94::i;:::-;66749:12;;66695:38;66736:26;;;:12;:26;;;;;66883:25;;;;66923:18;;;;66736:26;;66775:207;;66736:26;;-1:-1:-1;;;;;66883:25:0;;;;66923:18;66956:15;66775:34;:207::i;:::-;67112:24;67169:9;:22;;;67151:15;:40;67147:431;;;67265:22;;;;67227:61;;:15;;:61;:37;:61;:::i;:::-;67361:28;;67208:80;;-1:-1:-1;67322:68:0;;67208:80;;67322:68;:38;:68;:::i;:::-;67303:87;-1:-1:-1;67424:46:0;67303:87;67463:6;67424:46;:38;:46;:::i;:::-;67405:65;;67511:16;67495:13;:32;67487:79;;;;-1:-1:-1;;;67487:79:0;;;;;;;;;67619:22;67656:13;67652:650;;;67703:130;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;67703:130:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;67743:9;;67805:13;67703:21;:130::i;:::-;67686:147;;67652:650;;;67870:9;67866:425;;67940:25;;;;67905:148;;-1:-1:-1;;;;;67940:25:0;67988:10;68021:13;67905:12;:148::i;:::-;67866:425;;;68115:13;68102:9;:26;68094:61;;;;-1:-1:-1;;;68094:61:0;;;;;;;;;68174:101;68214:10;68247:9;68174:17;:101::i;:::-;68318:21;;68314:330;;68372:53;:13;68408:16;68372:53;:35;:53;:::i;:::-;68522:16;;;;68557:25;;;;68356:69;;-1:-1:-1;68483:149:0;;-1:-1:-1;;;;;68522:16:0;;;;68557:25;68601:16;68483:20;:149::i;:::-;68732:28;;68674:87;;:39;:13;68706:6;68674:39;:31;:39;:::i;:87::-;68799:22;;;;68656:105;;-1:-1:-1;68799:57:0;;68656:105;68799:57;:40;:57;:::i;:::-;68774:22;;;:82;;;68902:15;-1:-1:-1;68877:112:0;;;;;68982:7;68963:15;68938:9;:22;;;:40;68937:52;68877:112;68869:162;;;;-1:-1:-1;;;68869:162:0;;;;;;;;;69077:30;;;;:63;;69126:13;69077:63;:48;:63;:::i;:::-;69044:30;;;:96;69225:14;69240:16;;;;-1:-1:-1;;;;;69240:16:0;;;69225:32;;;;;;;;;;;;69258:25;;;;;;;;69225:59;;;;;;;;;:69;;:102;;69313:13;69225:102;:87;:102;:::i;:::-;69153:14;:32;69168:9;:16;;;;;;;;;;-1:-1:-1;;;;;69168:16:0;-1:-1:-1;;;;;69153:32:0;-1:-1:-1;;;;;69153:32:0;;;;;;;;;;;;:59;69186:15;:25;;;;;;;;;;-1:-1:-1;;;;;69186:25:0;-1:-1:-1;;;;;69153:59:0;-1:-1:-1;;;;;69153:59:0;;;;;;;;;;;;:69;;:174;;;;69451:6;69411:15;:25;;;;;;;;;;-1:-1:-1;;;;;69411:25:0;-1:-1:-1;;;;;69345:217:0;69378:9;:18;;;;;;;;;;-1:-1:-1;;;;;69378:18:0;-1:-1:-1;;;;;69345:217:0;;69472:13;69500:14;69529:9;:22;;;69345:217;;;;;;;;;;;;;;;;;-1:-1:-1;;8177:1:0;9000:14;:38;-1:-1:-1;65603:3967:0;;;-1:-1:-1;;;;;;;65603:3967:0:o;74809:1094::-;74958:20;74993:24;75032:26;75073:22;75110:26;75151:22;75191:41;;:::i;:::-;-1:-1:-1;;;;;;75235:22:0;;;;;;;:14;:22;;;;;;;;:33;;;;;;;;;;;;75191:77;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;75298:105;;75396:6;;75298:93;;75191:77;75298:57;;:15;;:57;:19;:57;:::i;:105::-;75281:122;;75435:19;:29;;;75418:14;:46;75414:111;;;75496:19;:29;;;75479:46;;75414:111;75560:29;;;;75604:34;:77;;75680:1;75604:77;;;75641:19;:36;;;75604:77;75696:30;;;;75741:36;;;;:62;;75802:1;75741:62;;;75785:14;75741:62;75818:17;;75850:34;;75538:357;;;;-1:-1:-1;75538:357:0;;-1:-1:-1;75538:357:0;-1:-1:-1;75818:17:0;;-1:-1:-1;75850:34:0;-1:-1:-1;74809:1094:0;-1:-1:-1;;;74809:1094:0:o;32929:40::-;;;;:::o;31032:56::-;;;;;;;;;;;;;:::o;62937:2417::-;63109:28;8177:1;8870:14;;:39;8862:64;;;;-1:-1:-1;;;8862:64:0;;;;;;;;;8285:1;8937:14;:40;63163:19;63155:51;;;;-1:-1:-1;;;63155:51:0;;;;;;;;;63217:22;63242:13;;;:5;:13;;;;;;;;63314:22;;;;63303:34;;:10;:34;;;;;;63358:16;;;;-1:-1:-1;;;63358:16:0;;;;63350:43;;;;-1:-1:-1;;;63350:43:0;;;;;;;;;63440:18;;;;-1:-1:-1;;;;;63440:18:0;63426:10;:32;;:92;;-1:-1:-1;63493:12:0;;63475:31;;;;:17;:31;;;;;;;;63507:10;63475:43;;;;;;;;;;63426:92;63404:154;;;;-1:-1:-1;;;63404:154:0;;;;;;;;;63597:31;;;;;63660:20;;;;;63727:10;;;63768:25;;;;63838:19;;;;63897:33;;;;63715:226;;-1:-1:-1;;;63715:226:0;;-1:-1:-1;;;;;63597:31:0;;;;63660:20;;63571:23;;63727:10;;;;63715:38;;:226;;63768:25;;;;;63597:31;;63660:20;;63715:226;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;63715:226:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;63715:226:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;63715:226:0;;;;;;;;;63693:248;;63975:11;63958:14;:28;63954:165;;;64026:11;64003:34;;63954:165;;;64093:14;64070:37;;63954:165;64144:77;;;;;;;;;;;;;;;;;;;:10;;64173:20;;64144:77;:28;:77;:::i;:::-;64232:20;;;:33;;;64131:90;-1:-1:-1;;;;;;64282:37:0;;1565:42;64282:37;64278:330;;;64336:99;64373:8;64400:20;64336:18;:99::i;:::-;64278:330;;;64468:128;64500:15;64534:8;64561:20;64468:13;:128::i;:::-;64734:10;;;64800:25;;;;64722:114;;-1:-1:-1;;;64722:114:0;;64655:28;;;;-1:-1:-1;;;;;64734:10:0;;;;64722:33;;:114;;64770:15;;64800:25;;;64722:114;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;64722:114:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;64722:114:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;64722:114:0;;;;;;;;;64654:182;;;;64851:20;64875:1;64851:25;64847:334;;64893:276;64929:6;64954:121;65049:25;64954:68;:20;65001;64954:68;:46;:68;:::i;:121::-;65094:20;65133:4;64893:17;:276::i;:::-;65231:18;;;;65198:148;;65294:6;;-1:-1:-1;;;;;65198:148:0;;;;65231:18;;;65198:148;;;;65315:20;;65198:148;;;;;;;;;;-1:-1:-1;;8177:1:0;9000:14;:38;-1:-1:-1;62937:2417:0;;;-1:-1:-1;;;;;;;62937:2417:0:o;61055:1874::-;8177:1;8870:14;;:39;8862:64;;;;-1:-1:-1;;;8862:64:0;;;;;;;;;8285:1;8937:14;:40;61262:18;61254:49;;;;-1:-1:-1;;;61254:49:0;;;;;;;;;61316:22;61341:13;;;:5;:13;;;;;61373:16;;;;-1:-1:-1;;;61373:16:0;;;;61365:43;;;;-1:-1:-1;;;61365:43:0;;;;;;;;;61469:22;;;;61421:34;61458;;;:10;:34;;;;;61531:31;;;;61594:20;;;;-1:-1:-1;;;;;61531:31:0;;;;61635:9;:14;;:55;;-1:-1:-1;;;;;;61653:37:0;;1565:42;61653:37;61635:55;61627:84;;;;-1:-1:-1;;;61627:84:0;;;;;;;;;61737:43;:10;61766:13;61737:43;:28;:43;:::i;:::-;61791:20;;;:33;;;61724:56;-1:-1:-1;61841:9:0;61837:367;;61872:122;61903:15;61937:10;61966:13;61872:12;:122::i;:::-;61837:367;;;62048:13;62035:9;:26;62027:61;;;;-1:-1:-1;;;62027:61:0;;;;;;;;;62103:89;62139:10;62168:9;62103:17;:89::i;:::-;62330:10;;;62396:25;;;;62318:114;;-1:-1:-1;;;62318:114:0;;62251:28;;;;-1:-1:-1;;;;;62330:10:0;;;;62318:33;;:114;;62366:15;;62396:25;;;62318:114;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;62318:114:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;62318:114:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;62318:114:0;;;;;;;;;62250:182;;;;62447:20;62471:1;62447:25;62443:321;;62489:263;62525:6;62550:114;62638:25;62550:61;:13;62590:20;62550:61;:39;:61;:::i;:114::-;62683:13;62715:5;62489:17;:263::i;:::-;62813:18;;;;62781:140;;62876:6;;-1:-1:-1;;;;;62781:140:0;;;;62813:18;;;62781:140;;;;62897:13;;62781:140;;;;;;;;;;-1:-1:-1;;8177:1:0;9000:14;:38;-1:-1:-1;;;;;;61055:1874:0:o;65362:233::-;65505:82;65532:10;65567:9;65505:12;:82::i;30290:29::-;;;-1:-1:-1;;;;;30290:29:0;;:::o;31382:47::-;;;;:::o;72928:771::-;73014:19;73051:12;73093:10;73105:13;;;;;;;;;;;;;-1:-1:-1;;;73105:13:0;;;73076:43;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;73076:43:0;;;73066:54;;;;;;73051:69;;73176:4;73170:11;73155:26;;73208:11;73223:1;73208:16;73204:488;;73282:1;73269:15;;73335:17;;:52;;73375:11;73335:52;:39;:52;:::i;:::-;73315:17;:72;73404:106;;-1:-1:-1;;;73404:106:0;;1751:42;;73404:34;;:106;;73457:8;;73484:11;;73404:106;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;73404:106:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;73404:106:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;73404:106:0;;;;;;;;;;1751:42;-1:-1:-1;;;;;73532:148:0;73591:8;-1:-1:-1;;;;;73532:148:0;73562:10;-1:-1:-1;;;;;73532:148:0;;73654:11;73532:148;;;;;;;;;;;;;;;73204:488;72928:771;;;;:::o;32274:84::-;;;;;;;;;;;;;;;;;;;;;;;:::o;11636:109::-;11253:9;:7;:9::i;:::-;11245:34;;;;-1:-1:-1;;;11245:34:0;;;;;;;;;11709:28;11728:8;11709:18;:28::i;45526:1300::-;-1:-1:-1;;;;;45685:22:0;;;45640:42;45685:22;;;:14;:22;;;;;;;;:37;;;;;;;;;;;45777:30;;;;45685:37;;45640:42;45777:35;;;;:80;;-1:-1:-1;45816:36:0;;;;:41;;45777:80;45773:1046;;;45892:159;46044:6;45892:129;45990:19;:30;;;45892:75;45930:19;:36;;;45892:15;:37;;:75;;;;:::i;:159::-;46107:15;46068:36;;;:54;46161:29;;;;45874:177;;-1:-1:-1;46143:47:0;;46139:114;;;-1:-1:-1;46224:29:0;;;;46139:114;46274:20;;46270:451;;46347:29;;;;:72;;46403:15;46347:72;:55;:72;:::i;:::-;46315:29;;;:104;46470:29;;;;:72;;46526:15;46470:72;:55;:72;:::i;:::-;46438:29;;;:104;46563:142;46606:6;46635:13;46671:15;46563:20;:142::i;:::-;45773:1046;;;46792:15;46753:36;;;:54;45773:1046;45526:1300;;;;:::o;39434:1202::-;39695:34;;;;39668:24;39783:21;;39779:357;;40052:17;;40000:28;;39925:199;;40093:30;;39925:145;;40052:17;39925:104;;;:12;39960:16;39925:52;:34;:52;:::i;:199::-;39904:220;;39779:357;40148:34;;;:49;;;40214:23;;40210:419;;40361:6;40334:8;-1:-1:-1;;;;;40259:160:0;40311:4;-1:-1:-1;;;;;40259:160:0;;40386:18;40259:160;;;;;;;;;;;;;;;40436:181;40468:4;40491:6;40516:8;40543:18;40580:22;40436:13;:181::i;:::-;39434:1202;;;;;;;:::o;13375:136::-;13433:7;13460:43;13464:1;13467;13460:43;;;;;;;;;;;;;;;;;:3;:43::i;14291:471::-;14349:7;14594:6;14590:47;;-1:-1:-1;14624:1:0;14617:8;;14590:47;14661:5;;;14665:1;14661;:5;:1;14685:5;;;;;:10;14677:56;;;;-1:-1:-1;;;14677:56:0;;;;;;;;15230:132;15288:7;15315:39;15319:1;15322;15315:39;;;;;;;;;;;;;;;;;:3;:39::i;43219:527::-;43331:10;;43327:412;;1565:42;43424:21;43464:15;;;43460:92;;;43500:36;;-1:-1:-1;;;43500:36:0;;-1:-1:-1;;;;;43500:19:0;;;;;:36;;43520:15;;;;43500:36;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;43500:36:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;43500:36:0;;;;43460:92;43566:28;43584:2;43588:5;43566:17;:28::i;:::-;43686:2;-1:-1:-1;;;;;43616:111:0;43656:10;-1:-1:-1;;;;;43616:111:0;;43707:5;43616:111;;;;;;;;;;;;;;;43327:412;;;43219:527;;:::o;44184:382::-;44315:10;;44311:248;;44342:86;-1:-1:-1;;;;;44342:26:0;;44387:2;44408:5;44342:86;:26;:86;:::i;:::-;44506:2;-1:-1:-1;;;;;44450:97:0;44482:5;-1:-1:-1;;;;;44450:97:0;;44527:5;44450:97;;;;;;;;;;;;;;;44184:382;;;:::o;6427:147::-;6549:10;;:17;;6427:147::o;12919:181::-;12977:7;13009:5;;;13033:6;;;;13025:46;;;;-1:-1:-1;;;13025:46:0;;;;;;;;18212:115;18275:7;18307:2;18302;:7;:17;;18317:2;18302:17;;;-1:-1:-1;18312:2:0;;18212:115;-1:-1:-1;18212:115:0:o;6906:159::-;7008:7;7040:3;:10;;7051:5;7040:17;;;;;;;;;;;;;;;;7033:24;;6906:159;;;;:::o;80709:3039::-;80857:30;;:::i;:::-;80905:21;;:::i;:::-;-1:-1:-1;80929:13:0;;;;:5;:13;;;;;;;;;80905:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;80905:37:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;80905:37:0;;;;;;;;;;;80953:33;;:::i;:::-;-1:-1:-1;81000:22:0;;;;;80989:34;;;;:10;:34;;;;;;;;80953:70;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;80953:70:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;81041:8;:27;;;;;;;;;:63;;;;-1:-1:-1;81072:27:0;;;;:32;81041:63;81040:150;;;-1:-1:-1;81135:18:0;81123:8;:30;;;;;;;;;:66;;;;-1:-1:-1;81157:27:0;;;;:32;;81123:66;81036:198;;;-1:-1:-1;81207:15:0;;-1:-1:-1;81207:15:0;81036:198;81246:37;;:::i;:::-;-1:-1:-1;81286:20:0;;;;:12;:20;;;;;;;;81246:60;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;81372:10;;81454:25;;;;81494:31;;;;;81540:19;;;;81574:20;;;;81360:245;;-1:-1:-1;;;81360:245:0;;81246:60;;81286:20;;;-1:-1:-1;;;;;81372:10:0;;;;81360:40;;:245;;81454:25;81540:19;81360:245;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;81360:245:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;81360:245:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;81360:245:0;;;;;;;;;81319:286;;;;81618:23;81652:19;81703:15;:33;;;81686:13;:50;81682:532;;81786:352;81827:9;:19;;;81865:9;:20;;;81904:13;81936:15;:33;;;81988:5;82036:27;:54;82064:15;:25;;;-1:-1:-1;;;;;82036:54:0;-1:-1:-1;;;;;82036:54:0;;;;;;;;;;;;:87;82091:15;:31;;;-1:-1:-1;;;;;82036:87:0;-1:-1:-1;;;;;82036:87:0;;;;;;;;;;;;;81786:22;:352::i;:::-;81753:385;;-1:-1:-1;81753:385:0;-1:-1:-1;81682:532:0;;;82160:10;82156:58;;;-1:-1:-1;82187:15:0;;-1:-1:-1;;;;;;82187:15:0;82156:58;82226:31;82268:37;82316:12;82352:6;82360:18;;;;;;;;;;;;;-1:-1:-1;;;82360:18:0;;;82341:38;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;82341:38:0;;;82331:49;;;;;;82316:64;;82448:4;82442:11;82415:38;;82516:1;82510:4;82506:12;82500:19;82467:52;;82571:15;82546:9;:22;;;:40;82542:266;;;82611:143;82747:6;82611:113;82695:17;:28;;;82611:61;82656:15;82611:9;:22;;;:44;;:61;;;;:::i;:143::-;82603:151;;82542:266;;;82795:1;82787:9;;82542:266;82827:913;;;;;;;;82865:6;82827:913;;;;82907:9;:22;;;-1:-1:-1;;;;;82827:913:0;;;;;82956:15;:25;;;-1:-1:-1;;;;;82827:913:0;;;;;83013:15;:31;;;-1:-1:-1;;;;;82827:913:0;;;;;83070:9;:19;;;82827:913;;;;83116:9;:20;;;82827:913;;;;83171:17;:28;;;82827:913;;;;83240:5;82827:913;;;;83271:9;:19;;;82827:913;;;;83318:9;:21;;;82827:913;;;;83373:15;:33;;;82827:913;;;;83436:13;82827:913;;;;83477:15;:27;;;82827:913;;;;83536:15;82827:913;;;;83579:11;82827:913;;;;83630:23;82827:913;;;;83699:29;82827:913;;;82820:920;;;;;;;;;;;;80709:3039;;;;;:::o;9832:98::-;9912:10;9832:98;:::o;85542:1430::-;85748:12;85784:6;85792:18;;;;;;;;;;;;;-1:-1:-1;;;85792:18:0;;;85773:38;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;85773:38:0;;;85763:49;;;;;;85748:64;;85864:4;85858:11;85890:13;85922:1;85917:88;;;;86061:23;86056:3;86053:32;86108:1;86103:96;;;;86261:1;86255:4;86248:15;86046:236;;86103:96;86155:23;86150:3;86146:33;86140:4;86133:47;86046:236;;85883:414;;85917:88;85965:23;85960:3;85956:33;85950:4;85943:47;85883:414;-1:-1:-1;;86331:1:0;86321:12;86354:11;;86386:13;86413:94;;;;86563:29;86558:3;86555:38;86616:1;86611:102;;;;86775:1;86769:4;86762:15;86548:248;;86611:102;86663:29;86658:3;86654:39;86648:4;86641:53;86548:248;;86379:432;;86413:94;86461:29;86456:3;86452:39;86446:4;86439:53;86379:432;;85832:990;86865:6;86839:125;86886:23;86924:29;86839:125;;;;;;;;;;;;;;;;85542:1430;;;;;:::o;33354:316::-;-1:-1:-1;;;;;;33455:17:0;;;;;;:12;:17;;;;;:26;;-1:-1:-1;;;;;;33455:26:0;-1:-1:-1;;;;;33455:26:0;;;;;;;;33498:20;33494:169;;33535:40;:15;-1:-1:-1;;;;;;33562:12:0;;33535:40;:26;:40;:::i;:::-;;33494:169;;;33608:43;:15;-1:-1:-1;;;;;;33638:12:0;;33608:43;:29;:43;:::i;83756:1778::-;83933:7;84025:29;84059:477;84083:9;:12;;;84110:15;:31;;;84156:15;:25;;;84196:9;:18;;;;;;;;;;-1:-1:-1;;;;;84196:18:0;84229:9;:20;;;84288:1;84359:13;84474:4;84059:477;;;;;;;;;;;;:9;:477::i;:::-;-1:-1:-1;84570:20:0;;;;84023:513;;-1:-1:-1;84570:61:0;;-1:-1:-1;84023:513:0;84570:61;:38;:61;:::i;:::-;84547:20;;;;:84;;;84757:10;;84800:25;;;;84840:31;;;;84886:19;;;;84745:206;;-1:-1:-1;;;84745:206:0;;84690:21;;;;-1:-1:-1;;;;;84757:10:0;;;;84745:40;;:206;;84800:25;;84840:31;;84886:19;;84547:84;84745:206;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;84745:206:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;84745:206:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;84745:206:0;;;;;;;;;84689:262;;;;85000:15;:33;;;84984:13;:49;84962:117;;;;-1:-1:-1;;;84962:117:0;;;;;;;;;85130:26;;;;;:55;;-1:-1:-1;85160:25:0;;;85130:55;85126:360;;;85238:12;;85202:272;;85269:110;1166:6;85269:69;:21;85317:20;85269:69;:47;:69;:::i;:110::-;85398:21;85438:4;85202:17;:272::i;:::-;-1:-1:-1;85505:21:0;;83756:1778;-1:-1:-1;;;;;83756:1778:0:o;43754:422::-;43886:10;;43882:287;;43913:124;-1:-1:-1;;;;;43913:30:0;;43962:4;43993;44017:5;43913:124;:30;:124;:::i;:::-;44114:4;-1:-1:-1;;;;;44059:98:0;44090:5;-1:-1:-1;;;;;44059:98:0;;44137:5;44059:98;;;;;;;42903:308;43012:21;1565:42;43012:33;;43056:10;-1:-1:-1;;;;;43056:18:0;;43081:5;43056:33;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;43056:33:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;43056:33:0;;;;;43168:4;-1:-1:-1;;;;;43107:96:0;43142:10;-1:-1:-1;;;;;43107:96:0;;43187:5;43107:96;;;;;;;46834:616;46990:18;47011:97;1229:6;47011:52;47045:17;;47011:15;:33;;:52;;;;:::i;:::-;:74;:97;:74;:97;:::i;:::-;46990:118;;47121:99;47150:6;47171:13;47199:10;47121:14;:99::i;:::-;47305:137;47333:13;47361:6;47382:49;:15;47420:10;47382:49;:37;:49;:::i;:::-;47305:13;:137::i;13848:192::-;13934:7;13970:12;13962:6;;;;13954:29;;;;-1:-1:-1;;;13954:29:0;;;;;;;;;;-1:-1:-1;;;14006:5:0;;;13848:192::o;11851:229::-;-1:-1:-1;;;;;11925:22:0;;11917:73;;;;-1:-1:-1;;;11917:73:0;;;;;;;;;12027:6;;12006:38;;-1:-1:-1;;;;;12006:38:0;;;;12027:6;;12006:38;;12027:6;;12006:38;12055:6;:17;;-1:-1:-1;;;;;;12055:17:0;-1:-1:-1;;;;;12055:17:0;;;;;;;;;;11851:229::o;40685:1890::-;41264:10;;;41358:282;;41211:20;;-1:-1:-1;;;;;41264:10:0;;;;41211:20;;41300:17;;41264:10;;-1:-1:-1;;;41399:45:0;41358:282;;41463:8;;1658:42;;41591:13;;;;41358:282;;;;;;;;-1:-1:-1;;26:21;;;22:32;6:49;;41358:282:0;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;;;;41358:282:0;;;179:29:-1;;;;160:49;;;41321:330:0;;;;41358:282;41321:330;;;;;;;;;;;;;;;;;14:1:-1;21;16:31;;;;75:4;69:11;64:16;;144:4;140:9;133:4;115:16;111:27;107:43;104:1;100:51;94:4;87:65;169:16;166:1;159:27;225:16;222:1;215:4;212:1;208:12;193:49;7:242;;16:31;36:4;31:9;;7:242;;41285:366:0;;;;41701:1;41692:7;41689:14;41686:2;;;41755;41749:4;41745:13;41739:20;41723:36;;41686:2;41801:17;;41797:771;;41858:17;;41894:27;;;41890:95;;;41957:12;41942:27;;41890:95;42003:17;;41999:558;;42061:52;:12;42100;42061:52;:38;:52;:::i;:::-;42041:17;:72;;;;42134:12;42176:4;42182:13;;;;;;;;;;;;;-1:-1:-1;;;42182:13:0;;;42159:37;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;42159:37:0;;;42149:48;;;;;;42134:63;;42278:12;42271:4;42265:11;42261:30;42255:4;42248:44;42425:7;42336:205;;;;;;;;42396:6;42369:4;-1:-1:-1;;;;;42336:205:0;;1751:42;42510:12;42336:205;;;;;;;;;;;;;;;;41999:558;;41797:771;;40685:1890;;;;;;;;;:::o;15892:346::-;15978:7;16081:12;16073:6;16065:29;;;;-1:-1:-1;;;16065:29:0;;;;;;;;;;;16105:9;16121:1;16117;:5;;;;;;;15892:346;-1:-1:-1;;;;;15892:346:0:o;20956:363::-;21063:6;21038:21;:31;;21030:73;;;;-1:-1:-1;;;21030:73:0;;;;;;;;;21172:12;21190:9;-1:-1:-1;;;;;21190:14:0;21211:6;21190:32;;;;;;;;;;;;;;;;;;;;;;;14:1:-1;21;16:31;;;;75:4;69:11;64:16;;144:4;140:9;133:4;115:16;111:27;107:43;104:1;100:51;94:4;87:65;169:16;166:1;159:27;225:16;222:1;215:4;212:1;208:12;193:49;7:242;;16:31;36:4;31:9;;7:242;;21171:51:0;;;21241:7;21233:78;;;;-1:-1:-1;;;21233:78:0;;;;;;;;21884:176;21993:58;;21967:85;;21986:5;;-1:-1:-1;;;22016:23:0;21993:58;;22041:2;;22045:5;;21993:58;;;;;;;;-1:-1:-1;;26:21;;;22:32;6:49;;21993:58:0;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;;;;21993:58:0;;;179:29:-1;;;;160:49;;;21967:18:0;:85::i;47502:1970::-;47784:23;47809:19;47866:17;47850:13;:33;:62;;;-1:-1:-1;47887:25:0;;47850:62;47846:234;;;47929:37;;47846:234;48005:16;47988:13;:33;47984:96;;-1:-1:-1;48046:9:0;;-1:-1:-1;48057:10:0;48038:30;;47984:96;48092:21;48116:44;:17;48152:7;48116:44;:35;:44;:::i;:::-;48092:68;-1:-1:-1;48365:124:0;1229:6;48365:83;48438:9;48365:54;48092:68;1229:6;48365:54;:31;:54;:::i;:124::-;48347:142;-1:-1:-1;48518:166:0;48570:99;1166:6;48570:58;:10;48607:20;48570:58;:36;:58;:::i;:99::-;48518:15;;:166;:33;:166;:::i;:::-;48500:184;-1:-1:-1;48713:165:0;48806:57;:13;48846:16;48806:57;:39;:57;:::i;:::-;48713:56;:15;1229:6;48713:56;:33;:56;:::i;:165::-;48695:183;;48911:9;48893:15;:27;48889:87;;;48955:9;48937:27;;48889:87;49092:132;49144:65;:16;1229:6;49144:65;:42;:65;:::i;:::-;49092:15;;:132;:33;:132;:::i;:::-;49078:146;-1:-1:-1;49249:74:0;49319:3;49249:51;49078:146;49279:20;49249:51;:29;:51;:::i;:74::-;49235:88;;49352:10;49338:11;:24;49334:81;;;49393:10;49379:24;;49334:81;-1:-1:-1;47502:1970:0;;;;;;;;;;:::o;2927:289::-;3022:4;3049:20;3058:3;3063:5;3049:8;:20::i;:::-;3044:165;;-1:-1:-1;3104:10:0;;;;27::-1;;23:18;;;45:23;;;-1:-1;3104:22:0;;;;;;;;;;;;;3085:16;;;;;;;;;;;:41;3141:11;;3044:165;-1:-1:-1;3192:5:0;3185:12;;3748:1054;3846:4;3872:20;3881:3;3886:5;3872:8;:20::i;:::-;3868:927;;;3908:21;3932:16;;;;;;;;;;;3951:1;3987:10;;:17;-1:-1:-1;;3932:20:0;;;;3987:21;4135:26;;;4131:389;;4182:17;4202:3;:10;;4213:9;4202:21;;;;;;;;;;;;;;;;4182:41;;4352:9;4324:3;:10;;4335:13;4324:25;;;;;;;;;;;;;;;;;;;:37;;;;4437:20;;;;;;;;;4476:1;4460:17;;4437:40;;4131:389;4604:9;:16;;;;;;;;;;4597:23;4694:10;;;:16;;;;;;;;;;;;;;;;;;;;;;;;4734:4;4727:11;;;;;;50613:1566;51118:449;;;;;;;;-1:-1:-1;;;;;51118:449:0;;;;;;;;;;;;;;;;51228:4;51118:449;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;50957:31;;;;;;51118:449;;;51498:6;51519:9;51543:13;51118:10;:449::i;:::-;51067:500;;-1:-1:-1;51067:500:0;-1:-1:-1;51627:50:0;51642:11;51067:500;51627:14;:50::i;:::-;51771:10;;51944:15;;51759:211;;-1:-1:-1;;;51759:211:0;;-1:-1:-1;;;;;51771:10:0;;;;51759:46;;:211;;51820:11;;51846:9;;51870:21;;51906:23;;51759:211;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;51759:211:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;51759:211:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;51759:211:0;;;;;;;;;51736:234;;52058:9;-1:-1:-1;;;;;51988:183:0;52032:11;-1:-1:-1;;;;;51988:183:0;52011:6;51988:183;52082:4;52101:21;52137:23;51988:183;;;;;;;;;;;;;;;;;50613:1566;;;;;;;;;;;;;:::o;22068:204::-;22195:68;;22169:95;;22188:5;;-1:-1:-1;;;22218:27:0;22195:68;;22247:4;;22253:2;;22257:5;;22195:68;;;;16348:140;16410:7;16437:43;16445:1;16448;16437:43;;;;;;;;;;;;;;;;;:7;:43::i;38849:487::-;38991:15;;38987:342;;-1:-1:-1;;;;;39056:30:0;;;;;;:20;:30;;;;;;:64;;39109:10;39056:64;:52;:64;:::i;:::-;-1:-1:-1;;;;;39023:30:0;;;;;;;:20;:30;;;;;;;:97;;;;39142:107;;;;;;;;;;39224:10;;39142:107;;23923:1114;24527:27;24535:5;-1:-1:-1;;;;;24527:25:0;;:27::i;:::-;24519:71;;;;-1:-1:-1;;;24519:71:0;;;;;;;;;24664:12;24678:23;24713:5;-1:-1:-1;;;;;24705:19:0;24725:4;24705:25;;;;;;;;;;;;;;;;;;;;;;;14:1:-1;21;16:31;;;;75:4;69:11;64:16;;144:4;140:9;133:4;115:16;111:27;107:43;104:1;100:51;94:4;87:65;169:16;166:1;159:27;225:16;222:1;215:4;212:1;208:12;193:49;7:242;;16:31;36:4;31:9;;7:242;;24663:67:0;;;;24749:7;24741:52;;;;-1:-1:-1;;;24741:52:0;;;;;;;;;24810:17;;:21;24806:224;;24952:10;24941:30;;;;;;;;;;;;;;24933:85;;;;-1:-1:-1;;;24933:85:0;;;;;;;;4888:165;4995:4;5024:16;;;;;;;;;;;;:21;;;4888:165::o;52187:3129::-;52739:7;;52410;;;;52731:42;;;;-1:-1:-1;;;52731:42:0;;;;;;;;;52786:31;52828:29;52870:18;52904:8;52899:873;;52946:7;;;;52942:819;;53069:23;53084:4;53089:1;53084:7;;;;;53069:14;:23::i;:::-;53056:36;-1:-1:-1;53115:15:0;;53111:348;;53196:8;;;;53155:200;;53239:6;53196:5;53278:1;53272:8;;;;;53322:10;53155:14;:200::i;:::-;53390:7;;:49;;53428:10;53390:37;:49::i;:::-;53380:59;;53111:348;52942:819;;;53579:23;53594:4;53599:1;53594:7;;53579:23;53566:36;-1:-1:-1;53627:15:0;;53623:123;;53677:7;;;;:49;;53715:10;53677:37;:49::i;:::-;53667:7;;;:59;53623:123;53788:7;;;;53784:146;;53827:7;;;53817;;:17;53784:146;;;53886:7;;;;53875;;:18;;53867:51;;;;-1:-1:-1;;;53867:51:0;;;;;;;;;53950:20;;:25;53942:51;;;;-1:-1:-1;;;53942:51:0;;;;;;;;;54055:69;54089:5;54109:4;54055:19;:69::i;:::-;54141:7;;;;54004:120;;-1:-1:-1;54004:120:0;-1:-1:-1;54137:1104:0;;54350:7;;54325:32;;54317:67;;;;-1:-1:-1;;;54317:67:0;;;;;;;;;54405:15;;54401:137;;54465:34;;;;54401:137;54137:1104;;;54742:7;;;;54717:32;;;54709:64;;;;-1:-1:-1;;;54709:64:0;;;;;;;;;54823:7;;;;54796:34;;;54788:74;;;;-1:-1:-1;;;54788:74:0;;;;;;;;;54883:15;;54879:351;;54956:8;;;;54919:189;;54995:6;54956:5;55041:1;55035:8;;54919:189;55181:10;55155:23;:36;55129:62;;54879:351;-1:-1:-1;55261:23:0;;;;-1:-1:-1;52187:3129:0;-1:-1:-1;;;;;;52187:3129:0:o;57017:540::-;57169:11;;57195:17;;57191:359;;57229:19;-1:-1:-1;;;;;57267:34:0;;1565:42;57267:34;57263:207;;;-1:-1:-1;57336:6:0;57263:207;;;57409:10;;57397:57;;-1:-1:-1;;;57397:57:0;;-1:-1:-1;;;;;57409:10:0;;;;57397:35;;:57;;57433:12;;57447:6;;57397:57;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;57397:57:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;57397:57:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;57397:57:0;;;;;;;;;57383:71;;57263:207;57507:12;57492:11;:27;;57484:54;;;;-1:-1:-1;;;57484:54:0;;;;;;;;16598:334;16688:7;16791:12;16783:6;16775:29;;;;-1:-1:-1;;;16775:29:0;;;;;;;;;;-1:-1:-1;16821:6:0;16817:47;;-1:-1:-1;16851:1:0;16844:8;;16817:47;16874:9;16897:1;16892;16888;:5;16887:11;;;;;;16902:1;16886:17;;16598:334;-1:-1:-1;;;;;16598:334:0:o;19016:619::-;19076:4;19544:20;;19387:66;19584:23;;;;;;:42;;-1:-1:-1;19611:15:0;;;19584:42;19576:51;19016:619;-1:-1:-1;;;;19016:619:0:o;36862:244::-;36970:7;37002:96;1229:6;37002:51;37035:17;;37002:14;:32;;:51;;;;:::i;37436:652::-;37603:15;;37599:482;;-1:-1:-1;;;;;37668:30:0;;;;;;:20;:30;;;;;;:64;;37721:10;37668:64;:52;:64;:::i;:::-;-1:-1:-1;;;;;37635:30:0;;;;;;;:20;:30;;;;;;;:97;;;;37754:132;;37836:6;;37635:30;37754:132;;;;;;;37861:10;;37754:132;;;;;;;;;;37903:166;37935:4;37958:6;37983:8;38010:10;38039:15;37903:13;:166::i;55324:860::-;55647:8;;;55685;;;;55721;;;;;55537:17;55763:8;;;;55811:7;;55858;;;;55905;;;;55557:395;;55457:31;;;;55537:17;;-1:-1:-1;;;55594:38:0;55557:395;;55647:8;;55685;;55721;;55763;;55811:7;;55858;55557:395;;;;;;;;-1:-1:-1;;26:21;;;22:32;6:49;;55557:395:0;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;;;;55557:395:0;;;179:29:-1;;;;160:49;;;56006:9:0;;:28;;55557:395;;-1:-1:-1;;;;;;;;56006:9:0;;:28;;55557:395;;56006:28;;;;;;;;;;;;;;;;;14:1:-1;21;16:31;;;;75:4;69:11;64:16;;144:4;140:9;133:4;115:16;111:27;107:43;104:1;100:51;94:4;87:65;169:16;166:1;159:27;225:16;222:1;215:4;212:1;208:12;193:49;7:242;;16:31;36:4;31:9;;7:242;-1:-1;55988:46:0;-1:-1:-1;55988:46:0;-1:-1:-1;55988:46:0;56045:31;;;;-1:-1:-1;;;56045:31:0;;;;;;;;;56151:4;56140:36;;;;;;;;;;;;;;56089:87;;;;-1:-1:-1;55324:860:0;-1:-1:-1;;;;;55324:860:0:o;59902:27073::-;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;59902:27073:0;;;;;;-1:-1:-1;;;;;59902:27073:0;;;;;;-1:-1:-1;;;;;59902:27073:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;-1:-1:-1;59902:27073:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;-1:-1:-1;59902:27073:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;:::o;5:130:-1:-;72:20;;97:33;72:20;97:33;;142:124;206:20;;231:30;206:20;231:30;;273:128;348:13;;366:30;348:13;366:30;;408:130;475:20;;500:33;475:20;500:33;;545:128;611:20;;636:32;611:20;636:32;;694:336;;;808:3;801:4;793:6;789:17;785:27;775:2;;826:1;823;816:12;775:2;-1:-1;846:20;;886:18;875:30;;872:2;;;918:1;915;908:12;872:2;952:4;944:6;940:17;928:29;;1003:3;995:4;987:6;983:17;973:8;969:32;966:41;963:2;;;1020:1;1017;1010:12;963:2;768:262;;;;;;1038:156;1118:20;;1143:46;1118:20;1143:46;;1338:134;1416:13;;1434:33;1416:13;1434:33;;1479:241;;1583:2;1571:9;1562:7;1558:23;1554:32;1551:2;;;1599:1;1596;1589:12;1551:2;1634:1;1651:53;1696:7;1676:9;1651:53;;1727:366;;;1848:2;1836:9;1827:7;1823:23;1819:32;1816:2;;;1864:1;1861;1854:12;1816:2;1899:1;1916:53;1961:7;1941:9;1916:53;;;1906:63;;1878:97;2006:2;2024:53;2069:7;2060:6;2049:9;2045:22;2024:53;;;2014:63;;1985:98;1810:283;;;;;;2100:360;;;2218:2;2206:9;2197:7;2193:23;2189:32;2186:2;;;2234:1;2231;2224:12;2186:2;2269:1;2286:53;2331:7;2311:9;2286:53;;;2276:63;;2248:97;2376:2;2394:50;2436:7;2427:6;2416:9;2412:22;2394:50;;2467:366;;;2588:2;2576:9;2567:7;2563:23;2559:32;2556:2;;;2604:1;2601;2594:12;2556:2;2639:1;2656:53;2701:7;2681:9;2656:53;;;2646:63;;2618:97;2746:2;2764:53;2809:7;2800:6;2789:9;2785:22;2764:53;;2840:883;;;;;;;3036:3;3024:9;3015:7;3011:23;3007:33;3004:2;;;3053:1;3050;3043:12;3004:2;3088:1;3105:53;3150:7;3130:9;3105:53;;;3095:63;;3067:97;3195:2;3213:53;3258:7;3249:6;3238:9;3234:22;3213:53;;;3203:63;;3174:98;3303:2;3321:53;3366:7;3357:6;3346:9;3342:22;3321:53;;;3311:63;;3282:98;3411:2;3429:66;3487:7;3478:6;3467:9;3463:22;3429:66;;;3419:76;;3390:111;3532:3;3551:50;3593:7;3584:6;3573:9;3569:22;3551:50;;;3541:60;;3511:96;3638:3;3657:50;3699:7;3690:6;3679:9;3675:22;3657:50;;;3647:60;;3617:96;2998:725;;;;;;;;;3730:257;;3842:2;3830:9;3821:7;3817:23;3813:32;3810:2;;;3858:1;3855;3848:12;3810:2;3893:1;3910:61;3963:7;3943:9;3910:61;;3994:241;;4098:2;4086:9;4077:7;4073:23;4069:32;4066:2;;;4114:1;4111;4104:12;4066:2;4149:1;4166:53;4211:7;4191:9;4166:53;;4242:366;;;4363:2;4351:9;4342:7;4338:23;4334:32;4331:2;;;4379:1;4376;4369:12;4331:2;4414:1;4431:53;4476:7;4456:9;4431:53;;4615:491;;;;4753:2;4741:9;4732:7;4728:23;4724:32;4721:2;;;4769:1;4766;4759:12;4721:2;4804:1;4821:53;4866:7;4846:9;4821:53;;;4811:63;;4783:97;4911:2;4929:53;4974:7;4965:6;4954:9;4950:22;4929:53;;;4919:63;;4890:98;5019:2;5037:53;5082:7;5073:6;5062:9;5058:22;5037:53;;;5027:63;;4998:98;4715:391;;;;;;5113:366;;;5234:2;5222:9;5213:7;5209:23;5205:32;5202:2;;;5250:1;5247;5240:12;5202:2;5285:1;5302:53;5347:7;5327:9;5302:53;;5486:735;;;;;;5657:3;5645:9;5636:7;5632:23;5628:33;5625:2;;;5674:1;5671;5664:12;5625:2;5709:1;5726:53;5771:7;5751:9;5726:53;;;5716:63;;5688:97;5816:2;5834:53;5879:7;5870:6;5859:9;5855:22;5834:53;;;5824:63;;5795:98;5924:2;5942:50;5984:7;5975:6;5964:9;5960:22;5942:50;;;5932:60;;5903:95;6057:2;6046:9;6042:18;6029:32;6081:18;6073:6;6070:30;6067:2;;;6113:1;6110;6103:12;6067:2;6141:64;6197:7;6188:6;6177:9;6173:22;6141:64;;;6131:74;;;;6008:203;5619:602;;;;;;;;;6228:491;;;;6366:2;6354:9;6345:7;6341:23;6337:32;6334:2;;;6382:1;6379;6372:12;6334:2;6417:1;6434:53;6479:7;6459:9;6434:53;;;6424:63;;6396:97;6524:2;6542:53;6587:7;6578:6;6567:9;6563:22;6542:53;;6726:239;;6829:2;6817:9;6808:7;6804:23;6800:32;6797:2;;;6845:1;6842;6835:12;6797:2;6880:1;6897:52;6941:7;6921:9;6897:52;;6972:263;;7087:2;7075:9;7066:7;7062:23;7058:32;7055:2;;;7103:1;7100;7093:12;7055:2;7138:1;7155:64;7211:7;7191:9;7155:64;;7242:399;;;7374:2;7362:9;7353:7;7349:23;7345:32;7342:2;;;7390:1;7387;7380:12;7342:2;7425:1;7442:64;7498:7;7478:9;7442:64;;;7432:74;;7404:108;7543:2;7561:64;7617:7;7608:6;7597:9;7593:22;7561:64;;7648:485;;;;7783:2;7771:9;7762:7;7758:23;7754:32;7751:2;;;7799:1;7796;7789:12;7751:2;7834:1;7851:53;7896:7;7876:9;7851:53;;;7841:63;;7813:97;7941:2;7959:53;8004:7;7995:6;7984:9;7980:22;7959:53;;;7949:63;;7920:98;8049:2;8067:50;8109:7;8100:6;8089:9;8085:22;8067:50;;8141:291;;8284:106;8386:3;8378:6;8284:106;;;-1:-1;;8419:6;8410:16;;8277:155;8440:184;8557:61;8585:32;8611:5;8585:32;;;8557:61;;;8552:3;8545:74;8539:85;;;8631:103;8704:24;8722:5;8704:24;;9123:914;;9324:82;9400:5;9324:82;;;9419:114;9526:6;9521:3;9419:114;;;9412:121;;9554:84;9632:5;9554:84;;;9658:7;9686:1;9671:344;9696:6;9693:1;9690:13;9671:344;;;9763:6;9757:13;9784:119;9899:3;9884:13;9784:119;;;9777:126;;9920:88;10001:6;9920:88;;;9910:98;-1:-1;;9718:1;9711:9;9671:344;;;-1:-1;10028:3;;9303:734;-1:-1;;;;;9303:734;10045:104;10122:21;10137:5;10122:21;;10156:103;10229:24;10247:5;10229:24;;10386:356;;10514:38;10546:5;10514:38;;;10564:88;10645:6;10640:3;10564:88;;;10557:95;;10657:52;10702:6;10697:3;10690:4;10683:5;10679:16;10657:52;;;10721:16;;;;;10494:248;-1:-1;;10494:248;10749:160;10849:54;10897:5;10849:54;;10916:347;;11028:39;11061:5;11028:39;;;11079:71;11143:6;11138:3;11079:71;;;11072:78;;11155:52;11200:6;11195:3;11188:4;11181:5;11177:16;11155:52;;;11228:29;11250:6;11228:29;;;11219:39;;;;11008:255;-1:-1;;;11008:255;11976:319;;12136:67;12200:2;12195:3;12136:67;;;-1:-1;;;12216:42;;12286:2;12277:12;;12122:173;-1:-1;;12122:173;12304:327;;12464:67;12528:2;12523:3;12464:67;;;12564:29;12544:50;;12622:2;12613:12;;12450:181;-1:-1;;12450:181;12640:375;;12800:67;12864:2;12859:3;12800:67;;;12900:34;12880:55;;-1:-1;;;12964:2;12955:12;;12948:30;13006:2;12997:12;;12786:229;-1:-1;;12786:229;13024:320;;13184:67;13248:2;13243:3;13184:67;;;-1:-1;;;13264:43;;13335:2;13326:12;;13170:174;-1:-1;;13170:174;13353:371;;13513:67;13577:2;13572:3;13513:67;;;13613:34;13593:55;;-1:-1;;;13677:2;13668:12;;13661:26;13715:2;13706:12;;13499:225;-1:-1;;13499:225;13733:327;;13893:67;13957:2;13952:3;13893:67;;;13993:29;13973:50;;14051:2;14042:12;;13879:181;-1:-1;;13879:181;14069:316;;14229:67;14293:2;14288:3;14229:67;;;-1:-1;;;14309:39;;14376:2;14367:12;;14215:170;-1:-1;;14215:170;14394:314;;14554:67;14618:2;14613:3;14554:67;;;-1:-1;;;14634:37;;14699:2;14690:12;;14540:168;-1:-1;;14540:168;14717:332;;14877:67;14941:2;14936:3;14877:67;;;14977:34;14957:55;;15040:2;15031:12;;14863:186;-1:-1;;14863:186;15058:319;;15218:67;15282:2;15277:3;15218:67;;;-1:-1;;;15298:42;;15368:2;15359:12;;15204:173;-1:-1;;15204:173;15386:317;;15546:67;15610:2;15605:3;15546:67;;;-1:-1;;;15626:40;;15694:2;15685:12;;15532:171;-1:-1;;15532:171;15712:395;;15872:67;15936:2;15931:3;15872:67;;;15972:34;15952:55;;16041:28;16036:2;16027:12;;16020:50;16098:2;16089:12;;15858:249;-1:-1;;15858:249;16116:329;;16276:67;16340:2;16335:3;16276:67;;;16376:31;16356:52;;16436:2;16427:12;;16262:183;-1:-1;;16262:183;16454:324;;16614:67;16678:2;16673:3;16614:67;;;16714:26;16694:47;;16769:2;16760:12;;16600:178;-1:-1;;16600:178;16787:314;;16947:67;17011:2;17006:3;16947:67;;;-1:-1;;;17027:37;;17092:2;17083:12;;16933:168;-1:-1;;16933:168;17110:314;;17270:67;17334:2;17329:3;17270:67;;;-1:-1;;;17350:37;;17415:2;17406:12;;17256:168;-1:-1;;17256:168;17433:370;;17593:67;17657:2;17652:3;17593:67;;;17693:34;17673:55;;-1:-1;;;17757:2;17748:12;;17741:25;17794:2;17785:12;;17579:224;-1:-1;;17579:224;17812:312;;17972:67;18036:2;18031:3;17972:67;;;-1:-1;;;18052:35;;18115:2;18106:12;;17958:166;-1:-1;;17958:166;18133:318;;18293:67;18357:2;18352:3;18293:67;;;-1:-1;;;18373:41;;18442:2;18433:12;;18279:172;-1:-1;;18279:172;18460:318;;18620:67;18684:2;18679:3;18620:67;;;-1:-1;;;18700:41;;18769:2;18760:12;;18606:172;-1:-1;;18606:172;18787:296;;18964:83;19045:1;19040:3;18964:83;;19092:314;;19252:67;19316:2;19311:3;19252:67;;;-1:-1;;;19332:37;;19397:2;19388:12;;19238:168;-1:-1;;19238:168;19415:312;;19575:67;19639:2;19634:3;19575:67;;;-1:-1;;;19655:35;;19718:2;19709:12;;19561:166;-1:-1;;19561:166;19736:313;;19896:67;19960:2;19955:3;19896:67;;;-1:-1;;;19976:36;;20040:2;20031:12;;19882:167;-1:-1;;19882:167;20058:379;;20218:67;20282:2;20277:3;20218:67;;;20318:34;20298:55;;-1:-1;;;20382:2;20373:12;;20366:34;20428:2;20419:12;;20204:233;-1:-1;;20204:233;20446:319;;20606:67;20670:2;20665:3;20606:67;;;-1:-1;;;20686:42;;20756:2;20747:12;;20592:173;-1:-1;;20592:173;20774:311;;20934:67;20998:2;20993:3;20934:67;;;-1:-1;;;21014:34;;21076:2;21067:12;;20920:165;-1:-1;;20920:165;21094:322;;21254:67;21318:2;21313:3;21254:67;;;-1:-1;;;21334:45;;21407:2;21398:12;;21240:176;-1:-1;;21240:176;21425:322;;21585:67;21649:2;21644:3;21585:67;;;-1:-1;;;21665:45;;21738:2;21729:12;;21571:176;-1:-1;;21571:176;21756:331;;21916:67;21980:2;21975:3;21916:67;;;22016:33;21996:54;;22078:2;22069:12;;21902:185;-1:-1;;21902:185;22096:320;;22256:67;22320:2;22315:3;22256:67;;;-1:-1;;;22336:43;;22407:2;22398:12;;22242:174;-1:-1;;22242:174;22521:3010;22748:23;;22678:6;22669:16;;;22777:63;22673:3;22748:23;22777:63;;;22700:146;22927:4;22920:5;22916:16;22910:23;22939:61;22994:4;22989:3;22985:14;22971:12;22939:61;;;22856:150;23084:4;23077:5;23073:16;23067:23;23096:63;23153:4;23148:3;23144:14;23130:12;23096:63;;;23016:149;23249:4;23242:5;23238:16;23232:23;23261:63;23318:4;23313:3;23309:14;23295:12;23261:63;;;23175:155;23408:4;23401:5;23397:16;23391:23;23420:63;23477:4;23472:3;23468:14;23454:12;23420:63;;;23340:149;23568:4;23561:5;23557:16;23551:23;23580:63;23637:4;23632:3;23628:14;23614:12;23580:63;;;23499:150;23736:4;23729:5;23725:16;23719:23;23748:63;23805:4;23800:3;23796:14;23782:12;23748:63;;;23659:158;23910:4;23903:5;23899:16;23893:23;23922:63;23979:4;23974:3;23970:14;23956:12;23922:63;;;23827:164;24069:6;24062:5;24058:18;24052:25;24083:65;24140:6;24135:3;24131:16;24117:12;24083:65;;;24001:153;24234:6;24227:5;24223:18;24217:25;24248:65;24305:6;24300:3;24296:16;24282:12;24248:65;;;24164:155;24405:6;24398:5;24394:18;24388:25;24419:65;24476:6;24471:3;24467:16;24453:12;24419:65;;;24329:161;24572:6;24565:5;24561:18;24555:25;24586:65;24643:6;24638:3;24634:16;24620:12;24586:65;;;24500:157;24737:6;24730:5;24726:18;24720:25;24751:65;24808:6;24803:3;24799:16;24785:12;24751:65;;;24667:155;24906:6;24899:5;24895:18;24889:25;24920:65;24977:6;24972:3;24968:16;24954:12;24920:65;;;24832:159;25071:6;25064:5;25060:18;25054:25;25085:65;25142:6;25137:3;25133:16;25119:12;25085:65;;;25001:155;25248:6;25241:5;25237:18;25231:25;25262:65;25319:6;25314:3;25310:16;25296:12;25262:65;;;25166:167;25431:6;25424:5;25420:18;25414:25;25445:65;25502:6;25497:3;25493:16;25479:12;25445:65;;28868:100;28939:23;28956:5;28939:23;;28975:429;;29154:91;29241:3;29232:6;29154:91;;;29267:2;29262:3;29258:12;29251:19;;29288:91;29375:3;29366:6;29288:91;;29815:262;;29959:93;30048:3;30039:6;29959:93;;30084:370;;30282:147;30425:3;30282:147;;30461:213;30579:2;30564:18;;30593:71;30568:9;30637:6;30593:71;;30681:324;30827:2;30812:18;;30841:71;30816:9;30885:6;30841:71;;;30923:72;30991:2;30980:9;30976:18;30967:6;30923:72;;31012:883;31298:3;31283:19;;31313:71;31287:9;31357:6;31313:71;;;31395:72;31463:2;31452:9;31448:18;31439:6;31395:72;;;31478;31546:2;31535:9;31531:18;31522:6;31478:72;;;31561;31629:2;31618:9;31614:18;31605:6;31561:72;;;31644:73;31712:3;31701:9;31697:19;31688:6;31644:73;;;31728;31796:3;31785:9;31781:19;31772:6;31728:73;;;31812;31880:3;31869:9;31865:19;31856:6;31812:73;;;31269:626;;;;;;;;;;;31902:435;32076:2;32061:18;;32090:71;32065:9;32134:6;32090:71;;;32172:72;32240:2;32229:9;32225:18;32216:6;32172:72;;;32255;32323:2;32312:9;32308:18;32299:6;32255:72;;32344:547;32546:3;32531:19;;32561:71;32535:9;32605:6;32561:71;;;32643:72;32711:2;32700:9;32696:18;32687:6;32643:72;;;32726;32794:2;32783:9;32779:18;32770:6;32726:72;;;32809;32877:2;32866:9;32862:18;32853:6;32809:72;;;32517:374;;;;;;;;32898:659;33128:3;33113:19;;33143:71;33117:9;33187:6;33143:71;;;33225:72;33293:2;33282:9;33278:18;33269:6;33225:72;;;33308;33376:2;33365:9;33361:18;33352:6;33308:72;;;33391;33459:2;33448:9;33444:18;33435:6;33391:72;;;33474:73;33542:3;33531:9;33527:19;33518:6;33474:73;;33564:324;33710:2;33695:18;;33724:71;33699:9;33768:6;33724:71;;;33806:72;33874:2;33863:9;33859:18;33850:6;33806:72;;33895:435;34069:2;34054:18;;34083:71;34058:9;34127:6;34083:71;;;34165:72;34233:2;34222:9;34218:18;34209:6;34165:72;;34337:547;34539:3;34524:19;;34554:71;34528:9;34598:6;34554:71;;;34636:72;34704:2;34693:9;34689:18;34680:6;34636:72;;34891:473;35115:2;35129:47;;;35100:18;;35190:164;35100:18;35340:6;35190:164;;35371:201;35483:2;35468:18;;35497:65;35472:9;35535:6;35497:65;;35579:983;35887:3;35872:19;;35902:71;35876:9;35946:6;35902:71;;;35984:66;36046:2;36035:9;36031:18;36022:6;35984:66;;;36061:72;36129:2;36118:9;36114:18;36105:6;36061:72;;;36144;36212:2;36201:9;36197:18;36188:6;36144:72;;;36227:73;36295:3;36284:9;36280:19;36271:6;36227:73;;;36311;36379:3;36368:9;36364:19;36355:6;36311:73;;;36395;36463:3;36452:9;36448:19;36439:6;36395:73;;;36479;36547:3;36536:9;36532:19;36523:6;36479:73;;;35858:704;;;;;;;;;;;;36569:1435;36991:3;36976:19;;37006:71;36980:9;37050:6;37006:71;;;37088:72;37156:2;37145:9;37141:18;37132:6;37088:72;;;37171;37239:2;37228:9;37224:18;37215:6;37171:72;;;37254;37322:2;37311:9;37307:18;37298:6;37254:72;;;37337:73;37405:3;37394:9;37390:19;37381:6;37337:73;;;37421;37489:3;37478:9;37474:19;37465:6;37421:73;;;37505;37573:3;37562:9;37558:19;37549:6;37505:73;;;37589;37657:3;37646:9;37642:19;37633:6;37589:73;;;37673;37741:3;37730:9;37726:19;37717:6;37673:73;;;37757;37825:3;37814:9;37810:19;37801:6;37757:73;;;37841:74;37910:3;37899:9;37895:19;37885:7;37841:74;;;37926:68;37989:3;37978:9;37974:19;37964:7;37926:68;;;36962:1042;;;;;;;;;;;;;;;;38011:404;38173:2;38158:18;;38187:71;38162:9;38231:6;38187:71;;;38306:9;38300:4;38296:20;38291:2;38280:9;38276:18;38269:48;38331:74;38400:4;38391:6;38331:74;;38422:247;38557:2;38542:18;;38571:88;38546:9;38632:6;38571:88;;38676:301;38814:2;38828:47;;;38799:18;;38889:78;38799:18;38953:6;38889:78;;38984:407;39175:2;39189:47;;;39160:18;;39250:131;39160:18;39250:131;;39398:407;39589:2;39603:47;;;39574:18;;39664:131;39574:18;39664:131;;39812:407;40003:2;40017:47;;;39988:18;;40078:131;39988:18;40078:131;;40226:407;40417:2;40431:47;;;40402:18;;40492:131;40402:18;40492:131;;40640:407;40831:2;40845:47;;;40816:18;;40906:131;40816:18;40906:131;;41054:407;41245:2;41259:47;;;41230:18;;41320:131;41230:18;41320:131;;41468:407;41659:2;41673:47;;;41644:18;;41734:131;41644:18;41734:131;;41882:407;42073:2;42087:47;;;42058:18;;42148:131;42058:18;42148:131;;42296:407;42487:2;42501:47;;;42472:18;;42562:131;42472:18;42562:131;;42710:407;42901:2;42915:47;;;42886:18;;42976:131;42886:18;42976:131;;43124:407;43315:2;43329:47;;;43300:18;;43390:131;43300:18;43390:131;;43538:407;43729:2;43743:47;;;43714:18;;43804:131;43714:18;43804:131;;43952:407;44143:2;44157:47;;;44128:18;;44218:131;44128:18;44218:131;;44366:407;44557:2;44571:47;;;44542:18;;44632:131;44542:18;44632:131;;44780:407;44971:2;44985:47;;;44956:18;;45046:131;44956:18;45046:131;;45194:407;45385:2;45399:47;;;45370:18;;45460:131;45370:18;45460:131;;45608:407;45799:2;45813:47;;;45784:18;;45874:131;45784:18;45874:131;;46022:407;46213:2;46227:47;;;46198:18;;46288:131;46198:18;46288:131;;46436:407;46627:2;46641:47;;;46612:18;;46702:131;46612:18;46702:131;;46850:407;47041:2;47055:47;;;47026:18;;47116:131;47026:18;47116:131;;47264:407;47455:2;47469:47;;;47440:18;;47530:131;47440:18;47530:131;;47678:407;47869:2;47883:47;;;47854:18;;47944:131;47854:18;47944:131;;48092:407;48283:2;48297:47;;;48268:18;;48358:131;48268:18;48358:131;;48506:407;48697:2;48711:47;;;48682:18;;48772:131;48682:18;48772:131;;48920:407;49111:2;49125:47;;;49096:18;;49186:131;49096:18;49186:131;;49334:407;49525:2;49539:47;;;49510:18;;49600:131;49510:18;49600:131;;49748:407;49939:2;49953:47;;;49924:18;;50014:131;49924:18;50014:131;;50162:407;50353:2;50367:47;;;50338:18;;50428:131;50338:18;50428:131;;50576:407;50767:2;50781:47;;;50752:18;;50842:131;50752:18;50842:131;;50990:407;51181:2;51195:47;;;51166:18;;51256:131;51166:18;51256:131;;51404:342;51586:3;51571:19;;51601:135;51575:9;51709:6;51601:135;;51753:213;51871:2;51856:18;;51885:71;51860:9;51929:6;51885:71;;51973:324;52119:2;52104:18;;52133:71;52108:9;52177:6;52133:71;;52304:435;52478:2;52463:18;;52492:71;52467:9;52536:6;52492:71;;52746:659;52976:3;52961:19;;52991:71;52965:9;53035:6;52991:71;;;53073:72;53141:2;53130:9;53126:18;53117:6;53073:72;;53412:771;53670:3;53655:19;;53685:71;53659:9;53729:6;53685:71;;;53767:72;53835:2;53824:9;53820:18;53811:6;53767:72;;;53850;53918:2;53907:9;53903:18;53894:6;53850:72;;;53933;54001:2;53990:9;53986:18;53977:6;53933:72;;;54016:73;54084:3;54073:9;54069:19;54060:6;54016:73;;;54100;54168:3;54157:9;54153:19;54144:6;54100:73;;;53641:542;;;;;;;;;;54190:179;54342:4;54333:14;;54290:79;54376:165;54507:12;;54478:63;55074:206;55220:19;;;55269:4;55260:14;;55213:67;55289:144;55424:3;55402:31;-1:-1;55402:31;55767:91;;55829:24;55847:5;55829:24;;55971:85;56037:13;56030:21;;56013:43;56063:72;56125:5;56108:27;56142:144;-1:-1;;;;;;56203:78;;56186:100;56293:121;-1:-1;;;;;56355:54;;56338:76;56500:104;-1:-1;;;;;56561:38;;56544:60;56611:155;;56707:54;56755:5;56707:54;;56906:268;56971:1;56978:101;56992:6;56989:1;56986:13;56978:101;;;57059:11;;;57053:18;57040:11;;;57033:39;57014:2;57007:10;56978:101;;;57094:6;57091:1;57088:13;57085:2;;;-1:-1;;57159:1;57141:16;;57134:27;56955:219;57182:95;;57246:26;57266:5;57394:89;57458:20;57472:5;57458:20;;57490:97;57578:2;57558:14;-1:-1;;57554:28;;57538:49;57595:94;57669:2;57665:14;;57637:52;57697:117;57766:24;57784:5;57766:24;;;57759:5;57756:35;57746:2;;57805:1;57802;57795:12;57821:111;57887:21;57902:5;57887:21;;57939:117;58008:24;58026:5;58008:24;;58063:115;58131:23;58148:5;58131:23;;58185:107;58267:1;58260:5;58257:12;58247:2;;58283:1;58280;58273:12

Swarm Source

bzzr://54acbafafa6908356df4b14019a2815a4f242caed603fbe98f637bc9471c488f

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

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.