ETH Price: $3,164.90 (+3.05%)
Gas: 1 Gwei

Contract

0xf0e55FB0cd9F1109691d365764DDB5FfB6BBC8CE
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Transfer172928682023-05-19 10:12:59421 days ago1684491179IN
0xf0e55FB0...fB6BBC8CE
0 ETH0.001077939.92551103
Claim DFL148162792022-05-21 8:40:54784 days ago1653122454IN
0xf0e55FB0...fB6BBC8CE
0 ETH0.0017919910
Claim DFL138742362021-12-25 12:07:01930 days ago1640434021IN
0xf0e55FB0...fB6BBC8CE
0 ETH0.0064881662.18295883
Claim DFL138742272021-12-25 12:04:24930 days ago1640433864IN
0xf0e55FB0...fB6BBC8CE
0 ETH0.006113558.59211854
Claim DFL138742242021-12-25 12:03:57930 days ago1640433837IN
0xf0e55FB0...fB6BBC8CE
0 ETH0.0103863771.72610381
Claim DFL135611962021-11-06 5:33:45980 days ago1636176825IN
0xf0e55FB0...fB6BBC8CE
0 ETH0.0099535971.5967231
Claim DFL134797082021-10-24 10:43:51992 days ago1635072231IN
0xf0e55FB0...fB6BBC8CE
0 ETH0.0043193635.42700132
Claim DFL133524582021-10-04 12:00:081012 days ago1633348808IN
0xf0e55FB0...fB6BBC8CE
0 ETH0.0080633358.00000145
Redeem132799952021-09-23 5:03:361024 days ago1632373416IN
0xf0e55FB0...fB6BBC8CE
0 ETH0.0127344858.00000156
Claim DFL132747382021-09-22 9:19:001025 days ago1632302340IN
0xf0e55FB0...fB6BBC8CE
0 ETH0.0049549540.64003827
Redeem132616282021-09-20 8:48:591027 days ago1632127739IN
0xf0e55FB0...fB6BBC8CE
0 ETH0.006586830
Redeem132217162021-09-14 4:41:021033 days ago1631594462IN
0xf0e55FB0...fB6BBC8CE
0 ETH0.013379561.28419036
Redeem132109532021-09-12 12:27:221034 days ago1631449642IN
0xf0e55FB0...fB6BBC8CE
0 ETH0.0097876941.57776002
Redeem132089122021-09-12 4:58:541035 days ago1631422734IN
0xf0e55FB0...fB6BBC8CE
0 ETH0.0074341937.03670539
Redeem132076602021-09-12 0:26:121035 days ago1631406372IN
0xf0e55FB0...fB6BBC8CE
0 ETH0.0068671735
Redeem132014162021-09-11 1:01:221036 days ago1631322082IN
0xf0e55FB0...fB6BBC8CE
0 ETH0.0132249162.00000145
Claim DFL131976622021-09-10 11:10:351036 days ago1631272235IN
0xf0e55FB0...fB6BBC8CE
0 ETH0.0088723263.81908464
Redeem131894702021-09-09 4:42:081038 days ago1631162528IN
0xf0e55FB0...fB6BBC8CE
0 ETH0.0215650391.60278427
Redeem131762942021-09-07 3:44:151040 days ago1630986255IN
0xf0e55FB0...fB6BBC8CE
0 ETH0.02152821110.00000145
Redeem131706192021-09-06 6:35:521041 days ago1630910152IN
0xf0e55FB0...fB6BBC8CE
0 ETH0.0193256196.27905592
Redeem131704062021-09-06 5:42:391041 days ago1630906959IN
0xf0e55FB0...fB6BBC8CE
0 ETH0.012798360
Claim DFL131577852021-09-04 7:11:231043 days ago1630739483IN
0xf0e55FB0...fB6BBC8CE
0 ETH0.0100163382.15297862
Redeem131510932021-09-03 6:22:481044 days ago1630650168IN
0xf0e55FB0...fB6BBC8CE
0 ETH0.013649368.00000145
Redeem131461752021-09-02 12:06:581044 days ago1630584418IN
0xf0e55FB0...fB6BBC8CE
0 ETH0.0164594582.00000134
Claim DFL131461602021-09-02 12:02:321044 days ago1630584152IN
0xf0e55FB0...fB6BBC8CE
0 ETH0.0095099978.00000134
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
DeFIL

Compiler Version
v0.5.17+commit.d19bba13

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, None license

Contract Source Code (Solidity)

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

// File: contracts\ErrorReporter.sol

pragma solidity ^0.5.16;

contract ErrorReporter {
    enum Error {
        NO_ERROR,
        UNAUTHORIZED,
        BAD_INPUT,
        REJECTION,
        MATH_ERROR,
        NOT_FRESH,
        TOKEN_INSUFFICIENT_CASH,
        TOKEN_TRANSFER_IN_FAILED,
        TOKEN_TRANSFER_OUT_FAILED,
        INSUFFICIENT_COLLATERAL
    }

    /*
     * Note: FailureInfo (but not Error) is kept in alphabetical order
     *       This is because FailureInfo grows significantly faster, and
     *       the order of Error has some meaning, while the order of FailureInfo
     *       is entirely arbitrary.
     */
    enum FailureInfo {
        ADMIN_CHECK,
        PARTICIPANT_CHECK,
        ACCRUE_INTEREST_FAILED,
        ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED,
        ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED,
        ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED,
        ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED,
        ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED,
        BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,
        BORROW_CASH_NOT_AVAILABLE,
        BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED,
        BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED,
        BORROW_REJECTION,
        BORROW_INSUFFICIENT_COLLATERAL,
        MINT_REJECTION,
        MINT_EXCHANGE_CALCULATION_FAILED,
        MINT_EXCHANGE_RATE_READ_FAILED,
        MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED,
        MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED,
        REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED,
        REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED,
        REDEEM_EXCHANGE_RATE_READ_FAILED,
        REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED,
        REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED,
        REDEEM_TRANSFER_OUT_NOT_POSSIBLE,
        REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,
        REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED,
        REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED,
        COLLATERALIZE_REJECTION,
        REDEEM_COLLATERAL_ACCUMULATED_BORROW_CALCULATION_FAILED,
        REDEEM_COLLATERAL_NEW_ACCOUNT_COLLATERAL_CALCULATION_FAILED,
        REDEEM_COLLATERAL_INSUFFICIENT_COLLATERAL,
        LIQUIDATE_BORROW_REJECTION,
        LIQUIDATE_BORROW_COLLATERAL_RATE_CALCULATION_FAILED,
        LIQUIDATE_BORROW_NOT_SATISFIED,
        SET_RESERVE_FACTOR_BOUNDS_CHECK,
        SET_LIQUIDATE_FACTOR_BOUNDS_CHECK,
        TRANSFER_NOT_ALLOWED,
        TRANSFER_NOT_ENOUGH,
        TRANSFER_TOO_MUCH
    }

    /**
      * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary
      * contract-specific code that enables us to report opaque error codes from upgradeable contracts.
      **/
    event Failure(uint error, uint info, uint detail);

    /**
      * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator
      */
    function fail(Error err, FailureInfo info) internal returns (uint) {
        emit Failure(uint(err), uint(info), 0);

        return uint(err);
    }

    /**
      * @dev use this when reporting an opaque error from an upgradeable collaborator contract
      */
    function failOpaque(Error err, FailureInfo info, uint opaqueError) internal returns (uint) {
        emit Failure(uint(err), uint(info), opaqueError);

        return uint(err);
    }
}

// File: contracts\EIP20Interface.sol

pragma solidity ^0.5.8;

/**
 * @title ERC 20 Token Standard Interface
 *  https://eips.ethereum.org/EIPS/eip-20
 */
interface EIP20Interface {

    /**
      * @notice Get the total number of tokens in circulation
      * @return The supply of tokens
      */
    function totalSupply() external view returns (uint256);

    /**
     * @notice Gets the balance of the specified address
     * @param owner The address from which the balance will be retrieved
     * @return The balance
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
      * @notice Transfer `amount` tokens from `msg.sender` to `dst`
      * @param dst The address of the destination account
      * @param amount The number of tokens to transfer
      * @return Whether or not the transfer succeeded
      */
    function transfer(address dst, uint256 amount) external returns (bool success);

    /**
      * @notice Transfer `amount` tokens from `src` to `dst`
      * @param src The address of the source account
      * @param dst The address of the destination account
      * @param amount The number of tokens to transfer
      * @return Whether or not the transfer succeeded
      */
    function transferFrom(address src, address dst, uint256 amount) external returns (bool success);

    /**
      * @notice Approve `spender` to transfer up to `amount` from `src`
      * @dev This will overwrite the approval amount for `spender`
      *  and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
      * @param spender The address of the account which may transfer tokens
      * @param amount The number of tokens that are approved (-1 means infinite)
      * @return Whether or not the approval succeeded
      */
    function approve(address spender, uint256 amount) external returns (bool success);

    /**
      * @notice Get the current allowance from `owner` for `spender`
      * @param owner The address of the account which owns the tokens to be spent
      * @param spender The address of the account which may transfer tokens
      * @return The number of tokens allowed to be spent (-1 means infinite)
      */
    function allowance(address owner, address spender) external view returns (uint256 remaining);

    event Transfer(address indexed from, address indexed to, uint256 amount);
    event Approval(address indexed owner, address indexed spender, uint256 amount);
}

// File: contracts\EIP20NonStandardInterface.sol

pragma solidity ^0.5.8;

/**
 * @title EIP20NonStandardInterface
 * @dev Version of ERC20 with no return values for `transfer` and `transferFrom`
 *  See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
 */
interface EIP20NonStandardInterface {

    /**
     * @notice Get the total number of tokens in circulation
     * @return The supply of tokens
     */
    function totalSupply() external view returns (uint256);

    /**
     * @notice Gets the balance of the specified address
     * @param owner The address from which the balance will be retrieved
     * @return The balance
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    ///
    /// !!!!!!!!!!!!!!
    /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification
    /// !!!!!!!!!!!!!!
    ///

    /**
      * @notice Transfer `amount` tokens from `msg.sender` to `dst`
      * @param dst The address of the destination account
      * @param amount The number of tokens to transfer
      */
    function transfer(address dst, uint256 amount) external;

    ///
    /// !!!!!!!!!!!!!!
    /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification
    /// !!!!!!!!!!!!!!
    ///

    /**
      * @notice Transfer `amount` tokens from `src` to `dst`
      * @param src The address of the source account
      * @param dst The address of the destination account
      * @param amount The number of tokens to transfer
      */
    function transferFrom(address src, address dst, uint256 amount) external;

    /**
      * @notice Approve `spender` to transfer up to `amount` from `src`
      * @dev This will overwrite the approval amount for `spender`
      *  and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
      * @param spender The address of the account which may transfer tokens
      * @param amount The number of tokens that are approved
      * @return Whether or not the approval succeeded
      */
    function approve(address spender, uint256 amount) external returns (bool success);

    /**
      * @notice Get the current allowance from `owner` for `spender`
      * @param owner The address of the account which owns the tokens to be spent
      * @param spender The address of the account which may transfer tokens
      * @return The number of tokens allowed to be spent
      */
    function allowance(address owner, address spender) external view returns (uint256 remaining);

    event Transfer(address indexed from, address indexed to, uint256 amount);
    event Approval(address indexed owner, address indexed spender, uint256 amount);
}

// File: contracts\CarefulMath.sol

// File: contracts/CarefulMath.sol

pragma solidity ^0.5.8;

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

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

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

        uint c = a * b;

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

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

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

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

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

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

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

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

        return subUInt(sum, c);
    }
}

// File: contracts\Exponential.sol

pragma solidity ^0.5.16;


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

    struct Exp {
        uint mantissa;
    }

    struct Double {
        uint mantissa;
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    /**
     * @dev Checks if first Exp is less than second Exp.
     */
    function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {
        return left.mantissa < right.mantissa;
    }

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

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

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

    function safe224(uint n, string memory errorMessage) pure internal returns (uint224) {
        require(n < 2**224, errorMessage);
        return uint224(n);
    }

    function safe32(uint n, string memory errorMessage) pure internal returns (uint32) {
        require(n < 2**32, errorMessage);
        return uint32(n);
    }

    function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {
        return Exp({mantissa: add_(a.mantissa, b.mantissa)});
    }

    function add_(Double memory a, Double memory b) pure internal returns (Double memory) {
        return Double({mantissa: add_(a.mantissa, b.mantissa)});
    }

    function add_(uint a, uint b) pure internal returns (uint) {
        return add_(a, b, "addition overflow");
    }

    function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {
        uint c = a + b;
        require(c >= a, errorMessage);
        return c;
    }

    function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {
        return Exp({mantissa: sub_(a.mantissa, b.mantissa)});
    }

    function sub_(Double memory a, Double memory b) pure internal returns (Double memory) {
        return Double({mantissa: sub_(a.mantissa, b.mantissa)});
    }

    function sub_(uint a, uint b) pure internal returns (uint) {
        return sub_(a, b, "subtraction underflow");
    }

    function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {
        require(b <= a, errorMessage);
        return a - b;
    }

    function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {
        return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale});
    }

    function mul_(Exp memory a, uint b) pure internal returns (Exp memory) {
        return Exp({mantissa: mul_(a.mantissa, b)});
    }

    function mul_(uint a, Exp memory b) pure internal returns (uint) {
        return mul_(a, b.mantissa) / expScale;
    }

    function mul_(Double memory a, Double memory b) pure internal returns (Double memory) {
        return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale});
    }

    function mul_(Double memory a, uint b) pure internal returns (Double memory) {
        return Double({mantissa: mul_(a.mantissa, b)});
    }

    function mul_(uint a, Double memory b) pure internal returns (uint) {
        return mul_(a, b.mantissa) / doubleScale;
    }

    function mul_(uint a, uint b) pure internal returns (uint) {
        return mul_(a, b, "multiplication overflow");
    }

    function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {
        if (a == 0 || b == 0) {
            return 0;
        }
        uint c = a * b;
        require(c / a == b, errorMessage);
        return c;
    }

    function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {
        return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)});
    }

    function div_(Exp memory a, uint b) pure internal returns (Exp memory) {
        return Exp({mantissa: div_(a.mantissa, b)});
    }

    function div_(uint a, Exp memory b) pure internal returns (uint) {
        return div_(mul_(a, expScale), b.mantissa);
    }

    function div_(Double memory a, Double memory b) pure internal returns (Double memory) {
        return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)});
    }

    function div_(Double memory a, uint b) pure internal returns (Double memory) {
        return Double({mantissa: div_(a.mantissa, b)});
    }

    function div_(uint a, Double memory b) pure internal returns (uint) {
        return div_(mul_(a, doubleScale), b.mantissa);
    }

    function div_(uint a, uint b) pure internal returns (uint) {
        return div_(a, b, "divide by zero");
    }

    function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {
        require(b > 0, errorMessage);
        return a / b;
    }

    function fraction(uint a, uint b) pure internal returns (Double memory) {
        return Double({mantissa: div_(mul_(a, doubleScale), b)});
    }
}

// File: contracts\InterestRateModel.sol

pragma solidity ^0.5.16;

/**
  * @title Compound's InterestRateModel Interface
  * @author Compound
  */
contract InterestRateModel {
    /// @notice Indicator that this is an InterestRateModel contract (for inspection)
    bool public constant isInterestRateModel = true;

    /**
      * @notice Calculates the current borrow interest rate per block
      * @param cash The total amount of cash the market has
      * @param borrows The total amount of borrows the market has outstanding
      * @param reserves The total amnount of reserves the market has
      * @return The borrow rate per block (as a percentage, and scaled by 1e18)
      */
    function getBorrowRate(uint cash, uint borrows, uint reserves) external view returns (uint);

    /**
      * @notice Calculates the current supply interest rate per block
      * @param cash The total amount of cash the market has
      * @param borrows The total amount of borrows the market has outstanding
      * @param reserves The total amnount of reserves the market has
      * @param reserveFactorMantissa The current reserve factor the market has
      * @return The supply rate per block (as a percentage, and scaled by 1e18)
      */
    function getSupplyRate(uint cash, uint borrows, uint reserves, uint reserveFactorMantissa) external view returns (uint);

}

// File: contracts\DFL.sol

pragma solidity ^0.5.16;
pragma experimental ABIEncoderV2;


// forked from Compound/COMP

/**
 * @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.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * 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 {
    address private _owner;

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

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

    /**
     * @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(_owner == msg.sender, "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

    /**
     * @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 {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

contract DFL is EIP20Interface, Ownable {
    /// @notice EIP-20 token name for this token
    string public constant name = "DeFIL";

    /// @notice EIP-20 token symbol for this token
    string public constant symbol = "DFL";

    /// @notice EIP-20 token decimals for this token
    uint8 public constant decimals = 18;

    /// @notice Total number of tokens in circulation
    uint96 internal _totalSupply;

    /// @notice Allowance amounts on behalf of others
    mapping (address => mapping (address => uint96)) internal allowances;

    /// @notice Official record of token balances for each account
    mapping (address => uint96) internal balances;

    /// @notice A record of each accounts delegate
    mapping (address => address) public delegates;

    /// @notice A checkpoint for marking number of votes from a given block
    struct Checkpoint {
        uint32 fromBlock;
        uint96 votes;
    }

    /// @notice A record of votes checkpoints for each account, by index
    mapping (address => mapping (uint32 => Checkpoint)) public checkpoints;

    /// @notice The number of checkpoints for each account
    mapping (address => uint32) public numCheckpoints;

    /// @notice The EIP-712 typehash for the contract's domain
    bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)");

    /// @notice The EIP-712 typehash for the delegation struct used by the contract
    bytes32 public constant DELEGATION_TYPEHASH = keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");

    /// @notice A record of states for signing / validating signatures
    mapping (address => uint) public nonces;

    /// @notice An event thats emitted when an account changes its delegate
    event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);

    /// @notice An event thats emitted when a delegate account's vote balance changes
    event DelegateVotesChanged(address indexed delegate, uint previousBalance, uint newBalance);

    /// @notice The standard EIP-20 transfer event
    event Transfer(address indexed from, address indexed to, uint256 amount);

    /// @notice The standard EIP-20 approval event
    event Approval(address indexed owner, address indexed spender, uint256 amount);

    /**
     * @notice Construct a new DFL token
     */
    constructor() public {
        emit Transfer(address(0), address(this), 0);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     * Emits a {Transfer} event with `from` set to the zero address.
     * @param account The address of the account holding the new funds
     * @param rawAmount The number of tokens that are minted
     */
    function mint(address account, uint rawAmount) public onlyOwner {
        require(account != address(0), "DFL:: mint: cannot mint to the zero address");
        uint96 amount = safe96(rawAmount, "DFL::mint: amount exceeds 96 bits");
        _totalSupply = add96(_totalSupply, amount, "DFL::mint: total supply exceeds");
        balances[account] = add96(balances[account], amount, "DFL::mint: mint amount exceeds balance");

        _moveDelegates(address(0), delegates[account], amount);
        emit Transfer(address(0), account, amount);
    }

    /**
     * @notice Get the number of tokens `spender` is approved to spend on behalf of `account`
     * @param account The address of the account holding the funds
     * @param spender The address of the account spending the funds
     * @return The number of tokens approved
     */
    function allowance(address account, address spender) external view returns (uint) {
        return allowances[account][spender];
    }

    /**
     * @notice Approve `spender` to transfer up to `amount` from `src`
     * @dev This will overwrite the approval amount for `spender`
     *  and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
     * @param spender The address of the account which may transfer tokens
     * @param rawAmount The number of tokens that are approved (2^256-1 means infinite)
     * @return Whether or not the approval succeeded
     */
    function approve(address spender, uint rawAmount) external returns (bool) {
        uint96 amount;
        if (rawAmount == uint(-1)) {
            amount = uint96(-1);
        } else {
            amount = safe96(rawAmount, "DFL::approve: amount exceeds 96 bits");
        }

        allowances[msg.sender][spender] = amount;

        emit Approval(msg.sender, spender, amount);
        return true;
    }

    /**
     * @notice Get the total supply of tokens
     * @return The total supply of tokens
     */
    function totalSupply() external view returns (uint) {
        return _totalSupply;
    }

    /**
     * @notice Get the number of tokens held by the `account`
     * @param account The address of the account to get the balance of
     * @return The number of tokens held
     */
    function balanceOf(address account) external view returns (uint) {
        return balances[account];
    }

    /**
     * @notice Transfer `amount` tokens from `msg.sender` to `dst`
     * @param dst The address of the destination account
     * @param rawAmount The number of tokens to transfer
     * @return Whether or not the transfer succeeded
     */
    function transfer(address dst, uint rawAmount) external returns (bool) {
        uint96 amount = safe96(rawAmount, "DFL::transfer: amount exceeds 96 bits");
        _transferTokens(msg.sender, dst, amount);
        return true;
    }

    /**
     * @notice Transfer `amount` tokens from `src` to `dst`
     * @param src The address of the source account
     * @param dst The address of the destination account
     * @param rawAmount The number of tokens to transfer
     * @return Whether or not the transfer succeeded
     */
    function transferFrom(address src, address dst, uint rawAmount) external returns (bool) {
        address spender = msg.sender;
        uint96 spenderAllowance = allowances[src][spender];
        uint96 amount = safe96(rawAmount, "DFL::approve: amount exceeds 96 bits");

        if (spender != src && spenderAllowance != uint96(-1)) {
            uint96 newAllowance = sub96(spenderAllowance, amount, "DFL::transferFrom: transfer amount exceeds spender allowance");
            allowances[src][spender] = newAllowance;

            emit Approval(src, spender, newAllowance);
        }

        _transferTokens(src, dst, amount);
        return true;
    }

    /**
     * @notice Delegate votes from `msg.sender` to `delegatee`
     * @param delegatee The address to delegate votes to
     */
    function delegate(address delegatee) public {
        return _delegate(msg.sender, delegatee);
    }

    /**
     * @notice Delegates votes from signatory to `delegatee`
     * @param delegatee The address to delegate votes to
     * @param nonce The contract state required to match the signature
     * @param expiry The time at which to expire the signature
     * @param v The recovery byte of the signature
     * @param r Half of the ECDSA signature pair
     * @param s Half of the ECDSA signature pair
     */
    function delegateBySig(address delegatee, uint nonce, uint expiry, uint8 v, bytes32 r, bytes32 s) public {
        bytes32 domainSeparator = keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), getChainId(), address(this)));
        bytes32 structHash = keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry));
        bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
        address signatory = ecrecover(digest, v, r, s);
        require(signatory != address(0), "DFL::delegateBySig: invalid signature");
        require(nonce == nonces[signatory]++, "DFL::delegateBySig: invalid nonce");
        require(block.timestamp <= expiry, "DFL::delegateBySig: signature expired");
        return _delegate(signatory, delegatee);
    }

    /**
     * @notice Gets the current votes balance for `account`
     * @param account The address to get votes balance
     * @return The number of current votes for `account`
     */
    function getCurrentVotes(address account) external view returns (uint96) {
        uint32 nCheckpoints = numCheckpoints[account];
        return nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0;
    }

    /**
     * @notice Determine the prior number of votes for an account as of a block number
     * @dev Block number must be a finalized block or else this function will revert to prevent misinformation.
     * @param account The address of the account to check
     * @param blockNumber The block number to get the vote balance at
     * @return The number of votes the account had as of the given block
     */
    function getPriorVotes(address account, uint blockNumber) public view returns (uint96) {
        require(blockNumber < block.number, "DFL::getPriorVotes: not yet determined");

        uint32 nCheckpoints = numCheckpoints[account];
        if (nCheckpoints == 0) {
            return 0;
        }

        // First check most recent balance
        if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) {
            return checkpoints[account][nCheckpoints - 1].votes;
        }

        // Next check implicit zero balance
        if (checkpoints[account][0].fromBlock > blockNumber) {
            return 0;
        }

        uint32 lower = 0;
        uint32 upper = nCheckpoints - 1;
        while (upper > lower) {
            uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow
            Checkpoint memory cp = checkpoints[account][center];
            if (cp.fromBlock == blockNumber) {
                return cp.votes;
            } else if (cp.fromBlock < blockNumber) {
                lower = center;
            } else {
                upper = center - 1;
            }
        }
        return checkpoints[account][lower].votes;
    }

    function _delegate(address delegator, address delegatee) internal {
        address currentDelegate = delegates[delegator];
        uint96 delegatorBalance = balances[delegator];
        delegates[delegator] = delegatee;

        emit DelegateChanged(delegator, currentDelegate, delegatee);

        _moveDelegates(currentDelegate, delegatee, delegatorBalance);
    }

    function _transferTokens(address src, address dst, uint96 amount) internal {
        require(src != address(0), "DFL::_transferTokens: cannot transfer from the zero address");
        require(dst != address(0), "DFL::_transferTokens: cannot transfer to the zero address");

        balances[src] = sub96(balances[src], amount, "DFL::_transferTokens: transfer amount exceeds balance");
        balances[dst] = add96(balances[dst], amount, "DFL::_transferTokens: transfer amount overflows");
        emit Transfer(src, dst, amount);

        _moveDelegates(delegates[src], delegates[dst], amount);
    }

    function _moveDelegates(address srcRep, address dstRep, uint96 amount) internal {
        if (srcRep != dstRep && amount > 0) {
            if (srcRep != address(0)) {
                uint32 srcRepNum = numCheckpoints[srcRep];
                uint96 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0;
                uint96 srcRepNew = sub96(srcRepOld, amount, "DFL::_moveVotes: vote amount underflows");
                _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew);
            }

            if (dstRep != address(0)) {
                uint32 dstRepNum = numCheckpoints[dstRep];
                uint96 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0;
                uint96 dstRepNew = add96(dstRepOld, amount, "DFL::_moveVotes: vote amount overflows");
                _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew);
            }
        }
    }

    function _writeCheckpoint(address delegatee, uint32 nCheckpoints, uint96 oldVotes, uint96 newVotes) internal {
      uint32 blockNumber = safe32(block.number, "DFL::_writeCheckpoint: block number exceeds 32 bits");

      if (nCheckpoints > 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber) {
          checkpoints[delegatee][nCheckpoints - 1].votes = newVotes;
      } else {
          checkpoints[delegatee][nCheckpoints] = Checkpoint(blockNumber, newVotes);
          numCheckpoints[delegatee] = nCheckpoints + 1;
      }

      emit DelegateVotesChanged(delegatee, oldVotes, newVotes);
    }

    function safe32(uint n, string memory errorMessage) internal pure returns (uint32) {
        require(n < 2**32, errorMessage);
        return uint32(n);
    }

    function safe96(uint n, string memory errorMessage) internal pure returns (uint96) {
        require(n < 2**96, errorMessage);
        return uint96(n);
    }

    function add96(uint96 a, uint96 b, string memory errorMessage) internal pure returns (uint96) {
        uint96 c = a + b;
        require(c >= a, errorMessage);
        return c;
    }

    function sub96(uint96 a, uint96 b, string memory errorMessage) internal pure returns (uint96) {
        require(b <= a, errorMessage);
        return a - b;
    }

    function getChainId() internal pure returns (uint) {
        uint256 chainId;
        assembly { chainId := chainid() }
        return chainId;
    }
}

// File: contracts\ReentrancyGuard.sol

pragma solidity ^0.5.16;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor () internal {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

// File: contracts\DeFIL.sol

pragma solidity ^0.5.16;

// Forked from Compound/CToken








contract DeFIL is ReentrancyGuard, EIP20Interface, Exponential, ErrorReporter {
    /**
     * @notice EIP-20 token name for this token
     */
    string public constant name = "Certificate of eFIL";
    /**
     * @notice EIP-20 token symbol for this token
     */
    string public constant symbol = "ceFIL";
    /**
     * @notice EIP-20 token decimals for this token
     */
    uint8 public constant decimals = 18;
    /**
     * @notice Maximum fraction of interest that can be set aside for reserves
     */
    uint internal constant reserveFactorMaxMantissa = 1e18;
    /**
     * @notice Address of eFIL token
     */
    address public eFILAddress;
    /**
     * @notice Address of mFIL token
     */
    address public mFILAddress;
    /**
     * @notice The address who owns the reserves
     */
    address public reservesOwner;
    /**
     * @notice Administrator for this contract
     */
    address public admin;
    /**
     * @notice Pending administrator for this contract
     */
    address public pendingAdmin;
    /**
     * @notice Model which tells what the current interest rate should be
     */
    InterestRateModel public interestRateModel;
    /**
     * @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0)
     */
    uint internal constant initialExchangeRateMantissa = 0.002e18; // 1 eFIL = 500 ceFIL
    /**
     * @notice Fraction of interest currently set aside for reserves
     */
    uint public reserveFactorMantissa;
    /**
     * @notice Block number that interest was last accrued at
     */
    uint public accrualBlockNumber;
    /**
     * @notice Accumulator of the total earned interest rate since the opening
     */
    uint public borrowIndex;
    /**
     * @notice Total amount of outstanding borrows of the underlying
     */
    uint public totalBorrows;
    /**
     * @notice Total amount of reserves of the underlying held
     */
    uint public totalReserves;
    /**
     * @notice Total number of tokens in circulation
     */
    uint public totalSupply;

    // Is mint allowed.
    bool public mintAllowed;
    // Is borrow allowed.
    bool public borrowAllowed;
    /**
     * @notice Official record of token balances for each account
     */
    mapping (address => uint) internal accountTokens;
    /**
     * @notice Approved token transfer amounts on behalf of others
     */
    mapping (address => mapping (address => uint)) internal transferAllowances;

    /**
     * @notice Container for borrow balance information
     * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action
     * @member interestIndex Global borrowIndex as of the most recent balance-changing action
     */
    struct BorrowSnapshot {
        uint principal;
        uint interestIndex;
    }
    /**
     * @notice Mapping of account addresses to outstanding borrow balances
     */
    mapping(address => BorrowSnapshot) internal accountBorrows;

    // Total collaterals
    uint public totalCollaterals;
    // Mapping of account to outstanding collateral balances
    mapping (address => uint) internal accountCollaterals;
    // Multiplier used to decide when liquidate borrow is allowed
    uint public liquidateFactorMantissa;
    // No liquidateFactorMantissa may bellows this value
    uint internal constant liquidateFactorMinMantissa = 1e18; // 100%

    /*** For DFL ***/
    /**
     * @notice Address of DFL token
     */
    DFL public dflToken;
    // By using the special 'min speed=0.00017e18' and 'start speed=86.805721e18'
    // We will got 99999999.8568 DFLs in the end.
    // The havle period in block number
    uint internal constant halvePeriod = 576000; // 100 days
    // Minimum speed
    uint internal constant minSpeed = 0.00017e18; // 1e18 / 5760
    // Current speed (per block)
    uint public currentSpeed = 86.805721e18; // 500000e18 / 5760; // start with 500,000 per day
    // The block number when next havle will happens
    uint public nextHalveBlockNumber;

    // The address of uniswap incentive contract for receiving DFL
    address public uniswapAddress;
    // The address of miner league for receiving DFL
    address public minerLeagueAddress;
    // The address of operator for receiving DFL
    address public operatorAddress;
    // The address of technical support for receiving DFL
    address public technicalAddress;
    // The address for undistributed DFL
    address public undistributedAddress;

    // The percentage of DFL distributes to uniswap incentive
    uint public uniswapPercentage;
    // The percentage of DFL distributes to miner league
    uint public minerLeaguePercentage;
    // The percentage of DFL distributes to operator
    uint public operatorPercentage;
    // The percentage of DFL distributes to technical support, unupdatable
    uint internal constant technicalPercentage = 0.02e18; // 2%

    // The threshold above which the flywheel transfers DFL
    uint internal constant dflClaimThreshold = 0.1e18; // 0.1 DFL
    // Block number that DFL was last accrued at
    uint public dflAccrualBlockNumber;
    // The last updated index of DFL for suppliers
    uint public dflSupplyIndex;
    // The initial dfl supply index
    uint internal constant dflInitialSupplyIndex = 1e36;
    // The index for each supplier as of the last time they accrued DFL
    mapping(address => uint) public dflSupplierIndex;
    // The DFL accrued but not yet transferred to each user
    mapping(address => uint) public dflAccrued;

    /*** Events ***/
    /**
     * @notice Event emitted when interest is accrued
     */
    event AccrueInterest(uint cashPrior, uint interestAccumulated, uint borrowIndex, uint totalBorrows);
    /**
     * @notice Event emitted when tokens are minted
     */
    event Mint(address minter, uint mintAmount, uint mintTokens);
    /**
     * @notice Event emitted when mFIL are collateralized
     */
    event Collateralize(address collateralizer, uint collateralizeAmount);
    /**
     * @notice Event emitted when tokens are redeemed
     */
    event Redeem(address redeemer, uint redeemAmount, uint redeemTokens);
    /**
     * @notice Event emitted when underlying is borrowed
     */
    event Borrow(address borrower, uint borrowAmount, uint accountBorrows, uint totalBorrows);
    /**
     * @notice Event emitted when a borrow is repaid
     */
    event RepayBorrow(address payer, address borrower, uint repayAmount, uint accountBorrows, uint totalBorrows);
    /**
     * @notice Event emitted when collaterals are redeemed
     */
    event RedeemCollateral(address redeemer, uint redeemAmount);
    /**
     * @notice Event emitted when a liquidate borrow is repaid
     */
    event LiquidateBorrow(address liquidator, address borrower, uint accountBorrows, uint accountCollaterals);

    /*** Admin Events ***/
    /**
     * @notice Event emitted when pendingAdmin is changed
     */
    event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin);
    /**
     * @notice Event emitted when pendingAdmin is accepted, which means admin is updated
     */
    event NewAdmin(address oldAdmin, address newAdmin);
    /**
     * @notice Event emitted when mintAllowed is changed
     */
    event MintAllowed(bool mintAllowed);
    /**
     * @notice Event emitted when borrowAllowed is changed
     */
    event BorrowAllowed(bool borrowAllowed);
    /**
     * @notice Event emitted when interestRateModel is changed
     */
    event NewInterestRateModel(InterestRateModel oldInterestRateModel, InterestRateModel newInterestRateModel);
    /**
     * @notice Event emitted when the reserve factor is changed
     */
    event NewReserveFactor(uint oldReserveFactorMantissa, uint newReserveFactorMantissa);
    /**
     * @notice Event emitted when the liquidate factor is changed
     */
    event NewLiquidateFactor(uint oldLiquidateFactorMantissa, uint newLiquidateFactorMantissa);
    /**
     * @notice EIP20 Transfer event
     */
    event Transfer(address indexed from, address indexed to, uint amount);
    /**
     * @notice EIP20 Approval event
     */
    event Approval(address indexed owner, address indexed spender, uint amount);
    /**
     * @notice Failure event
     */
    event Failure(uint error, uint info, uint detail);

    // Event emitted when reserves owner is changed
    event ReservesOwnerChanged(address oldAddress, address newAddress);
    // Event emitted when uniswap address is changed
    event UniswapAddressChanged(address oldAddress, address newAddress);
    // Event emitted when miner leagure address is changed
    event MinerLeagueAddressChanged(address oldAddress, address newAddress);
    // Event emitted when operator address is changed
    event OperatorAddressChanged(address oldAddress, address newAddress);
    // Event emitted when technical address is changed
    event TechnicalAddressChanged(address oldAddress, address newAddress);
    // Event emitted when undistributed address is changed
    event UndistributedAddressChanged(address oldAddress, address newAddress);
    // Event emitted when reserved is reduced
    event ReservesReduced(address toTho, uint amount);
    // Event emitted when DFL is accrued
    event AccrueDFL(uint uniswapPart, uint minerLeaguePart, uint operatorPart, uint technicalPart, uint supplyPart, uint dflSupplyIndex);
    // Emitted when DFL is distributed to a supplier
    event DistributedDFL(address supplier, uint supplierDelta);
    // Event emitted when DFL percentage is changed
    event PercentagesChanged(uint uniswapPercentage, uint minerLeaguePercentage, uint operatorPercentage);

    /**
     * @notice constructor
     */
    constructor(address interestRateModelAddress,
                address eFILAddress_,
                address mFILAddress_,
                address dflAddress_,
                address reservesOwner_,
                address uniswapAddress_,
                address minerLeagueAddress_,
                address operatorAddress_,
                address technicalAddress_,
                address undistributedAddress_) public {
        // set admin
        admin = msg.sender;

        // Initialize block number and borrow index
        accrualBlockNumber = getBlockNumber();
        borrowIndex = mantissaOne;

        // reserve 50%
        uint err = _setReserveFactorFresh(0.5e18);
        require(err == uint(Error.NO_ERROR), "setting reserve factor failed");

        // set liquidate factor to 200%
        err = _setLiquidateFactorFresh(2e18);
        require(err == uint(Error.NO_ERROR), "setting liquidate factor failed");

        // Set the interest rate model (depends on block number / borrow index)
        err = _setInterestRateModelFresh(InterestRateModel(interestRateModelAddress));
        require(err == uint(Error.NO_ERROR), "setting interest rate model failed");

        // uniswapPercentage = 0.25e18; // 25%
        // minerLeaguePercentage = 0.1e18; // 10%
        // operatorPercentage = 0.03e18; // 3%
        err = _setDFLPercentagesFresh(0.25e18, 0.1e18, 0.03e18);
        require(err == uint(Error.NO_ERROR), "setting DFL percentages failed");

        // allow mint/borrow
        mintAllowed = true;
        borrowAllowed = true;

        // token addresses & tokens
        eFILAddress = eFILAddress_;
        mFILAddress = mFILAddress_;
        dflToken = DFL(dflAddress_);
        // set owner of reserves
        reservesOwner = reservesOwner_;

        // DFL
        dflAccrualBlockNumber = getBlockNumber();
        dflSupplyIndex = dflInitialSupplyIndex;
        nextHalveBlockNumber = dflAccrualBlockNumber + halvePeriod;

        // DFL addresses
        uniswapAddress = uniswapAddress_;
        minerLeagueAddress = minerLeagueAddress_;
        operatorAddress = operatorAddress_;
        technicalAddress = technicalAddress_;
        undistributedAddress = undistributedAddress_;

        emit Transfer(address(0), address(this), 0);
    }

    /**
     * @notice Transfer `tokens` tokens from `src` to `dst` by `spender`
     * @dev Called by both `transfer` and `transferFrom` internally
     * @param spender The address of the account performing the transfer
     * @param src The address of the source account
     * @param dst The address of the destination account
     * @param tokens The number of tokens to transfer
     * @return Whether or not the transfer succeeded
     */
    function transferTokens(address spender, address src, address dst, uint tokens) internal returns (uint) {
        /* Do not allow self-transfers */
        if (src == dst || dst == address(0)) {
            return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED);
        }

        // Keep the flywheel moving
        accrueDFL();
        distributeSupplierDFL(src, false);
        distributeSupplierDFL(dst, false);

        /* Get the allowance, infinite for the account owner */
        uint startingAllowance = 0;
        if (spender == src) {
            startingAllowance = uint(-1);
        } else {
            startingAllowance = transferAllowances[src][spender];
        }

        /* Do the calculations, checking for {under,over}flow */
        MathError mathErr;
        uint allowanceNew;
        uint srcTokensNew;
        uint dstTokensNew;

        (mathErr, allowanceNew) = subUInt(startingAllowance, tokens);
        if (mathErr != MathError.NO_ERROR) {
            return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ALLOWED);
        }

        (mathErr, srcTokensNew) = subUInt(accountTokens[src], tokens);
        if (mathErr != MathError.NO_ERROR) {
            return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ENOUGH);
        }

        (mathErr, dstTokensNew) = addUInt(accountTokens[dst], tokens);
        if (mathErr != MathError.NO_ERROR) {
            return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH);
        }

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)

        accountTokens[src] = srcTokensNew;
        accountTokens[dst] = dstTokensNew;

        /* Eat some of the allowance (if necessary) */
        if (startingAllowance != uint(-1)) {
            transferAllowances[src][spender] = allowanceNew;
        }

        /* We emit a Transfer event */
        emit Transfer(src, dst, tokens);
        return uint(Error.NO_ERROR);
    }

    /**
     * @notice Transfer `amount` tokens from `msg.sender` to `dst`
     * @param dst The address of the destination account
     * @param amount The number of tokens to transfer
     * @return Whether or not the transfer succeeded
     */
    function transfer(address dst, uint256 amount) external nonReentrant returns (bool) {
        return transferTokens(msg.sender, msg.sender, dst, amount) == uint(Error.NO_ERROR);
    }

    /**
     * @notice Transfer `amount` tokens from `src` to `dst`
     * @param src The address of the source account
     * @param dst The address of the destination account
     * @param amount The number of tokens to transfer
     * @return Whether or not the transfer succeeded
     */
    function transferFrom(address src, address dst, uint256 amount) external nonReentrant returns (bool) {
        return transferTokens(msg.sender, src, dst, amount) == uint(Error.NO_ERROR);
    }

    /**
     * @notice Approve `spender` to transfer up to `amount` from `src`
     * @dev This will overwrite the approval amount for `spender`
     *  and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
     * @param spender The address of the account which may transfer tokens
     * @param amount The number of tokens that are approved (-1 means infinite)
     * @return Whether or not the approval succeeded
     */
    function approve(address spender, uint256 amount) external returns (bool) {
        require(spender != address(0), "cannot approve to the zero address");
        address src = msg.sender;
        transferAllowances[src][spender] = amount;
        emit Approval(src, spender, amount);
        return true;
    }

    /**
     * @notice Get the current allowance from `owner` for `spender`
     * @param owner The address of the account which owns the tokens to be spent
     * @param spender The address of the account which may transfer tokens
     * @return The number of tokens allowed to be spent (-1 means infinite)
     */
    function allowance(address owner, address spender) external view returns (uint256) {
        return transferAllowances[owner][spender];
    }

    /**
     * @notice Get the token balance of the `owner`
     * @param owner The address of the account to query
     * @return The number of tokens owned by `owner`
     */
    function balanceOf(address owner) external view returns (uint256) {
        return accountTokens[owner];
    }

    /**
     * @notice Get the underlying balance of the `owner`
     * @dev This also accrues interest in a transaction
     * @param owner The address of the account to query
     * @return The amount of underlying owned by `owner`
     */
    function balanceOfUnderlying(address owner) external returns (uint) {
        Exp memory exchangeRate = Exp({mantissa: exchangeRateCurrent()});
        (MathError mErr, uint balance) = mulScalarTruncate(exchangeRate, accountTokens[owner]);
        require(mErr == MathError.NO_ERROR, "balance could not be calculated");
        return balance;
    }

    /**
     * @notice Get the collateral of the `account`
     * @param account The address of the account to query
     * @return The number of collaterals owned by `account`
     */
    function getCollateral(address account) external view returns (uint256) {
        return accountCollaterals[account];
    }

    /**
     * @dev Function to simply retrieve block number
     *  This exists mainly for inheriting test contracts to stub this result.
     */
    function getBlockNumber() internal view returns (uint) {
        return block.number;
    }

    /**
     * @notice Returns the current per-block borrow interest rate
     * @return The borrow interest rate per block, scaled by 1e18
     */
    function borrowRatePerBlock() external view returns (uint) {
        return interestRateModel.getBorrowRate(getCashPrior(), totalBorrows, totalReserves);
    }

    /**
     * @notice Returns the current per-block supply interest rate
     * @return The supply interest rate per block, scaled by 1e18
     */
    function supplyRatePerBlock() external view returns (uint) {
        return interestRateModel.getSupplyRate(getCashPrior(), totalBorrows, totalReserves, reserveFactorMantissa);
    }

    /**
     * @notice Returns the current total borrows plus accrued interest
     * @return The total borrows with interest
     */
    function totalBorrowsCurrent() external nonReentrant returns (uint) {
        require(accrueInterest() == uint(Error.NO_ERROR), "accrue interest failed");
        return totalBorrows;
    }

    /**
     * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex
     * @param account The address whose balance should be calculated after updating borrowIndex
     * @return The calculated balance
     */
    function borrowBalanceCurrent(address account) external nonReentrant returns (uint) {
        require(accrueInterest() == uint(Error.NO_ERROR), "accrue interest failed");
        return borrowBalanceStored(account);
    }

    /**
     * @notice Return the borrow balance of account based on stored data
     * @param account The address whose balance should be calculated
     * @return The calculated balance
     */
    function borrowBalanceStored(address account) public view returns (uint) {
        (MathError err, uint result) = borrowBalanceStoredInternal(account);
        require(err == MathError.NO_ERROR, "borrowBalanceStored: borrowBalanceStoredInternal failed");
        return result;
    }

    /**
     * @notice Return the borrow balance of account based on stored data
     * @param account The address whose balance should be calculated
     * @return (error code, the calculated balance or 0 if error code is non-zero)
     */
    function borrowBalanceStoredInternal(address account) internal view returns (MathError, uint) {
        /* Note: we do not assert that is up to date */
        MathError mathErr;
        uint principalTimesIndex;
        uint result;

        /* Get borrowBalance and borrowIndex */
        BorrowSnapshot storage borrowSnapshot = accountBorrows[account];

        /* If borrowBalance = 0 then borrowIndex is likely also 0.
         * Rather than failing the calculation with a division by 0, we immediately return 0 in this case.
         */
        if (borrowSnapshot.principal == 0) {
            return (MathError.NO_ERROR, 0);
        }

        /* Calculate new borrow balance using the interest index:
         *  recentBorrowBalance = borrower.borrowBalance * global.borrowIndex / borrower.borrowIndex
         */
        (mathErr, principalTimesIndex) = mulUInt(borrowSnapshot.principal, borrowIndex);
        if (mathErr != MathError.NO_ERROR) {
            return (mathErr, 0);
        }

        (mathErr, result) = divUInt(principalTimesIndex, borrowSnapshot.interestIndex);
        if (mathErr != MathError.NO_ERROR) {
            return (mathErr, 0);
        }

        return (MathError.NO_ERROR, result);
    }

    /**
     * @notice Accrue interest then return the up-to-date exchange rate
     * @return Calculated exchange rate scaled by 1e18
     */
    function exchangeRateCurrent() public returns (uint) {
        require(accrueInterest() == uint(Error.NO_ERROR), "accrue interest failed");
        return exchangeRateStored();
    }

    /**
     * @notice Calculates the exchange rate from the underlying to the ceFIL
     * @dev This function does not accrue interest before calculating the exchange rate
     * @return Calculated exchange rate scaled by 1e18
     */
    function exchangeRateStored() public view returns (uint) {
        (MathError err, uint result) = exchangeRateStoredInternal();
        require(err == MathError.NO_ERROR, "exchangeRateStored: exchangeRateStoredInternal failed");
        return result;
    }

    /**
     * @notice Calculates the exchange rate from the underlying to the ceFIL
     * @dev This function does not accrue interest before calculating the exchange rate
     * @return (error code, calculated exchange rate scaled by 1e18)
     */
    function exchangeRateStoredInternal() internal view returns (MathError, uint) {
        uint _totalSupply = totalSupply;
        if (_totalSupply == 0) {
            /*
             * If there are no tokens minted:
             *  exchangeRate = initialExchangeRate
             */
            return (MathError.NO_ERROR, initialExchangeRateMantissa);
        } else {
            /*
             * Otherwise:
             *  exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply
             */
            uint totalCash = getCashPrior();
            uint cashPlusBorrowsMinusReserves;
            Exp memory exchangeRate;
            MathError mathErr;

            (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt(totalCash, totalBorrows, totalReserves);
            if (mathErr != MathError.NO_ERROR) {
                return (mathErr, 0);
            }

            (mathErr, exchangeRate) = getExp(cashPlusBorrowsMinusReserves, _totalSupply);
            if (mathErr != MathError.NO_ERROR) {
                return (mathErr, 0);
            }

            return (MathError.NO_ERROR, exchangeRate.mantissa);
        }
    }

    /**
     * @notice Accrue interest then return the up-to-date collateral rate
     * @return Calculated collateral rate scaled by 1e18
     */
    function collateralRateCurrent(address borrower) external returns (uint) {
        require(accrueInterest() == uint(Error.NO_ERROR), "accrue interest failed");
        return collateralRateStored(borrower);
    }

    /**
     * @notice Calculates the collateral rate of borrower from stored states
     * @dev This function does not accrue interest before calculating the collateral rate
     * @return Calculated exchange rate scaled by 1e18
     */
    function collateralRateStored(address borrower) public view returns (uint) {
        (MathError err, uint rate, ,) = collateralRateInternal(borrower);
        require(err == MathError.NO_ERROR, "collateralRateStored: collateralRateInternal failed");
        return rate;
    }

    function collateralRateInternal(address borrower) internal view returns (MathError, uint, uint, uint) {
        MathError mathErr;
        uint _accountBorrows;
        uint _accountCollaterals;
        Exp memory collateralRate;

        (mathErr, _accountBorrows) = borrowBalanceStoredInternal(borrower);
        if (mathErr != MathError.NO_ERROR) {
            return (mathErr, 0, 0, 0);
        }

        _accountCollaterals = accountCollaterals[borrower];
        (mathErr, collateralRate) = getExp(_accountBorrows, _accountCollaterals);
        if (mathErr != MathError.NO_ERROR) {
            return (mathErr, 0, 0, 0);
        }

        return (MathError.NO_ERROR, collateralRate.mantissa, _accountBorrows, _accountCollaterals);
    }

    // Accrue DFL then return the up-to-date accrued amount
    function accruedDFLCurrent(address supplier) external nonReentrant returns (uint) {
        accrueDFL();
        return accruedDFLStoredInternal(supplier);
    }

    // Accrue DFL then return the up-to-date accrued amount
    function accruedDFLStored(address supplier) public view returns (uint) {
        return accruedDFLStoredInternal(supplier);
    }

    // Return the accrued DFL of account based on stored data
    function accruedDFLStoredInternal(address supplier) internal view returns(uint) {
        Double memory supplyIndex = Double({mantissa: dflSupplyIndex});
        Double memory supplierIndex = Double({mantissa: dflSupplierIndex[supplier]});
        if (supplierIndex.mantissa == 0 && supplyIndex.mantissa > 0) {
            supplierIndex.mantissa = dflInitialSupplyIndex;
        }

        Double memory deltaIndex = sub_(supplyIndex, supplierIndex);
        uint supplierDelta = mul_(accountTokens[supplier], deltaIndex);
        uint supplierAccrued = add_(dflAccrued[supplier], supplierDelta);
        return supplierAccrued;
    }

    /**
     * @notice Get cash balance of this in the underlying asset
     * @return The quantity of underlying asset owned by this contract
     */
    function getCash() external view returns (uint) {
        return getCashPrior();
    }

    /**
     * @notice Applies accrued interest to total borrows and reserves
     * @dev This calculates interest accrued from the last checkpointed block
     *   up to the current block and writes new checkpoint to storage.
     */
    function accrueInterest() public returns (uint) {
        /* Remember the initial block number */
        uint currentBlockNumber = getBlockNumber();
        uint accrualBlockNumberPrior = accrualBlockNumber;

        /* Short-circuit accumulating 0 interest */
        if (accrualBlockNumberPrior == currentBlockNumber) {
            return uint(Error.NO_ERROR);
        }

        /* Read the previous values out of storage */
        uint cashPrior = getCashPrior();
        uint borrowsPrior = totalBorrows;
        uint reservesPrior = totalReserves;
        uint borrowIndexPrior = borrowIndex;

        /* Calculate the current borrow interest rate */
        uint borrowRateMantissa = interestRateModel.getBorrowRate(cashPrior, borrowsPrior, reservesPrior);

        /* Calculate the number of blocks elapsed since the last accrual */
        (MathError mathErr, uint blockDelta) = subUInt(currentBlockNumber, accrualBlockNumberPrior);
        require(mathErr == MathError.NO_ERROR, "could not calculate block delta");

        /*
         * Calculate the interest accumulated into borrows and reserves and the new index:
         *  simpleInterestFactor = borrowRate * blockDelta
         *  interestAccumulated = simpleInterestFactor * totalBorrows
         *  totalBorrowsNew = interestAccumulated + totalBorrows
         *  totalReservesNew = interestAccumulated * reserveFactor + totalReserves
         *  borrowIndexNew = simpleInterestFactor * borrowIndex + borrowIndex
         */

        Exp memory simpleInterestFactor;
        uint interestAccumulated;
        uint totalBorrowsNew;
        uint totalReservesNew;
        uint borrowIndexNew;

        (mathErr, simpleInterestFactor) = mulScalar(Exp({mantissa: borrowRateMantissa}), blockDelta);
        if (mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, uint(mathErr));
        }

        (mathErr, interestAccumulated) = mulScalarTruncate(simpleInterestFactor, borrowsPrior);
        if (mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, uint(mathErr));
        }

        (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior);
        if (mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, uint(mathErr));
        }

        (mathErr, totalReservesNew) = mulScalarTruncateAddUInt(Exp({mantissa: reserveFactorMantissa}), interestAccumulated, reservesPrior);
        if (mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, uint(mathErr));
        }

        (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt(simpleInterestFactor, borrowIndexPrior, borrowIndexPrior);
        if (mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, uint(mathErr));
        }

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)

        /* We write the previously calculated values into storage */
        accrualBlockNumber = currentBlockNumber;
        borrowIndex = borrowIndexNew;
        totalBorrows = totalBorrowsNew;
        totalReserves = totalReservesNew;

        /* We emit an AccrueInterest event */
        emit AccrueInterest(cashPrior, interestAccumulated, borrowIndexNew, totalBorrowsNew);

        return uint(Error.NO_ERROR);
    }

    /**
     * @notice Sender supplies assets into and receives cTokens in exchange
     * @dev Accrues interest whether or not the operation succeeds, unless reverted
     * @param mintAmount The amount of the underlying asset to supply
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function mint(uint mintAmount) external nonReentrant returns (uint) {
        uint err = accrueInterest();
        if (err != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed
            return fail(Error(err), FailureInfo.ACCRUE_INTEREST_FAILED);
        }

        // Keep the flywheel moving
        accrueDFL();
        distributeSupplierDFL(msg.sender, false);

        // mintFresh emits the actual Mint event if successful and logs on errors, so we don't need to
        (err,) = mintFresh(msg.sender, mintAmount);
        return err;
    }

    struct MintLocalVars {
        Error err;
        MathError mathErr;
        uint exchangeRateMantissa;
        uint mintTokens;
        uint totalSupplyNew;
        uint accountTokensNew;
        uint actualMintAmount;
    }

    /**
     * @notice User supplies assets into and receives cTokens in exchange
     * @dev Assumes interest has already been accrued up to the current block
     * @param minter The address of the account which is supplying the assets
     * @param mintAmount The amount of the underlying asset to supply
     * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount.
     */
    function mintFresh(address minter, uint mintAmount) internal returns (uint, uint) {
        if (!mintAllowed || accountCollaterals[minter] != 0) {
            return (fail(Error.REJECTION, FailureInfo.MINT_REJECTION), 0);
        }

        MintLocalVars memory vars;

        (vars.mathErr, vars.exchangeRateMantissa) = exchangeRateStoredInternal();
        if (vars.mathErr != MathError.NO_ERROR) {
            return (failOpaque(Error.MATH_ERROR, FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, uint(vars.mathErr)), 0);
        }

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)
        vars.actualMintAmount = doTransferIn(eFILAddress, minter, mintAmount);

        /*
         * We get the current exchange rate and calculate the number of cTokens to be minted:
         *  mintTokens = actualMintAmount / exchangeRate
         */

        (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate(vars.actualMintAmount, Exp({mantissa: vars.exchangeRateMantissa}));
        require(vars.mathErr == MathError.NO_ERROR, "MINT_EXCHANGE_CALCULATION_FAILED");

        /*
         * We calculate the new total supply of cTokens and minter token balance, checking for overflow:
         *  totalSupplyNew = totalSupply + mintTokens
         *  accountTokensNew = accountTokens[minter] + mintTokens
         */
        (vars.mathErr, vars.totalSupplyNew) = addUInt(totalSupply, vars.mintTokens);
        require(vars.mathErr == MathError.NO_ERROR, "MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED");

        (vars.mathErr, vars.accountTokensNew) = addUInt(accountTokens[minter], vars.mintTokens);
        require(vars.mathErr == MathError.NO_ERROR, "MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED");

        /* We write previously calculated values into storage */
        totalSupply = vars.totalSupplyNew;
        accountTokens[minter] = vars.accountTokensNew;

        /* We emit a Mint event, and a Transfer event */
        emit Mint(minter, vars.actualMintAmount, vars.mintTokens);
        emit Transfer(address(this), minter, vars.mintTokens);

        return (uint(Error.NO_ERROR), vars.actualMintAmount);
    }

    /**
     * @dev Accrues interest whether or not the operation succeeds, unless reverted
     * @param collateralizeAmount The amount of the underlying asset to collateralize
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function collateralize(uint collateralizeAmount) external nonReentrant returns (uint) {
        uint err = accrueInterest();
        if (err != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed
            return fail(Error(err), FailureInfo.ACCRUE_INTEREST_FAILED);
        }

        // Keep the flywheel moving
        accrueDFL();

        (err,) = collateralizeFresh(msg.sender, collateralizeAmount);
        return err;
    }

    struct CollateralizeLocalVars {
        Error err;
        MathError mathErr;
        uint totalCollateralsNew;
        uint accountCollateralsNew;
        uint actualCollateralizeAmount;
    }

    /**
     * @param collateralizer The address of the account which is supplying the assets
     * @param collateralizeAmount The amount of the underlying asset to supply
     * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual collateralize amount.
     */
    function collateralizeFresh(address collateralizer, uint collateralizeAmount) internal returns (uint, uint) {
        if (accountTokens[collateralizer] != 0) {
            return (fail(Error.REJECTION, FailureInfo.COLLATERALIZE_REJECTION), 0);
        }

        CollateralizeLocalVars memory vars;

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)
        vars.actualCollateralizeAmount = doTransferIn(mFILAddress, collateralizer, collateralizeAmount);

        (vars.mathErr, vars.totalCollateralsNew) = addUInt(totalCollaterals, vars.actualCollateralizeAmount);
        require(vars.mathErr == MathError.NO_ERROR, "COLLATERALIZE_NEW_TOTAL_COLLATERALS_CALCULATION_FAILED");

        (vars.mathErr, vars.accountCollateralsNew) = addUInt(accountCollaterals[collateralizer], vars.actualCollateralizeAmount);
        require(vars.mathErr == MathError.NO_ERROR, "COLLATERALIZE_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED");

        /* We write previously calculated values into storage */
        totalCollaterals = vars.totalCollateralsNew;
        accountCollaterals[collateralizer] = vars.accountCollateralsNew;

        /* We emit a Collateralize event, and a Transfer event */
        emit Collateralize(collateralizer, vars.actualCollateralizeAmount);
        return (uint(Error.NO_ERROR), vars.actualCollateralizeAmount);
    }

    /**
     * @notice Sender redeems cTokens in exchange for the underlying asset
     * @dev Accrues interest whether or not the operation succeeds, unless reverted
     * @param redeemTokens The number of cTokens to redeem into underlying
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function redeem(uint redeemTokens) external nonReentrant returns (uint) {
        uint err = accrueInterest();
        if (err != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but we still want to log the fact that an attempted redeem failed
            return fail(Error(err), FailureInfo.ACCRUE_INTEREST_FAILED);
        }

        // Keep the flywheel moving
        accrueDFL();
        distributeSupplierDFL(msg.sender, false);

        // redeemFresh emits redeem-specific logs on errors, so we don't need to
        return redeemFresh(msg.sender, redeemTokens, 0);
    }

    /**
     * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset
     * @dev Accrues interest whether or not the operation succeeds, unless reverted
     * @param redeemAmount The amount of underlying to redeem
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function redeemUnderlying(uint redeemAmount) external nonReentrant returns (uint) {
        uint err = accrueInterest();
        if (err != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but we still want to log the fact that an attempted redeem failed
            return fail(Error(err), FailureInfo.ACCRUE_INTEREST_FAILED);
        }
        // Keep the flywheel moving
        accrueDFL();
        distributeSupplierDFL(msg.sender, false);

        // redeemFresh emits redeem-specific logs on errors, so we don't need to
        return redeemFresh(msg.sender, 0, redeemAmount);
    }

    struct RedeemLocalVars {
        Error err;
        MathError mathErr;
        uint exchangeRateMantissa;
        uint redeemTokens;
        uint redeemAmount;
        uint totalSupplyNew;
        uint accountTokensNew;
    }

    /**
     * @notice User redeems cTokens in exchange for the underlying asset
     * @dev Assumes interest has already been accrued up to the current block
     * @param redeemer The address of the account which is redeeming the tokens
     * @param redeemTokensIn The number of cTokens to redeem into underlying (only one of redeemTokensIn or redeemAmountIn may be non-zero)
     * @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens (only one of redeemTokensIn or redeemAmountIn may be non-zero)
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function redeemFresh(address redeemer, uint redeemTokensIn, uint redeemAmountIn) internal returns (uint) {
        require(redeemTokensIn == 0 || redeemAmountIn == 0, "one of redeemTokensIn or redeemAmountIn must be zero");

        RedeemLocalVars memory vars;

        /* exchangeRate = invoke Exchange Rate Stored() */
        (vars.mathErr, vars.exchangeRateMantissa) = exchangeRateStoredInternal();
        if (vars.mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, uint(vars.mathErr));
        }

        /* If redeemTokensIn > 0: */
        if (redeemTokensIn > 0) {
            /*
             * We calculate the exchange rate and the amount of underlying to be redeemed:
             *  redeemTokens = redeemTokensIn
             *  redeemAmount = redeemTokensIn x exchangeRateCurrent
             */
            vars.redeemTokens = redeemTokensIn;

            (vars.mathErr, vars.redeemAmount) = mulScalarTruncate(Exp({mantissa: vars.exchangeRateMantissa}), redeemTokensIn);
            if (vars.mathErr != MathError.NO_ERROR) {
                return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, uint(vars.mathErr));
            }
        } else {
            /*
             * We get the current exchange rate and calculate the amount to be redeemed:
             *  redeemTokens = redeemAmountIn / exchangeRate
             *  redeemAmount = redeemAmountIn
             */

            (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate(redeemAmountIn, Exp({mantissa: vars.exchangeRateMantissa}));
            if (vars.mathErr != MathError.NO_ERROR) {
                return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, uint(vars.mathErr));
            }

            vars.redeemAmount = redeemAmountIn;
        }

        /*
         * We calculate the new total supply and redeemer balance, checking for underflow:
         *  totalSupplyNew = totalSupply - redeemTokens
         *  accountTokensNew = accountTokens[redeemer] - redeemTokens
         */
        (vars.mathErr, vars.totalSupplyNew) = subUInt(totalSupply, vars.redeemTokens);
        if (vars.mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, uint(vars.mathErr));
        }

        (vars.mathErr, vars.accountTokensNew) = subUInt(accountTokens[redeemer], vars.redeemTokens);
        if (vars.mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, uint(vars.mathErr));
        }

        /* Fail gracefully if protocol has insufficient cash */
        if (getCashPrior() < vars.redeemAmount) {
            return fail(Error.TOKEN_INSUFFICIENT_CASH, FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE);
        }

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)
        doTransferOut(eFILAddress, redeemer, vars.redeemAmount);

        /* We write previously calculated values into storage */
        totalSupply = vars.totalSupplyNew;
        accountTokens[redeemer] = vars.accountTokensNew;

        /* We emit a Transfer event, and a Redeem event */
        emit Transfer(redeemer, address(this), vars.redeemTokens);
        emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens);
        return uint(Error.NO_ERROR);
    }

    /**
      * @notice Sender borrows assets from the protocol to their own address
      * @param borrowAmount The amount of the underlying asset to borrow
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function borrow(uint borrowAmount) external nonReentrant returns (uint) {
        uint err = accrueInterest();
        if (err != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed
            return fail(Error(err), FailureInfo.ACCRUE_INTEREST_FAILED);
        }
        // Keep the flywheel moving
        accrueDFL();

        // borrowFresh emits borrow-specific logs on errors, so we don't need to
        return borrowFresh(msg.sender, borrowAmount);
    }

    struct BorrowLocalVars {
        MathError mathErr;
        uint actualBorrowAmount;
        uint accountBorrows;
        uint accountBorrowsNew;
        uint totalBorrowsNew;
    }

    /**
      * @notice Users borrow assets from the protocol to their own address
      * @param borrowAmount The amount of the underlying asset to borrow
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function borrowFresh(address borrower, uint borrowAmount) internal returns (uint) {
        if (!borrowAllowed) {
            return fail(Error.REJECTION, FailureInfo.BORROW_REJECTION);
        }

        BorrowLocalVars memory vars;

        (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(borrower);
        if (vars.mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, uint(vars.mathErr));
        }

        if (borrowAmount == uint(-1)) {
            vars.actualBorrowAmount = accountCollaterals[borrower] > vars.accountBorrows ? accountCollaterals[borrower] - vars.accountBorrows : 0;
        } else {
            vars.actualBorrowAmount = borrowAmount;
        }

        /* Fail gracefully if protocol has insufficient underlying cash */
        if (getCashPrior() < vars.actualBorrowAmount) {
            return fail(Error.TOKEN_INSUFFICIENT_CASH, FailureInfo.BORROW_CASH_NOT_AVAILABLE);
        }

        /*
         * We calculate the new borrower and total borrow balances, failing on overflow:
         *  accountBorrowsNew = accountBorrows + actualBorrowAmount
         *  totalBorrowsNew = totalBorrows + actualBorrowAmount
         */
        (vars.mathErr, vars.accountBorrowsNew) = addUInt(vars.accountBorrows, vars.actualBorrowAmount);
        if (vars.mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, uint(vars.mathErr));
        }

        // Check collaterals
        if (accountCollaterals[borrower] < vars.accountBorrowsNew) {
            return fail(Error.INSUFFICIENT_COLLATERAL, FailureInfo.BORROW_INSUFFICIENT_COLLATERAL);
        }

        (vars.mathErr, vars.totalBorrowsNew) = addUInt(totalBorrows, vars.actualBorrowAmount);
        if (vars.mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, uint(vars.mathErr));
        }

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)
        doTransferOut(eFILAddress, borrower, vars.actualBorrowAmount);

        /* We write the previously calculated values into storage */
        accountBorrows[borrower].principal = vars.accountBorrowsNew;
        accountBorrows[borrower].interestIndex = borrowIndex;
        totalBorrows = vars.totalBorrowsNew;

        /* We emit a Borrow event */
        emit Borrow(borrower, vars.actualBorrowAmount, vars.accountBorrowsNew, vars.totalBorrowsNew);
        return uint(Error.NO_ERROR);
    }

    /**
     * @notice Sender repays their own borrow
     * @param repayAmount The amount to repay
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function repayBorrow(uint repayAmount) external nonReentrant returns (uint) {
        uint err = accrueInterest();
        if (err != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed
            return fail(Error(err), FailureInfo.ACCRUE_INTEREST_FAILED);
        }
        // Keep the flywheel moving
        accrueDFL();

        // repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to
        (err,) = repayBorrowFresh(msg.sender, msg.sender, repayAmount);
        return err;
    }

    /**
     * @notice Sender repays a borrow belonging to borrower
     * @param borrower the account with the debt being payed off
     * @param repayAmount The amount to repay
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function repayBorrowBehalf(address borrower, uint repayAmount) external nonReentrant returns (uint) {
        uint err = accrueInterest();
        if (err != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed
            return fail(Error(err), FailureInfo.ACCRUE_INTEREST_FAILED);
        }
        // Keep the flywheel moving
        accrueDFL();

        // repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to
        (err,) = repayBorrowFresh(msg.sender, borrower, repayAmount);
        return err;
    }

    struct RepayBorrowLocalVars {
        Error err;
        MathError mathErr;
        uint repayAmount;
        uint borrowerIndex;
        uint accountBorrows;
        uint accountBorrowsNew;
        uint totalBorrowsNew;
        uint actualRepayAmount;
    }

    /**
     * @notice Borrows are repaid by another user (possibly the borrower).
     * @param payer the account paying off the borrow
     * @param borrower the account with the debt being payed off
     * @param repayAmount the amount of undelrying tokens being returned
     * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount.
     */
    function repayBorrowFresh(address payer, address borrower, uint repayAmount) internal returns (uint, uint) {
        RepayBorrowLocalVars memory vars;

        /* We remember the original borrowerIndex for verification purposes */
        vars.borrowerIndex = accountBorrows[borrower].interestIndex;

        /* We fetch the amount the borrower owes, with accumulated interest */
        (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(borrower);
        if (vars.mathErr != MathError.NO_ERROR) {
            return (failOpaque(Error.MATH_ERROR, FailureInfo.REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, uint(vars.mathErr)), 0);
        }

        /* If repayAmount == -1, repayAmount = accountBorrows */
        if (repayAmount == uint(-1)) {
            vars.repayAmount = vars.accountBorrows;
        } else {
            vars.repayAmount = repayAmount;
        }

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)
        vars.actualRepayAmount = doTransferIn(eFILAddress, payer, vars.repayAmount);

        /*
         * We calculate the new borrower and total borrow balances, failing on underflow:
         *  accountBorrowsNew = accountBorrows - actualRepayAmount
         *  totalBorrowsNew = totalBorrows - actualRepayAmount
         */
        (vars.mathErr, vars.accountBorrowsNew) = subUInt(vars.accountBorrows, vars.actualRepayAmount);
        require(vars.mathErr == MathError.NO_ERROR, "REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED");

        (vars.mathErr, vars.totalBorrowsNew) = subUInt(totalBorrows, vars.actualRepayAmount);
        require(vars.mathErr == MathError.NO_ERROR, "REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED");

        /* We write the previously calculated values into storage */
        accountBorrows[borrower].principal = vars.accountBorrowsNew;
        accountBorrows[borrower].interestIndex = borrowIndex;
        totalBorrows = vars.totalBorrowsNew;

        /* We emit a RepayBorrow event */
        emit RepayBorrow(payer, borrower, vars.actualRepayAmount, vars.accountBorrowsNew, vars.totalBorrowsNew);
        return (uint(Error.NO_ERROR), vars.actualRepayAmount);
    }

    /**
     * redeem collaterals
     * @dev Accrues interest whether or not the operation succeeds, unless reverted
     * @param redeemAmount The number of collateral to redeem into underlying
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function redeemCollateral(uint redeemAmount) external nonReentrant returns (uint) {
        uint err = accrueInterest();
        if (err != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but we still want to log the fact that an attempted redeem failed
            return fail(Error(err), FailureInfo.ACCRUE_INTEREST_FAILED);
        }
        // Keep the flywheel moving
        accrueDFL();

        // redeemCollateralFresh emits redeem-collaterals-specific logs on errors, so we don't need to
        return redeemCollateralFresh(msg.sender, redeemAmount);
    }

    struct RedeemCollateralLocalVars {
        Error err;
        MathError mathErr;
        uint redeemAmount;
        uint accountBorrows;
        uint accountCollateralsOld;
        uint accountCollateralsNew;
        uint totalCollateralsNew;
    }

    /**
     * redeem collaterals
     * @dev Assumes interest has already been accrued up to the current block
     * @param redeemer The address of the account which is redeeming
     * @param redeemAmount The number of collaterals to redeem into underlying
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function redeemCollateralFresh(address redeemer, uint redeemAmount) internal returns (uint) {
        RedeemCollateralLocalVars memory vars;

        (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(redeemer);
        if (vars.mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_COLLATERAL_ACCUMULATED_BORROW_CALCULATION_FAILED, uint(vars.mathErr));
        }

        vars.accountCollateralsOld = accountCollaterals[redeemer];
        if (redeemAmount == uint(-1)) {
            vars.redeemAmount = vars.accountCollateralsOld >= vars.accountBorrows ? vars.accountCollateralsOld - vars.accountBorrows : 0;
        } else {
            vars.redeemAmount = redeemAmount;
        }

        (vars.mathErr, vars.accountCollateralsNew) = subUInt(accountCollaterals[redeemer], vars.redeemAmount);
        if (vars.mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_COLLATERAL_NEW_ACCOUNT_COLLATERAL_CALCULATION_FAILED, uint(vars.mathErr));
        }

        // Check collateral
        if (vars.accountCollateralsNew < vars.accountBorrows) {
            return fail(Error.INSUFFICIENT_COLLATERAL, FailureInfo.REDEEM_COLLATERAL_INSUFFICIENT_COLLATERAL);
        }

        (vars.mathErr, vars.totalCollateralsNew) = subUInt(totalCollaterals, vars.redeemAmount);
        require(vars.mathErr == MathError.NO_ERROR, "REDEEM_COLLATERALS_NEW_TOTAL_COLLATERALS_CALCULATION_FAILED");

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)
        doTransferOut(mFILAddress, redeemer, vars.redeemAmount);

        /* We write previously calculated values into storage */
        totalCollaterals = vars.totalCollateralsNew;
        accountCollaterals[redeemer] = vars.accountCollateralsNew;

        /* We emit a RedeemCollateral event */
        emit RedeemCollateral(redeemer, vars.redeemAmount);
        return uint(Error.NO_ERROR);
    }

    /**
     * liquidate borrow
     * @dev Accrues interest whether or not the operation succeeds, unless reverted
     * @param borrower The borrower's address
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function liquidateBorrow(address borrower) external nonReentrant returns (uint) {
        uint err = accrueInterest();
        if (err != uint(Error.NO_ERROR)) {
            return fail(Error(err), FailureInfo.ACCRUE_INTEREST_FAILED);
        }
        // Keep the flywheel moving
        accrueDFL();

        return liquidateBorrowFresh(msg.sender, borrower);
    }

    struct LiquidateBorrowLocalVars {
        Error err;
        MathError mathErr;
        uint accountBorrows;
        uint accountCollaterals;
        uint collateralRate;
        uint totalBorrowsNew;
    }

    /**
     * liquidate borrow
     * @dev Assumes interest has already been accrued up to the current block
     * @param liquidator The liquidator's address
     * @param borrower The borrower's address
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function liquidateBorrowFresh(address liquidator, address borrower) internal returns (uint) {
        // make things simple
        if (accountCollaterals[liquidator] != 0 || accountTokens[liquidator] != 0) {
            return fail(Error.REJECTION, FailureInfo.LIQUIDATE_BORROW_REJECTION);
        }

        LiquidateBorrowLocalVars memory vars;

        (vars.mathErr, vars.collateralRate, vars.accountBorrows, vars.accountCollaterals) = collateralRateInternal(borrower);
        if (vars.mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.LIQUIDATE_BORROW_COLLATERAL_RATE_CALCULATION_FAILED, uint(vars.mathErr));
        }

        if (vars.collateralRate < liquidateFactorMantissa) {
            return fail(Error.REJECTION, FailureInfo.LIQUIDATE_BORROW_NOT_SATISFIED);
        }

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)
        require(doTransferIn(eFILAddress, liquidator, vars.accountBorrows) == vars.accountBorrows, "LIQUIDATE_BORROW_TRANSFER_IN_FAILED");

        (vars.mathErr, vars.totalBorrowsNew) = subUInt(totalBorrows, vars.accountBorrows);
        require(vars.mathErr == MathError.NO_ERROR, "LIQUIDATE_BORROW_NEW_TOTAL_BORROWS_CALCULATION_FAILED");

        /* We write the previously calculated values into storage */
        accountBorrows[borrower].principal = 0;
        accountBorrows[borrower].interestIndex = borrowIndex;
        totalBorrows = vars.totalBorrowsNew;

        accountCollaterals[borrower] = 0;
        accountCollaterals[liquidator] = vars.accountCollaterals;

        /* We emit a RepayBorrow event */
        emit LiquidateBorrow(liquidator, borrower, vars.accountBorrows, vars.accountCollaterals);
        return uint(Error.NO_ERROR);
    }

    /*** DFL ***/

    // accrue DFL
    function accrueDFL() internal {
        uint startBlockNumber = dflAccrualBlockNumber;
        uint endBlockNumber = startBlockNumber;
        uint currentBlockNumber = getBlockNumber();
        while (endBlockNumber < currentBlockNumber) {
            if (currentSpeed < minSpeed) {
                break;
            }

            startBlockNumber = endBlockNumber;
            if (currentBlockNumber < nextHalveBlockNumber) {
                endBlockNumber = currentBlockNumber;
            } else {
                endBlockNumber = nextHalveBlockNumber;
            }

            distributeAndUpdateSupplyIndex(startBlockNumber, endBlockNumber);

            if (endBlockNumber == nextHalveBlockNumber) {
                nextHalveBlockNumber = nextHalveBlockNumber + halvePeriod;
                currentSpeed = currentSpeed / 2;
            }
        }
        // update dflAccrualBlockNumber
        dflAccrualBlockNumber = currentBlockNumber;
    }

    // Accrue DFL for suppliers by updating the supply index
    function distributeAndUpdateSupplyIndex(uint startBlockNumber, uint endBlockNumber) internal {
        uint deltaBlocks = sub_(endBlockNumber, startBlockNumber);
        if (deltaBlocks > 0) {
            uint deltaDFLs = mul_(deltaBlocks, currentSpeed);
            dflToken.mint(address(this), deltaDFLs);

            uint uniswapPart = div_(mul_(uniswapPercentage, deltaDFLs), mantissaOne);
            uint minerLeaguePart = div_(mul_(minerLeaguePercentage, deltaDFLs), mantissaOne);
            uint operatorPart = div_(mul_(operatorPercentage, deltaDFLs), mantissaOne);
            uint technicalPart = div_(mul_(technicalPercentage, deltaDFLs), mantissaOne);
            uint supplyPart = sub_(sub_(sub_(sub_(deltaDFLs, uniswapPart), minerLeaguePart), operatorPart), technicalPart);

            // accrue, not transfer directly
            dflAccrued[uniswapAddress] = add_(dflAccrued[uniswapAddress], uniswapPart);
            dflAccrued[minerLeagueAddress] = add_(dflAccrued[minerLeagueAddress], minerLeaguePart);
            dflAccrued[operatorAddress] = add_(dflAccrued[operatorAddress], operatorPart);
            dflAccrued[technicalAddress] = add_(dflAccrued[technicalAddress], technicalPart);

            if (totalSupply > 0) {
                Double memory ratio = fraction(supplyPart, totalSupply);
                Double memory index = add_(Double({mantissa: dflSupplyIndex}), ratio);
                dflSupplyIndex = index.mantissa;
            } else {
                dflAccrued[undistributedAddress] = add_(dflAccrued[undistributedAddress], supplyPart);
            }

            emit AccrueDFL(uniswapPart, minerLeaguePart, operatorPart, technicalPart, supplyPart, dflSupplyIndex);
        }
    }

    // Calculate DFL accrued by a supplier and possibly transfer it to them
    function distributeSupplierDFL(address supplier, bool distributeAll) internal {
        /* Verify accrued block number equals current block number */
        require(dflAccrualBlockNumber == getBlockNumber(), "FRESHNESS_CHECK");
        uint supplierAccrued = accruedDFLStoredInternal(supplier);

        dflAccrued[supplier] = transferDFL(supplier, supplierAccrued, distributeAll ? 0 : dflClaimThreshold);
        dflSupplierIndex[supplier] = dflSupplyIndex;
        emit DistributedDFL(supplier, supplierAccrued - dflAccrued[supplier]);
    }

    // Transfer DFL to the user, if they are above the threshold
    function transferDFL(address user, uint userAccrued, uint threshold) internal returns (uint) {
        if (userAccrued >= threshold && userAccrued > 0) {
            uint dflRemaining = dflToken.balanceOf(address(this));
            if (userAccrued <= dflRemaining) {
                dflToken.transfer(user, userAccrued);
                return 0;
            }
        }
        return userAccrued;
    }

    function claimDFL() public nonReentrant {
        accrueDFL();
        distributeSupplierDFL(msg.sender, true);
    }

    // Claim all DFL accrued by the suppliers
    function claimDFL(address[] memory holders) public nonReentrant {
        accrueDFL();
        for (uint i = 0; i < holders.length; i++) {
            distributeSupplierDFL(holders[i], true);
        }
    }

    // Reduce reserves, only by staking contract
    function claimReserves() public nonReentrant {
        require(accrueInterest() == uint(Error.NO_ERROR), "accrue interest failed");

        uint cash = getCashPrior();
        uint actualAmount = cash > totalReserves ? totalReserves : cash;

        doTransferOut(eFILAddress, reservesOwner, actualAmount);
        totalReserves = sub_(totalReserves, actualAmount);

        emit ReservesReduced(reservesOwner, actualAmount);
    }

    /*** Admin Functions ***/

    /**
      * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.
      * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.
      * @param newPendingAdmin New pending admin.
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _setPendingAdmin(address newPendingAdmin) external returns (uint) {
        // Check caller = admin
        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.ADMIN_CHECK);
        }

        // Save current value, if any, for inclusion in log
        address oldPendingAdmin = pendingAdmin;

        // Store pendingAdmin with value newPendingAdmin
        pendingAdmin = newPendingAdmin;

        // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin)
        emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin);

        return uint(Error.NO_ERROR);
    }

    /**
      * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin
      * @dev Admin function for pending admin to accept role and update admin
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _acceptAdmin() external returns (uint) {
        // Check caller is pendingAdmin and pendingAdmin ≠ address(0)
        if (msg.sender != pendingAdmin || msg.sender == address(0)) {
            return fail(Error.UNAUTHORIZED, FailureInfo.ADMIN_CHECK);
        }

        // Save current values for inclusion in log
        address oldAdmin = admin;
        address oldPendingAdmin = pendingAdmin;

        // Store admin with value pendingAdmin
        admin = pendingAdmin;

        // Clear the pending value
        pendingAdmin = address(0);

        emit NewAdmin(oldAdmin, admin);
        emit NewPendingAdmin(oldPendingAdmin, pendingAdmin);

        return uint(Error.NO_ERROR);
    }

    /**
      * @dev Change mintAllowed
      * @param mintAllowed_ New value.
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _setMintAllowed(bool mintAllowed_) external returns (uint) {
        // Check caller = admin
        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.ADMIN_CHECK);
        }

        if (mintAllowed != mintAllowed_) {
            mintAllowed = mintAllowed_;
            emit MintAllowed(mintAllowed_);
        }

        return uint(Error.NO_ERROR);
    }

    /**
      * @dev Change borrowAllowed
      * @param borrowAllowed_ New value.
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _setBorrowAllowed(bool borrowAllowed_) external returns (uint) {
        // Check caller = admin
        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.ADMIN_CHECK);
        }

        if (borrowAllowed != borrowAllowed_) {
            borrowAllowed = borrowAllowed_;
            emit BorrowAllowed(borrowAllowed_);
        }

        return uint(Error.NO_ERROR);
    }

    /**
      * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh
      * @dev Admin function to accrue interest and set a new reserve factor
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _setReserveFactor(uint newReserveFactorMantissa) external nonReentrant returns (uint) {
        uint error = accrueInterest();
        if (error != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reserve factor change failed.
            return fail(Error(error), FailureInfo.ACCRUE_INTEREST_FAILED);
        }
        // _setReserveFactorFresh emits reserve-factor-specific logs on errors, so we don't need to.
        return _setReserveFactorFresh(newReserveFactorMantissa);
    }

    /**
      * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual)
      * @dev Admin function to set a new reserve factor
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _setReserveFactorFresh(uint newReserveFactorMantissa) internal returns (uint) {
        // Check caller is admin
        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.ADMIN_CHECK);
        }

        // Check newReserveFactor ≤ maxReserveFactor
        if (newReserveFactorMantissa > reserveFactorMaxMantissa) {
            return fail(Error.BAD_INPUT, FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK);
        }

        uint oldReserveFactorMantissa = reserveFactorMantissa;
        reserveFactorMantissa = newReserveFactorMantissa;

        emit NewReserveFactor(oldReserveFactorMantissa, newReserveFactorMantissa);

        return uint(Error.NO_ERROR);
    }

    /**
      * @notice accrues interest and sets a new liquidate factor for the protocol using _setLiquidateFactorFresh
      * @dev Admin function to accrue interest and set a new liquidate factor
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _setLiquidateFactor(uint newLiquidateFactorMantissa) external nonReentrant returns (uint) {
        uint error = accrueInterest();
        if (error != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted liquidate factor change failed.
            return fail(Error(error), FailureInfo.ACCRUE_INTEREST_FAILED);
        }
        return _setLiquidateFactorFresh(newLiquidateFactorMantissa);
    }

    function _setLiquidateFactorFresh(uint newLiquidateFactorMantissa) internal returns (uint) {
        // Check caller is admin
        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.ADMIN_CHECK);
        }

        if (newLiquidateFactorMantissa < liquidateFactorMinMantissa) {
            return fail(Error.BAD_INPUT, FailureInfo.SET_LIQUIDATE_FACTOR_BOUNDS_CHECK);
        }

        uint oldLiquidateFactorMantissa = liquidateFactorMantissa;
        liquidateFactorMantissa = newLiquidateFactorMantissa;

        emit NewLiquidateFactor(oldLiquidateFactorMantissa, newLiquidateFactorMantissa);

        return uint(Error.NO_ERROR);
    }

    /**
     * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh
     * @dev Admin function to accrue interest and update the interest rate model
     * @param newInterestRateModel the new interest rate model to use
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function _setInterestRateModel(InterestRateModel newInterestRateModel) public nonReentrant returns (uint) {
        uint error = accrueInterest();
        if (error != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted change of interest rate model failed
            return fail(Error(error), FailureInfo.ACCRUE_INTEREST_FAILED);
        }
        // _setInterestRateModelFresh emits interest-rate-model-update-specific logs on errors, so we don't need to.
        return _setInterestRateModelFresh(newInterestRateModel);
    }

    /**
     * @notice updates the interest rate model (*requires fresh interest accrual)
     * @dev Admin function to update the interest rate model
     * @param newInterestRateModel the new interest rate model to use
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) internal returns (uint) {
        // Used to store old model for use in the event that is emitted on success
        InterestRateModel oldInterestRateModel;

        // Check caller is admin
        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.ADMIN_CHECK);
        }

        // Track the current interest rate model
        oldInterestRateModel = interestRateModel;

        // Ensure invoke newInterestRateModel.isInterestRateModel() returns true
        require(newInterestRateModel.isInterestRateModel(), "marker method returned false");

        // Set the interest rate model to newInterestRateModel
        interestRateModel = newInterestRateModel;

        // Emit NewInterestRateModel(oldInterestRateModel, newInterestRateModel)
        emit NewInterestRateModel(oldInterestRateModel, newInterestRateModel);

        return uint(Error.NO_ERROR);
    }

    /**
      * @dev Change reservesOwner
      * @param newReservesOwner New value.
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _setReservesOwner(address newReservesOwner) public returns (uint) {
        claimReserves();
        return _setReservesOwnerFresh(newReservesOwner);
    }

    function _setReservesOwnerFresh(address newReservesOwner) internal returns (uint) {
        // Check caller = admin
        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.ADMIN_CHECK);
        }

        address oldReservesOwner = reservesOwner;
        reservesOwner = newReservesOwner;

        emit ReservesOwnerChanged(oldReservesOwner, newReservesOwner);
        return uint(Error.NO_ERROR);
    }

    /**
      * @dev Change minerLeagueAddress
      * @param newMinerLeagueAddress New value.
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _setMinerLeagueAddress(address newMinerLeagueAddress) external nonReentrant returns (uint) {
        // accrue
        accrueDFL();
        return _setMinerLeagueAddressFresh(newMinerLeagueAddress);
    }

    function _setMinerLeagueAddressFresh(address newMinerLeagueAddress) internal returns (uint) {
        if (msg.sender != minerLeagueAddress) {
            return fail(Error.UNAUTHORIZED, FailureInfo.PARTICIPANT_CHECK);
        }

        // transfers accrued
        if (dflAccrued[minerLeagueAddress] != 0) {
            doTransferOut(address(dflToken), minerLeagueAddress, dflAccrued[minerLeagueAddress]);
            delete dflAccrued[minerLeagueAddress];
        }

        address oldMinerLeagueAddress = minerLeagueAddress;
        minerLeagueAddress = newMinerLeagueAddress;

        emit MinerLeagueAddressChanged(oldMinerLeagueAddress, newMinerLeagueAddress);
        return uint(Error.NO_ERROR);
    }

    /**
      * @dev Change operatorAddress
      * @param newOperatorAddress New value.
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _setOperatorAddress(address newOperatorAddress) external nonReentrant returns (uint) {
        // accrue
        accrueDFL();
        return _setOperatorAddressFresh(newOperatorAddress);
    }

    function _setOperatorAddressFresh(address newOperatorAddress) internal returns (uint) {
        if (msg.sender != operatorAddress) {
            return fail(Error.UNAUTHORIZED, FailureInfo.PARTICIPANT_CHECK);
        }

        // transfers accrued
        if (dflAccrued[operatorAddress] != 0) {
            doTransferOut(address(dflToken), operatorAddress, dflAccrued[operatorAddress]);
            delete dflAccrued[operatorAddress];
        }

        address oldOperatorAddress = operatorAddress;
        operatorAddress = newOperatorAddress;

        emit OperatorAddressChanged(oldOperatorAddress, newOperatorAddress);
        return uint(Error.NO_ERROR);
    }

    /**
      * @dev Change technicalAddress
      * @param newTechnicalAddress New value.
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _setTechnicalAddress(address newTechnicalAddress) external nonReentrant returns (uint) {
        // accrue
        accrueDFL();
        return _setTechnicalAddressFresh(newTechnicalAddress);
    }

    function _setTechnicalAddressFresh(address newTechnicalAddress) internal returns (uint) {
        if (msg.sender != technicalAddress) {
            return fail(Error.UNAUTHORIZED, FailureInfo.PARTICIPANT_CHECK);
        }

        // transfers accrued
        if (dflAccrued[technicalAddress] != 0) {
            doTransferOut(address(dflToken), technicalAddress, dflAccrued[technicalAddress]);
            delete dflAccrued[technicalAddress];
        }

        address oldTechnicalAddress = technicalAddress;
        technicalAddress = newTechnicalAddress;

        emit TechnicalAddressChanged(oldTechnicalAddress, newTechnicalAddress);
        return uint(Error.NO_ERROR);
    }

    /**
      * @dev Change uniswapAddress
      * @param newUniswapAddress New value.
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _setUniswapAddress(address newUniswapAddress) external nonReentrant returns (uint) {
        // accrue
        accrueDFL();
        return _setUniswapAddressFresh(newUniswapAddress);
    }

    function _setUniswapAddressFresh(address newUniswapAddress) internal returns (uint) {
        // Check caller = admin
        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.ADMIN_CHECK);
        }

        // transfers accrued
        if (dflAccrued[uniswapAddress] != 0) {
            doTransferOut(address(dflToken), uniswapAddress, dflAccrued[uniswapAddress]);
            delete dflAccrued[uniswapAddress];
        }

        address oldUniswapAddress = uniswapAddress;
        uniswapAddress = newUniswapAddress;

        emit UniswapAddressChanged(oldUniswapAddress, newUniswapAddress);
        return uint(Error.NO_ERROR);
    }

    /**
      * @dev Change undistributedAddress
      * @param newUndistributedAddress New value.
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _setUndistributedAddress(address newUndistributedAddress) external nonReentrant returns (uint) {
        // accrue
        accrueDFL();
        return _setUndistributedAddressFresh(newUndistributedAddress);
    }

    function _setUndistributedAddressFresh(address newUndistributedAddress) internal returns (uint) {
        // Check caller = admin
        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.ADMIN_CHECK);
        }

        // transfers accrued to old address
        if (dflAccrued[undistributedAddress] != 0) {
            doTransferOut(address(dflToken), undistributedAddress, dflAccrued[undistributedAddress]);
            delete dflAccrued[undistributedAddress];
        }

        address oldUndistributedAddress = undistributedAddress;
        undistributedAddress = newUndistributedAddress;

        emit UndistributedAddressChanged(oldUndistributedAddress, newUndistributedAddress);
        return uint(Error.NO_ERROR);
    }

    /**
      * @dev Change DFL percentages
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _setDFLPercentages(uint uniswapPercentage_,
                                uint minerLeaguePercentage_,
                                uint operatorPercentage_) external nonReentrant returns (uint) {
        accrueDFL();
        return _setDFLPercentagesFresh(uniswapPercentage_, minerLeaguePercentage_, operatorPercentage_);
    }

    function _setDFLPercentagesFresh(uint uniswapPercentage_,
                                     uint minerLeaguePercentage_,
                                     uint operatorPercentage_) internal returns (uint) {
        // Check caller = admin
        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.ADMIN_CHECK);
        }

        uint sumPercentage = add_(add_(add_(uniswapPercentage_, minerLeaguePercentage_), operatorPercentage_), technicalPercentage);
        require(sumPercentage <= mantissaOne, "PERCENTAGE_EXCEEDS");

        uniswapPercentage = uniswapPercentage_;
        minerLeaguePercentage = minerLeaguePercentage_;
        operatorPercentage = operatorPercentage_;

        emit PercentagesChanged(uniswapPercentage_, minerLeaguePercentage_, operatorPercentage_);
        return uint(Error.NO_ERROR);
    }

    /*** Safe Token ***/

    /**
     * @notice Gets balance of this contract in terms of the underlying
     * @dev This excludes the value of the current message, if any
     * @return The quantity of underlying tokens owned by this contract
     */
    function getCashPrior() internal view returns (uint) {
        EIP20Interface token = EIP20Interface(eFILAddress);
        return token.balanceOf(address(this));
    }

    /**
     * @dev Similar to EIP20 transfer, except it handles a False result from `transferFrom` and reverts in that case.
     *      This will revert due to insufficient balance or insufficient allowance.
     *      This function returns the actual amount received,
     *      which may be less than `amount` if there is a fee attached to the transfer.
     *
     *      Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value.
     *            See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
     */
    function doTransferIn(address underlying, address from, uint amount) internal returns (uint) {
        EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying);
        uint balanceBefore = EIP20Interface(underlying).balanceOf(address(this));
        token.transferFrom(from, address(this), amount);

        bool success;
        assembly {
            switch returndatasize()
                case 0 {                       // This is a non-standard ERC-20
                    success := not(0)          // set success to true
                }
                case 32 {                      // This is a compliant ERC-20
                    returndatacopy(0, 0, 32)
                    success := mload(0)        // Set `success = returndata` of external call
                }
                default {                      // This is an excessively non-compliant ERC-20, revert.
                    revert(0, 0)
                }
        }
        require(success, "TOKEN_TRANSFER_IN_FAILED");

        // Calculate the amount that was *actually* transferred
        uint balanceAfter = EIP20Interface(underlying).balanceOf(address(this));
        require(balanceAfter >= balanceBefore, "TOKEN_TRANSFER_IN_OVERFLOW");
        return balanceAfter - balanceBefore;   // underflow already checked above, just subtract
    }

    /**
     * @dev Similar to EIP20 transfer, except it handles a False success from `transfer` and returns an explanatory
     *      error code rather than reverting. If caller has not called checked protocol's balance, this may revert due to
     *      insufficient cash held in this contract. If caller has checked protocol's balance prior to this call, and verified
     *      it is >= amount, this should not revert in normal conditions.
     *
     *      Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value.
     *            See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
     */
    function doTransferOut(address underlying, address to, uint amount) internal {
        EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying);
        token.transfer(to, amount);

        bool success;
        assembly {
            switch returndatasize()
                case 0 {                      // This is a non-standard ERC-20
                    success := not(0)          // set success to true
                }
                case 32 {                     // This is a complaint ERC-20
                    returndatacopy(0, 0, 32)
                    success := mload(0)        // Set `success = returndata` of external call
                }
                default {                     // This is an excessively non-compliant ERC-20, revert.
                    revert(0, 0)
                }
        }
        require(success, "TOKEN_TRANSFER_OUT_FAILED");
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"interestRateModelAddress","type":"address"},{"internalType":"address","name":"eFILAddress_","type":"address"},{"internalType":"address","name":"mFILAddress_","type":"address"},{"internalType":"address","name":"dflAddress_","type":"address"},{"internalType":"address","name":"reservesOwner_","type":"address"},{"internalType":"address","name":"uniswapAddress_","type":"address"},{"internalType":"address","name":"minerLeagueAddress_","type":"address"},{"internalType":"address","name":"operatorAddress_","type":"address"},{"internalType":"address","name":"technicalAddress_","type":"address"},{"internalType":"address","name":"undistributedAddress_","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"uniswapPart","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minerLeaguePart","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"operatorPart","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"technicalPart","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"supplyPart","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"dflSupplyIndex","type":"uint256"}],"name":"AccrueDFL","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"cashPrior","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"interestAccumulated","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"borrowIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"AccrueInterest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"borrowAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accountBorrows","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"Borrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"borrowAllowed","type":"bool"}],"name":"BorrowAllowed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"collateralizer","type":"address"},{"indexed":false,"internalType":"uint256","name":"collateralizeAmount","type":"uint256"}],"name":"Collateralize","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"supplier","type":"address"},{"indexed":false,"internalType":"uint256","name":"supplierDelta","type":"uint256"}],"name":"DistributedDFL","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"error","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"info","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"detail","type":"uint256"}],"name":"Failure","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"liquidator","type":"address"},{"indexed":false,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"accountBorrows","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accountCollaterals","type":"uint256"}],"name":"LiquidateBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAddress","type":"address"},{"indexed":false,"internalType":"address","name":"newAddress","type":"address"}],"name":"MinerLeagueAddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint256","name":"mintAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mintTokens","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"mintAllowed","type":"bool"}],"name":"MintAllowed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"NewAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract InterestRateModel","name":"oldInterestRateModel","type":"address"},{"indexed":false,"internalType":"contract InterestRateModel","name":"newInterestRateModel","type":"address"}],"name":"NewInterestRateModel","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldLiquidateFactorMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newLiquidateFactorMantissa","type":"uint256"}],"name":"NewLiquidateFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldPendingAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newPendingAdmin","type":"address"}],"name":"NewPendingAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldReserveFactorMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newReserveFactorMantissa","type":"uint256"}],"name":"NewReserveFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAddress","type":"address"},{"indexed":false,"internalType":"address","name":"newAddress","type":"address"}],"name":"OperatorAddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"uniswapPercentage","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minerLeaguePercentage","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"operatorPercentage","type":"uint256"}],"name":"PercentagesChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"redeemer","type":"address"},{"indexed":false,"internalType":"uint256","name":"redeemAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"redeemTokens","type":"uint256"}],"name":"Redeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"redeemer","type":"address"},{"indexed":false,"internalType":"uint256","name":"redeemAmount","type":"uint256"}],"name":"RedeemCollateral","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"payer","type":"address"},{"indexed":false,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"repayAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accountBorrows","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"}],"name":"RepayBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAddress","type":"address"},{"indexed":false,"internalType":"address","name":"newAddress","type":"address"}],"name":"ReservesOwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"toTho","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ReservesReduced","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAddress","type":"address"},{"indexed":false,"internalType":"address","name":"newAddress","type":"address"}],"name":"TechnicalAddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAddress","type":"address"},{"indexed":false,"internalType":"address","name":"newAddress","type":"address"}],"name":"UndistributedAddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAddress","type":"address"},{"indexed":false,"internalType":"address","name":"newAddress","type":"address"}],"name":"UniswapAddressChanged","type":"event"},{"constant":false,"inputs":[],"name":"_acceptAdmin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bool","name":"borrowAllowed_","type":"bool"}],"name":"_setBorrowAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"uniswapPercentage_","type":"uint256"},{"internalType":"uint256","name":"minerLeaguePercentage_","type":"uint256"},{"internalType":"uint256","name":"operatorPercentage_","type":"uint256"}],"name":"_setDFLPercentages","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract InterestRateModel","name":"newInterestRateModel","type":"address"}],"name":"_setInterestRateModel","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"newLiquidateFactorMantissa","type":"uint256"}],"name":"_setLiquidateFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newMinerLeagueAddress","type":"address"}],"name":"_setMinerLeagueAddress","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bool","name":"mintAllowed_","type":"bool"}],"name":"_setMintAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newOperatorAddress","type":"address"}],"name":"_setOperatorAddress","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newPendingAdmin","type":"address"}],"name":"_setPendingAdmin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"newReserveFactorMantissa","type":"uint256"}],"name":"_setReserveFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newReservesOwner","type":"address"}],"name":"_setReservesOwner","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newTechnicalAddress","type":"address"}],"name":"_setTechnicalAddress","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newUndistributedAddress","type":"address"}],"name":"_setUndistributedAddress","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newUniswapAddress","type":"address"}],"name":"_setUniswapAddress","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"accrualBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"accrueInterest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"supplier","type":"address"}],"name":"accruedDFLCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"supplier","type":"address"}],"name":"accruedDFLStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOfUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"borrow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"borrowAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"borrowBalanceCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"borrowBalanceStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"borrowIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"borrowRatePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address[]","name":"holders","type":"address[]"}],"name":"claimDFL","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"claimDFL","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"claimReserves","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"borrower","type":"address"}],"name":"collateralRateCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"borrower","type":"address"}],"name":"collateralRateStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"collateralizeAmount","type":"uint256"}],"name":"collateralize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"currentSpeed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"dflAccrualBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"dflAccrued","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"dflSupplierIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"dflSupplyIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"dflToken","outputs":[{"internalType":"contract DFL","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"eFILAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"exchangeRateCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"exchangeRateStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCash","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getCollateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"interestRateModel","outputs":[{"internalType":"contract InterestRateModel","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"borrower","type":"address"}],"name":"liquidateBorrow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"liquidateFactorMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"mFILAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"minerLeagueAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"minerLeaguePercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"mintAmount","type":"uint256"}],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"mintAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"nextHalveBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"operatorAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"operatorPercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"pendingAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"redeemTokens","type":"uint256"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"redeemAmount","type":"uint256"}],"name":"redeemCollateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"redeemAmount","type":"uint256"}],"name":"redeemUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"repayBorrow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"repayBorrowBehalf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"reserveFactorMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"reservesOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"supplyRatePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"technicalAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalBorrows","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"totalBorrowsCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalCollaterals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"undistributedAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"uniswapAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"uniswapPercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]

60806040526804b4abdf5544aa90006015553480156200001e57600080fd5b50604051620065513803806200655183398101604081905262000041916200072b565b6001600055600480546001600160a01b031916331790556200006b6001600160e01b03620002bc16565b600855670de0b6b3a76400006009556000620000986706f05b59d3b200006001600160e01b03620002c016565b90508015620000c45760405162461bcd60e51b8152600401620000bb9062000a83565b60405180910390fd5b620000e0671bc16d674ec800006001600160e01b036200036c16565b90508015620001035760405162461bcd60e51b8152600401620000bb9062000a95565b620001178b6001600160e01b03620003fd16565b905080156200013a5760405162461bcd60e51b8152600401620000bb9062000a4d565b620001676703782dace9d9000067016345785d8a0000666a94d74f4300006001600160e01b036200053016565b905080156200018a5760405162461bcd60e51b8152600401620000bb9062000a5f565b600d8054610100600160ff19909216821761ff0019161790915580546001600160a01b03199081166001600160a01b038d8116919091179092556002805482168c84161790556014805482168b841617905560038054909116918916919091179055620001f6620002bc565b601f8190556ec097ce7bc90715b34b9f10000000006020556208ca0001601655601780546001600160a01b03199081166001600160a01b0389811691909117909255601880548216888416179055601980548216878416179055601a80548216868416179055601b805490911691841691909117905560405130906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90620002a390839062000a2a565b60405180910390a3505050505050505050505062000bde565b4390565b6004546000906001600160a01b03163314620002f557620002ed600160006001600160e01b036200063216565b905062000367565b670de0b6b3a76400008211156200031d57620002ed600260236001600160e01b036200063216565b60078054908390556040517faaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f8214609062000359908390869062000ab9565b60405180910390a160009150505b919050565b6004546000906001600160a01b031633146200039957620002ed600160006001600160e01b036200063216565b670de0b6b3a7640000821015620003c157620002ed600260246001600160e01b036200063216565b60138054908390556040517f389ce8cc8e8243c4ee80c30e284539a8f6fa01c546c8f3f3d76093aace77367e9062000359908390869062000ab9565b60045460009081906001600160a01b0316331462000435576200042c600160006001600160e01b036200063216565b91505062000367565b600660009054906101000a90046001600160a01b03169050826001600160a01b0316632191f92a6040518163ffffffff1660e01b815260040160206040518083038186803b1580156200048757600080fd5b505afa1580156200049c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620004c2919081019062000819565b620004e15760405162461bcd60e51b8152600401620000bb9062000a71565b600680546001600160a01b0319166001600160a01b0385161790556040517feb5cc99f497dc2d7106563bb080e06c9b09e3d81a38623ac4d0839575658d1fa9062000359908390869062000a0b565b6004546000906001600160a01b0316331462000565576200055d600160006001600160e01b036200063216565b90506200062b565b6000620005ab620005946200058487876001600160e01b03620006a016565b856001600160e01b03620006a016565b66470de4df8200006001600160e01b03620006a016565b9050670de0b6b3a7640000811115620005d85760405162461bcd60e51b8152600401620000bb9062000aa7565b601c859055601d849055601e8390556040517fcd7c868d12f9f21e0929ab121136064b02723c01ee44a918628a00560d24f66e906200061d9087908790879062000b06565b60405180910390a160009150505b9392505050565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa08360098111156200066257fe5b8360278111156200066f57fe5b6000604051620006829392919062000ad8565b60405180910390a18260098111156200069757fe5b90505b92915050565b6000620006978383604051806040016040528060118152602001706164646974696f6e206f766572666c6f7760781b815250620006de60201b60201c565b60008383018285821015620007085760405162461bcd60e51b8152600401620000bb919062000a3a565b50949350505050565b80516200069a8162000bb9565b80516200069a8162000bd3565b6000806000806000806000806000806101408b8d0312156200074c57600080fd5b60006200075a8d8d62000711565b9a505060206200076d8d828e0162000711565b9950506040620007808d828e0162000711565b9850506060620007938d828e0162000711565b9750506080620007a68d828e0162000711565b96505060a0620007b98d828e0162000711565b95505060c0620007cc8d828e0162000711565b94505060e0620007df8d828e0162000711565b935050610100620007f38d828e0162000711565b925050610120620008078d828e0162000711565b9150509295989b9194979a5092959850565b6000602082840312156200082c57600080fd5b60006200083a84846200071e565b949350505050565b6200084d8162000b62565b82525050565b6200084d8162000b6f565b60006200086b8262000b34565b62000877818562000b38565b93506200088981856020860162000b7c565b620008948162000baf565b9093019392505050565b6000620008ad60228362000b38565b7f73657474696e6720696e7465726573742072617465206d6f64656c206661696c815261195960f21b602082015260400192915050565b6000620008f3601e8362000b38565b7f73657474696e672044464c2070657263656e7461676573206661696c65640000815260200192915050565b60006200092e601c8362000b38565b7f6d61726b6572206d6574686f642072657475726e65642066616c736500000000815260200192915050565b600062000969601d8362000b38565b7f73657474696e67207265736572766520666163746f72206661696c6564000000815260200192915050565b6000620009a4601f8362000b38565b7f73657474696e67206c697175696461746520666163746f72206661696c656400815260200192915050565b6000620009df60128362000b38565b7150455243454e544147455f4558434545445360701b815260200192915050565b6200084d8162000b5f565b6040810162000a1b828562000842565b6200062b602083018462000842565b602081016200069a828462000853565b602080825281016200069781846200085e565b602080825281016200069a816200089e565b602080825281016200069a81620008e4565b602080825281016200069a816200091f565b602080825281016200069a816200095a565b602080825281016200069a8162000995565b602080825281016200069a81620009d0565b6040810162000ac9828562000a00565b6200062b602083018462000a00565b6060810162000ae8828662000a00565b62000af7602083018562000a00565b6200083a604083018462000853565b6060810162000b16828662000a00565b62000b25602083018562000a00565b6200083a604083018462000a00565b5190565b90815260200190565b60006200069a8262000b53565b151590565b6001600160a01b031690565b90565b60006200069a8262000b41565b60006200069a8262000b5f565b60005b8381101562000b9957818101518382015260200162000b7f565b8381111562000ba9576000848401525b50505050565b601f01601f191690565b62000bc48162000b41565b811462000bd057600080fd5b50565b62000bc48162000b4e565b6159638062000bee6000396000f3fe608060405234801561001057600080fd5b506004361061047f5760003560e01c80639262e7a511610257578063bd6d894d11610146578063dd62ed3e116100c3578063f2b3abbd11610087578063f2b3abbd146108c1578063f3fdb15a146108d4578063f851a440146108dc578063f8f9da28146108e4578063fca7820b146108ec5761047f565b8063dd62ed3e14610883578063e524b36c14610896578063e9c714f2146108a9578063ea0ecf53146108b1578063efa5cd2d146108b95761047f565b8063c95de7cf1161010a578063c95de7cf1461083a578063cb34a8051461084d578063ce8b5b5c14610855578063d8e94ea91461085d578063db006a75146108705761047f565b8063bd6d894d146107f1578063be26a714146107f9578063c467201e1461080c578063c477c3ff14610814578063c5ebeaec146108275761047f565b8063a6afed95116101d4578063b078393111610198578063b0783931146107a8578063b2879ee4146107b0578063b71d1a0c146107b8578063b928cb4e146107cb578063bd37b775146107de5761047f565b8063a6afed951461076a578063a9059cbb14610772578063aa5af0fd14610785578063ae9d70b01461078d578063af0a619c146107955761047f565b80639937edfe1161021b5780639937edfe146107165780639b56d6c9146107295780639f06aa081461073c578063a0712d681461074f578063a2e354c8146107625761047f565b80639262e7a5146106c2578063944f3771146106d557806394ecb85b146106e857806395d89b41146106fb57806395dd9193146107035761047f565b806326782247116103735780634b76f669116102f057806370a08231116102b457806370a082311461068257806373acee9814610695578063852a12e31461069d5780638af7cb8f146106b05780638f840ddd146106ba5761047f565b80634b76f669146106425780635bb316931461065757806362a38b2d1461065f578063669f8413146106725780636c540baf1461067a5761047f565b80633b1d21a2116103375780633b1d21a2146106045780633c5873c01461060c5780634025a4a61461061f57806344dbd5ec1461062757806347bd37181461063a5761047f565b806326782247146105c45780632eb0ed25146105cc57806330504b6f146105d4578063313ce567146105dc5780633af9e669146105f15761047f565b806312f0dea711610401578063182df0f5116103c5578063182df0f51461057b578063195c083114610583578063233cf1971461058b57806323b872dd1461059e5780632608f818146105b15761047f565b806312f0dea714610532578063173b99041461054557806317539b1e1461054d57806317bfdfbc1461056057806318160ddd146105735761047f565b80630e752702116104485780630e752702146104ff5780630f98c918146105125780631119f0341461051a5780631256142114610522578063127effb21461052a5761047f565b8062517f62146104845780630520db11146104ad57806306fdde03146104c2578063095ea7b3146104d75780630e2feb05146104f7575b600080fd5b610497610492366004614b36565b6108ff565b6040516104a4919061576a565b60405180910390f35b6104b5610952565b6040516104a49190615466565b6104ca610961565b6040516104a491906155c9565b6104ea6104e5366004614bdb565b610990565b6040516104a49190615592565b6104b5610a25565b61049761050d366004614c9a565b610a34565b610497610ab0565b610497610ab6565b610497610abc565b6104b5610ac2565b610497610540366004614b36565b610ad1565b610497610b3a565b61049761055b366004614c40565b610b40565b61049761056e366004614b36565b610bd2565b610497610c37565b610497610c3d565b6104b5610c81565b610497610599366004614b36565b610c90565b6104ea6105ac366004614b8e565b610ccb565b6104976105bf366004614bdb565b610d11565b6104b5610d85565b610497610d94565b610497610d9a565b6105e4610da0565b6040516104a49190615819565b6104976105ff366004614b36565b610da5565b610497610e26565b61049761061a366004614b36565b610e35565b6104b5610e70565b610497610635366004614b36565b610e7f565b610497610e91565b61064a610e97565b6040516104a491906155a0565b6104ea610ea6565b61049761066d366004614b36565b610eb4565b610497610eef565b610497610ef5565b610497610690366004614b36565b610efb565b610497610f16565b6104976106ab366004614c9a565b610f73565b6106b8610fdd565b005b6104976110cc565b6104976106d0366004614b36565b6110d2565b6104976106e3366004614b36565b61110d565b6104976106f6366004614b36565b611120565b6104ca61115b565b610497610711366004614b36565b61117c565b610497610724366004614b36565b6111ba565b610497610737366004614b36565b6111eb565b61049761074a366004614c9a565b611206565b61049761075d366004614c9a565b611263565b6104976112cb565b6104976112d1565b6104ea610780366004614bdb565b61158c565b6104976115d1565b6104976115d7565b6104976107a3366004614b36565b61166b565b61049761167d565b6104b5611683565b6104976107c6366004614b36565b611692565b6104976107d9366004614b36565b611717565b6104976107ec366004614c9a565b611752565b6104976117af565b610497610807366004614b36565b6117df565b6104ea6117ea565b6106b8610822366004614c0b565b6117f3565b610497610835366004614c9a565b61185e565b610497610848366004614c9a565b6118bb565b6104b561190f565b61049761191e565b61049761086b366004614c40565b611924565b61049761087e366004614c9a565b611993565b610497610891366004614b54565b6119fd565b6104976108a4366004614cd6565b611a28565b610497611a72565b6106b8611b5f565b6104b5611ba1565b6104976108cf366004614c7c565b611bb0565b61064a611c04565b6104b5611c13565b610497611c22565b6104976108fa366004614c9a565b611c62565b600080600061090d84611cb6565b5091935091506000905082600381111561092357fe5b146109495760405162461bcd60e51b81526004016109409061564a565b60405180910390fd5b9150505b919050565b6002546001600160a01b031681565b6040518060400160405280601381526020017210d95c9d1a599a58d85d19481bd98819519253606a1b81525081565b60006001600160a01b0383166109b85760405162461bcd60e51b81526004016109409061568a565b336000818152600f602090815260408083206001600160a01b038816808552925291829020859055905182907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610a1190879061576a565b60405180910390a360019150505b92915050565b6017546001600160a01b031681565b600060026000541415610a595760405162461bcd60e51b81526004016109409061573a565b60026000908155610a686112d1565b90508015610a8e57610a86816009811115610a7f57fe5b6002611d68565b915050610aa6565b610a96611dcf565b610aa1333385611e4e565b509150505b6001600055919050565b601c5481565b60155481565b601d5481565b6019546001600160a01b031681565b600060026000541415610af65760405162461bcd60e51b81526004016109409061573a565b60026000908155610b056112d1565b90508015610b1c57610a86816009811115610a7f57fe5b610b24611dcf565b610b2e3384612080565b60016000559392505050565b60075481565b6004546000906001600160a01b03163314610b6857610b6160016000611d68565b905061094d565b600d5460ff61010090910416151582151514610bca57600d805461ff001916610100841515021790556040517f1717b5ea3deee7263023836cdd49998ac11579e79797df6028a834abad3619a290610bc1908490615592565b60405180910390a15b600092915050565b600060026000541415610bf75760405162461bcd60e51b81526004016109409061573a565b60026000908155610c066112d1565b14610c235760405162461bcd60e51b8152600401610940906155ea565b610c2c8261117c565b600160005592915050565b600c5481565b6000806000610c4a6122aa565b90925090506000826003811115610c5d57fe5b14610c7a5760405162461bcd60e51b81526004016109409061570a565b9150505b90565b601a546001600160a01b031681565b600060026000541415610cb55760405162461bcd60e51b81526004016109409061573a565b6002600055610cc2611dcf565b610c2c8261235f565b600060026000541415610cf05760405162461bcd60e51b81526004016109409061573a565b60026000908155610d033386868661243c565b600160005514949350505050565b600060026000541415610d365760405162461bcd60e51b81526004016109409061573a565b60026000908155610d456112d1565b90508015610d6457610d5c816009811115610a7f57fe5b915050610c2c565b610d6c611dcf565b610d77338585611e4e565b506001600055949350505050565b6005546001600160a01b031681565b60165481565b60115481565b601281565b6000610daf614963565b6040518060200160405280610dc26117af565b90526001600160a01b0384166000908152600e6020526040812054919250908190610dee908490612663565b90925090506000826003811115610e0157fe5b14610e1e5760405162461bcd60e51b81526004016109409061560a565b949350505050565b6000610e306126b7565b905090565b600060026000541415610e5a5760405162461bcd60e51b81526004016109409061573a565b6002600055610e67611dcf565b610c2c8261273a565b601b546001600160a01b031681565b60216020526000908152604090205481565b600a5481565b6014546001600160a01b031681565b600d54610100900460ff1681565b600060026000541415610ed95760405162461bcd60e51b81526004016109409061573a565b6002600055610ee6611dcf565b610c2c82612818565b601f5481565b60085481565b6001600160a01b03166000908152600e602052604090205490565b600060026000541415610f3b5760405162461bcd60e51b81526004016109409061573a565b60026000908155610f4a6112d1565b14610f675760405162461bcd60e51b8152600401610940906155ea565b50600a54600160005590565b600060026000541415610f985760405162461bcd60e51b81526004016109409061573a565b60026000908155610fa76112d1565b90508015610fbe57610a86816009811115610a7f57fe5b610fc6611dcf565b610fd13360006128f5565b610b2e336000856129b8565b600260005414156110005760405162461bcd60e51b81526004016109409061573a565b6002600090815561100f6112d1565b1461102c5760405162461bcd60e51b8152600401610940906155ea565b60006110366126b7565b90506000600b548211611049578161104d565b600b545b60015460035491925061106d916001600160a01b03918216911683612d1b565b611079600b5482612dd0565b600b556003546040517fdcce521f2489558369ff1238d30b9893cc8892398f54cd7acffcce6077349f00916110bb916001600160a01b03909116908490615541565b60405180910390a150506001600055565b600b5481565b6000600260005414156110f75760405162461bcd60e51b81526004016109409061573a565b6002600055611104611dcf565b610c2c82612e0a565b6000611117610fdd565b610a1f82612ee7565b6000600260005414156111455760405162461bcd60e51b81526004016109409061573a565b6002600055611152611dcf565b610c2c82612f5b565b6040518060400160405280600581526020016418d951925360da1b81525081565b600080600061118a84613039565b9092509050600082600381111561119d57fe5b146109495760405162461bcd60e51b81526004016109409061567a565b6000806111c56112d1565b146111e25760405162461bcd60e51b8152600401610940906155ea565b610a1f826108ff565b6001600160a01b031660009081526012602052604090205490565b60006002600054141561122b5760405162461bcd60e51b81526004016109409061573a565b6002600090815561123a6112d1565b9050801561125157610a86816009811115610a7f57fe5b611259611dcf565b610aa133846130ed565b6000600260005414156112885760405162461bcd60e51b81526004016109409061573a565b600260009081556112976112d1565b905080156112ae57610a86816009811115610a7f57fe5b6112b6611dcf565b6112c13360006128f5565b610aa1338461329d565b60135481565b6000806112dc61358e565b600854909150808214156112f557600092505050610c7e565b60006112ff6126b7565b600a54600b546009546006546040516315f2405360e01b81529495509293919290916000916001600160a01b0316906315f2405390611346908890889088906004016157ae565b60206040518083038186803b15801561135e57600080fd5b505afa158015611372573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506113969190810190614cb8565b90506000806113a58989613592565b909250905060008260038111156113b857fe5b146113d55760405162461bcd60e51b8152600401610940906156ca565b6113dd614963565b6000806000806113fb60405180602001604052808a815250876135b5565b9097509450600087600381111561140e57fe5b146114405761142b6004600789600381111561142657fe5b61361d565b9e505050505050505050505050505050610c7e565b61144a858c612663565b9097509350600087600381111561145d57fe5b146114755761142b6004600389600381111561142657fe5b61147f848c61367c565b9097509250600087600381111561149257fe5b146114aa5761142b6004600589600381111561142657fe5b6114c56040518060200160405280600754815250858c6136a2565b909750915060008760038111156114d857fe5b146114f05761142b6004600689600381111561142657fe5b6114fb858a8b6136a2565b9097509050600087600381111561150e57fe5b146115255761142b60048089600381111561142657fe5b60088e90556009819055600a839055600b8290556040517f4dec04e750ca11537cabcd8a9eab06494de08da3735bc8871cd41250e190bc049061156f908e908790859088906157bc565b60405180910390a160009e50505050505050505050505050505090565b6000600260005414156115b15760405162461bcd60e51b81526004016109409061573a565b600260009081556115c43333868661243c565b6001600055149392505050565b60095481565b6006546000906001600160a01b031663b81688166115f36126b7565b600a54600b546007546040518563ffffffff1660e01b815260040161161b94939291906157bc565b60206040518083038186803b15801561163357600080fd5b505afa158015611647573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610e309190810190614cb8565b60226020526000908152604090205481565b601e5481565b6001546001600160a01b031681565b6004546000906001600160a01b031633146116b357610b6160016000611d68565b600580546001600160a01b038481166001600160a01b03198316179092556040519116907fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9906117069083908690615474565b60405180910390a160009392505050565b60006002600054141561173c5760405162461bcd60e51b81526004016109409061573a565b6002600055611749611dcf565b610c2c826136fd565b6000600260005414156117775760405162461bcd60e51b81526004016109409061573a565b600260009081556117866112d1565b9050801561179d57610a86816009811115610a7f57fe5b6117a5611dcf565b610b2e33846137da565b6000806117ba6112d1565b146117d75760405162461bcd60e51b8152600401610940906155ea565b610e30610c3d565b6000610a1f82612e0a565b600d5460ff1681565b600260005414156118165760405162461bcd60e51b81526004016109409061573a565b6002600055611823611dcf565b60005b81518110156118555761184d82828151811061183e57fe5b602002602001015160016128f5565b600101611826565b50506001600055565b6000600260005414156118835760405162461bcd60e51b81526004016109409061573a565b600260009081556118926112d1565b905080156118a957610a86816009811115610a7f57fe5b6118b1611dcf565b610b2e3384613a1b565b6000600260005414156118e05760405162461bcd60e51b81526004016109409061573a565b600260009081556118ef6112d1565b9050801561190657610a86816009811115610a7f57fe5b610b2e83613c9f565b6003546001600160a01b031681565b60205481565b6004546000906001600160a01b0316331461194557610b6160016000611d68565b600d5460ff16151582151514610bca57600d805460ff19168315151790556040517f7c11d7b79bdcc9099218ef3518d3a3202389ab06e9690c937f724618b9e0c46f90610bc1908490615592565b6000600260005414156119b85760405162461bcd60e51b81526004016109409061573a565b600260009081556119c76112d1565b905080156119de57610a86816009811115610a7f57fe5b6119e6611dcf565b6119f13360006128f5565b610b2e338460006129b8565b6001600160a01b039182166000908152600f6020908152604080832093909416825291909152205490565b600060026000541415611a4d5760405162461bcd60e51b81526004016109409061573a565b6002600055611a5a611dcf565b611a65848484613d16565b6001600055949350505050565b6005546000906001600160a01b031633141580611a8d575033155b15611aa557611a9e60016000611d68565b9050610c7e565b60048054600580546001600160a01b038082166001600160a01b03198086168217968790559092169092556040519282169390927ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc92611b09928692911690615474565b60405180910390a16005546040517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a991611b4e9184916001600160a01b031690615474565b60405180910390a160009250505090565b60026000541415611b825760405162461bcd60e51b81526004016109409061573a565b6002600055611b8f611dcf565b611b9a3360016128f5565b6001600055565b6018546001600160a01b031681565b600060026000541415611bd55760405162461bcd60e51b81526004016109409061573a565b60026000908155611be46112d1565b90508015611bfb57610a86816009811115610a7f57fe5b610b2e83613dd0565b6006546001600160a01b031681565b6004546001600160a01b031681565b6006546000906001600160a01b03166315f24053611c3e6126b7565b600a54600b546040518463ffffffff1660e01b815260040161161b939291906157ae565b600060026000541415611c875760405162461bcd60e51b81526004016109409061573a565b60026000908155611c966112d1565b90508015611cad57610a86816009811115610a7f57fe5b610b2e83613eed565b6000806000806000806000611cc9614963565b611cd289613039565b90945092506000846003811115611ce557fe5b14611d00575091955060009450849350839250611d61915050565b6001600160a01b0389166000908152601260205260409020549150611d258383613f64565b90945090506000846003811115611d3857fe5b14611d53575091955060009450849350839250611d61915050565b516000975095509093509150505b9193509193565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0836009811115611d9757fe5b836027811115611da357fe5b6000604051611db493929190615786565b60405180910390a1826009811115611dc857fe5b9392505050565b601f54806000611ddd61358e565b90505b80821015611e4757659a9d359ca0006015541015611dfd57611e47565b819250601654811015611e1257809150611e18565b60165491505b611e228383614014565b601654821415611e4257601680546208ca00019055601554600290046015555b611de0565b601f555050565b600080611e59614976565b6001600160a01b0385166000908152601060205260409020600101546060820152611e8385613039565b6080830181905260208301826003811115611e9a57fe5b6003811115611ea557fe5b9052506000905081602001516003811115611ebc57fe5b14611ee557611ed8600460198360200151600381111561142657fe5b9250600091506120789050565b600019841415611efe5760808101516040820152611f06565b604081018490525b6001546040820151611f23916001600160a01b03169088906142df565b60e082018190526080820151611f3891613592565b60a0830181905260208301826003811115611f4f57fe5b6003811115611f5a57fe5b9052506000905081602001516003811115611f7157fe5b14611f8e5760405162461bcd60e51b8152600401610940906156aa565b611f9e600a548260e00151613592565b60c0830181905260208301826003811115611fb557fe5b6003811115611fc057fe5b9052506000905081602001516003811115611fd757fe5b14611ff45760405162461bcd60e51b8152600401610940906156da565b60a0810180516001600160a01b0387166000908152601060205260409081902091825560095460019092019190915560c0830151600a81905560e0840151925191517f1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a193612065938b938b936154f5565b60405180910390a160e001516000925090505b935093915050565b6001600160a01b0382166000908152601260205260408120541515806120bd57506001600160a01b0383166000908152600e602052604090205415155b156120d5576120ce60036020611d68565b9050610a1f565b6120dd6149bc565b6120e683611cb6565b6060850181905260408501829052608085018390526020850184600381111561210b57fe5b600381111561211657fe5b90525060009250612125915050565b8160200151600381111561213557fe5b1461215957612151600460218360200151600381111561142657fe5b915050610a1f565b601354816080015110156121735761215160036022611d68565b604081015160015461218f906001600160a01b031686836142df565b146121ac5760405162461bcd60e51b8152600401610940906156ba565b6121bc600a548260400151613592565b60a08301819052602083018260038111156121d357fe5b60038111156121de57fe5b90525060009050816020015160038111156121f557fe5b146122125760405162461bcd60e51b81526004016109409061569a565b6001600160a01b03808416600090815260106020908152604080832083815560095460019091015560a0850151600a5560129091528082208290556060840180519388168352918190209290925582820151905191517f08b197b6ae66d18ee6fa20a826a84579a925b9e646a3bf19e96f59ed568c2688926122989288928892906154b7565b60405180910390a16000949350505050565b600c546000908190806122cb57600066071afd498d0000925092505061235b565b60006122d56126b7565b905060006122e1614963565b60006122f284600a54600b546144c2565b93509050600081600381111561230457fe5b146123195795506000945061235b9350505050565b6123238386613f64565b92509050600081600381111561233557fe5b1461234a5795506000945061235b9350505050565b505160009550935061235b92505050565b9091565b6018546000906001600160a01b0316331461237f57610b61600180611d68565b6018546001600160a01b0316600090815260226020526040902054156123e9576014546018546001600160a01b039081166000818152602260205260409020546123cd939290921691612d1b565b6018546001600160a01b03166000908152602260205260408120555b601880546001600160a01b038481166001600160a01b03198316179092556040519116907f892afdc1ab392697c78738b453a93a3b982d3294cee6b445ba02fc0428285c6b906117069083908690615474565b6000826001600160a01b0316846001600160a01b0316148061246557506001600160a01b038316155b1561247d5761247660026025611d68565b9050610e1e565b612485611dcf565b6124908460006128f5565b61249b8360006128f5565b60006001600160a01b0386811690861614156124ba57506000196124e2565b506001600160a01b038085166000908152600f60209081526040808320938916835292905220545b6000806000806124f28588613592565b9094509250600084600381111561250557fe5b146125225761251660046025611d68565b95505050505050610e1e565b6001600160a01b0389166000908152600e60205260409020546125459088613592565b9094509150600084600381111561255857fe5b146125695761251660046026611d68565b6001600160a01b0388166000908152600e602052604090205461258c908861367c565b9094509050600084600381111561259f57fe5b146125b05761251660046027611d68565b6001600160a01b03808a166000908152600e6020526040808220859055918a168152208190556000198514612608576001600160a01b03808a166000908152600f60209081526040808320938e168352929052208390555b876001600160a01b0316896001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8960405161264b919061576a565b60405180910390a35060009998505050505050505050565b6000806000612670614963565b61267a86866135b5565b9092509050600082600381111561268d57fe5b1461269e57509150600090506126b0565b60006126a982614500565b9350935050505b9250929050565b6001546040516370a0823160e01b81526000916001600160a01b03169081906370a08231906126ea903090600401615466565b60206040518083038186803b15801561270257600080fd5b505afa158015612716573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610c7a9190810190614cb8565b6004546000906001600160a01b0316331461275b57610b6160016000611d68565b6017546001600160a01b0316600090815260226020526040902054156127c5576014546017546001600160a01b039081166000818152602260205260409020546127a9939290921691612d1b565b6017546001600160a01b03166000908152602260205260408120555b601780546001600160a01b038481166001600160a01b03198316179092556040519116907f44daa1a06d9d2bc8b2510a777695b4fa7d67cce7b382694da99bec750e00f97d906117069083908690615474565b6019546000906001600160a01b0316331461283857610b61600180611d68565b6019546001600160a01b0316600090815260226020526040902054156128a2576014546019546001600160a01b03908116600081815260226020526040902054612886939290921691612d1b565b6019546001600160a01b03166000908152602260205260408120555b601980546001600160a01b038481166001600160a01b03198316179092556040519116907f6d83175096b0de3f5de98ab86d95234fb1a95bd44b8e97696d5b195b27bf42fd906117069083908690615474565b6128fd61358e565b601f541461291d5760405162461bcd60e51b8152600401610940906156ea565b600061292883612e0a565b905061294a8382846129425767016345785d8a0000612945565b60005b61450f565b6001600160a01b0384166000908152602260208181526040808420948555815460218352938190209390935552905490517fd549ebef7c0522539f1cece1b90b7ee6a2612c8d398a1d7c828398326882d898916129ab918691850390615541565b60405180910390a1505050565b60008215806129c5575081155b6129e15760405162461bcd60e51b81526004016109409061572a565b6129e96149f4565b6129f16122aa565b6040830181905260208301826003811115612a0857fe5b6003811115612a1357fe5b9052506000905081602001516003811115612a2a57fe5b14612a4e57612a46600460158360200151600381111561142657fe5b915050611dc8565b8315612acf576060810184905260408051602081018252908201518152612a759085612663565b6080830181905260208301826003811115612a8c57fe5b6003811115612a9757fe5b9052506000905081602001516003811115612aae57fe5b14612aca57612a46600460138360200151600381111561142657fe5b612b48565b612aeb8360405180602001604052808460400151815250614649565b6060830181905260208301826003811115612b0257fe5b6003811115612b0d57fe5b9052506000905081602001516003811115612b2457fe5b14612b4057612a46600460148360200151600381111561142657fe5b608081018390525b612b58600c548260600151613592565b60a0830181905260208301826003811115612b6f57fe5b6003811115612b7a57fe5b9052506000905081602001516003811115612b9157fe5b14612bad57612a46600460178360200151600381111561142657fe5b6001600160a01b0385166000908152600e60205260409020546060820151612bd59190613592565b60c0830181905260208301826003811115612bec57fe5b6003811115612bf757fe5b9052506000905081602001516003811115612c0e57fe5b14612c2a57612a46600460168360200151600381111561142657fe5b8060800151612c376126b7565b1015612c4957612a4660066018611d68565b6001546080820151612c66916001600160a01b0316908790612d1b565b60a0810151600c5560c08101516001600160a01b0386166000818152600e602052604090819020929092556060830151915130927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91612cc6919061576a565b60405180910390a3608081015160608201516040517fe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a92992612d0892899261555c565b60405180910390a1506000949350505050565b60405163a9059cbb60e01b815283906001600160a01b0382169063a9059cbb90612d4b9086908690600401615541565b600060405180830381600087803b158015612d6557600080fd5b505af1158015612d79573d6000803e3d6000fd5b5050505060003d60008114612d955760208114612d9f57600080fd5b6000199150612dab565b60206000803e60005191505b5080612dc95760405162461bcd60e51b81526004016109409061562a565b5050505050565b6000611dc88383604051806040016040528060158152602001747375627472616374696f6e20756e646572666c6f7760581b815250614660565b6000612e14614963565b60405180602001604052806020548152509050612e2f614963565b5060408051602080820183526001600160a01b038616600090815260219091529190912054808252158015612e645750815115155b15612e7c576ec097ce7bc90715b34b9f100000000081525b612e84614963565b612e8e838361468c565b6001600160a01b0386166000908152600e602052604081205491925090612eb590836146ba565b6001600160a01b03871660009081526022602052604081205491925090612edc90836146e9565b979650505050505050565b6004546000906001600160a01b03163314612f0857610b6160016000611d68565b600380546001600160a01b038481166001600160a01b03198316179092556040519116907f7f91866f1e694ba3479d7897c4168696dffec20ff3dc527eb363a2245177399e906117069083908690615474565b6004546000906001600160a01b03163314612f7c57610b6160016000611d68565b601b546001600160a01b031660009081526022602052604090205415612fe657601454601b546001600160a01b03908116600081815260226020526040902054612fca939290921691612d1b565b601b546001600160a01b03166000908152602260205260408120555b601b80546001600160a01b038481166001600160a01b03198316179092556040519116907f5caaf6ff987f0604398c4e98fd3247ccd4052e166f0eb51308e1001f27aadd4a906117069083908690615474565b6001600160a01b0381166000908152601060205260408120805482918291829182916130705750600094508493506130e892505050565b613080816000015460095461471f565b9094509250600084600381111561309357fe5b146130a85750919350600092506130e8915050565b6130b683826001015461475e565b909450915060008460038111156130c957fe5b146130de5750919350600092506130e8915050565b5060009450925050505b915091565b6001600160a01b0382166000908152600e6020526040812054819015613124576131196003601c611d68565b9150600090506126b0565b61312c614a32565b600254613143906001600160a01b031686866142df565b608082018190526011546131569161367c565b604083018190526020830182600381111561316d57fe5b600381111561317857fe5b905250600090508160200151600381111561318f57fe5b146131ac5760405162461bcd60e51b81526004016109409061574a565b6001600160a01b03851660009081526012602052604090205460808201516131d4919061367c565b60608301819052602083018260038111156131eb57fe5b60038111156131f657fe5b905250600090508160200151600381111561320d57fe5b1461322a5760405162461bcd60e51b81526004016109409061563a565b60408082015160115560608201516001600160a01b0387166000908152601260205282902055608082015190517f94c9d5464fed48366596c718219e5fbd3c0c61c1a21391bf239075e9de5a727a9161328591889190615541565b60405180910390a16080015160009590945092505050565b600d54600090819060ff1615806132cb57506001600160a01b03841660009081526012602052604090205415155b156132dc576131196003600e611d68565b6132e46149f4565b6132ec6122aa565b604083018190526020830182600381111561330357fe5b600381111561330e57fe5b905250600090508160200151600381111561332557fe5b1461334e57613341600460108360200151600381111561142657fe5b9250600091506126b09050565b600154613365906001600160a01b031686866142df565b60c08201819052604080516020810182529083015181526133869190614649565b606083018190526020830182600381111561339d57fe5b60038111156133a857fe5b90525060009050816020015160038111156133bf57fe5b146133dc5760405162461bcd60e51b8152600401610940906156fa565b6133ec600c54826060015161367c565b608083018190526020830182600381111561340357fe5b600381111561340e57fe5b905250600090508160200151600381111561342557fe5b146134425760405162461bcd60e51b81526004016109409061571a565b6001600160a01b0385166000908152600e6020526040902054606082015161346a919061367c565b60a083018190526020830182600381111561348157fe5b600381111561348c57fe5b90525060009050816020015160038111156134a357fe5b146134c05760405162461bcd60e51b81526004016109409061566a565b6080810151600c5560a08101516001600160a01b0386166000908152600e6020526040908190209190915560c0820151606083015191517f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f9261352792899290919061555c565b60405180910390a1846001600160a01b0316306001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360600151604051613576919061576a565b60405180910390a360c0015160009590945092505050565b4390565b6000808383116135a95750600090508183036126b0565b506003905060006126b0565b60006135bf614963565b6000806135d086600001518661471f565b909250905060008260038111156135e357fe5b14613602575060408051602081019091526000815290925090506126b0565b60408051602081019091529081526000969095509350505050565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa084600981111561364c57fe5b84602781111561365857fe5b84604051613668939291906157ae565b60405180910390a1836009811115610e1e57fe5b600080838301848110613694576000925090506126b0565b5060029150600090506126b0565b60008060006136af614963565b6136b987876135b5565b909250905060008260038111156136cc57fe5b146136dd5750915060009050612078565b6136ef6136e982614500565b8661367c565b935093505050935093915050565b601a546000906001600160a01b0316331461371d57610b61600180611d68565b601a546001600160a01b03166000908152602260205260409020541561378757601454601a546001600160a01b0390811660008181526022602052604090205461376b939290921691612d1b565b601a546001600160a01b03166000908152602260205260408120555b601a80546001600160a01b038481166001600160a01b03198316179092556040519116907f8e5c54c990c754c8d254d080a1be0ce860f5bb354e131626d998b584961e27aa906117069083908690615474565b60006137e46149f4565b6137ed84613039565b606083018190526020830182600381111561380457fe5b600381111561380f57fe5b905250600090508160200151600381111561382657fe5b14613842576121516004601d8360200151600381111561142657fe5b6001600160a01b03841660009081526012602052604090205460808201526000198314156138975780606001518160800151101561388157600061388d565b80606001518160800151035b604082015261389f565b604081018390525b6001600160a01b0384166000908152601260205260409081902054908201516138c89190613592565b60a08301819052602083018260038111156138df57fe5b60038111156138ea57fe5b905250600090508160200151600381111561390157fe5b1461391d576121516004601e8360200151600381111561142657fe5b80606001518160a001511015613939576121516009601f611d68565b6139496011548260400151613592565b60c083018190526020830182600381111561396057fe5b600381111561396b57fe5b905250600090508160200151600381111561398257fe5b1461399f5760405162461bcd60e51b8152600401610940906155da565b60025460408201516139bc916001600160a01b0316908690612d1b565b60c081015160115560a08101516001600160a01b03851660009081526012602052604090819020919091558082015190517f925b1add21f66e1e2c8c9e9fffb3e0f4105df02dbd05c280f2fe4d19f5c50be59161229891879190615541565b600d54600090610100900460ff16613a39576120ce6003600c611d68565b613a41614a62565b613a4a84613039565b6040830181905282826003811115613a5e57fe5b6003811115613a6957fe5b9052506000905081516003811115613a7d57fe5b14613a9957612151600460088360000151600381111561142657fe5b600019831415613af9576040808201516001600160a01b03861660009081526012602052919091205411613ace576000613aef565b6040808201516001600160a01b038616600090815260126020529190912054035b6020820152613b01565b602081018390525b8060200151613b0e6126b7565b1015613b205761215160066009611d68565b613b328160400151826020015161367c565b6060830181905282826003811115613b4657fe5b6003811115613b5157fe5b9052506000905081516003811115613b6557fe5b14613b81576121516004600b8360000151600381111561142657fe5b60608101516001600160a01b0385166000908152601260205260409020541015613bb1576121516009600d611d68565b613bc1600a54826020015161367c565b6080830181905282826003811115613bd557fe5b6003811115613be057fe5b9052506000905081516003811115613bf457fe5b14613c10576121516004600a8360000151600381111561142657fe5b6001546020820151613c2d916001600160a01b0316908690612d1b565b6060810180516001600160a01b0386166000908152601060209081526040918290209283556009546001909301929092556080840151600a81905591840151925190517f13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80936122989389939192615577565b6004546000906001600160a01b03163314613cc057610b6160016000611d68565b670de0b6b3a7640000821015613cdc57610b6160026024611d68565b60138054908390556040517f389ce8cc8e8243c4ee80c30e284539a8f6fa01c546c8f3f3d76093aace77367e906117069083908690615778565b6004546000906001600160a01b03163314613d3e57613d3760016000611d68565b9050611dc8565b6000613d63613d56613d5087876146e9565b856146e9565b66470de4df8200006146e9565b9050670de0b6b3a7640000811115613d8d5760405162461bcd60e51b81526004016109409061575a565b601c859055601d849055601e8390556040517fcd7c868d12f9f21e0929ab121136064b02723c01ee44a918628a00560d24f66e90612d08908790879087906157ae565b60045460009081906001600160a01b03163314613dfb57613df360016000611d68565b91505061094d565b600660009054906101000a90046001600160a01b03169050826001600160a01b0316632191f92a6040518163ffffffff1660e01b815260040160206040518083038186803b158015613e4c57600080fd5b505afa158015613e60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250613e849190810190614c5e565b613ea05760405162461bcd60e51b81526004016109409061565a565b600680546001600160a01b0319166001600160a01b0385161790556040517feb5cc99f497dc2d7106563bb080e06c9b09e3d81a38623ac4d0839575658d1fa9061170690839086906155ae565b6004546000906001600160a01b03163314613f0e57610b6160016000611d68565b670de0b6b3a7640000821115613f2a57610b6160026023611d68565b60078054908390556040517faaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460906117069083908690615778565b6000613f6e614963565b600080613f8386670de0b6b3a764000061471f565b90925090506000826003811115613f9657fe5b14613fb5575060408051602081019091526000815290925090506126b0565b600080613fc2838861475e565b90925090506000826003811115613fd557fe5b14613ff7575060408051602081019091526000815290945092506126b0915050565b604080516020810190915290815260009890975095505050505050565b60006140208284612dd0565b905080156142da57600061403682601554614789565b6014546040516340c10f1960e01b81529192506001600160a01b0316906340c10f19906140699030908590600401615541565b600060405180830381600087803b15801561408357600080fd5b505af1158015614097573d6000803e3d6000fd5b5050505060006140ba6140ac601c5484614789565b670de0b6b3a76400006147cb565b905060006140cd6140ac601d5485614789565b905060006140e06140ac601e5486614789565b905060006140f86140ac66470de4df82000087614789565b9050600061412161411b61411561410f8989612dd0565b87612dd0565b85612dd0565b83612dd0565b6017546001600160a01b031660009081526022602052604090205490915061414990866146e9565b6017546001600160a01b03908116600090815260226020526040808220939093556018549091168152205461417e90856146e9565b6018546001600160a01b0390811660009081526022602052604080822093909355601954909116815220546141b390846146e9565b6019546001600160a01b0390811660009081526022602052604080822093909355601a54909116815220546141e890836146e9565b601a546001600160a01b0316600090815260226020526040902055600c541561424f57614213614963565b61421f82600c546147fe565b9050614229614963565b614243604051806020016040528060205481525083614833565b51602055506142909050565b601b546001600160a01b031660009081526022602052604090205461427490826146e9565b601b546001600160a01b03166000908152602260205260409020555b7f7804cfecd8a9799aa709736da54261f2c0fea131b30aa8ed0f492de57bcf754585858585856020546040516142cb969594939291906157ca565b60405180910390a15050505050505b505050565b6040516370a0823160e01b8152600090849082906001600160a01b038316906370a0823190614312903090600401615466565b60206040518083038186803b15801561432a57600080fd5b505afa15801561433e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506143629190810190614cb8565b6040516323b872dd60e01b81529091506001600160a01b038316906323b872dd906143959088903090899060040161548f565b600060405180830381600087803b1580156143af57600080fd5b505af11580156143c3573d6000803e3d6000fd5b5050505060003d600081146143df57602081146143e957600080fd5b60001991506143f5565b60206000803e60005191505b50806144135760405162461bcd60e51b8152600401610940906155fa565b6040516370a0823160e01b81526000906001600160a01b038916906370a0823190614442903090600401615466565b60206040518083038186803b15801561445a57600080fd5b505afa15801561446e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506144929190810190614cb8565b9050828110156144b45760405162461bcd60e51b81526004016109409061561a565b919091039695505050505050565b6000806000806144d2878761367c565b909250905060008260038111156144e557fe5b146144f65750915060009050612078565b6136ef8186613592565b51670de0b6b3a7640000900490565b60008183101580156145215750600083115b15614641576014546040516370a0823160e01b81526000916001600160a01b0316906370a0823190614557903090600401615466565b60206040518083038186803b15801561456f57600080fd5b505afa158015614583573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506145a79190810190614cb8565b905080841161463f5760145460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb906145e29088908890600401615541565b602060405180830381600087803b1580156145fc57600080fd5b505af1158015614610573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506146349190810190614c5e565b506000915050611dc8565b505b509092915050565b6000806000614656614963565b61267a8686614858565b600081848411156146845760405162461bcd60e51b815260040161094091906155c9565b505050900390565b614694614963565b60405180602001604052806146b185600001518560000151612dd0565b90529392505050565b60006ec097ce7bc90715b34b9f10000000006146da848460000151614789565b816146e157fe5b049392505050565b6000611dc88383604051806040016040528060118152602001706164646974696f6e206f766572666c6f7760781b8152506148b7565b60008083614732575060009050806126b0565b8383028385828161473f57fe5b0414614753575060029150600090506126b0565b6000925090506126b0565b6000808261477257506001905060006126b0565b600083858161477d57fe5b04915091509250929050565b6000611dc883836040518060400160405280601781526020017f6d756c7469706c69636174696f6e206f766572666c6f770000000000000000008152506148e7565b6000611dc883836040518060400160405280600e81526020016d646976696465206279207a65726f60901b81525061492f565b614806614963565b60405180602001604052806146b161482d866ec097ce7bc90715b34b9f1000000000614789565b856147cb565b61483b614963565b60405180602001604052806146b1856000015185600001516146e9565b6000614862614963565b600080614877670de0b6b3a76400008761471f565b9092509050600082600381111561488a57fe5b146148a9575060408051602081019091526000815290925090506126b0565b6126a9818660000151613f64565b600083830182858210156148de5760405162461bcd60e51b815260040161094091906155c9565b50949350505050565b60008315806148f4575082155b1561490157506000611dc8565b8383028385828161490e57fe5b041483906148de5760405162461bcd60e51b815260040161094091906155c9565b600081836149505760405162461bcd60e51b815260040161094091906155c9565b5082848161495a57fe5b04949350505050565b6040518060200160405280600081525090565b6040805161010081019091528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805160c08101909152806000815260200160005b8152602001600081526020016000815260200160008152602001600081525090565b6040805160e0810190915280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805160a081019091528060008152602001600081526020016000815260200160008152602001600081525090565b6040805160a081019091528060006149d2565b8035610a1f816158ee565b600082601f830112614a9157600080fd5b8135614aa4614a9f8261584e565b615827565b91508181835260208401935060208101905083856020840282011115614ac957600080fd5b60005b83811015614af55781614adf8882614a75565b8452506020928301929190910190600101614acc565b5050505092915050565b8035610a1f81615905565b8051610a1f81615905565b8035610a1f8161590e565b8035610a1f81615917565b8051610a1f81615917565b600060208284031215614b4857600080fd5b6000610e1e8484614a75565b60008060408385031215614b6757600080fd5b6000614b738585614a75565b9250506020614b8485828601614a75565b9150509250929050565b600080600060608486031215614ba357600080fd5b6000614baf8686614a75565b9350506020614bc086828701614a75565b9250506040614bd186828701614b20565b9150509250925092565b60008060408385031215614bee57600080fd5b6000614bfa8585614a75565b9250506020614b8485828601614b20565b600060208284031215614c1d57600080fd5b813567ffffffffffffffff811115614c3457600080fd5b610e1e84828501614a80565b600060208284031215614c5257600080fd5b6000610e1e8484614aff565b600060208284031215614c7057600080fd5b6000610e1e8484614b0a565b600060208284031215614c8e57600080fd5b6000610e1e8484614b15565b600060208284031215614cac57600080fd5b6000610e1e8484614b20565b600060208284031215614cca57600080fd5b6000610e1e8484614b2b565b600080600060608486031215614ceb57600080fd5b6000614cf78686614b20565b9350506020614bc086828701614b20565b614d118161587c565b82525050565b614d1181615887565b614d118161588c565b614d11816158a9565b6000614d3d8261586f565b614d478185615873565b9350614d578185602086016158b4565b614d60816158e4565b9093019392505050565b6000614d77603b83615873565b7f52454445454d5f434f4c4c41544552414c535f4e45575f544f54414c5f434f4c81527f4c41544552414c535f43414c43554c4154494f4e5f4641494c45440000000000602082015260400192915050565b6000614dd6601683615873565b751858d8dc9d59481a5b9d195c995cdd0819985a5b195960521b815260200192915050565b6000614e08601883615873565b7f544f4b454e5f5452414e534645525f494e5f4641494c45440000000000000000815260200192915050565b6000614e41601f83615873565b7f62616c616e636520636f756c64206e6f742062652063616c63756c6174656400815260200192915050565b6000614e7a601a83615873565b7f544f4b454e5f5452414e534645525f494e5f4f564552464c4f57000000000000815260200192915050565b6000614eb3601983615873565b7f544f4b454e5f5452414e534645525f4f55545f4641494c454400000000000000815260200192915050565b6000614eec603483615873565b7f434f4c4c41544552414c495a455f4e45575f4143434f554e545f42414c414e438152731157d0d05310d55310551253d397d1905253115160621b602082015260400192915050565b6000614f42603383615873565b7f636f6c6c61746572616c5261746553746f7265643a20636f6c6c61746572616c81527214985d19525b9d195c9b985b0819985a5b1959606a1b602082015260400192915050565b6000614f97601c83615873565b7f6d61726b6572206d6574686f642072657475726e65642066616c736500000000815260200192915050565b6000614fd0602b83615873565b7f4d494e545f4e45575f4143434f554e545f42414c414e43455f43414c43554c4181526a151253d397d1905253115160aa1b602082015260400192915050565b600061501d603783615873565b7f626f72726f7742616c616e636553746f7265643a20626f72726f7742616c616e81527f636553746f726564496e7465726e616c206661696c6564000000000000000000602082015260400192915050565b600061507c602283615873565b7f63616e6e6f7420617070726f766520746f20746865207a65726f206164647265815261737360f01b602082015260400192915050565b60006150c0603583615873565b7f4c49515549444154455f424f52524f575f4e45575f544f54414c5f424f52524f81527415d4d7d0d05310d55310551253d397d19052531151605a1b602082015260400192915050565b6000615117603a83615873565b7f52455041595f424f52524f575f4e45575f4143434f554e545f424f52524f575f81527f42414c414e43455f43414c43554c4154494f4e5f4641494c4544000000000000602082015260400192915050565b6000615176602383615873565b7f4c49515549444154455f424f52524f575f5452414e534645525f494e5f46414981526213115160ea1b602082015260400192915050565b60006151bb601f83615873565b7f636f756c64206e6f742063616c63756c61746520626c6f636b2064656c746100815260200192915050565b60006151f4603183615873565b7f52455041595f424f52524f575f4e45575f544f54414c5f42414c414e43455f43815270105310d55310551253d397d19052531151607a1b602082015260400192915050565b6000615247600f83615873565b6e46524553484e4553535f434845434b60881b815260200192915050565b6000615272602083615873565b7f4d494e545f45584348414e47455f43414c43554c4154494f4e5f4641494c4544815260200192915050565b60006152ab603583615873565b7f65786368616e67655261746553746f7265643a2065786368616e67655261746581527414dd1bdc9959125b9d195c9b985b0819985a5b1959605a1b602082015260400192915050565b6000615302602883615873565b7f4d494e545f4e45575f544f54414c5f535550504c595f43414c43554c4154494f8152671397d1905253115160c21b602082015260400192915050565b600061534c603483615873565b7f6f6e65206f662072656465656d546f6b656e73496e206f722072656465656d418152736d6f756e74496e206d757374206265207a65726f60601b602082015260400192915050565b60006153a2601f83615873565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00815260200192915050565b60006153db603683615873565b7f434f4c4c41544552414c495a455f4e45575f544f54414c5f434f4c4c41544552815275105314d7d0d05310d55310551253d397d1905253115160521b602082015260400192915050565b6000615433601283615873565b7150455243454e544147455f4558434545445360701b815260200192915050565b614d1181610c7e565b614d11816158a3565b60208101610a1f8284614d08565b604081016154828285614d08565b611dc86020830184614d08565b6060810161549d8286614d08565b6154aa6020830185614d08565b610e1e6040830184615454565b608081016154c58287614d08565b6154d26020830186614d08565b6154df6040830185615454565b6154ec6060830184615454565b95945050505050565b60a081016155038288614d08565b6155106020830187614d08565b61551d6040830186615454565b61552a6060830185615454565b6155376080830184615454565b9695505050505050565b6040810161554f8285614d08565b611dc86020830184615454565b6060810161556a8286614d08565b6154aa6020830185615454565b608081016155858287614d08565b6154d26020830186615454565b60208101610a1f8284614d17565b60208101610a1f8284614d20565b604081016155bc8285614d20565b611dc86020830184614d20565b60208082528101611dc88184614d32565b60208082528101610a1f81614d6a565b60208082528101610a1f81614dc9565b60208082528101610a1f81614dfb565b60208082528101610a1f81614e34565b60208082528101610a1f81614e6d565b60208082528101610a1f81614ea6565b60208082528101610a1f81614edf565b60208082528101610a1f81614f35565b60208082528101610a1f81614f8a565b60208082528101610a1f81614fc3565b60208082528101610a1f81615010565b60208082528101610a1f8161506f565b60208082528101610a1f816150b3565b60208082528101610a1f8161510a565b60208082528101610a1f81615169565b60208082528101610a1f816151ae565b60208082528101610a1f816151e7565b60208082528101610a1f8161523a565b60208082528101610a1f81615265565b60208082528101610a1f8161529e565b60208082528101610a1f816152f5565b60208082528101610a1f8161533f565b60208082528101610a1f81615395565b60208082528101610a1f816153ce565b60208082528101610a1f81615426565b60208101610a1f8284615454565b6040810161554f8285615454565b606081016157948286615454565b6157a16020830185615454565b610e1e6040830184614d29565b6060810161556a8286615454565b608081016155858287615454565b60c081016157d88289615454565b6157e56020830188615454565b6157f26040830187615454565b6157ff6060830186615454565b61580c6080830185615454565b612edc60a0830184615454565b60208101610a1f828461545d565b60405181810167ffffffffffffffff8111828210171561584657600080fd5b604052919050565b600067ffffffffffffffff82111561586557600080fd5b5060209081020190565b5190565b90815260200190565b6000610a1f82615897565b151590565b6000610a1f8261587c565b6001600160a01b031690565b60ff1690565b6000610a1f82610c7e565b60005b838110156158cf5781810151838201526020016158b7565b838111156158de576000848401525b50505050565b601f01601f191690565b6158f78161587c565b811461590257600080fd5b50565b6158f781615887565b6158f78161588c565b6158f781610c7e56fea365627a7a72315820fe162c8ca51d2716e9ccef45430f6f5edb626940c809bcfa0508fb3e482d8caa6c6578706572696d656e74616cf564736f6c63430005110040000000000000000000000000784ca62029caa80ee54fca4256100f720e89456900000000000000000000000022b475f3e93390b7e523873ad7073337f4e56c2c0000000000000000000000003c392c3fbe6ada6049373478a4f8dd668ab27b0c0000000000000000000000006ded0f2c886568fb4bb6f04f179093d3d167c9d7000000000000000000000000842738637f84b4dac335b832d9890cf8e11da214000000000000000000000000f8a90b87e5ed066f818b40fa6913ceef059dbee3000000000000000000000000e1e7731a5f262ba3ccf93cc98ff5d37d9566ea7e000000000000000000000000aed324f13ef9fd341eefcc301e7b3ec3097705cc000000000000000000000000f2d0b6165a336bd68b75e8a88fee041323040228000000000000000000000000913e8eeb3dcd3687218ec68b92b10c3ef9148425

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061047f5760003560e01c80639262e7a511610257578063bd6d894d11610146578063dd62ed3e116100c3578063f2b3abbd11610087578063f2b3abbd146108c1578063f3fdb15a146108d4578063f851a440146108dc578063f8f9da28146108e4578063fca7820b146108ec5761047f565b8063dd62ed3e14610883578063e524b36c14610896578063e9c714f2146108a9578063ea0ecf53146108b1578063efa5cd2d146108b95761047f565b8063c95de7cf1161010a578063c95de7cf1461083a578063cb34a8051461084d578063ce8b5b5c14610855578063d8e94ea91461085d578063db006a75146108705761047f565b8063bd6d894d146107f1578063be26a714146107f9578063c467201e1461080c578063c477c3ff14610814578063c5ebeaec146108275761047f565b8063a6afed95116101d4578063b078393111610198578063b0783931146107a8578063b2879ee4146107b0578063b71d1a0c146107b8578063b928cb4e146107cb578063bd37b775146107de5761047f565b8063a6afed951461076a578063a9059cbb14610772578063aa5af0fd14610785578063ae9d70b01461078d578063af0a619c146107955761047f565b80639937edfe1161021b5780639937edfe146107165780639b56d6c9146107295780639f06aa081461073c578063a0712d681461074f578063a2e354c8146107625761047f565b80639262e7a5146106c2578063944f3771146106d557806394ecb85b146106e857806395d89b41146106fb57806395dd9193146107035761047f565b806326782247116103735780634b76f669116102f057806370a08231116102b457806370a082311461068257806373acee9814610695578063852a12e31461069d5780638af7cb8f146106b05780638f840ddd146106ba5761047f565b80634b76f669146106425780635bb316931461065757806362a38b2d1461065f578063669f8413146106725780636c540baf1461067a5761047f565b80633b1d21a2116103375780633b1d21a2146106045780633c5873c01461060c5780634025a4a61461061f57806344dbd5ec1461062757806347bd37181461063a5761047f565b806326782247146105c45780632eb0ed25146105cc57806330504b6f146105d4578063313ce567146105dc5780633af9e669146105f15761047f565b806312f0dea711610401578063182df0f5116103c5578063182df0f51461057b578063195c083114610583578063233cf1971461058b57806323b872dd1461059e5780632608f818146105b15761047f565b806312f0dea714610532578063173b99041461054557806317539b1e1461054d57806317bfdfbc1461056057806318160ddd146105735761047f565b80630e752702116104485780630e752702146104ff5780630f98c918146105125780631119f0341461051a5780631256142114610522578063127effb21461052a5761047f565b8062517f62146104845780630520db11146104ad57806306fdde03146104c2578063095ea7b3146104d75780630e2feb05146104f7575b600080fd5b610497610492366004614b36565b6108ff565b6040516104a4919061576a565b60405180910390f35b6104b5610952565b6040516104a49190615466565b6104ca610961565b6040516104a491906155c9565b6104ea6104e5366004614bdb565b610990565b6040516104a49190615592565b6104b5610a25565b61049761050d366004614c9a565b610a34565b610497610ab0565b610497610ab6565b610497610abc565b6104b5610ac2565b610497610540366004614b36565b610ad1565b610497610b3a565b61049761055b366004614c40565b610b40565b61049761056e366004614b36565b610bd2565b610497610c37565b610497610c3d565b6104b5610c81565b610497610599366004614b36565b610c90565b6104ea6105ac366004614b8e565b610ccb565b6104976105bf366004614bdb565b610d11565b6104b5610d85565b610497610d94565b610497610d9a565b6105e4610da0565b6040516104a49190615819565b6104976105ff366004614b36565b610da5565b610497610e26565b61049761061a366004614b36565b610e35565b6104b5610e70565b610497610635366004614b36565b610e7f565b610497610e91565b61064a610e97565b6040516104a491906155a0565b6104ea610ea6565b61049761066d366004614b36565b610eb4565b610497610eef565b610497610ef5565b610497610690366004614b36565b610efb565b610497610f16565b6104976106ab366004614c9a565b610f73565b6106b8610fdd565b005b6104976110cc565b6104976106d0366004614b36565b6110d2565b6104976106e3366004614b36565b61110d565b6104976106f6366004614b36565b611120565b6104ca61115b565b610497610711366004614b36565b61117c565b610497610724366004614b36565b6111ba565b610497610737366004614b36565b6111eb565b61049761074a366004614c9a565b611206565b61049761075d366004614c9a565b611263565b6104976112cb565b6104976112d1565b6104ea610780366004614bdb565b61158c565b6104976115d1565b6104976115d7565b6104976107a3366004614b36565b61166b565b61049761167d565b6104b5611683565b6104976107c6366004614b36565b611692565b6104976107d9366004614b36565b611717565b6104976107ec366004614c9a565b611752565b6104976117af565b610497610807366004614b36565b6117df565b6104ea6117ea565b6106b8610822366004614c0b565b6117f3565b610497610835366004614c9a565b61185e565b610497610848366004614c9a565b6118bb565b6104b561190f565b61049761191e565b61049761086b366004614c40565b611924565b61049761087e366004614c9a565b611993565b610497610891366004614b54565b6119fd565b6104976108a4366004614cd6565b611a28565b610497611a72565b6106b8611b5f565b6104b5611ba1565b6104976108cf366004614c7c565b611bb0565b61064a611c04565b6104b5611c13565b610497611c22565b6104976108fa366004614c9a565b611c62565b600080600061090d84611cb6565b5091935091506000905082600381111561092357fe5b146109495760405162461bcd60e51b81526004016109409061564a565b60405180910390fd5b9150505b919050565b6002546001600160a01b031681565b6040518060400160405280601381526020017210d95c9d1a599a58d85d19481bd98819519253606a1b81525081565b60006001600160a01b0383166109b85760405162461bcd60e51b81526004016109409061568a565b336000818152600f602090815260408083206001600160a01b038816808552925291829020859055905182907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610a1190879061576a565b60405180910390a360019150505b92915050565b6017546001600160a01b031681565b600060026000541415610a595760405162461bcd60e51b81526004016109409061573a565b60026000908155610a686112d1565b90508015610a8e57610a86816009811115610a7f57fe5b6002611d68565b915050610aa6565b610a96611dcf565b610aa1333385611e4e565b509150505b6001600055919050565b601c5481565b60155481565b601d5481565b6019546001600160a01b031681565b600060026000541415610af65760405162461bcd60e51b81526004016109409061573a565b60026000908155610b056112d1565b90508015610b1c57610a86816009811115610a7f57fe5b610b24611dcf565b610b2e3384612080565b60016000559392505050565b60075481565b6004546000906001600160a01b03163314610b6857610b6160016000611d68565b905061094d565b600d5460ff61010090910416151582151514610bca57600d805461ff001916610100841515021790556040517f1717b5ea3deee7263023836cdd49998ac11579e79797df6028a834abad3619a290610bc1908490615592565b60405180910390a15b600092915050565b600060026000541415610bf75760405162461bcd60e51b81526004016109409061573a565b60026000908155610c066112d1565b14610c235760405162461bcd60e51b8152600401610940906155ea565b610c2c8261117c565b600160005592915050565b600c5481565b6000806000610c4a6122aa565b90925090506000826003811115610c5d57fe5b14610c7a5760405162461bcd60e51b81526004016109409061570a565b9150505b90565b601a546001600160a01b031681565b600060026000541415610cb55760405162461bcd60e51b81526004016109409061573a565b6002600055610cc2611dcf565b610c2c8261235f565b600060026000541415610cf05760405162461bcd60e51b81526004016109409061573a565b60026000908155610d033386868661243c565b600160005514949350505050565b600060026000541415610d365760405162461bcd60e51b81526004016109409061573a565b60026000908155610d456112d1565b90508015610d6457610d5c816009811115610a7f57fe5b915050610c2c565b610d6c611dcf565b610d77338585611e4e565b506001600055949350505050565b6005546001600160a01b031681565b60165481565b60115481565b601281565b6000610daf614963565b6040518060200160405280610dc26117af565b90526001600160a01b0384166000908152600e6020526040812054919250908190610dee908490612663565b90925090506000826003811115610e0157fe5b14610e1e5760405162461bcd60e51b81526004016109409061560a565b949350505050565b6000610e306126b7565b905090565b600060026000541415610e5a5760405162461bcd60e51b81526004016109409061573a565b6002600055610e67611dcf565b610c2c8261273a565b601b546001600160a01b031681565b60216020526000908152604090205481565b600a5481565b6014546001600160a01b031681565b600d54610100900460ff1681565b600060026000541415610ed95760405162461bcd60e51b81526004016109409061573a565b6002600055610ee6611dcf565b610c2c82612818565b601f5481565b60085481565b6001600160a01b03166000908152600e602052604090205490565b600060026000541415610f3b5760405162461bcd60e51b81526004016109409061573a565b60026000908155610f4a6112d1565b14610f675760405162461bcd60e51b8152600401610940906155ea565b50600a54600160005590565b600060026000541415610f985760405162461bcd60e51b81526004016109409061573a565b60026000908155610fa76112d1565b90508015610fbe57610a86816009811115610a7f57fe5b610fc6611dcf565b610fd13360006128f5565b610b2e336000856129b8565b600260005414156110005760405162461bcd60e51b81526004016109409061573a565b6002600090815561100f6112d1565b1461102c5760405162461bcd60e51b8152600401610940906155ea565b60006110366126b7565b90506000600b548211611049578161104d565b600b545b60015460035491925061106d916001600160a01b03918216911683612d1b565b611079600b5482612dd0565b600b556003546040517fdcce521f2489558369ff1238d30b9893cc8892398f54cd7acffcce6077349f00916110bb916001600160a01b03909116908490615541565b60405180910390a150506001600055565b600b5481565b6000600260005414156110f75760405162461bcd60e51b81526004016109409061573a565b6002600055611104611dcf565b610c2c82612e0a565b6000611117610fdd565b610a1f82612ee7565b6000600260005414156111455760405162461bcd60e51b81526004016109409061573a565b6002600055611152611dcf565b610c2c82612f5b565b6040518060400160405280600581526020016418d951925360da1b81525081565b600080600061118a84613039565b9092509050600082600381111561119d57fe5b146109495760405162461bcd60e51b81526004016109409061567a565b6000806111c56112d1565b146111e25760405162461bcd60e51b8152600401610940906155ea565b610a1f826108ff565b6001600160a01b031660009081526012602052604090205490565b60006002600054141561122b5760405162461bcd60e51b81526004016109409061573a565b6002600090815561123a6112d1565b9050801561125157610a86816009811115610a7f57fe5b611259611dcf565b610aa133846130ed565b6000600260005414156112885760405162461bcd60e51b81526004016109409061573a565b600260009081556112976112d1565b905080156112ae57610a86816009811115610a7f57fe5b6112b6611dcf565b6112c13360006128f5565b610aa1338461329d565b60135481565b6000806112dc61358e565b600854909150808214156112f557600092505050610c7e565b60006112ff6126b7565b600a54600b546009546006546040516315f2405360e01b81529495509293919290916000916001600160a01b0316906315f2405390611346908890889088906004016157ae565b60206040518083038186803b15801561135e57600080fd5b505afa158015611372573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506113969190810190614cb8565b90506000806113a58989613592565b909250905060008260038111156113b857fe5b146113d55760405162461bcd60e51b8152600401610940906156ca565b6113dd614963565b6000806000806113fb60405180602001604052808a815250876135b5565b9097509450600087600381111561140e57fe5b146114405761142b6004600789600381111561142657fe5b61361d565b9e505050505050505050505050505050610c7e565b61144a858c612663565b9097509350600087600381111561145d57fe5b146114755761142b6004600389600381111561142657fe5b61147f848c61367c565b9097509250600087600381111561149257fe5b146114aa5761142b6004600589600381111561142657fe5b6114c56040518060200160405280600754815250858c6136a2565b909750915060008760038111156114d857fe5b146114f05761142b6004600689600381111561142657fe5b6114fb858a8b6136a2565b9097509050600087600381111561150e57fe5b146115255761142b60048089600381111561142657fe5b60088e90556009819055600a839055600b8290556040517f4dec04e750ca11537cabcd8a9eab06494de08da3735bc8871cd41250e190bc049061156f908e908790859088906157bc565b60405180910390a160009e50505050505050505050505050505090565b6000600260005414156115b15760405162461bcd60e51b81526004016109409061573a565b600260009081556115c43333868661243c565b6001600055149392505050565b60095481565b6006546000906001600160a01b031663b81688166115f36126b7565b600a54600b546007546040518563ffffffff1660e01b815260040161161b94939291906157bc565b60206040518083038186803b15801561163357600080fd5b505afa158015611647573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610e309190810190614cb8565b60226020526000908152604090205481565b601e5481565b6001546001600160a01b031681565b6004546000906001600160a01b031633146116b357610b6160016000611d68565b600580546001600160a01b038481166001600160a01b03198316179092556040519116907fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9906117069083908690615474565b60405180910390a160009392505050565b60006002600054141561173c5760405162461bcd60e51b81526004016109409061573a565b6002600055611749611dcf565b610c2c826136fd565b6000600260005414156117775760405162461bcd60e51b81526004016109409061573a565b600260009081556117866112d1565b9050801561179d57610a86816009811115610a7f57fe5b6117a5611dcf565b610b2e33846137da565b6000806117ba6112d1565b146117d75760405162461bcd60e51b8152600401610940906155ea565b610e30610c3d565b6000610a1f82612e0a565b600d5460ff1681565b600260005414156118165760405162461bcd60e51b81526004016109409061573a565b6002600055611823611dcf565b60005b81518110156118555761184d82828151811061183e57fe5b602002602001015160016128f5565b600101611826565b50506001600055565b6000600260005414156118835760405162461bcd60e51b81526004016109409061573a565b600260009081556118926112d1565b905080156118a957610a86816009811115610a7f57fe5b6118b1611dcf565b610b2e3384613a1b565b6000600260005414156118e05760405162461bcd60e51b81526004016109409061573a565b600260009081556118ef6112d1565b9050801561190657610a86816009811115610a7f57fe5b610b2e83613c9f565b6003546001600160a01b031681565b60205481565b6004546000906001600160a01b0316331461194557610b6160016000611d68565b600d5460ff16151582151514610bca57600d805460ff19168315151790556040517f7c11d7b79bdcc9099218ef3518d3a3202389ab06e9690c937f724618b9e0c46f90610bc1908490615592565b6000600260005414156119b85760405162461bcd60e51b81526004016109409061573a565b600260009081556119c76112d1565b905080156119de57610a86816009811115610a7f57fe5b6119e6611dcf565b6119f13360006128f5565b610b2e338460006129b8565b6001600160a01b039182166000908152600f6020908152604080832093909416825291909152205490565b600060026000541415611a4d5760405162461bcd60e51b81526004016109409061573a565b6002600055611a5a611dcf565b611a65848484613d16565b6001600055949350505050565b6005546000906001600160a01b031633141580611a8d575033155b15611aa557611a9e60016000611d68565b9050610c7e565b60048054600580546001600160a01b038082166001600160a01b03198086168217968790559092169092556040519282169390927ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc92611b09928692911690615474565b60405180910390a16005546040517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a991611b4e9184916001600160a01b031690615474565b60405180910390a160009250505090565b60026000541415611b825760405162461bcd60e51b81526004016109409061573a565b6002600055611b8f611dcf565b611b9a3360016128f5565b6001600055565b6018546001600160a01b031681565b600060026000541415611bd55760405162461bcd60e51b81526004016109409061573a565b60026000908155611be46112d1565b90508015611bfb57610a86816009811115610a7f57fe5b610b2e83613dd0565b6006546001600160a01b031681565b6004546001600160a01b031681565b6006546000906001600160a01b03166315f24053611c3e6126b7565b600a54600b546040518463ffffffff1660e01b815260040161161b939291906157ae565b600060026000541415611c875760405162461bcd60e51b81526004016109409061573a565b60026000908155611c966112d1565b90508015611cad57610a86816009811115610a7f57fe5b610b2e83613eed565b6000806000806000806000611cc9614963565b611cd289613039565b90945092506000846003811115611ce557fe5b14611d00575091955060009450849350839250611d61915050565b6001600160a01b0389166000908152601260205260409020549150611d258383613f64565b90945090506000846003811115611d3857fe5b14611d53575091955060009450849350839250611d61915050565b516000975095509093509150505b9193509193565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0836009811115611d9757fe5b836027811115611da357fe5b6000604051611db493929190615786565b60405180910390a1826009811115611dc857fe5b9392505050565b601f54806000611ddd61358e565b90505b80821015611e4757659a9d359ca0006015541015611dfd57611e47565b819250601654811015611e1257809150611e18565b60165491505b611e228383614014565b601654821415611e4257601680546208ca00019055601554600290046015555b611de0565b601f555050565b600080611e59614976565b6001600160a01b0385166000908152601060205260409020600101546060820152611e8385613039565b6080830181905260208301826003811115611e9a57fe5b6003811115611ea557fe5b9052506000905081602001516003811115611ebc57fe5b14611ee557611ed8600460198360200151600381111561142657fe5b9250600091506120789050565b600019841415611efe5760808101516040820152611f06565b604081018490525b6001546040820151611f23916001600160a01b03169088906142df565b60e082018190526080820151611f3891613592565b60a0830181905260208301826003811115611f4f57fe5b6003811115611f5a57fe5b9052506000905081602001516003811115611f7157fe5b14611f8e5760405162461bcd60e51b8152600401610940906156aa565b611f9e600a548260e00151613592565b60c0830181905260208301826003811115611fb557fe5b6003811115611fc057fe5b9052506000905081602001516003811115611fd757fe5b14611ff45760405162461bcd60e51b8152600401610940906156da565b60a0810180516001600160a01b0387166000908152601060205260409081902091825560095460019092019190915560c0830151600a81905560e0840151925191517f1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a193612065938b938b936154f5565b60405180910390a160e001516000925090505b935093915050565b6001600160a01b0382166000908152601260205260408120541515806120bd57506001600160a01b0383166000908152600e602052604090205415155b156120d5576120ce60036020611d68565b9050610a1f565b6120dd6149bc565b6120e683611cb6565b6060850181905260408501829052608085018390526020850184600381111561210b57fe5b600381111561211657fe5b90525060009250612125915050565b8160200151600381111561213557fe5b1461215957612151600460218360200151600381111561142657fe5b915050610a1f565b601354816080015110156121735761215160036022611d68565b604081015160015461218f906001600160a01b031686836142df565b146121ac5760405162461bcd60e51b8152600401610940906156ba565b6121bc600a548260400151613592565b60a08301819052602083018260038111156121d357fe5b60038111156121de57fe5b90525060009050816020015160038111156121f557fe5b146122125760405162461bcd60e51b81526004016109409061569a565b6001600160a01b03808416600090815260106020908152604080832083815560095460019091015560a0850151600a5560129091528082208290556060840180519388168352918190209290925582820151905191517f08b197b6ae66d18ee6fa20a826a84579a925b9e646a3bf19e96f59ed568c2688926122989288928892906154b7565b60405180910390a16000949350505050565b600c546000908190806122cb57600066071afd498d0000925092505061235b565b60006122d56126b7565b905060006122e1614963565b60006122f284600a54600b546144c2565b93509050600081600381111561230457fe5b146123195795506000945061235b9350505050565b6123238386613f64565b92509050600081600381111561233557fe5b1461234a5795506000945061235b9350505050565b505160009550935061235b92505050565b9091565b6018546000906001600160a01b0316331461237f57610b61600180611d68565b6018546001600160a01b0316600090815260226020526040902054156123e9576014546018546001600160a01b039081166000818152602260205260409020546123cd939290921691612d1b565b6018546001600160a01b03166000908152602260205260408120555b601880546001600160a01b038481166001600160a01b03198316179092556040519116907f892afdc1ab392697c78738b453a93a3b982d3294cee6b445ba02fc0428285c6b906117069083908690615474565b6000826001600160a01b0316846001600160a01b0316148061246557506001600160a01b038316155b1561247d5761247660026025611d68565b9050610e1e565b612485611dcf565b6124908460006128f5565b61249b8360006128f5565b60006001600160a01b0386811690861614156124ba57506000196124e2565b506001600160a01b038085166000908152600f60209081526040808320938916835292905220545b6000806000806124f28588613592565b9094509250600084600381111561250557fe5b146125225761251660046025611d68565b95505050505050610e1e565b6001600160a01b0389166000908152600e60205260409020546125459088613592565b9094509150600084600381111561255857fe5b146125695761251660046026611d68565b6001600160a01b0388166000908152600e602052604090205461258c908861367c565b9094509050600084600381111561259f57fe5b146125b05761251660046027611d68565b6001600160a01b03808a166000908152600e6020526040808220859055918a168152208190556000198514612608576001600160a01b03808a166000908152600f60209081526040808320938e168352929052208390555b876001600160a01b0316896001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8960405161264b919061576a565b60405180910390a35060009998505050505050505050565b6000806000612670614963565b61267a86866135b5565b9092509050600082600381111561268d57fe5b1461269e57509150600090506126b0565b60006126a982614500565b9350935050505b9250929050565b6001546040516370a0823160e01b81526000916001600160a01b03169081906370a08231906126ea903090600401615466565b60206040518083038186803b15801561270257600080fd5b505afa158015612716573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610c7a9190810190614cb8565b6004546000906001600160a01b0316331461275b57610b6160016000611d68565b6017546001600160a01b0316600090815260226020526040902054156127c5576014546017546001600160a01b039081166000818152602260205260409020546127a9939290921691612d1b565b6017546001600160a01b03166000908152602260205260408120555b601780546001600160a01b038481166001600160a01b03198316179092556040519116907f44daa1a06d9d2bc8b2510a777695b4fa7d67cce7b382694da99bec750e00f97d906117069083908690615474565b6019546000906001600160a01b0316331461283857610b61600180611d68565b6019546001600160a01b0316600090815260226020526040902054156128a2576014546019546001600160a01b03908116600081815260226020526040902054612886939290921691612d1b565b6019546001600160a01b03166000908152602260205260408120555b601980546001600160a01b038481166001600160a01b03198316179092556040519116907f6d83175096b0de3f5de98ab86d95234fb1a95bd44b8e97696d5b195b27bf42fd906117069083908690615474565b6128fd61358e565b601f541461291d5760405162461bcd60e51b8152600401610940906156ea565b600061292883612e0a565b905061294a8382846129425767016345785d8a0000612945565b60005b61450f565b6001600160a01b0384166000908152602260208181526040808420948555815460218352938190209390935552905490517fd549ebef7c0522539f1cece1b90b7ee6a2612c8d398a1d7c828398326882d898916129ab918691850390615541565b60405180910390a1505050565b60008215806129c5575081155b6129e15760405162461bcd60e51b81526004016109409061572a565b6129e96149f4565b6129f16122aa565b6040830181905260208301826003811115612a0857fe5b6003811115612a1357fe5b9052506000905081602001516003811115612a2a57fe5b14612a4e57612a46600460158360200151600381111561142657fe5b915050611dc8565b8315612acf576060810184905260408051602081018252908201518152612a759085612663565b6080830181905260208301826003811115612a8c57fe5b6003811115612a9757fe5b9052506000905081602001516003811115612aae57fe5b14612aca57612a46600460138360200151600381111561142657fe5b612b48565b612aeb8360405180602001604052808460400151815250614649565b6060830181905260208301826003811115612b0257fe5b6003811115612b0d57fe5b9052506000905081602001516003811115612b2457fe5b14612b4057612a46600460148360200151600381111561142657fe5b608081018390525b612b58600c548260600151613592565b60a0830181905260208301826003811115612b6f57fe5b6003811115612b7a57fe5b9052506000905081602001516003811115612b9157fe5b14612bad57612a46600460178360200151600381111561142657fe5b6001600160a01b0385166000908152600e60205260409020546060820151612bd59190613592565b60c0830181905260208301826003811115612bec57fe5b6003811115612bf757fe5b9052506000905081602001516003811115612c0e57fe5b14612c2a57612a46600460168360200151600381111561142657fe5b8060800151612c376126b7565b1015612c4957612a4660066018611d68565b6001546080820151612c66916001600160a01b0316908790612d1b565b60a0810151600c5560c08101516001600160a01b0386166000818152600e602052604090819020929092556060830151915130927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91612cc6919061576a565b60405180910390a3608081015160608201516040517fe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a92992612d0892899261555c565b60405180910390a1506000949350505050565b60405163a9059cbb60e01b815283906001600160a01b0382169063a9059cbb90612d4b9086908690600401615541565b600060405180830381600087803b158015612d6557600080fd5b505af1158015612d79573d6000803e3d6000fd5b5050505060003d60008114612d955760208114612d9f57600080fd5b6000199150612dab565b60206000803e60005191505b5080612dc95760405162461bcd60e51b81526004016109409061562a565b5050505050565b6000611dc88383604051806040016040528060158152602001747375627472616374696f6e20756e646572666c6f7760581b815250614660565b6000612e14614963565b60405180602001604052806020548152509050612e2f614963565b5060408051602080820183526001600160a01b038616600090815260219091529190912054808252158015612e645750815115155b15612e7c576ec097ce7bc90715b34b9f100000000081525b612e84614963565b612e8e838361468c565b6001600160a01b0386166000908152600e602052604081205491925090612eb590836146ba565b6001600160a01b03871660009081526022602052604081205491925090612edc90836146e9565b979650505050505050565b6004546000906001600160a01b03163314612f0857610b6160016000611d68565b600380546001600160a01b038481166001600160a01b03198316179092556040519116907f7f91866f1e694ba3479d7897c4168696dffec20ff3dc527eb363a2245177399e906117069083908690615474565b6004546000906001600160a01b03163314612f7c57610b6160016000611d68565b601b546001600160a01b031660009081526022602052604090205415612fe657601454601b546001600160a01b03908116600081815260226020526040902054612fca939290921691612d1b565b601b546001600160a01b03166000908152602260205260408120555b601b80546001600160a01b038481166001600160a01b03198316179092556040519116907f5caaf6ff987f0604398c4e98fd3247ccd4052e166f0eb51308e1001f27aadd4a906117069083908690615474565b6001600160a01b0381166000908152601060205260408120805482918291829182916130705750600094508493506130e892505050565b613080816000015460095461471f565b9094509250600084600381111561309357fe5b146130a85750919350600092506130e8915050565b6130b683826001015461475e565b909450915060008460038111156130c957fe5b146130de5750919350600092506130e8915050565b5060009450925050505b915091565b6001600160a01b0382166000908152600e6020526040812054819015613124576131196003601c611d68565b9150600090506126b0565b61312c614a32565b600254613143906001600160a01b031686866142df565b608082018190526011546131569161367c565b604083018190526020830182600381111561316d57fe5b600381111561317857fe5b905250600090508160200151600381111561318f57fe5b146131ac5760405162461bcd60e51b81526004016109409061574a565b6001600160a01b03851660009081526012602052604090205460808201516131d4919061367c565b60608301819052602083018260038111156131eb57fe5b60038111156131f657fe5b905250600090508160200151600381111561320d57fe5b1461322a5760405162461bcd60e51b81526004016109409061563a565b60408082015160115560608201516001600160a01b0387166000908152601260205282902055608082015190517f94c9d5464fed48366596c718219e5fbd3c0c61c1a21391bf239075e9de5a727a9161328591889190615541565b60405180910390a16080015160009590945092505050565b600d54600090819060ff1615806132cb57506001600160a01b03841660009081526012602052604090205415155b156132dc576131196003600e611d68565b6132e46149f4565b6132ec6122aa565b604083018190526020830182600381111561330357fe5b600381111561330e57fe5b905250600090508160200151600381111561332557fe5b1461334e57613341600460108360200151600381111561142657fe5b9250600091506126b09050565b600154613365906001600160a01b031686866142df565b60c08201819052604080516020810182529083015181526133869190614649565b606083018190526020830182600381111561339d57fe5b60038111156133a857fe5b90525060009050816020015160038111156133bf57fe5b146133dc5760405162461bcd60e51b8152600401610940906156fa565b6133ec600c54826060015161367c565b608083018190526020830182600381111561340357fe5b600381111561340e57fe5b905250600090508160200151600381111561342557fe5b146134425760405162461bcd60e51b81526004016109409061571a565b6001600160a01b0385166000908152600e6020526040902054606082015161346a919061367c565b60a083018190526020830182600381111561348157fe5b600381111561348c57fe5b90525060009050816020015160038111156134a357fe5b146134c05760405162461bcd60e51b81526004016109409061566a565b6080810151600c5560a08101516001600160a01b0386166000908152600e6020526040908190209190915560c0820151606083015191517f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f9261352792899290919061555c565b60405180910390a1846001600160a01b0316306001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360600151604051613576919061576a565b60405180910390a360c0015160009590945092505050565b4390565b6000808383116135a95750600090508183036126b0565b506003905060006126b0565b60006135bf614963565b6000806135d086600001518661471f565b909250905060008260038111156135e357fe5b14613602575060408051602081019091526000815290925090506126b0565b60408051602081019091529081526000969095509350505050565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa084600981111561364c57fe5b84602781111561365857fe5b84604051613668939291906157ae565b60405180910390a1836009811115610e1e57fe5b600080838301848110613694576000925090506126b0565b5060029150600090506126b0565b60008060006136af614963565b6136b987876135b5565b909250905060008260038111156136cc57fe5b146136dd5750915060009050612078565b6136ef6136e982614500565b8661367c565b935093505050935093915050565b601a546000906001600160a01b0316331461371d57610b61600180611d68565b601a546001600160a01b03166000908152602260205260409020541561378757601454601a546001600160a01b0390811660008181526022602052604090205461376b939290921691612d1b565b601a546001600160a01b03166000908152602260205260408120555b601a80546001600160a01b038481166001600160a01b03198316179092556040519116907f8e5c54c990c754c8d254d080a1be0ce860f5bb354e131626d998b584961e27aa906117069083908690615474565b60006137e46149f4565b6137ed84613039565b606083018190526020830182600381111561380457fe5b600381111561380f57fe5b905250600090508160200151600381111561382657fe5b14613842576121516004601d8360200151600381111561142657fe5b6001600160a01b03841660009081526012602052604090205460808201526000198314156138975780606001518160800151101561388157600061388d565b80606001518160800151035b604082015261389f565b604081018390525b6001600160a01b0384166000908152601260205260409081902054908201516138c89190613592565b60a08301819052602083018260038111156138df57fe5b60038111156138ea57fe5b905250600090508160200151600381111561390157fe5b1461391d576121516004601e8360200151600381111561142657fe5b80606001518160a001511015613939576121516009601f611d68565b6139496011548260400151613592565b60c083018190526020830182600381111561396057fe5b600381111561396b57fe5b905250600090508160200151600381111561398257fe5b1461399f5760405162461bcd60e51b8152600401610940906155da565b60025460408201516139bc916001600160a01b0316908690612d1b565b60c081015160115560a08101516001600160a01b03851660009081526012602052604090819020919091558082015190517f925b1add21f66e1e2c8c9e9fffb3e0f4105df02dbd05c280f2fe4d19f5c50be59161229891879190615541565b600d54600090610100900460ff16613a39576120ce6003600c611d68565b613a41614a62565b613a4a84613039565b6040830181905282826003811115613a5e57fe5b6003811115613a6957fe5b9052506000905081516003811115613a7d57fe5b14613a9957612151600460088360000151600381111561142657fe5b600019831415613af9576040808201516001600160a01b03861660009081526012602052919091205411613ace576000613aef565b6040808201516001600160a01b038616600090815260126020529190912054035b6020820152613b01565b602081018390525b8060200151613b0e6126b7565b1015613b205761215160066009611d68565b613b328160400151826020015161367c565b6060830181905282826003811115613b4657fe5b6003811115613b5157fe5b9052506000905081516003811115613b6557fe5b14613b81576121516004600b8360000151600381111561142657fe5b60608101516001600160a01b0385166000908152601260205260409020541015613bb1576121516009600d611d68565b613bc1600a54826020015161367c565b6080830181905282826003811115613bd557fe5b6003811115613be057fe5b9052506000905081516003811115613bf457fe5b14613c10576121516004600a8360000151600381111561142657fe5b6001546020820151613c2d916001600160a01b0316908690612d1b565b6060810180516001600160a01b0386166000908152601060209081526040918290209283556009546001909301929092556080840151600a81905591840151925190517f13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab80936122989389939192615577565b6004546000906001600160a01b03163314613cc057610b6160016000611d68565b670de0b6b3a7640000821015613cdc57610b6160026024611d68565b60138054908390556040517f389ce8cc8e8243c4ee80c30e284539a8f6fa01c546c8f3f3d76093aace77367e906117069083908690615778565b6004546000906001600160a01b03163314613d3e57613d3760016000611d68565b9050611dc8565b6000613d63613d56613d5087876146e9565b856146e9565b66470de4df8200006146e9565b9050670de0b6b3a7640000811115613d8d5760405162461bcd60e51b81526004016109409061575a565b601c859055601d849055601e8390556040517fcd7c868d12f9f21e0929ab121136064b02723c01ee44a918628a00560d24f66e90612d08908790879087906157ae565b60045460009081906001600160a01b03163314613dfb57613df360016000611d68565b91505061094d565b600660009054906101000a90046001600160a01b03169050826001600160a01b0316632191f92a6040518163ffffffff1660e01b815260040160206040518083038186803b158015613e4c57600080fd5b505afa158015613e60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250613e849190810190614c5e565b613ea05760405162461bcd60e51b81526004016109409061565a565b600680546001600160a01b0319166001600160a01b0385161790556040517feb5cc99f497dc2d7106563bb080e06c9b09e3d81a38623ac4d0839575658d1fa9061170690839086906155ae565b6004546000906001600160a01b03163314613f0e57610b6160016000611d68565b670de0b6b3a7640000821115613f2a57610b6160026023611d68565b60078054908390556040517faaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460906117069083908690615778565b6000613f6e614963565b600080613f8386670de0b6b3a764000061471f565b90925090506000826003811115613f9657fe5b14613fb5575060408051602081019091526000815290925090506126b0565b600080613fc2838861475e565b90925090506000826003811115613fd557fe5b14613ff7575060408051602081019091526000815290945092506126b0915050565b604080516020810190915290815260009890975095505050505050565b60006140208284612dd0565b905080156142da57600061403682601554614789565b6014546040516340c10f1960e01b81529192506001600160a01b0316906340c10f19906140699030908590600401615541565b600060405180830381600087803b15801561408357600080fd5b505af1158015614097573d6000803e3d6000fd5b5050505060006140ba6140ac601c5484614789565b670de0b6b3a76400006147cb565b905060006140cd6140ac601d5485614789565b905060006140e06140ac601e5486614789565b905060006140f86140ac66470de4df82000087614789565b9050600061412161411b61411561410f8989612dd0565b87612dd0565b85612dd0565b83612dd0565b6017546001600160a01b031660009081526022602052604090205490915061414990866146e9565b6017546001600160a01b03908116600090815260226020526040808220939093556018549091168152205461417e90856146e9565b6018546001600160a01b0390811660009081526022602052604080822093909355601954909116815220546141b390846146e9565b6019546001600160a01b0390811660009081526022602052604080822093909355601a54909116815220546141e890836146e9565b601a546001600160a01b0316600090815260226020526040902055600c541561424f57614213614963565b61421f82600c546147fe565b9050614229614963565b614243604051806020016040528060205481525083614833565b51602055506142909050565b601b546001600160a01b031660009081526022602052604090205461427490826146e9565b601b546001600160a01b03166000908152602260205260409020555b7f7804cfecd8a9799aa709736da54261f2c0fea131b30aa8ed0f492de57bcf754585858585856020546040516142cb969594939291906157ca565b60405180910390a15050505050505b505050565b6040516370a0823160e01b8152600090849082906001600160a01b038316906370a0823190614312903090600401615466565b60206040518083038186803b15801561432a57600080fd5b505afa15801561433e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506143629190810190614cb8565b6040516323b872dd60e01b81529091506001600160a01b038316906323b872dd906143959088903090899060040161548f565b600060405180830381600087803b1580156143af57600080fd5b505af11580156143c3573d6000803e3d6000fd5b5050505060003d600081146143df57602081146143e957600080fd5b60001991506143f5565b60206000803e60005191505b50806144135760405162461bcd60e51b8152600401610940906155fa565b6040516370a0823160e01b81526000906001600160a01b038916906370a0823190614442903090600401615466565b60206040518083038186803b15801561445a57600080fd5b505afa15801561446e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506144929190810190614cb8565b9050828110156144b45760405162461bcd60e51b81526004016109409061561a565b919091039695505050505050565b6000806000806144d2878761367c565b909250905060008260038111156144e557fe5b146144f65750915060009050612078565b6136ef8186613592565b51670de0b6b3a7640000900490565b60008183101580156145215750600083115b15614641576014546040516370a0823160e01b81526000916001600160a01b0316906370a0823190614557903090600401615466565b60206040518083038186803b15801561456f57600080fd5b505afa158015614583573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506145a79190810190614cb8565b905080841161463f5760145460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb906145e29088908890600401615541565b602060405180830381600087803b1580156145fc57600080fd5b505af1158015614610573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506146349190810190614c5e565b506000915050611dc8565b505b509092915050565b6000806000614656614963565b61267a8686614858565b600081848411156146845760405162461bcd60e51b815260040161094091906155c9565b505050900390565b614694614963565b60405180602001604052806146b185600001518560000151612dd0565b90529392505050565b60006ec097ce7bc90715b34b9f10000000006146da848460000151614789565b816146e157fe5b049392505050565b6000611dc88383604051806040016040528060118152602001706164646974696f6e206f766572666c6f7760781b8152506148b7565b60008083614732575060009050806126b0565b8383028385828161473f57fe5b0414614753575060029150600090506126b0565b6000925090506126b0565b6000808261477257506001905060006126b0565b600083858161477d57fe5b04915091509250929050565b6000611dc883836040518060400160405280601781526020017f6d756c7469706c69636174696f6e206f766572666c6f770000000000000000008152506148e7565b6000611dc883836040518060400160405280600e81526020016d646976696465206279207a65726f60901b81525061492f565b614806614963565b60405180602001604052806146b161482d866ec097ce7bc90715b34b9f1000000000614789565b856147cb565b61483b614963565b60405180602001604052806146b1856000015185600001516146e9565b6000614862614963565b600080614877670de0b6b3a76400008761471f565b9092509050600082600381111561488a57fe5b146148a9575060408051602081019091526000815290925090506126b0565b6126a9818660000151613f64565b600083830182858210156148de5760405162461bcd60e51b815260040161094091906155c9565b50949350505050565b60008315806148f4575082155b1561490157506000611dc8565b8383028385828161490e57fe5b041483906148de5760405162461bcd60e51b815260040161094091906155c9565b600081836149505760405162461bcd60e51b815260040161094091906155c9565b5082848161495a57fe5b04949350505050565b6040518060200160405280600081525090565b6040805161010081019091528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805160c08101909152806000815260200160005b8152602001600081526020016000815260200160008152602001600081525090565b6040805160e0810190915280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805160a081019091528060008152602001600081526020016000815260200160008152602001600081525090565b6040805160a081019091528060006149d2565b8035610a1f816158ee565b600082601f830112614a9157600080fd5b8135614aa4614a9f8261584e565b615827565b91508181835260208401935060208101905083856020840282011115614ac957600080fd5b60005b83811015614af55781614adf8882614a75565b8452506020928301929190910190600101614acc565b5050505092915050565b8035610a1f81615905565b8051610a1f81615905565b8035610a1f8161590e565b8035610a1f81615917565b8051610a1f81615917565b600060208284031215614b4857600080fd5b6000610e1e8484614a75565b60008060408385031215614b6757600080fd5b6000614b738585614a75565b9250506020614b8485828601614a75565b9150509250929050565b600080600060608486031215614ba357600080fd5b6000614baf8686614a75565b9350506020614bc086828701614a75565b9250506040614bd186828701614b20565b9150509250925092565b60008060408385031215614bee57600080fd5b6000614bfa8585614a75565b9250506020614b8485828601614b20565b600060208284031215614c1d57600080fd5b813567ffffffffffffffff811115614c3457600080fd5b610e1e84828501614a80565b600060208284031215614c5257600080fd5b6000610e1e8484614aff565b600060208284031215614c7057600080fd5b6000610e1e8484614b0a565b600060208284031215614c8e57600080fd5b6000610e1e8484614b15565b600060208284031215614cac57600080fd5b6000610e1e8484614b20565b600060208284031215614cca57600080fd5b6000610e1e8484614b2b565b600080600060608486031215614ceb57600080fd5b6000614cf78686614b20565b9350506020614bc086828701614b20565b614d118161587c565b82525050565b614d1181615887565b614d118161588c565b614d11816158a9565b6000614d3d8261586f565b614d478185615873565b9350614d578185602086016158b4565b614d60816158e4565b9093019392505050565b6000614d77603b83615873565b7f52454445454d5f434f4c4c41544552414c535f4e45575f544f54414c5f434f4c81527f4c41544552414c535f43414c43554c4154494f4e5f4641494c45440000000000602082015260400192915050565b6000614dd6601683615873565b751858d8dc9d59481a5b9d195c995cdd0819985a5b195960521b815260200192915050565b6000614e08601883615873565b7f544f4b454e5f5452414e534645525f494e5f4641494c45440000000000000000815260200192915050565b6000614e41601f83615873565b7f62616c616e636520636f756c64206e6f742062652063616c63756c6174656400815260200192915050565b6000614e7a601a83615873565b7f544f4b454e5f5452414e534645525f494e5f4f564552464c4f57000000000000815260200192915050565b6000614eb3601983615873565b7f544f4b454e5f5452414e534645525f4f55545f4641494c454400000000000000815260200192915050565b6000614eec603483615873565b7f434f4c4c41544552414c495a455f4e45575f4143434f554e545f42414c414e438152731157d0d05310d55310551253d397d1905253115160621b602082015260400192915050565b6000614f42603383615873565b7f636f6c6c61746572616c5261746553746f7265643a20636f6c6c61746572616c81527214985d19525b9d195c9b985b0819985a5b1959606a1b602082015260400192915050565b6000614f97601c83615873565b7f6d61726b6572206d6574686f642072657475726e65642066616c736500000000815260200192915050565b6000614fd0602b83615873565b7f4d494e545f4e45575f4143434f554e545f42414c414e43455f43414c43554c4181526a151253d397d1905253115160aa1b602082015260400192915050565b600061501d603783615873565b7f626f72726f7742616c616e636553746f7265643a20626f72726f7742616c616e81527f636553746f726564496e7465726e616c206661696c6564000000000000000000602082015260400192915050565b600061507c602283615873565b7f63616e6e6f7420617070726f766520746f20746865207a65726f206164647265815261737360f01b602082015260400192915050565b60006150c0603583615873565b7f4c49515549444154455f424f52524f575f4e45575f544f54414c5f424f52524f81527415d4d7d0d05310d55310551253d397d19052531151605a1b602082015260400192915050565b6000615117603a83615873565b7f52455041595f424f52524f575f4e45575f4143434f554e545f424f52524f575f81527f42414c414e43455f43414c43554c4154494f4e5f4641494c4544000000000000602082015260400192915050565b6000615176602383615873565b7f4c49515549444154455f424f52524f575f5452414e534645525f494e5f46414981526213115160ea1b602082015260400192915050565b60006151bb601f83615873565b7f636f756c64206e6f742063616c63756c61746520626c6f636b2064656c746100815260200192915050565b60006151f4603183615873565b7f52455041595f424f52524f575f4e45575f544f54414c5f42414c414e43455f43815270105310d55310551253d397d19052531151607a1b602082015260400192915050565b6000615247600f83615873565b6e46524553484e4553535f434845434b60881b815260200192915050565b6000615272602083615873565b7f4d494e545f45584348414e47455f43414c43554c4154494f4e5f4641494c4544815260200192915050565b60006152ab603583615873565b7f65786368616e67655261746553746f7265643a2065786368616e67655261746581527414dd1bdc9959125b9d195c9b985b0819985a5b1959605a1b602082015260400192915050565b6000615302602883615873565b7f4d494e545f4e45575f544f54414c5f535550504c595f43414c43554c4154494f8152671397d1905253115160c21b602082015260400192915050565b600061534c603483615873565b7f6f6e65206f662072656465656d546f6b656e73496e206f722072656465656d418152736d6f756e74496e206d757374206265207a65726f60601b602082015260400192915050565b60006153a2601f83615873565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00815260200192915050565b60006153db603683615873565b7f434f4c4c41544552414c495a455f4e45575f544f54414c5f434f4c4c41544552815275105314d7d0d05310d55310551253d397d1905253115160521b602082015260400192915050565b6000615433601283615873565b7150455243454e544147455f4558434545445360701b815260200192915050565b614d1181610c7e565b614d11816158a3565b60208101610a1f8284614d08565b604081016154828285614d08565b611dc86020830184614d08565b6060810161549d8286614d08565b6154aa6020830185614d08565b610e1e6040830184615454565b608081016154c58287614d08565b6154d26020830186614d08565b6154df6040830185615454565b6154ec6060830184615454565b95945050505050565b60a081016155038288614d08565b6155106020830187614d08565b61551d6040830186615454565b61552a6060830185615454565b6155376080830184615454565b9695505050505050565b6040810161554f8285614d08565b611dc86020830184615454565b6060810161556a8286614d08565b6154aa6020830185615454565b608081016155858287614d08565b6154d26020830186615454565b60208101610a1f8284614d17565b60208101610a1f8284614d20565b604081016155bc8285614d20565b611dc86020830184614d20565b60208082528101611dc88184614d32565b60208082528101610a1f81614d6a565b60208082528101610a1f81614dc9565b60208082528101610a1f81614dfb565b60208082528101610a1f81614e34565b60208082528101610a1f81614e6d565b60208082528101610a1f81614ea6565b60208082528101610a1f81614edf565b60208082528101610a1f81614f35565b60208082528101610a1f81614f8a565b60208082528101610a1f81614fc3565b60208082528101610a1f81615010565b60208082528101610a1f8161506f565b60208082528101610a1f816150b3565b60208082528101610a1f8161510a565b60208082528101610a1f81615169565b60208082528101610a1f816151ae565b60208082528101610a1f816151e7565b60208082528101610a1f8161523a565b60208082528101610a1f81615265565b60208082528101610a1f8161529e565b60208082528101610a1f816152f5565b60208082528101610a1f8161533f565b60208082528101610a1f81615395565b60208082528101610a1f816153ce565b60208082528101610a1f81615426565b60208101610a1f8284615454565b6040810161554f8285615454565b606081016157948286615454565b6157a16020830185615454565b610e1e6040830184614d29565b6060810161556a8286615454565b608081016155858287615454565b60c081016157d88289615454565b6157e56020830188615454565b6157f26040830187615454565b6157ff6060830186615454565b61580c6080830185615454565b612edc60a0830184615454565b60208101610a1f828461545d565b60405181810167ffffffffffffffff8111828210171561584657600080fd5b604052919050565b600067ffffffffffffffff82111561586557600080fd5b5060209081020190565b5190565b90815260200190565b6000610a1f82615897565b151590565b6000610a1f8261587c565b6001600160a01b031690565b60ff1690565b6000610a1f82610c7e565b60005b838110156158cf5781810151838201526020016158b7565b838111156158de576000848401525b50505050565b601f01601f191690565b6158f78161587c565b811461590257600080fd5b50565b6158f781615887565b6158f78161588c565b6158f781610c7e56fea365627a7a72315820fe162c8ca51d2716e9ccef45430f6f5edb626940c809bcfa0508fb3e482d8caa6c6578706572696d656e74616cf564736f6c63430005110040

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

000000000000000000000000784ca62029caa80ee54fca4256100f720e89456900000000000000000000000022b475f3e93390b7e523873ad7073337f4e56c2c0000000000000000000000003c392c3fbe6ada6049373478a4f8dd668ab27b0c0000000000000000000000006ded0f2c886568fb4bb6f04f179093d3d167c9d7000000000000000000000000842738637f84b4dac335b832d9890cf8e11da214000000000000000000000000f8a90b87e5ed066f818b40fa6913ceef059dbee3000000000000000000000000e1e7731a5f262ba3ccf93cc98ff5d37d9566ea7e000000000000000000000000aed324f13ef9fd341eefcc301e7b3ec3097705cc000000000000000000000000f2d0b6165a336bd68b75e8a88fee041323040228000000000000000000000000913e8eeb3dcd3687218ec68b92b10c3ef9148425

-----Decoded View---------------
Arg [0] : interestRateModelAddress (address): 0x784cA62029CaA80Ee54fca4256100f720E894569
Arg [1] : eFILAddress_ (address): 0x22B475f3e93390b7E523873ad7073337f4E56C2c
Arg [2] : mFILAddress_ (address): 0x3C392C3FBE6ADA6049373478A4f8dD668Ab27b0C
Arg [3] : dflAddress_ (address): 0x6ded0F2c886568Fb4Bb6F04f179093D3D167c9D7
Arg [4] : reservesOwner_ (address): 0x842738637f84b4Dac335b832d9890cf8e11DA214
Arg [5] : uniswapAddress_ (address): 0xF8A90B87e5eD066F818b40FA6913CeEf059DBEE3
Arg [6] : minerLeagueAddress_ (address): 0xe1E7731a5f262Ba3cCf93cC98Ff5d37D9566EA7E
Arg [7] : operatorAddress_ (address): 0xAed324F13eF9fD341eEFCc301e7b3eC3097705CC
Arg [8] : technicalAddress_ (address): 0xf2D0B6165A336Bd68b75E8a88FEE041323040228
Arg [9] : undistributedAddress_ (address): 0x913e8EeB3dcD3687218eC68b92b10c3Ef9148425

-----Encoded View---------------
10 Constructor Arguments found :
Arg [0] : 000000000000000000000000784ca62029caa80ee54fca4256100f720e894569
Arg [1] : 00000000000000000000000022b475f3e93390b7e523873ad7073337f4e56c2c
Arg [2] : 0000000000000000000000003c392c3fbe6ada6049373478a4f8dd668ab27b0c
Arg [3] : 0000000000000000000000006ded0f2c886568fb4bb6f04f179093d3d167c9d7
Arg [4] : 000000000000000000000000842738637f84b4dac335b832d9890cf8e11da214
Arg [5] : 000000000000000000000000f8a90b87e5ed066f818b40fa6913ceef059dbee3
Arg [6] : 000000000000000000000000e1e7731a5f262ba3ccf93cc98ff5d37d9566ea7e
Arg [7] : 000000000000000000000000aed324f13ef9fd341eefcc301e7b3ec3097705cc
Arg [8] : 000000000000000000000000f2d0b6165a336bd68b75e8a88fee041323040228
Arg [9] : 000000000000000000000000913e8eeb3dcd3687218ec68b92b10c3ef9148425


Deployed Bytecode Sourcemap

44236:85670:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;44236:85670:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;69192:280;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;44978:26;;;:::i;:::-;;;;;;;;44388:51;;;:::i;:::-;;;;;;;;60467:316;;;;;;;;;:::i;:::-;;;;;;;;48488:29;;;:::i;92984:618::-;;;;;;;;;:::i;48951:29::-;;;:::i;48228:39::-;;;:::i;49045:33::-;;;:::i;48668:30::-;;;:::i;101365:376::-;;;;;;;;;:::i;45755:33::-;;;:::i;111846:426::-;;;;;;;;;:::i;64037:224::-;;;;;;;;;:::i;46346:23::-;;;:::i;66857:261::-;;;:::i;48764:31::-;;;:::i;119000:217::-;;;;;;;;;:::i;59802:195::-;;;;;;;;;:::i;93890:640::-;;;;;;;;;:::i;45281:27::-;;;:::i;48379:32::-;;;:::i;47368:28::-;;;:::i;44632:35::-;;;:::i;:::-;;;;;;;;61814:354;;;;;;;;;:::i;71554:88::-;;;:::i;122360:201::-;;;;;;;;;:::i;48844:35::-;;;:::i;49790:48::-;;;;;;;;;:::i;46129:24::-;;;:::i;47843:19::-;;;:::i;:::-;;;;;;;;46460:25;;;:::i;120150:205::-;;;;;;;;;:::i;49497:33::-;;;:::i;45876:30::-;;;:::i;61446:112::-;;;;;;;;;:::i;63554:192::-;;;:::i;83668:628::-;;;;;;;;;:::i;108545:442::-;;;:::i;:::-;;46242:25;;;:::i;70311:164::-;;;;;;;;;:::i;118171:167::-;;;;;;;;;:::i;123466:225::-;;;;;;;;;:::i;44515:39::-;;;:::i;64470:287::-;;;;;;;;;:::i;68726:215::-;;;;;;;;;:::i;62366:125::-;;;;;;;;;:::i;79850:535::-;;;;;;;;;:::i;75994:654::-;;;;;;;;;:::i;47592:35::-;;;:::i;71890:3757::-;;;:::i;59310:185::-;;;;;;;;;:::i;46011:23::-;;;:::i;63224:184::-;;;:::i;49906:42::-;;;;;;;;;:::i;49139:30::-;;;:::i;44889:26::-;;;:::i;109434:621::-;;;;;;;;;:::i;121248:209::-;;;;;;;;;:::i;97810:606::-;;;;;;;;;:::i;66423:185::-;;;:::i;70544:131::-;;;;;;;;;:::i;46403:23::-;;;:::i;108275:212::-;;;;;;;;;:::i;89032:564::-;;;;;;;;;:::i;114463:496::-;;;;;;;;;:::i;45079:28::-;;;:::i;49589:26::-;;;:::i;111243:410::-;;;;;;;;;:::i;82692:620::-;;;;;;;;;:::i;61113:143::-;;;;;;;;;:::i;124633:347::-;;;;;;;;;:::i;110333:721::-;;;:::i;108100:120::-;;;:::i;48578:33::-;;;:::i;116027:622::-;;;;;;;;;:::i;45408:42::-;;;:::i;45180:20::-;;;:::i;62903:161::-;;;:::i;112575:588::-;;;;;;;;;:::i;69192:280::-;69261:4;69279:13;69294:9;69310:32;69333:8;69310:22;:32::i;:::-;-1:-1:-1;69278:64:0;;-1:-1:-1;69278:64:0;-1:-1:-1;69368:18:0;;-1:-1:-1;69361:3:0;:25;;;;;;;;;69353:89;;;;-1:-1:-1;;;69353:89:0;;;;;;;;;;;;;;;;;69460:4;-1:-1:-1;;69192:280:0;;;;:::o;44978:26::-;;;-1:-1:-1;;;;;44978:26:0;;:::o;44388:51::-;;;;;;;;;;;;;;-1:-1:-1;;;44388:51:0;;;;:::o;60467:316::-;60535:4;-1:-1:-1;;;;;60560:21:0;;60552:68;;;;-1:-1:-1;;;60552:68:0;;;;;;;;;60645:10;60631:11;60666:23;;;:18;:23;;;;;;;;-1:-1:-1;;;;;60666:32:0;;;;;;;;;;;:41;;;60723:30;;60645:10;;60723:30;;;;60701:6;;60723:30;;;;;;;;;;60771:4;60764:11;;;60467:316;;;;;:::o;48488:29::-;;;-1:-1:-1;;;;;48488:29:0;;:::o;92984:618::-;93054:4;43173:1;43779:7;;:19;;43771:63;;;;-1:-1:-1;;;43771:63:0;;;;;;;;;43173:1;43912:7;:18;;;93082:16;:14;:16::i;:::-;93071:27;-1:-1:-1;93113:27:0;;93109:238;;93283:52;93294:3;93288:10;;;;;;;;93300:34;93283:4;:52::i;:::-;93276:59;;;;;93109:238;93394:11;:9;:11::i;:::-;93520:53;93537:10;93549;93561:11;93520:16;:53::i;:::-;-1:-1:-1;93511:62:0;-1:-1:-1;;43943:1:0;43129;44091:7;:22;92984:618;;-1:-1:-1;92984:618:0:o;48951:29::-;;;;:::o;48228:39::-;;;;:::o;49045:33::-;;;;:::o;48668:30::-;;;-1:-1:-1;;;;;48668:30:0;;:::o;101365:376::-;101439:4;43173:1;43779:7;;:19;;43771:63;;;;-1:-1:-1;;;43771:63:0;;;;;;;;;43173:1;43912:7;:18;;;101467:16;:14;:16::i;:::-;101456:27;-1:-1:-1;101498:27:0;;101494:119;;101549:52;101560:3;101554:10;;;;;;;101494:119;101660:11;:9;:11::i;:::-;101691:42;101712:10;101724:8;101691:20;:42::i;:::-;43129:1;44091:7;:22;101684:49;101365:376;-1:-1:-1;;;101365:376:0:o;45755:33::-;;;;:::o;111846:426::-;111980:5;;111912:4;;-1:-1:-1;;;;;111980:5:0;111966:10;:19;111962:108;;112009:49;112014:18;112034:23;112009:4;:49::i;:::-;112002:56;;;;111962:108;112086:13;;;;;;;;:31;;;;;;112082:143;;112134:13;:30;;-1:-1:-1;;112134:30:0;;;;;;;;;112184:29;;;;;;112134:30;;112184:29;;;;;;;;;;112082:143;112249:14;112237:27;111846:426;-1:-1:-1;;111846:426:0:o;64037:224::-;64115:4;43173:1;43779:7;;:19;;43771:63;;;;-1:-1:-1;;;43771:63:0;;;;;;;;;43173:1;43912:7;:18;;;64140:16;:14;:16::i;:::-;:40;64132:75;;;;-1:-1:-1;;;64132:75:0;;;;;;;;;64225:28;64245:7;64225:19;:28::i;:::-;43129:1;44091:7;:22;64218:35;64037:224;-1:-1:-1;;64037:224:0:o;46346:23::-;;;;:::o;66857:261::-;66908:4;66926:13;66941:11;66956:28;:26;:28::i;:::-;66925:59;;-1:-1:-1;66925:59:0;-1:-1:-1;67010:18:0;67003:3;:25;;;;;;;;;66995:91;;;;-1:-1:-1;;;66995:91:0;;;;;;;;;67104:6;-1:-1:-1;;66857:261:0;;:::o;48764:31::-;;;-1:-1:-1;;;;;48764:31:0;;:::o;119000:217::-;119094:4;43173:1;43779:7;;:19;;43771:63;;;;-1:-1:-1;;;43771:63:0;;;;;;;;;43173:1;43912:7;:18;119130:11;:9;:11::i;:::-;119159:50;119187:21;119159:27;:50::i;59802:195::-;59897:4;43173:1;43779:7;;:19;;43771:63;;;;-1:-1:-1;;;43771:63:0;;;;;;;;;43173:1;43912:7;:18;;;59921:44;59936:10;59948:3;59953;59958:6;59921:14;:44::i;:::-;43129:1;44091:7;:22;59921:68;;59802:195;-1:-1:-1;;;;59802:195:0:o;93890:640::-;93984:4;43173:1;43779:7;;:19;;43771:63;;;;-1:-1:-1;;;43771:63:0;;;;;;;;;43173:1;43912:7;:18;;;94012:16;:14;:16::i;:::-;94001:27;-1:-1:-1;94043:27:0;;94039:238;;94213:52;94224:3;94218:10;;;;;;;94213:52;94206:59;;;;;94039:238;94324:11;:9;:11::i;:::-;94450:51;94467:10;94479:8;94489:11;94450:16;:51::i;:::-;-1:-1:-1;43129:1:0;44091:7;:22;94441:60;93890:640;-1:-1:-1;;;;93890:640:0:o;45281:27::-;;;-1:-1:-1;;;;;45281:27:0;;:::o;48379:32::-;;;;:::o;47368:28::-;;;;:::o;44632:35::-;44665:2;44632:35;:::o;61814:354::-;61876:4;61893:23;;:::i;:::-;61919:38;;;;;;;;61934:21;:19;:21::i;:::-;61919:38;;-1:-1:-1;;;;;62033:20:0;;61969:14;62033:20;;;:13;:20;;;;;;61893:64;;-1:-1:-1;61969:14:0;;;62001:53;;61893:64;;62001:17;:53::i;:::-;61968:86;;-1:-1:-1;61968:86:0;-1:-1:-1;62081:18:0;62073:4;:26;;;;;;;;;62065:70;;;;-1:-1:-1;;;62065:70:0;;;;;;;;;62153:7;61814:354;-1:-1:-1;;;;61814:354:0:o;71554:88::-;71596:4;71620:14;:12;:14::i;:::-;71613:21;;71554:88;:::o;122360:201::-;122446:4;43173:1;43779:7;;:19;;43771:63;;;;-1:-1:-1;;;43771:63:0;;;;;;;;;43173:1;43912:7;:18;122482:11;:9;:11::i;:::-;122511:42;122535:17;122511:23;:42::i;48844:35::-;;;-1:-1:-1;;;;;48844:35:0;;:::o;49790:48::-;;;;;;;;;;;;;:::o;46129:24::-;;;;:::o;47843:19::-;;;-1:-1:-1;;;;;47843:19:0;;:::o;46460:25::-;;;;;;;;;:::o;120150:205::-;120238:4;43173:1;43779:7;;:19;;43771:63;;;;-1:-1:-1;;;43771:63:0;;;;;;;;;43173:1;43912:7;:18;120274:11;:9;:11::i;:::-;120303:44;120328:18;120303:24;:44::i;49497:33::-;;;;:::o;45876:30::-;;;;:::o;61446:112::-;-1:-1:-1;;;;;61530:20:0;61503:7;61530:20;;;:13;:20;;;;;;;61446:112::o;63554:192::-;63616:4;43173:1;43779:7;;:19;;43771:63;;;;-1:-1:-1;;;43771:63:0;;;;;;;;;43173:1;43912:7;:18;;;63641:16;:14;:16::i;:::-;:40;63633:75;;;;-1:-1:-1;;;63633:75:0;;;;;;;;;-1:-1:-1;63726:12:0;;43129:1;44091:7;:22;63554:192;:::o;83668:628::-;83744:4;43173:1;43779:7;;:19;;43771:63;;;;-1:-1:-1;;;43771:63:0;;;;;;;;;43173:1;43912:7;:18;;;83772:16;:14;:16::i;:::-;83761:27;-1:-1:-1;83803:27:0;;83799:238;;83973:52;83984:3;83978:10;;;;;;;83799:238;84084:11;:9;:11::i;:::-;84106:40;84128:10;84140:5;84106:21;:40::i;:::-;84248;84260:10;84272:1;84275:12;84248:11;:40::i;108545:442::-;43173:1;43779:7;;:19;;43771:63;;;;-1:-1:-1;;;43771:63:0;;;;;;;;;43173:1;43912:7;:18;;;108609:16;:14;:16::i;:::-;:40;108601:75;;;;-1:-1:-1;;;108601:75:0;;;;;;;;;108689:9;108701:14;:12;:14::i;:::-;108689:26;;108726:17;108753:13;;108746:4;:20;:43;;108785:4;108746:43;;;108769:13;;108746:43;108816:11;;108829:13;;108726:63;;-1:-1:-1;108802:55:0;;-1:-1:-1;;;;;108816:11:0;;;;108829:13;108726:63;108802:13;:55::i;:::-;108884:33;108889:13;;108904:12;108884:4;:33::i;:::-;108868:13;:49;108951:13;;108935:44;;;;;;-1:-1:-1;;;;;108951:13:0;;;;108966:12;;108935:44;;;;;;;;;;-1:-1:-1;;43129:1:0;44091:7;:22;108545:442::o;46242:25::-;;;;:::o;70311:164::-;70387:4;43173:1;43779:7;;:19;;43771:63;;;;-1:-1:-1;;;43771:63:0;;;;;;;;;43173:1;43912:7;:18;70404:11;:9;:11::i;:::-;70433:34;70458:8;70433:24;:34::i;118171:167::-;118240:4;118257:15;:13;:15::i;:::-;118290:40;118313:16;118290:22;:40::i;123466:225::-;123564:4;43173:1;43779:7;;:19;;43771:63;;;;-1:-1:-1;;;43771:63:0;;;;;;;;;43173:1;43912:7;:18;123600:11;:9;:11::i;:::-;123629:54;123659:23;123629:29;:54::i;44515:39::-;;;;;;;;;;;;;;-1:-1:-1;;;44515:39:0;;;;:::o;64470:287::-;64537:4;64555:13;64570:11;64585:36;64613:7;64585:27;:36::i;:::-;64554:67;;-1:-1:-1;64554:67:0;-1:-1:-1;64647:18:0;64640:3;:25;;;;;;;;;64632:93;;;;-1:-1:-1;;;64632:93:0;;;;;;;;68726:215;68793:4;;68818:16;:14;:16::i;:::-;:40;68810:75;;;;-1:-1:-1;;;68810:75:0;;;;;;;;;68903:30;68924:8;68903:20;:30::i;62366:125::-;-1:-1:-1;;;;;62456:27:0;62429:7;62456:27;;;:18;:27;;;;;;;62366:125::o;79850:535::-;79930:4;43173:1;43779:7;;:19;;43771:63;;;;-1:-1:-1;;;43771:63:0;;;;;;;;;43173:1;43912:7;:18;;;79958:16;:14;:16::i;:::-;79947:27;-1:-1:-1;79989:27:0;;79985:238;;80159:52;80170:3;80164:10;;;;;;;79985:238;80272:11;:9;:11::i;:::-;80305:51;80324:10;80336:19;80305:18;:51::i;75994:654::-;76056:4;43173:1;43779:7;;:19;;43771:63;;;;-1:-1:-1;;;43771:63:0;;;;;;;;;43173:1;43912:7;:18;;;76084:16;:14;:16::i;:::-;76073:27;-1:-1:-1;76115:27:0;;76111:238;;76285:52;76296:3;76290:10;;;;;;;76111:238;76398:11;:9;:11::i;:::-;76420:40;76442:10;76454:5;76420:21;:40::i;:::-;76586:33;76596:10;76608;76586:9;:33::i;47592:35::-;;;;:::o;71890:3757::-;71932:4;71998:23;72024:16;:14;:16::i;:::-;72082:18;;71998:42;;-1:-1:-1;72170:45:0;;;72166:105;;;72244:14;72232:27;;;;;;72166:105;72338:14;72355;:12;:14::i;:::-;72400:12;;72444:13;;72492:11;;72600:17;;:71;;-1:-1:-1;;;72600:71:0;;72338:31;;-1:-1:-1;72400:12:0;;72444:13;;72492:11;;72380:17;;-1:-1:-1;;;;;72600:17:0;;:31;;:71;;72338:31;;72400:12;;72444:13;;72600:71;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;72600:71:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;72600:71: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;72600:71:0;;;;;;;;;72574:97;;72762:17;72781:15;72800:52;72808:18;72828:23;72800:7;:52::i;:::-;72761:91;;-1:-1:-1;72761:91:0;-1:-1:-1;72882:18:0;72871:7;:29;;;;;;;;;72863:73;;;;-1:-1:-1;;;72863:73:0;;;;;;;;;73428:31;;:::i;:::-;73470:24;73505:20;73536:21;73568:19;73634:58;73644:35;;;;;;;;73659:18;73644:35;;;73681:10;73634:9;:58::i;:::-;73600:92;;-1:-1:-1;73600:92:0;-1:-1:-1;73718:18:0;73707:7;:29;;;;;;;;;73703:183;;73760:114;73771:16;73789:69;73865:7;73860:13;;;;;;;;73760:10;:114::i;:::-;73753:121;;;;;;;;;;;;;;;;;;73703:183;73931:53;73949:20;73971:12;73931:17;:53::i;:::-;73898:86;;-1:-1:-1;73898:86:0;-1:-1:-1;74010:18:0;73999:7;:29;;;;;;;;;73995:181;;74052:112;74063:16;74081:67;74155:7;74150:13;;;;;;;73995:181;74217:42;74225:19;74246:12;74217:7;:42::i;:::-;74188:71;;-1:-1:-1;74188:71:0;-1:-1:-1;74285:18:0;74274:7;:29;;;;;;;;;74270:178;;74327:109;74338:16;74356:64;74427:7;74422:13;;;;;;;74270:178;74490:100;74515:38;;;;;;;;74530:21;;74515:38;;;74555:19;74576:13;74490:24;:100::i;:::-;74460:130;;-1:-1:-1;74460:130:0;-1:-1:-1;74616:18:0;74605:7;:29;;;;;;;;;74601:179;;74658:110;74669:16;74687:65;74759:7;74754:13;;;;;;;74601:179;74820:82;74845:20;74867:16;74885;74820:24;:82::i;:::-;74792:110;;-1:-1:-1;74792:110:0;-1:-1:-1;74928:18:0;74917:7;:29;;;;;;;;;74913:177;;74970:108;74981:16;74999:63;75069:7;75064:13;;;;;;;74913:177;75293:18;:39;;;75343:11;:28;;;75382:12;:30;;;75423:13;:32;;;75520:79;;;;;;75535:9;;75546:19;;75357:14;;75397:15;;75520:79;;;;;;;;;;75624:14;75612:27;;;;;;;;;;;;;;;;71890:3757;:::o;59310:185::-;59388:4;43173:1;43779:7;;:19;;43771:63;;;;-1:-1:-1;;;43771:63:0;;;;;;;;;43173:1;43912:7;:18;;;59412:51;59427:10;59439;59451:3;59456:6;59412:14;:51::i;:::-;43129:1;44091:7;:22;59412:75;;59310:185;-1:-1:-1;;;59310:185:0:o;46011:23::-;;;;:::o;63224:184::-;63301:17;;63277:4;;-1:-1:-1;;;;;63301:17:0;:31;63333:14;:12;:14::i;:::-;63349:12;;63363:13;;63378:21;;63301:99;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;63301:99:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;63301:99: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;63301:99:0;;;;;;;;49906:42;;;;;;;;;;;;;:::o;49139:30::-;;;;:::o;44889:26::-;;;-1:-1:-1;;;;;44889:26:0;;:::o;109434:621::-;109571:5;;109503:4;;-1:-1:-1;;;;;109571:5:0;109557:10;:19;109553:108;;109600:49;109605:18;109625:23;109600:4;:49::i;109553:108::-;109760:12;;;-1:-1:-1;;;;;109843:30:0;;;-1:-1:-1;;;;;;109843:30:0;;;;;;109958:49;;109760:12;;;109958:49;;;;109760:12;;109858:15;;109958:49;;;;;;;;;;110032:14;110020:27;109434:621;-1:-1:-1;;;109434:621:0:o;121248:209::-;121338:4;43173:1;43779:7;;:19;;43771:63;;;;-1:-1:-1;;;43771:63:0;;;;;;;;;43173:1;43912:7;:18;121374:11;:9;:11::i;:::-;121403:46;121429:19;121403:25;:46::i;97810:606::-;97886:4;43173:1;43779:7;;:19;;43771:63;;;;-1:-1:-1;;;43771:63:0;;;;;;;;;43173:1;43912:7;:18;;;97914:16;:14;:16::i;:::-;97903:27;-1:-1:-1;97945:27:0;;97941:238;;98115:52;98126:3;98120:10;;;;;;;97941:238;98226:11;:9;:11::i;:::-;98361:47;98383:10;98395:12;98361:21;:47::i;66423:185::-;66470:4;;66495:16;:14;:16::i;:::-;:40;66487:75;;;;-1:-1:-1;;;66487:75:0;;;;;;;;;66580:20;:18;:20::i;70544:131::-;70609:4;70633:34;70658:8;70633:24;:34::i;46403:23::-;;;;;;:::o;108275:212::-;43173:1;43779:7;;:19;;43771:63;;;;-1:-1:-1;;;43771:63:0;;;;;;;;;43173:1;43912:7;:18;108350:11;:9;:11::i;:::-;108377:6;108372:108;108393:7;:14;108389:1;:18;108372:108;;;108429:39;108451:7;108459:1;108451:10;;;;;;;;;;;;;;108463:4;108429:21;:39::i;:::-;108409:3;;108372:108;;;-1:-1:-1;;43129:1:0;44091:7;:22;108275:212::o;89032:564::-;89098:4;43173:1;43779:7;;:19;;43771:63;;;;-1:-1:-1;;;43771:63:0;;;;;;;;;43173:1;43912:7;:18;;;89126:16;:14;:16::i;:::-;89115:27;-1:-1:-1;89157:27:0;;89153:238;;89327:52;89338:3;89332:10;;;;;;;89153:238;89438:11;:9;:11::i;:::-;89551:37;89563:10;89575:12;89551:11;:37::i;114463:496::-;114556:4;43173:1;43779:7;;:19;;43771:63;;;;-1:-1:-1;;;43771:63:0;;;;;;;;;43173:1;43912:7;:18;;;114586:16;:14;:16::i;:::-;114573:29;-1:-1:-1;114617:29:0;;114613:269;;114816:54;114827:5;114821:12;;;;;;;114613:269;114899:52;114924:26;114899:24;:52::i;45079:28::-;;;-1:-1:-1;;;;;45079:28:0;;:::o;49589:26::-;;;;:::o;111243:410::-;111373:5;;111305:4;;-1:-1:-1;;;;;111373:5:0;111359:10;:19;111355:108;;111402:49;111407:18;111427:23;111402:4;:49::i;111355:108::-;111479:11;;;;:27;;;;;;111475:131;;111523:11;:26;;-1:-1:-1;;111523:26:0;;;;;;;111569:25;;;;;;111523:26;;111569:25;;82692:620;82758:4;43173:1;43779:7;;:19;;43771:63;;;;-1:-1:-1;;;43771:63:0;;;;;;;;;43173:1;43912:7;:18;;;82786:16;:14;:16::i;:::-;82775:27;-1:-1:-1;82817:27:0;;82813:238;;82987:52;82998:3;82992:10;;;;;;;82813:238;83100:11;:9;:11::i;:::-;83122:40;83144:10;83156:5;83122:21;:40::i;:::-;83264;83276:10;83288:12;83302:1;83264:11;:40::i;61113:143::-;-1:-1:-1;;;;;61214:25:0;;;61187:7;61214:25;;;:18;:25;;;;;;;;:34;;;;;;;;;;;;;61113:143::o;124633:347::-;124838:4;43173:1;43779:7;;:19;;43771:63;;;;-1:-1:-1;;;43771:63:0;;;;;;;;;43173:1;43912:7;:18;124855:11;:9;:11::i;:::-;124884:88;124908:18;124928:22;124952:19;124884:23;:88::i;:::-;43129:1;44091:7;:22;124877:95;124633:347;-1:-1:-1;;;;124633:347:0:o;110333:721::-;110483:12;;110375:4;;-1:-1:-1;;;;;110483:12:0;110469:10;:26;;;:54;;-1:-1:-1;110499:10:0;:24;110469:54;110465:143;;;110547:49;110552:18;110572:23;110547:4;:49::i;:::-;110540:56;;;;110465:143;110692:5;;;110734:12;;;-1:-1:-1;;;;;110734:12:0;;;-1:-1:-1;;;;;;110807:20:0;;;;;;;;;110876:25;;;;;;110919;;110692:5;;;;110734:12;;110919:25;;;;110692:5;;110938;;;110919:25;;;;;;;;;;110993:12;;110960:46;;;;;;110976:15;;-1:-1:-1;;;;;110993:12:0;;110960:46;;;;;;;;;;111031:14;111019:27;;;;110333:721;:::o;108100:120::-;43173:1;43779:7;;:19;;43771:63;;;;-1:-1:-1;;;43771:63:0;;;;;;;;;43173:1;43912:7;:18;108151:11;:9;:11::i;:::-;108173:39;108195:10;108207:4;108173:21;:39::i;:::-;43129:1;44091:7;:22;108100:120::o;48578:33::-;;;-1:-1:-1;;;;;48578:33:0;;:::o;116027:622::-;116127:4;43173:1;43779:7;;:19;;43771:63;;;;-1:-1:-1;;;43771:63:0;;;;;;;;;43173:1;43912:7;:18;;;116157:16;:14;:16::i;:::-;116144:29;-1:-1:-1;116188:29:0;;116184:274;;116392:54;116403:5;116397:12;;;;;;;116184:274;116593:48;116620:20;116593:26;:48::i;45408:42::-;;;-1:-1:-1;;;;;45408:42:0;;:::o;45180:20::-;;;-1:-1:-1;;;;;45180:20:0;;:::o;62903:161::-;62980:17;;62956:4;;-1:-1:-1;;;;;62980:17:0;:31;63012:14;:12;:14::i;:::-;63028:12;;63042:13;;62980:76;;;;;;;;;;;;;;;;;;112575:588;112664:4;43173:1;43779:7;;:19;;43771:63;;;;-1:-1:-1;;;43771:63:0;;;;;;;;;43173:1;43912:7;:18;;;112694:16;:14;:16::i;:::-;112681:29;-1:-1:-1;112725:29:0;;112721:267;;112922:54;112933:5;112927:12;;;;;;;112721:267;113107:48;113130:24;113107:22;:48::i;69480:762::-;69553:9;69564:4;69570;69576;69593:17;69621:20;69652:24;69687:25;;:::i;:::-;69754:37;69782:8;69754:27;:37::i;:::-;69725:66;;-1:-1:-1;69725:66:0;-1:-1:-1;69817:18:0;69806:7;:29;;;;;;;;;69802:87;;-1:-1:-1;69860:7:0;;-1:-1:-1;69869:1:0;;-1:-1:-1;69869:1:0;;-1:-1:-1;69869:1:0;;-1:-1:-1;69852:25:0;;-1:-1:-1;;69852:25:0;69802:87;-1:-1:-1;;;;;69923:28:0;;;;;;:18;:28;;;;;;;-1:-1:-1;69990:44:0;69997:15;69923:28;69990:6;:44::i;:::-;69962:72;;-1:-1:-1;69962:72:0;-1:-1:-1;70060:18:0;70049:7;:29;;;;;;;;;70045:87;;-1:-1:-1;70103:7:0;;-1:-1:-1;70112:1:0;;-1:-1:-1;70112:1:0;;-1:-1:-1;70112:1:0;;-1:-1:-1;70095:25:0;;-1:-1:-1;;70095:25:0;70045:87;70172:23;70152:18;;-1:-1:-1;70172:23:0;-1:-1:-1;70197:15:0;;-1:-1:-1;70214:19:0;-1:-1:-1;;69480:762:0;;;;;;:::o;3052:153::-;3113:4;3135:33;3148:3;3143:9;;;;;;;;3159:4;3154:10;;;;;;;;3166:1;3135:33;;;;;;;;;;;;;;;;;3193:3;3188:9;;;;;;;;3181:16;3052:153;-1:-1:-1;;;3052:153:0:o;104164:981::-;104229:21;;;104205;104336:16;:14;:16::i;:::-;104310:42;;104363:681;104387:18;104370:14;:35;104363:681;;;48162:10;104426:12;;:23;104422:69;;;104470:5;;104422:69;104526:14;104507:33;;104580:20;;104559:18;:41;104555:195;;;104638:18;104621:35;;104555:195;;;104714:20;;104697:37;;104555:195;104766:64;104797:16;104815:14;104766:30;:64::i;:::-;104869:20;;104851:14;:38;104847:186;;;104933:20;;;48081:6;104933:34;104910:57;;105001:12;;105016:1;;105001:16;104986:12;:31;104847:186;104363:681;;;105095:21;:42;-1:-1:-1;;104164:981:0:o;95235:2270::-;95330:4;95336;95353:32;;:::i;:::-;-1:-1:-1;;;;;95499:24:0;;;;;;:14;:24;;;;;:38;;;95478:18;;;:59;95668:37;95514:8;95668:27;:37::i;:::-;95645:19;;;95630:75;;;95631:12;;;95630:75;;;;;;;;;;;;;;;;;;;-1:-1:-1;95736:18:0;;-1:-1:-1;95720:4:0;:12;;;:34;;;;;;;;;95716:192;;95779:113;95790:16;95808:63;95878:4;:12;;;95873:18;;;;;;;95779:113;95771:125;-1:-1:-1;95894:1:0;;-1:-1:-1;95771:125:0;;-1:-1:-1;95771:125:0;95716:192;-1:-1:-1;;95990:11:0;:23;95986:157;;;96049:19;;;;96030:16;;;:38;95986:157;;;96101:16;;;:30;;;95986:157;96312:11;;96332:16;;;;96299:50;;-1:-1:-1;;;;;96312:11:0;;96325:5;;96299:12;:50::i;:::-;96274:22;;;:75;;;96659:19;;;;96651:52;;:7;:52::i;:::-;96625:22;;;96610:93;;;96611:12;;;96610:93;;;;;;;;;;;;;;;;;;;-1:-1:-1;96738:18:0;;-1:-1:-1;96722:4:0;:12;;;:34;;;;;;;;;96714:105;;;;-1:-1:-1;;;96714:105:0;;;;;;;;;96871:45;96879:12;;96893:4;:22;;;96871:7;:45::i;:::-;96847:20;;;96832:84;;;96833:12;;;96832:84;;;;;;;;;;;;;;;;;;;-1:-1:-1;96951:18:0;;-1:-1:-1;96935:4:0;:12;;;:34;;;;;;;;;96927:96;;;;-1:-1:-1;;;96927:96:0;;;;;;;;;97143:22;;;;;-1:-1:-1;;;;;97106:24:0;;;;;;:14;:24;;;;;;;:59;;;97217:11;;97176:38;;;;:52;;;;97254:20;;;;97239:12;:35;;;97364:22;;;;97388;;97335:98;;;;;;97347:5;;97121:8;;97335:98;;;;;;;;;;97474:22;;;97457:14;;-1:-1:-1;97474:22:0;-1:-1:-1;95235:2270:0;;;;;;;:::o;102278:1838::-;-1:-1:-1;;;;;102416:30:0;;102364:4;102416:30;;;:18;:30;;;;;;:35;;;:69;;-1:-1:-1;;;;;;102455:25:0;;;;;;:13;:25;;;;;;:30;;102416:69;102412:170;;;102509:61;102514:15;102531:38;102509:4;:61::i;:::-;102502:68;;;;102412:170;102594:36;;:::i;:::-;102727:32;102750:8;102727:22;:32::i;:::-;102700:23;;;102643:116;;;102679:19;;;102643:116;;;102658:19;;;102643:116;;;102644:12;;;102643:116;;;;;;;;;;;;;;;;;;;-1:-1:-1;102790:18:0;;-1:-1:-1;102774:34:0;;-1:-1:-1;;102774:34:0;;:4;:12;;;:34;;;;;;;;;102770:187;;102832:113;102843:16;102861:63;102931:4;:12;;;102926:18;;;;;;;102832:113;102825:120;;;;;102770:187;102995:23;;102973:4;:19;;;:45;102969:150;;;103042:65;103047:15;103064:42;103042:4;:65::i;102969:150::-;103320:19;;;;103271:11;;103258:58;;-1:-1:-1;;;;;103271:11:0;103284:10;103320:19;103258:12;:58::i;:::-;:81;103250:129;;;;-1:-1:-1;;;103250:129:0;;;;;;;;;103431:42;103439:12;;103453:4;:19;;;103431:7;:42::i;:::-;103407:20;;;103392:81;;;103393:12;;;103392:81;;;;;;;;;;;;;;;;;;;-1:-1:-1;103508:18:0;;-1:-1:-1;103492:4:0;:12;;;:34;;;;;;;;;103484:100;;;;-1:-1:-1;;;103484:100:0;;;;;;;;;-1:-1:-1;;;;;103667:24:0;;;103704:1;103667:24;;;:14;:24;;;;;;;;:38;;;103757:11;;103716:38;;;;:52;103794:20;;;;103779:12;:35;103827:18;:28;;;;;;:32;;;103903:23;;;;;103870:30;;;;;;;;;:56;;;;104025:19;;;;104046:23;;103987:83;;;;;;103889:10;;103682:8;;104046:23;103987:83;;;;;;;;;;104093:14;104081:27;102278:1838;-1:-1:-1;;;;102278:1838:0:o;67381:1186::-;67490:11;;67442:9;;;;67516:17;67512:1048;;67690:18;45630:8;67682:56;;;;;;;67512:1048;67920:14;67937;:12;:14::i;:::-;67920:31;;67966:33;68014:23;;:::i;:::-;68052:17;68128:54;68143:9;68154:12;;68168:13;;68128:14;:54::i;:::-;68086:96;-1:-1:-1;68086:96:0;-1:-1:-1;68212:18:0;68201:7;:29;;;;;;;;;68197:89;;68259:7;-1:-1:-1;68268:1:0;;-1:-1:-1;68251:19:0;;-1:-1:-1;;;;68251:19:0;68197:89;68328:50;68335:28;68365:12;68328:6;:50::i;:::-;68302:76;-1:-1:-1;68302:76:0;-1:-1:-1;68408:18:0;68397:7;:29;;;;;;;;;68393:89;;68455:7;-1:-1:-1;68464:1:0;;-1:-1:-1;68447:19:0;;-1:-1:-1;;;;68447:19:0;68393:89;-1:-1:-1;68526:21:0;68506:18;;-1:-1:-1;68526:21:0;-1:-1:-1;68498:50:0;;-1:-1:-1;;;68498:50:0;67381:1186;;;:::o;119225:726::-;119346:18;;119311:4;;-1:-1:-1;;;;;119346:18:0;119332:10;:32;119328:127;;119388:55;119393:18;119413:29;119388:4;:55::i;119328:127::-;119512:18;;-1:-1:-1;;;;;119512:18:0;119501:30;;;;:10;:30;;;;;;:35;119497:204;;119575:8;;119586:18;;-1:-1:-1;;;;;119586:18:0;;;119575:8;119606:30;;;:10;:30;;;;;;119553:84;;119575:8;;;;;119553:13;:84::i;:::-;119670:18;;-1:-1:-1;;;;;119670:18:0;119659:30;;;;:10;:30;;;;;119652:37;119497:204;119745:18;;;-1:-1:-1;;;;;119774:42:0;;;-1:-1:-1;;;;;;119774:42:0;;;;;;119834:71;;119745:18;;;119834:71;;;;119745:18;;119795:21;;119834:71;;57023:2026;57121:4;57192:3;-1:-1:-1;;;;;57185:10:0;:3;-1:-1:-1;;;;;57185:10:0;;:31;;;-1:-1:-1;;;;;;57199:17:0;;;57185:31;57181:126;;;57240:55;57245:15;57262:32;57240:4;:55::i;:::-;57233:62;;;;57181:126;57356:11;:9;:11::i;:::-;57378:33;57400:3;57405:5;57378:21;:33::i;:::-;57422;57444:3;57449:5;57422:21;:33::i;:::-;57533:22;-1:-1:-1;;;;;57574:14:0;;;;;;;57570:160;;;-1:-1:-1;;;57570:160:0;;;-1:-1:-1;;;;;;57686:23:0;;;;;;;:18;:23;;;;;;;;:32;;;;;;;;;;57570:160;57808:17;57836;57864;57892;57948:34;57956:17;57975:6;57948:7;:34::i;:::-;57922:60;;-1:-1:-1;57922:60:0;-1:-1:-1;58008:18:0;57997:7;:29;;;;;;;;;57993:125;;58050:56;58055:16;58073:32;58050:4;:56::i;:::-;58043:63;;;;;;;;;57993:125;-1:-1:-1;;;;;58164:18:0;;;;;;:13;:18;;;;;;58156:35;;58184:6;58156:7;:35::i;:::-;58130:61;;-1:-1:-1;58130:61:0;-1:-1:-1;58217:18:0;58206:7;:29;;;;;;;;;58202:124;;58259:55;58264:16;58282:31;58259:4;:55::i;58202:124::-;-1:-1:-1;;;;;58372:18:0;;;;;;:13;:18;;;;;;58364:35;;58392:6;58364:7;:35::i;:::-;58338:61;;-1:-1:-1;58338:61:0;-1:-1:-1;58425:18:0;58414:7;:29;;;;;;;;;58410:122;;58467:53;58472:16;58490:29;58467:4;:53::i;58410:122::-;-1:-1:-1;;;;;58665:18:0;;;;;;;:13;:18;;;;;;:33;;;58709:18;;;;;;:33;;;-1:-1:-1;;58815:29:0;;58811:109;;-1:-1:-1;;;;;58861:23:0;;;;;;;:18;:23;;;;;;;;:32;;;;;;;;;:47;;;58811:109;58991:3;-1:-1:-1;;;;;58977:26:0;58986:3;-1:-1:-1;;;;;58977:26:0;;58996:6;58977:26;;;;;;;;;;;;;;;-1:-1:-1;59026:14:0;;57023:2026;-1:-1:-1;;;;;;;;;57023:2026:0:o;13896:313::-;13973:9;13984:4;14002:13;14017:18;;:::i;:::-;14039:20;14049:1;14052:6;14039:9;:20::i;:::-;14001:58;;-1:-1:-1;14001:58:0;-1:-1:-1;14081:18:0;14074:3;:25;;;;;;;;;14070:73;;-1:-1:-1;14124:3:0;-1:-1:-1;14129:1:0;;-1:-1:-1;14116:15:0;;14070:73;14163:18;14183:17;14192:7;14183:8;:17::i;:::-;14155:46;;;;;;13896:313;;;;;;:::o;126132:170::-;126234:11;;126264:30;;-1:-1:-1;;;126264:30:0;;126179:4;;-1:-1:-1;;;;;126234:11:0;;;;126264:15;;:30;;126288:4;;126264:30;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;126264:30:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;126264:30: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;126264:30:0;;;;;;;;122569:688;122715:5;;122647:4;;-1:-1:-1;;;;;122715:5:0;122701:10;:19;122697:108;;122744:49;122749:18;122769:23;122744:4;:49::i;122697:108::-;122862:14;;-1:-1:-1;;;;;122862:14:0;122851:26;;;;:10;:26;;;;;;:31;122847:188;;122921:8;;122932:14;;-1:-1:-1;;;;;122932:14:0;;;122921:8;122948:26;;;:10;:26;;;;;;122899:76;;122921:8;;;;;122899:13;:76::i;:::-;123008:14;;-1:-1:-1;;;;;123008:14:0;122997:26;;;;:10;:26;;;;;122990:33;122847:188;123075:14;;;-1:-1:-1;;;;;123100:34:0;;;-1:-1:-1;;;;;;123100:34:0;;;;;;123152:59;;123075:14;;;123152:59;;;;123075:14;;123117:17;;123152:59;;120363:684;120478:15;;120443:4;;-1:-1:-1;;;;;120478:15:0;120464:10;:29;120460:124;;120517:55;120522:18;120542:29;120517:4;:55::i;120460:124::-;120641:15;;-1:-1:-1;;;;;120641:15:0;120630:27;;;;:10;:27;;;;;;:32;120626:192;;120701:8;;120712:15;;-1:-1:-1;;;;;120712:15:0;;;120701:8;120729:27;;;:10;:27;;;;;;120679:78;;120701:8;;;;;120679:13;:78::i;:::-;120790:15;;-1:-1:-1;;;;;120790:15:0;120779:27;;;;:10;:27;;;;;120772:34;120626:192;120859:15;;;-1:-1:-1;;;;;120885:36:0;;;-1:-1:-1;;;;;;120885:36:0;;;;;;120939:62;;120859:15;;;120939:62;;;;120859:15;;120903:18;;120939:62;;107052:552;107245:16;:14;:16::i;:::-;107220:21;;:41;107212:69;;;;-1:-1:-1;;;107212:69:0;;;;;;;;;107292:20;107315:34;107340:8;107315:24;:34::i;:::-;107292:57;;107385:77;107397:8;107407:15;107424:13;:37;;49423:6;107424:37;;;107440:1;107424:37;107385:11;:77::i;:::-;-1:-1:-1;;;;;107362:20:0;;;;;;:10;:20;;;;;;;;:100;;;107502:14;;107473:16;:26;;;;;;:43;;;;107575:20;;;107532:64;;;;;;107373:8;;107557:38;;;107532:64;;;;;;;;;;107052:552;;;:::o;85185:3579::-;85284:4;85309:19;;;:42;;-1:-1:-1;85332:19:0;;85309:42;85301:107;;;;-1:-1:-1;;;85301:107:0;;;;;;;;;85421:27;;:::i;:::-;85565:28;:26;:28::i;:::-;85536:25;;;85521:72;;;85522:12;;;85521:72;;;;;;;;;;;;;;;;;;;-1:-1:-1;85624:18:0;;-1:-1:-1;85608:4:0;:12;;;:34;;;;;;;;;85604:168;;85666:94;85677:16;85695:44;85746:4;:12;;;85741:18;;;;;;;85666:94;85659:101;;;;;85604:168;85826:18;;85822:1290;;86102:17;;;:34;;;86207:42;;;;;;;;86222:25;;;;86207:42;;86189:77;;86122:14;86189:17;:77::i;:::-;86168:17;;;86153:113;;;86154:12;;;86153:113;;;;;;;;;;;;;;;;;;;-1:-1:-1;86301:18:0;;-1:-1:-1;86285:4:0;:12;;;:34;;;;;;;;;86281:185;;86347:103;86358:16;86376:53;86436:4;:12;;;86431:18;;;;;;;86281:185;85822:1290;;;86768:82;86791:14;86807:42;;;;;;;;86822:4;:25;;;86807:42;;;86768:22;:82::i;:::-;86747:17;;;86732:118;;;86733:12;;;86732:118;;;;;;;;;;;;;;;;;;;-1:-1:-1;86885:18:0;;-1:-1:-1;86869:4:0;:12;;;:34;;;;;;;;;86865:185;;86931:103;86942:16;86960:53;87020:4;:12;;;87015:18;;;;;;;86865:185;87066:17;;;:34;;;85822:1290;87407:39;87415:11;;87428:4;:17;;;87407:7;:39::i;:::-;87384:19;;;87369:77;;;87370:12;;;87369:77;;;;;;;;;;;;;;;;;;;-1:-1:-1;87477:18:0;;-1:-1:-1;87461:4:0;:12;;;:34;;;;;;;;;87457:178;;87519:104;87530:16;87548:54;87609:4;:12;;;87604:18;;;;;;;87457:178;-1:-1:-1;;;;;87695:23:0;;;;;;:13;:23;;;;;;87720:17;;;;87687:51;;87695:23;87687:7;:51::i;:::-;87662:21;;;87647:91;;;87648:12;;;87647:91;;;;;;;;;;;;;;;;;;;-1:-1:-1;87769:18:0;;-1:-1:-1;87753:4:0;:12;;;:34;;;;;;;;;87749:181;;87811:107;87822:16;87840:57;87904:4;:12;;;87899:18;;;;;;;87749:181;88028:4;:17;;;88011:14;:12;:14::i;:::-;:34;88007:155;;;88069:81;88074:29;88105:44;88069:4;:81::i;88007:155::-;88307:11;;88330:17;;;;88293:55;;-1:-1:-1;;;;;88307:11:0;;88320:8;;88293:13;:55::i;:::-;88441:19;;;;88427:11;:33;88497:21;;;;-1:-1:-1;;;;;88471:23:0;;;;;;:13;:23;;;;;;;:47;;;;88630:17;;;;88596:52;;88623:4;;88596:52;;;;88630:17;88596:52;;;;;;;;;;88681:17;;;;88700;;;;88664:54;;;;;;88671:8;;88664:54;;;;;;;;;;-1:-1:-1;88741:14:0;;85185:3579;-1:-1:-1;;;;85185:3579:0:o;128987:916::-;129157:26;;-1:-1:-1;;;129157:26:0;;129135:10;;-1:-1:-1;;;;;129157:14:0;;;;;:26;;129172:2;;129176:6;;129157:26;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;129157:26:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;129157:26:0;;;;129196:12;129250:16;129289:1;129284:152;;;;129459:2;129454:219;;;;129808:1;129805;129798:12;129284:152;-1:-1:-1;;129379:6:0;-1:-1:-1;129284:152:0;;129454:219;129556:2;129553:1;129550;129535:24;129598:1;129592:8;129581:19;;129243:586;;129858:7;129850:45;;;;-1:-1:-1;;;129850:45:0;;;;;;;;;128987:916;;;;;:::o;21078:120::-;21131:4;21155:35;21160:1;21163;21155:35;;;;;;;;;;;;;-1:-1:-1;;;21155:35:0;;;:4;:35::i;70746:645::-;70820:4;70837:25;;:::i;:::-;70865:34;;;;;;;;70883:14;;70865:34;;;70837:62;;70910:27;;:::i;:::-;-1:-1:-1;70940:46:0;;;;;;;;;-1:-1:-1;;;;;70958:26:0;;-1:-1:-1;70958:26:0;;;:16;:26;;;;;;;;70940:46;;;71001:27;:55;;;;-1:-1:-1;71032:20:0;;:24;;71001:55;70997:134;;;49706:4;71073:46;;70997:134;71143:24;;:::i;:::-;71170:32;71175:11;71188:13;71170:4;:32::i;:::-;-1:-1:-1;;;;;71239:23:0;;71213:18;71239:23;;;:13;:23;;;;;;71143:59;;-1:-1:-1;71213:18:0;71234:41;;71143:59;71234:4;:41::i;:::-;-1:-1:-1;;;;;71314:20:0;;71286;71314;;;:10;:20;;;;;;71213:62;;-1:-1:-1;71286:20:0;71309:41;;71213:62;71309:4;:41::i;:::-;71286:64;70746:645;-1:-1:-1;;;;;;;70746:645:0:o;118346:449::-;118490:5;;118422:4;;-1:-1:-1;;;;;118490:5:0;118476:10;:19;118472:108;;118519:49;118524:18;118544:23;118519:4;:49::i;118472:108::-;118619:13;;;-1:-1:-1;;;;;118643:32:0;;;-1:-1:-1;;;;;;118643:32:0;;;;;;118693:56;;118619:13;;;118693:56;;;;118619:13;;118659:16;;118693:56;;123699:781;123857:5;;123789:4;;-1:-1:-1;;;;;123857:5:0;123843:10;:19;123839:108;;123886:49;123891:18;123911:23;123886:4;:49::i;123839:108::-;124019:20;;-1:-1:-1;;;;;124019:20:0;124008:32;;;;:10;:32;;;;;;:37;124004:212;;124084:8;;124095:20;;-1:-1:-1;;;;;124095:20:0;;;124084:8;124117:32;;;:10;:32;;;;;;124062:88;;124084:8;;;;;124062:13;:88::i;:::-;124183:20;;-1:-1:-1;;;;;124183:20:0;124172:32;;;;:10;:32;;;;;124165:39;124004:212;124262:20;;;-1:-1:-1;;;;;124293:46:0;;;-1:-1:-1;;;;;;124293:46:0;;;;;;124357:77;;124262:20;;;124357:77;;;;124262:20;;124316:23;;124357:77;;65011:1257;-1:-1:-1;;;;;65349:23:0;;65088:9;65349:23;;;:14;:23;;;;;65578:24;;65088:9;;;;;;;;65574:92;;-1:-1:-1;65632:18:0;;-1:-1:-1;65632:18:0;;-1:-1:-1;65624:30:0;;-1:-1:-1;;;65624:30:0;65574:92;65893:46;65901:14;:24;;;65927:11;;65893:7;:46::i;:::-;65860:79;;-1:-1:-1;65860:79:0;-1:-1:-1;65965:18:0;65954:7;:29;;;;;;;;;65950:81;;-1:-1:-1;66008:7:0;;-1:-1:-1;66017:1:0;;-1:-1:-1;66000:19:0;;-1:-1:-1;;66000:19:0;65950:81;66063:58;66071:19;66092:14;:28;;;66063:7;:58::i;:::-;66043:78;;-1:-1:-1;66043:78:0;-1:-1:-1;66147:18:0;66136:7;:29;;;;;;;;;66132:81;;-1:-1:-1;66190:7:0;;-1:-1:-1;66199:1:0;;-1:-1:-1;66182:19:0;;-1:-1:-1;;66182:19:0;66132:81;-1:-1:-1;66233:18:0;;-1:-1:-1;66253:6:0;-1:-1:-1;;;65011:1257:0;;;;:::o;80922:1419::-;-1:-1:-1;;;;;81045:29:0;;81018:4;81045:29;;;:13;:29;;;;;;81018:4;;81045:34;81041:137;;81104:58;81109:15;81126:35;81104:4;:58::i;:::-;81096:70;-1:-1:-1;81164:1:0;;-1:-1:-1;81096:70:0;;81041:137;81190:34;;:::i;:::-;81402:11;;81389:62;;-1:-1:-1;;;;;81402:11:0;81415:14;81431:19;81389:12;:62::i;:::-;81356:30;;;:95;;;81515:16;;81507:57;;:7;:57::i;:::-;81479:24;;;81464:100;;;81465:12;;;81464:100;;;;;;;;;;;;;;;;;;;-1:-1:-1;81599:18:0;;-1:-1:-1;81583:4:0;:12;;;:34;;;;;;;;;81575:101;;;;-1:-1:-1;;;81575:101:0;;;;;;;;;-1:-1:-1;;;;;81742:34:0;;;;;;:18;:34;;;;;;81778:30;;;;81734:75;;81742:34;81734:7;:75::i;:::-;81704:26;;;81689:120;;;81690:12;;;81689:120;;;;;;;;;;;;;;;;;;;-1:-1:-1;81844:18:0;;-1:-1:-1;81828:4:0;:12;;;:34;;;;;;;;;81820:99;;;;-1:-1:-1;;;81820:99:0;;;;;;;;;82017:24;;;;;81998:16;:43;82089:26;;;;-1:-1:-1;;;;;82052:34:0;;;;;;:18;:34;;;;;:63;82230:30;;;;82200:61;;;;;;82071:14;;82230:30;82200:61;;;;;;;;;;82302:30;;;82285:14;;82302:30;;-1:-1:-1;80922:1419:0;-1:-1:-1;;;80922:1419:0:o;77347:2217::-;77445:11;;77417:4;;;;77445:11;;77444:12;;:47;;-1:-1:-1;;;;;;77460:26:0;;;;;;:18;:26;;;;;;:31;;77444:47;77440:141;;;77516:49;77521:15;77538:26;77516:4;:49::i;77440:141::-;77593:25;;:::i;:::-;77675:28;:26;:28::i;:::-;77646:25;;;77631:72;;;77632:12;;;77631:72;;;;;;;;;;;;;;;;;;;-1:-1:-1;77734:18:0;;-1:-1:-1;77718:4:0;:12;;;:34;;;;;;;;;77714:171;;77777:92;77788:16;77806:42;77855:4;:12;;;77850:18;;;;;;;77777:92;77769:104;-1:-1:-1;77871:1:0;;-1:-1:-1;77769:104:0;;-1:-1:-1;77769:104:0;77714:171;78053:11;;78040:45;;-1:-1:-1;;;;;78053:11:0;78066:6;78074:10;78040:12;:45::i;:::-;78016:21;;;:69;;;78358:42;;;;;;;;78373:25;;;;78358:42;;78312:89;;78016:69;78312:22;:89::i;:::-;78293:15;;;78278:123;;;78279:12;;;78278:123;;;;;;;;;;;;;;;;;;;-1:-1:-1;78436:18:0;;-1:-1:-1;78420:4:0;:12;;;:34;;;;;;;;;78412:79;;;;-1:-1:-1;;;78412:79:0;;;;;;;;;78795:37;78803:11;;78816:4;:15;;;78795:7;:37::i;:::-;78772:19;;;78757:75;;;78758:12;;;78757:75;;;;;;;;;;;;;;;;;;;-1:-1:-1;78867:18:0;;-1:-1:-1;78851:4:0;:12;;;:34;;;;;;;;;78843:87;;;;-1:-1:-1;;;78843:87:0;;;;;;;;;-1:-1:-1;;;;;78991:21:0;;;;;;:13;:21;;;;;;79014:15;;;;78983:47;;78991:21;78983:7;:47::i;:::-;78958:21;;;78943:87;;;78944:12;;;78943:87;;;;;;;;;;;;;;;;;;;-1:-1:-1;79065:18:0;;-1:-1:-1;79049:4:0;:12;;;:34;;;;;;;;;79041:90;;;;-1:-1:-1;;;79041:90:0;;;;;;;;;79224:19;;;;79210:11;:33;79278:21;;;;-1:-1:-1;;;;;79254:21:0;;;;;;:13;:21;;;;;;;:45;;;;79388:21;;;;79411:15;;;;79375:52;;;;;;79268:6;;79388:21;;79411:15;79375:52;;;;;;;;;;79467:6;-1:-1:-1;;;;;79443:48:0;79460:4;-1:-1:-1;;;;;79443:48:0;;79475:4;:15;;;79443:48;;;;;;;;;;;;;;;79534:21;;;79517:14;;79534:21;;-1:-1:-1;77347:2217:0;-1:-1:-1;;;77347:2217:0:o;62650:93::-;62723:12;62650:93;:::o;10348:236::-;10404:9;10415:4;10441:1;10436;:6;10432:145;;-1:-1:-1;10467:18:0;;-1:-1:-1;10487:5:0;;;10459:34;;10432:145;-1:-1:-1;10534:27:0;;-1:-1:-1;10563:1:0;10526:39;;13430:353;13499:9;13510:10;;:::i;:::-;13534:14;13550:19;13573:27;13581:1;:10;;;13593:6;13573:7;:27::i;:::-;13533:67;;-1:-1:-1;13533:67:0;-1:-1:-1;13623:18:0;13615:4;:26;;;;;;;;;13611:92;;-1:-1:-1;13672:18:0;;;;;;;;;-1:-1:-1;13672:18:0;;13666:4;;-1:-1:-1;13672:18:0;-1:-1:-1;13658:33:0;;13611:92;13743:31;;;;;;;;;;;;-1:-1:-1;;13743:31:0;;-1:-1:-1;13430:353:0;-1:-1:-1;;;;13430:353:0:o;3328:187::-;3413:4;3435:43;3448:3;3443:9;;;;;;;;3459:4;3454:10;;;;;;;;3466:11;3435:43;;;;;;;;;;;;;;;;;3503:3;3498:9;;;;;;;10669:258;10725:9;;10762:5;;;10784:6;;;10780:140;;10815:18;;-1:-1:-1;10835:1:0;-1:-1:-1;10807:30:0;;10780:140;-1:-1:-1;10878:26:0;;-1:-1:-1;10906:1:0;;-1:-1:-1;10870:38:0;;14354:328;14451:9;14462:4;14480:13;14495:18;;:::i;:::-;14517:20;14527:1;14530:6;14517:9;:20::i;:::-;14479:58;;-1:-1:-1;14479:58:0;-1:-1:-1;14559:18:0;14552:3;:25;;;;;;;;;14548:73;;-1:-1:-1;14602:3:0;-1:-1:-1;14607:1:0;;-1:-1:-1;14594:15:0;;14548:73;14640:34;14648:17;14657:7;14648:8;:17::i;:::-;14667:6;14640:7;:34::i;:::-;14633:41;;;;;;14354:328;;;;;;:::o;121465:698::-;121582:16;;121547:4;;-1:-1:-1;;;;;121582:16:0;121568:10;:30;121564:125;;121622:55;121627:18;121647:29;121622:4;:55::i;121564:125::-;121746:16;;-1:-1:-1;;;;;121746:16:0;121735:28;;;;:10;:28;;;;;;:33;121731:196;;121807:8;;121818:16;;-1:-1:-1;;;;;121818:16:0;;;121807:8;121836:28;;;:10;:28;;;;;;121785:80;;121807:8;;;;;121785:13;:80::i;:::-;121898:16;;-1:-1:-1;;;;;121898:16:0;121887:28;;;;:10;:28;;;;;121880:35;121731:196;121969:16;;;-1:-1:-1;;;;;121996:38:0;;;-1:-1:-1;;;;;;121996:38:0;;;;;;122052:65;;121969:16;;;122052:65;;;;121969:16;;122015:19;;122052:65;;99050:2044;99136:4;99153:37;;:::i;:::-;99241;99269:8;99241:27;:37::i;:::-;99218:19;;;99203:75;;;99204:12;;;99203:75;;;;;;;;;;;;;;;;;;;-1:-1:-1;99309:18:0;;-1:-1:-1;99293:4:0;:12;;;:34;;;;;;;;;99289:191;;99351:117;99362:16;99380:67;99454:4;:12;;;99449:18;;;;;;;99289:191;-1:-1:-1;;;;;99521:28:0;;;;;;:18;:28;;;;;;99492:26;;;:57;-1:-1:-1;;99564:24:0;;99560:246;;;99655:4;:19;;;99625:4;:26;;;:49;;:104;;99728:1;99625:104;;;99706:4;:19;;;99677:4;:26;;;:48;99625:104;99605:17;;;:124;99560:246;;;99762:17;;;:32;;;99560:246;-1:-1:-1;;;;;99871:28:0;;;;;;:18;:28;;;;;;;;99901:17;;;;99863:56;;99871:28;99863:7;:56::i;:::-;99833:26;;;99818:101;;;99819:12;;;99818:101;;;;;;;;;;;;;;;;;;;-1:-1:-1;99950:18:0;;-1:-1:-1;99934:4:0;:12;;;:34;;;;;;;;;99930:195;;99992:121;100003:16;100021:71;100099:4;:12;;;100094:18;;;;;;;99930:195;100199:4;:19;;;100170:4;:26;;;:48;100166:178;;;100242:90;100247:29;100278:53;100242:4;:90::i;100166:178::-;100399:44;100407:16;;100425:4;:17;;;100399:7;:44::i;:::-;100371:24;;;100356:87;;;100357:12;;;100356:87;;;;;;;;;;;;;;;;;;;-1:-1:-1;100478:18:0;;-1:-1:-1;100462:4:0;:12;;;:34;;;;;;;;;100454:106;;;;-1:-1:-1;;;100454:106:0;;;;;;;;;100706:11;;100729:17;;;;100692:55;;-1:-1:-1;;;;;100706:11:0;;100719:8;;100692:13;:55::i;:::-;100845:24;;;;100826:16;:43;100911:26;;;;-1:-1:-1;;;;;100880:28:0;;;;;;:18;:28;;;;;;;:57;;;;101030:17;;;;101003:45;;;;;;100899:8;;101030:17;101003:45;;90057:2719;90155:13;;90133:4;;90155:13;;;;;90150:105;;90192:51;90197:15;90214:28;90192:4;:51::i;90150:105::-;90267:27;;:::i;:::-;90345:37;90373:8;90345:27;:37::i;:::-;90322:19;;;90307:75;;;90308:4;90307:75;;;;;;;;;;;;;;;;;;;-1:-1:-1;90413:18:0;;-1:-1:-1;90397:12:0;;:34;;;;;;;;;90393:181;;90455:107;90466:16;90484:57;90548:4;:12;;;90543:18;;;;;;;90393:181;-1:-1:-1;;90590:12:0;:24;90586:261;;;90688:19;;;;;-1:-1:-1;;;;;90657:28:0;;;;;;:18;:28;;;;;;;:50;:107;;90763:1;90657:107;;;90741:19;;;;;-1:-1:-1;;;;;90710:28:0;;;;;;:18;:28;;;;;;;:50;90657:107;90631:23;;;:133;90586:261;;;90797:23;;;:38;;;90586:261;90956:4;:23;;;90939:14;:12;:14::i;:::-;:40;90935:154;;;91003:74;91008:29;91039:37;91003:4;:74::i;90935:154::-;91391:53;91399:4;:19;;;91420:4;:23;;;91391:7;:53::i;:::-;91365:22;;;91350:94;;;91351:4;91350:94;;;;;;;;;;;;;;;;;;;-1:-1:-1;91475:18:0;;-1:-1:-1;91459:12:0;;:34;;;;;;;;;91455:188;;91517:114;91528:16;91546:64;91617:4;:12;;;91612:18;;;;;;;91455:188;91720:22;;;;-1:-1:-1;;;;;91689:28:0;;;;;;:18;:28;;;;;;:53;91685:172;;;91766:79;91771:29;91802:42;91766:4;:79::i;91685:172::-;91908:46;91916:12;;91930:4;:23;;;91908:7;:46::i;:::-;91884:20;;;91869:85;;;91870:4;91869:85;;;;;;;;;;;;;;;;;;;-1:-1:-1;91985:18:0;;-1:-1:-1;91969:12:0;;:34;;;;;;;;;91965:179;;92027:105;92038:16;92056:55;92118:4;:12;;;92113:18;;;;;;;91965:179;92289:11;;92312:23;;;;92275:61;;-1:-1:-1;;;;;92289:11:0;;92302:8;;92275:13;:61::i;:::-;92456:22;;;;;-1:-1:-1;;;;;92419:24:0;;;;;;:14;:24;;;;;;;;;:59;;;92530:11;;92489:38;;;;:52;;;;92567:20;;;;92552:12;:35;;;92660:23;;;;92685:22;;92643:87;;;;;;92434:8;;92660:23;;92643:87;;114967:691;115121:5;;115052:4;;-1:-1:-1;;;;;115121:5:0;115107:10;:19;115103:108;;115150:49;115155:18;115175:23;115150:4;:49::i;115103:108::-;47744:4;115227:26;:55;115223:163;;;115306:68;115311:15;115328:45;115306:4;:68::i;115223:163::-;115432:23;;;115466:52;;;;115536:74;;;;;;115432:23;;115492:26;;115536:74;;124988:876;125263:5;;125195:4;;-1:-1:-1;;;;;125263:5:0;125249:10;:19;125245:108;;125292:49;125297:18;125317:23;125292:4;:49::i;:::-;125285:56;;;;125245:108;125365:18;125386:102;125391:75;125396:48;125401:18;125421:22;125396:4;:48::i;:::-;125446:19;125391:4;:75::i;:::-;49297:7;125386:4;:102::i;:::-;125365:123;;11742:4;125507:13;:28;;125499:59;;;;-1:-1:-1;;;125499:59:0;;;;;;;;;125571:17;:38;;;125620:21;:46;;;125677:18;:40;;;125735:83;;;;;;125591:18;;125644:22;;125698:19;;125735:83;;116979:997;117277:5;;117073:4;;;;-1:-1:-1;;;;;117277:5:0;117263:10;:19;117259:108;;117306:49;117311:18;117331:23;117306:4;:49::i;:::-;117299:56;;;;;117259:108;117452:17;;;;;;;;;-1:-1:-1;;;;;117452:17:0;117429:40;;117572:20;-1:-1:-1;;;;;117572:40:0;;:42;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;117572:42:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;117572:42: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;117572:42:0;;;;;;;;;117564:83;;;;-1:-1:-1;;;117564:83:0;;;;;;;;;117724:17;:40;;-1:-1:-1;;;;;;117724:40:0;-1:-1:-1;;;;;117724:40:0;;;;;117864:64;;;;;;117885:20;;117724:40;;117864:64;;113431:723;113581:5;;113512:4;;-1:-1:-1;;;;;113581:5:0;113567:10;:19;113563:108;;113610:49;113615:18;113635:23;113610:4;:49::i;113563:108::-;44822:4;113743:24;:51;113739:157;;;113818:66;113823:15;113840:43;113818:4;:66::i;113739:157::-;113940:21;;;113972:48;;;;114038:68;;;;;;113940:21;;113996:24;;114038:68;;12189:515;12250:9;12261:10;;:::i;:::-;12285:14;12301:20;12325:22;12333:3;11742:4;12325:7;:22::i;:::-;12284:63;;-1:-1:-1;12284:63:0;-1:-1:-1;12370:18:0;12362:4;:26;;;;;;;;;12358:92;;-1:-1:-1;12419:18:0;;;;;;;;;-1:-1:-1;12419:18:0;;12413:4;;-1:-1:-1;12419:18:0;-1:-1:-1;12405:33:0;;12358:92;12463:14;12479:13;12496:31;12504:15;12521:5;12496:7;:31::i;:::-;12462:65;;-1:-1:-1;12462:65:0;-1:-1:-1;12550:18:0;12542:4;:26;;;;;;;;;12538:92;;-1:-1:-1;12599:18:0;;;;;;;;;-1:-1:-1;12599:18:0;;12593:4;;-1:-1:-1;12599:18:0;-1:-1:-1;12585:33:0;;-1:-1:-1;;12585:33:0;12538:92;12670:25;;;;;;;;;;;;-1:-1:-1;;12670:25:0;;-1:-1:-1;12189:515:0;-1:-1:-1;;;;;;12189:515:0:o;105215:1752::-;105319:16;105338:38;105343:14;105359:16;105338:4;:38::i;:::-;105319:57;-1:-1:-1;105391:15:0;;105387:1573;;105423:14;105440:31;105445:11;105458:12;;105440:4;:31::i;:::-;105486:8;;:39;;-1:-1:-1;;;105486:39:0;;105423:48;;-1:-1:-1;;;;;;105486:8:0;;:13;;:39;;105508:4;;105423:48;;105486:39;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;105486:39:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;105486:39:0;;;;105542:16;105561:53;105566:34;105571:17;;105590:9;105566:4;:34::i;:::-;11742:4;105561;:53::i;:::-;105542:72;;105629:20;105652:57;105657:38;105662:21;;105685:9;105657:4;:38::i;105652:57::-;105629:80;;105724:17;105744:54;105749:35;105754:18;;105774:9;105749:4;:35::i;105744:54::-;105724:74;;105813:18;105834:55;105839:36;49297:7;105865:9;105839:4;:36::i;105834:55::-;105813:76;;105904:15;105922:92;105927:71;105932:51;105937:28;105942:9;105953:11;105937:4;:28::i;:::-;105967:15;105932:4;:51::i;:::-;105985:12;105927:4;:71::i;:::-;106000:13;105922:4;:92::i;:::-;106122:14;;-1:-1:-1;;;;;106122:14:0;106111:26;;;;:10;:26;;;;;;105904:110;;-1:-1:-1;106106:45:0;;106139:11;106106:4;:45::i;:::-;106088:14;;-1:-1:-1;;;;;106088:14:0;;;106077:26;;;;:10;:26;;;;;;:74;;;;106215:18;;;;;106204:30;;;;106199:53;;106236:15;106199:4;:53::i;:::-;106177:18;;-1:-1:-1;;;;;106177:18:0;;;106166:30;;;;:10;:30;;;;;;:86;;;;106313:15;;;;;106302:27;;;;106297:47;;106331:12;106297:4;:47::i;:::-;106278:15;;-1:-1:-1;;;;;106278:15:0;;;106267:27;;;;:10;:27;;;;;;:77;;;;106406:16;;;;;106395:28;;;;106390:49;;106425:13;106390:4;:49::i;:::-;106370:16;;-1:-1:-1;;;;;106370:16:0;106359:28;;;;:10;:28;;;;;:80;106460:11;;:15;106456:375;;106496:19;;:::i;:::-;106518:33;106527:10;106539:11;;106518:8;:33::i;:::-;106496:55;;106570:19;;:::i;:::-;106592:47;106597:34;;;;;;;;106615:14;;106597:34;;;106633:5;106592:4;:47::i;:::-;106675:14;106658;:31;-1:-1:-1;106456:375:0;;-1:-1:-1;106456:375:0;;106781:20;;-1:-1:-1;;;;;106781:20:0;106770:32;;;;:10;:32;;;;;;106765:50;;106804:10;106765:4;:50::i;:::-;106741:20;;-1:-1:-1;;;;;106741:20:0;106730:32;;;;:10;:32;;;;;:85;106456:375;106852:96;106862:11;106875:15;106892:12;106906:13;106921:10;106933:14;;106852:96;;;;;;;;;;;;;;;;;;;;105387:1573;;;;;;;105215:1752;;;:::o;126919:1364::-;127126:51;;-1:-1:-1;;;127126:51:0;;127006:4;;127083:10;;127006:4;;-1:-1:-1;;;;;127126:36:0;;;;;:51;;127171:4;;127126:51;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;127126:51:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;127126:51: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;127126:51:0;;;;;;;;;127188:47;;-1:-1:-1;;;127188:47:0;;127105:72;;-1:-1:-1;;;;;;127188:18:0;;;;;:47;;127207:4;;127221;;127228:6;;127188:47;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;127188:47:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;127188:47:0;;;;127248:12;127302:16;127341:1;127336:153;;;;127512:2;127507:220;;;;127863:1;127860;127853:12;127336:153;-1:-1:-1;;127432:6:0;-1:-1:-1;127336:153:0;;127507:220;127610:2;127607:1;127604;127589:24;127652:1;127646:8;127635:19;;127295:589;;127913:7;127905:44;;;;-1:-1:-1;;;127905:44:0;;;;;;;;;128047:51;;-1:-1:-1;;;128047:51:0;;128027:17;;-1:-1:-1;;;;;128047:36:0;;;;;:51;;128092:4;;128047:51;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;128047:51:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;128047:51: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;128047:51:0;;;;;;;;;128027:71;;128133:13;128117:12;:29;;128109:68;;;;-1:-1:-1;;;128109:68:0;;;;;;;;;128195:28;;;;;126919:1364;-1:-1:-1;;;;;;126919:1364:0:o;10996:271::-;11067:9;11078:4;11096:14;11112:8;11124:13;11132:1;11135;11124:7;:13::i;:::-;11095:42;;-1:-1:-1;11095:42:0;-1:-1:-1;11162:18:0;11154:4;:26;;;;;;;;;11150:75;;-1:-1:-1;11205:4:0;-1:-1:-1;11211:1:0;;-1:-1:-1;11197:16:0;;11150:75;11244:15;11252:3;11257:1;11244:7;:15::i;18709:213::-;18891:12;11742:4;18891:23;;;18709:213::o;107678:414::-;107765:4;107801:9;107786:11;:24;;:43;;;;;107828:1;107814:11;:15;107786:43;107782:274;;;107866:8;;:33;;-1:-1:-1;;;107866:33:0;;107846:17;;-1:-1:-1;;;;;107866:8:0;;:18;;:33;;107893:4;;107866:33;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;107866:33:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;107866:33: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;107866:33:0;;;;;;;;;107846:53;;107933:12;107918:11;:27;107914:131;;107966:8;;:36;;-1:-1:-1;;;107966:36:0;;-1:-1:-1;;;;;107966:8:0;;;;:17;;:36;;107984:4;;107990:11;;107966:36;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;107966:36:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;107966:36: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;107966:36:0;;;;;;;;;;108028:1;108021:8;;;;;107914:131;107782:274;;-1:-1:-1;108073:11:0;;107678:414;-1:-1:-1;;107678:414:0:o;15944:337::-;16032:9;16043:4;16061:13;16076:19;;:::i;:::-;16099:31;16114:6;16122:7;16099:14;:31::i;21206:158::-;21287:4;21320:12;21312:6;;;;21304:29;;;;-1:-1:-1;;;21304:29:0;;;;;;;;;;-1:-1:-1;;;21351:5:0;;;21206:158::o;20910:160::-;20981:13;;:::i;:::-;21014:48;;;;;;;;21032:28;21037:1;:10;;;21049:1;:10;;;21032:4;:28::i;:::-;21014:48;;21007:55;20910:160;-1:-1:-1;;;20910:160:0:o;22141:127::-;22203:4;11781;22227:19;22232:1;22235;:10;;;22227:4;:19::i;:::-;:33;;;;;;;22141:127;-1:-1:-1;;;22141:127:0:o;20443:116::-;20496:4;20520:31;20525:1;20528;20520:31;;;;;;;;;;;;;-1:-1:-1;;;20520:31:0;;;:4;:31::i;9560:343::-;9616:9;;9648:6;9644:69;;-1:-1:-1;9679:18:0;;-1:-1:-1;9679:18:0;9671:30;;9644:69;9734:5;;;9738:1;9734;:5;:1;9756:5;;;;;:10;9752:144;;-1:-1:-1;9791:26:0;;-1:-1:-1;9819:1:0;;-1:-1:-1;9783:38:0;;9752:144;9862:18;;-1:-1:-1;9882:1:0;-1:-1:-1;9854:30:0;;9998:215;10054:9;;10086:6;10082:77;;-1:-1:-1;10117:26:0;;-1:-1:-1;10145:1:0;10109:38;;10082:77;10179:18;10203:1;10199;:5;;;;;;10171:34;;;;9998:215;;;;;:::o;22276:122::-;22329:4;22353:37;22358:1;22361;22353:37;;;;;;;;;;;;;;;;;:4;:37::i;23588:113::-;23641:4;23665:28;23670:1;23673;23665:28;;;;;;;;;;;;;-1:-1:-1;;;23665:28:0;;;:4;:28::i;23874:147::-;23931:13;;:::i;:::-;23964:49;;;;;;;;23982:29;23987:20;23992:1;11781:4;23987;:20::i;:::-;24009:1;23982:4;:29::i;20275:160::-;20346:13;;:::i;:::-;20379:48;;;;;;;;20397:28;20402:1;:10;;;20414:1;:10;;;20397:4;:28::i;15213:620::-;15293:9;15304:10;;:::i;:::-;15611:14;15627;15645:25;11742:4;15663:6;15645:7;:25::i;:::-;15610:60;;-1:-1:-1;15610:60:0;-1:-1:-1;15693:18:0;15685:4;:26;;;;;;;;;15681:92;;-1:-1:-1;15742:18:0;;;;;;;;;-1:-1:-1;15742:18:0;;15736:4;;-1:-1:-1;15742:18:0;-1:-1:-1;15728:33:0;;15681:92;15790:35;15797:9;15808:7;:16;;;15790:6;:35::i;20567:179::-;20648:4;20674:5;;;20706:12;20698:6;;;;20690:29;;;;-1:-1:-1;;;20690:29:0;;;;;;;;;;-1:-1:-1;20737:1:0;20567:179;-1:-1:-1;;;;20567:179:0:o;22406:250::-;22487:4;22508:6;;;:16;;-1:-1:-1;22518:6:0;;22508:16;22504:57;;;-1:-1:-1;22548:1:0;22541:8;;22504:57;22580:5;;;22584:1;22580;:5;:1;22604:5;;;;;:10;22616:12;22596:33;;;;;-1:-1:-1;;;22596:33:0;;;;;;;;;23709:157;23790:4;23822:12;23815:5;23807:28;;;;-1:-1:-1;;;23807:28:0;;;;;;;;;;;23857:1;23853;:5;;;;;;;23709:157;-1:-1:-1;;;;23709:157:0:o;44236:85670::-;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;-1:-1:-1;44236:85670:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;-1:-1:-1;44236:85670:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;-1:-1:-1;44236:85670:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;-1:-1:-1;44236:85670:0;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;-1:-1:-1;44236:85670:0;;5:130:-1;72:20;;97:33;72:20;97:33;;160:707;;277:3;270:4;262:6;258:17;254:27;244:2;;295:1;292;285:12;244:2;332:6;319:20;354:80;369:64;426:6;369:64;;;354:80;;;345:89;;451:5;476:6;469:5;462:21;506:4;498:6;494:17;484:27;;528:4;523:3;519:14;512:21;;581:6;628:3;620:4;612:6;608:17;603:3;599:27;596:36;593:2;;;645:1;642;635:12;593:2;670:1;655:206;680:6;677:1;674:13;655:206;;;738:3;760:37;793:3;781:10;760:37;;;748:50;;-1:-1;821:4;812:14;;;;840;;;;;702:1;695:9;655:206;;;659:14;237:630;;;;;;;;875:124;939:20;;964:30;939:20;964:30;;1006:128;1081:13;;1099:30;1081:13;1099:30;;1141:182;1234:20;;1259:59;1234:20;1259:59;;1330:130;1397:20;;1422:33;1397:20;1422:33;;1467:134;1545:13;;1563:33;1545:13;1563:33;;1608:241;;1712:2;1700:9;1691:7;1687:23;1683:32;1680:2;;;1728:1;1725;1718:12;1680:2;1763:1;1780:53;1825:7;1805:9;1780:53;;1856:366;;;1977:2;1965:9;1956:7;1952:23;1948:32;1945:2;;;1993:1;1990;1983:12;1945:2;2028:1;2045:53;2090:7;2070:9;2045:53;;;2035:63;;2007:97;2135:2;2153:53;2198:7;2189:6;2178:9;2174:22;2153:53;;;2143:63;;2114:98;1939:283;;;;;;2229:491;;;;2367:2;2355:9;2346:7;2342:23;2338:32;2335:2;;;2383:1;2380;2373:12;2335:2;2418:1;2435:53;2480:7;2460:9;2435:53;;;2425:63;;2397:97;2525:2;2543:53;2588:7;2579:6;2568:9;2564:22;2543:53;;;2533:63;;2504:98;2633:2;2651:53;2696:7;2687:6;2676:9;2672:22;2651:53;;;2641:63;;2612:98;2329:391;;;;;;2727:366;;;2848:2;2836:9;2827:7;2823:23;2819:32;2816:2;;;2864:1;2861;2854:12;2816:2;2899:1;2916:53;2961:7;2941:9;2916:53;;;2906:63;;2878:97;3006:2;3024:53;3069:7;3060:6;3049:9;3045:22;3024:53;;3100:377;;3229:2;3217:9;3208:7;3204:23;3200:32;3197:2;;;3245:1;3242;3235:12;3197:2;3280:31;;3331:18;3320:30;;3317:2;;;3363:1;3360;3353:12;3317:2;3383:78;3453:7;3444:6;3433:9;3429:22;3383:78;;3484:235;;3585:2;3573:9;3564:7;3560:23;3556:32;3553:2;;;3601:1;3598;3591:12;3553:2;3636:1;3653:50;3695:7;3675:9;3653:50;;3726:257;;3838:2;3826:9;3817:7;3813:23;3809:32;3806:2;;;3854:1;3851;3844:12;3806:2;3889:1;3906:61;3959:7;3939:9;3906:61;;3990:293;;4120:2;4108:9;4099:7;4095:23;4091:32;4088:2;;;4136:1;4133;4126:12;4088:2;4171:1;4188:79;4259:7;4239:9;4188:79;;4290:241;;4394:2;4382:9;4373:7;4369:23;4365:32;4362:2;;;4410:1;4407;4400:12;4362:2;4445:1;4462:53;4507:7;4487:9;4462:53;;4538:263;;4653:2;4641:9;4632:7;4628:23;4624:32;4621:2;;;4669:1;4666;4659:12;4621:2;4704:1;4721:64;4777:7;4757:9;4721:64;;4808:491;;;;4946:2;4934:9;4925:7;4921:23;4917:32;4914:2;;;4962:1;4959;4952:12;4914:2;4997:1;5014:53;5059:7;5039:9;5014:53;;;5004:63;;4976:97;5104:2;5122:53;5167:7;5158:6;5147:9;5143:22;5122:53;;5306:113;5389:24;5407:5;5389:24;;;5384:3;5377:37;5371:48;;;5426:104;5503:21;5518:5;5503:21;;5537:150;5632:49;5675:5;5632:49;;5879:142;5970:45;6009:5;5970:45;;6028:347;;6140:39;6173:5;6140:39;;;6191:71;6255:6;6250:3;6191:71;;;6184:78;;6267:52;6312:6;6307:3;6300:4;6293:5;6289:16;6267:52;;;6340:29;6362:6;6340:29;;;6331:39;;;;6120:255;-1:-1;;;6120:255;6729:396;;6889:67;6953:2;6948:3;6889:67;;;6989:34;6969:55;;7058:29;7053:2;7044:12;;7037:51;7116:2;7107:12;;6875:250;-1:-1;;6875:250;7134:322;;7294:67;7358:2;7353:3;7294:67;;;-1:-1;;;7374:45;;7447:2;7438:12;;7280:176;-1:-1;;7280:176;7465:324;;7625:67;7689:2;7684:3;7625:67;;;7725:26;7705:47;;7780:2;7771:12;;7611:178;-1:-1;;7611:178;7798:331;;7958:67;8022:2;8017:3;7958:67;;;8058:33;8038:54;;8120:2;8111:12;;7944:185;-1:-1;;7944:185;8138:326;;8298:67;8362:2;8357:3;8298:67;;;8398:28;8378:49;;8455:2;8446:12;;8284:180;-1:-1;;8284:180;8473:325;;8633:67;8697:2;8692:3;8633:67;;;8733:27;8713:48;;8789:2;8780:12;;8619:179;-1:-1;;8619:179;8807:389;;8967:67;9031:2;9026:3;8967:67;;;9067:34;9047:55;;-1:-1;;;9131:2;9122:12;;9115:44;9187:2;9178:12;;8953:243;-1:-1;;8953:243;9205:388;;9365:67;9429:2;9424:3;9365:67;;;9465:34;9445:55;;-1:-1;;;9529:2;9520:12;;9513:43;9584:2;9575:12;;9351:242;-1:-1;;9351:242;9602:328;;9762:67;9826:2;9821:3;9762:67;;;9862:30;9842:51;;9921:2;9912:12;;9748:182;-1:-1;;9748:182;9939:380;;10099:67;10163:2;10158:3;10099:67;;;10199:34;10179:55;;-1:-1;;;10263:2;10254:12;;10247:35;10310:2;10301:12;;10085:234;-1:-1;;10085:234;10328:392;;10488:67;10552:2;10547:3;10488:67;;;10588:34;10568:55;;10657:25;10652:2;10643:12;;10636:47;10711:2;10702:12;;10474:246;-1:-1;;10474:246;10729:371;;10889:67;10953:2;10948:3;10889:67;;;10989:34;10969:55;;-1:-1;;;11053:2;11044:12;;11037:26;11091:2;11082:12;;10875:225;-1:-1;;10875:225;11109:390;;11269:67;11333:2;11328:3;11269:67;;;11369:34;11349:55;;-1:-1;;;11433:2;11424:12;;11417:45;11490:2;11481:12;;11255:244;-1:-1;;11255:244;11508:395;;11668:67;11732:2;11727:3;11668:67;;;11768:34;11748:55;;11837:28;11832:2;11823:12;;11816:50;11894:2;11885:12;;11654:249;-1:-1;;11654:249;11912:372;;12072:67;12136:2;12131:3;12072:67;;;12172:34;12152:55;;-1:-1;;;12236:2;12227:12;;12220:27;12275:2;12266:12;;12058:226;-1:-1;;12058:226;12293:331;;12453:67;12517:2;12512:3;12453:67;;;12553:33;12533:54;;12615:2;12606:12;;12439:185;-1:-1;;12439:185;12633:386;;12793:67;12857:2;12852:3;12793:67;;;12893:34;12873:55;;-1:-1;;;12957:2;12948:12;;12941:41;13010:2;13001:12;;12779:240;-1:-1;;12779:240;13028:315;;13188:67;13252:2;13247:3;13188:67;;;-1:-1;;;13268:38;;13334:2;13325:12;;13174:169;-1:-1;;13174:169;13352:332;;13512:67;13576:2;13571:3;13512:67;;;13612:34;13592:55;;13675:2;13666:12;;13498:186;-1:-1;;13498:186;13693:390;;13853:67;13917:2;13912:3;13853:67;;;13953:34;13933:55;;-1:-1;;;14017:2;14008:12;;14001:45;14074:2;14065:12;;13839:244;-1:-1;;13839:244;14092:377;;14252:67;14316:2;14311:3;14252:67;;;14352:34;14332:55;;-1:-1;;;14416:2;14407:12;;14400:32;14460:2;14451:12;;14238:231;-1:-1;;14238:231;14478:389;;14638:67;14702:2;14697:3;14638:67;;;14738:34;14718:55;;-1:-1;;;14802:2;14793:12;;14786:44;14858:2;14849:12;;14624:243;-1:-1;;14624:243;14876:331;;15036:67;15100:2;15095:3;15036:67;;;15136:33;15116:54;;15198:2;15189:12;;15022:185;-1:-1;;15022:185;15216:391;;15376:67;15440:2;15435:3;15376:67;;;15476:34;15456:55;;-1:-1;;;15540:2;15531:12;;15524:46;15598:2;15589:12;;15362:245;-1:-1;;15362:245;15616:318;;15776:67;15840:2;15835:3;15776:67;;;-1:-1;;;15856:41;;15925:2;15916:12;;15762:172;-1:-1;;15762:172;15942:113;16025:24;16043:5;16025:24;;16062:107;16141:22;16157:5;16141:22;;16176:213;16294:2;16279:18;;16308:71;16283:9;16352:6;16308:71;;16396:324;16542:2;16527:18;;16556:71;16531:9;16600:6;16556:71;;;16638:72;16706:2;16695:9;16691:18;16682:6;16638:72;;16727:435;16901:2;16886:18;;16915:71;16890:9;16959:6;16915:71;;;16997:72;17065:2;17054:9;17050:18;17041:6;16997:72;;;17080;17148:2;17137:9;17133:18;17124:6;17080:72;;17169:547;17371:3;17356:19;;17386:71;17360:9;17430:6;17386:71;;;17468:72;17536:2;17525:9;17521:18;17512:6;17468:72;;;17551;17619:2;17608:9;17604:18;17595:6;17551:72;;;17634;17702:2;17691:9;17687:18;17678:6;17634:72;;;17342:374;;;;;;;;17723:659;17953:3;17938:19;;17968:71;17942:9;18012:6;17968:71;;;18050:72;18118:2;18107:9;18103:18;18094:6;18050:72;;;18133;18201:2;18190:9;18186:18;18177:6;18133:72;;;18216;18284:2;18273:9;18269:18;18260:6;18216:72;;;18299:73;18367:3;18356:9;18352:19;18343:6;18299:73;;;17924:458;;;;;;;;;18389:324;18535:2;18520:18;;18549:71;18524:9;18593:6;18549:71;;;18631:72;18699:2;18688:9;18684:18;18675:6;18631:72;;18720:435;18894:2;18879:18;;18908:71;18883:9;18952:6;18908:71;;;18990:72;19058:2;19047:9;19043:18;19034:6;18990:72;;19162:547;19364:3;19349:19;;19379:71;19353:9;19423:6;19379:71;;;19461:72;19529:2;19518:9;19514:18;19505:6;19461:72;;19716:201;19828:2;19813:18;;19842:65;19817:9;19880:6;19842:65;;19924:237;20054:2;20039:18;;20068:83;20043:9;20124:6;20068:83;;20440:428;20638:2;20623:18;;20652:97;20627:9;20722:6;20652:97;;;20760:98;20854:2;20843:9;20839:18;20830:6;20760:98;;20875:293;21009:2;21023:47;;;20994:18;;21084:74;20994:18;21144:6;21084:74;;21483:407;21674:2;21688:47;;;21659:18;;21749:131;21659:18;21749:131;;21897:407;22088:2;22102:47;;;22073:18;;22163:131;22073:18;22163:131;;22311:407;22502:2;22516:47;;;22487:18;;22577:131;22487:18;22577:131;;22725:407;22916:2;22930:47;;;22901:18;;22991:131;22901:18;22991:131;;23139:407;23330:2;23344:47;;;23315:18;;23405:131;23315:18;23405:131;;23553:407;23744:2;23758:47;;;23729:18;;23819:131;23729:18;23819:131;;23967:407;24158:2;24172:47;;;24143:18;;24233:131;24143:18;24233:131;;24381:407;24572:2;24586:47;;;24557:18;;24647:131;24557:18;24647:131;;24795:407;24986:2;25000:47;;;24971:18;;25061:131;24971:18;25061:131;;25209:407;25400:2;25414:47;;;25385:18;;25475:131;25385:18;25475:131;;25623:407;25814:2;25828:47;;;25799:18;;25889:131;25799:18;25889:131;;26037:407;26228:2;26242:47;;;26213:18;;26303:131;26213:18;26303:131;;26451:407;26642:2;26656:47;;;26627:18;;26717:131;26627:18;26717:131;;26865:407;27056:2;27070:47;;;27041:18;;27131:131;27041:18;27131:131;;27279:407;27470:2;27484:47;;;27455:18;;27545:131;27455:18;27545:131;;27693:407;27884:2;27898:47;;;27869:18;;27959:131;27869:18;27959:131;;28107:407;28298:2;28312:47;;;28283:18;;28373:131;28283:18;28373:131;;28521:407;28712:2;28726:47;;;28697:18;;28787:131;28697:18;28787:131;;28935:407;29126:2;29140:47;;;29111:18;;29201:131;29111:18;29201:131;;29349:407;29540:2;29554:47;;;29525:18;;29615:131;29525:18;29615:131;;29763:407;29954:2;29968:47;;;29939:18;;30029:131;29939:18;30029:131;;30177:407;30368:2;30382:47;;;30353:18;;30443:131;30353:18;30443:131;;30591:407;30782:2;30796:47;;;30767:18;;30857:131;30767:18;30857:131;;31005:407;31196:2;31210:47;;;31181:18;;31271:131;31181:18;31271:131;;31419:407;31610:2;31624:47;;;31595:18;;31685:131;31595:18;31685:131;;31833:213;31951:2;31936:18;;31965:71;31940:9;32009:6;31965:71;;32053:324;32199:2;32184:18;;32213:71;32188:9;32257:6;32213:71;;32384:451;32566:2;32551:18;;32580:71;32555:9;32624:6;32580:71;;;32662:72;32730:2;32719:9;32715:18;32706:6;32662:72;;;32745:80;32821:2;32810:9;32806:18;32797:6;32745:80;;32842:435;33016:2;33001:18;;33030:71;33005:9;33074:6;33030:71;;33284:547;33486:3;33471:19;;33501:71;33475:9;33545:6;33501:71;;33838:771;34096:3;34081:19;;34111:71;34085:9;34155:6;34111:71;;;34193:72;34261:2;34250:9;34246:18;34237:6;34193:72;;;34276;34344:2;34333:9;34329:18;34320:6;34276:72;;;34359;34427:2;34416:9;34412:18;34403:6;34359:72;;;34442:73;34510:3;34499:9;34495:19;34486:6;34442:73;;;34526;34594:3;34583:9;34579:19;34570:6;34526:73;;34616:205;34730:2;34715:18;;34744:67;34719:9;34784:6;34744:67;;34828:256;34890:2;34884:9;34916:17;;;34991:18;34976:34;;35012:22;;;34973:62;34970:2;;;35048:1;35045;35038:12;34970:2;35064;35057:22;34868:216;;-1:-1;34868:216;35091:304;;35250:18;35242:6;35239:30;35236:2;;;35282:1;35279;35272:12;35236:2;-1:-1;35317:4;35305:17;;;35370:15;;35173:222;35402:118;35486:12;;35457:63;35657:163;35760:19;;;35809:4;35800:14;;35753:67;35828:91;;35890:24;35908:5;35890:24;;35926:85;35992:13;35985:21;;35968:43;36018:117;;36106:24;36124:5;36106:24;;36142:121;-1:-1;;;;;36204:54;;36187:76;36349:81;36420:4;36409:16;;36392:38;37037:116;;37124:24;37142:5;37124:24;;37161:268;37226:1;37233:101;37247:6;37244:1;37241:13;37233:101;;;37314:11;;;37308:18;37295:11;;;37288:39;37269:2;37262:10;37233:101;;;37349:6;37346:1;37343:13;37340:2;;;37414:1;37405:6;37400:3;37396:16;37389:27;37340:2;37210:219;;;;;37437:97;37525:2;37505:14;-1:-1;;37501:28;;37485:49;37542:117;37611:24;37629:5;37611:24;;;37604:5;37601:35;37591:2;;37650:1;37647;37640:12;37591:2;37585:74;;37666:111;37732:21;37747:5;37732:21;;37784:169;37879:50;37923:5;37879:50;;37960:117;38029:24;38047:5;38029:24;

Swarm Source

bzzr://fe162c8ca51d2716e9ccef45430f6f5edb626940c809bcfa0508fb3e482d8caa

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.