ETH Price: $2,154.36 (+5.45%)

Token

ERC20 ***
 

Overview

Max Total Supply

0 ERC20 ***

Holders

0

Transfers

-
0 (0%)

Market

Onchain Market Cap

-

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 0 Decimals)

Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.

Contract Source Code Verified (Exact Match)

Contract Name:
Strategy

Compiler Version
v0.6.12+commit.27d51765

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, GNU AGPLv3 license
/**
 *Submitted for verification at Etherscan.io on 2021-05-27
*/

// SPDX-License-Identifier: AGPL-3.0

pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;

// Global Enums and Structs

library DataTypes {
    // refer to the whitepaper, section 1.1 basic concepts for a formal description of these properties.
    struct ReserveData {
        //stores the reserve configuration
        ReserveConfigurationMap configuration;
        //the liquidity index. Expressed in ray
        uint128 liquidityIndex;
        //variable borrow index. Expressed in ray
        uint128 variableBorrowIndex;
        //the current supply rate. Expressed in ray
        uint128 currentLiquidityRate;
        //the current variable borrow rate. Expressed in ray
        uint128 currentVariableBorrowRate;
        //the current stable borrow rate. Expressed in ray
        uint128 currentStableBorrowRate;
        uint40 lastUpdateTimestamp;
        //tokens addresses
        address aTokenAddress;
        address stableDebtTokenAddress;
        address variableDebtTokenAddress;
        //address of the interest rate strategy
        address interestRateStrategyAddress;
        //the id of the reserve. Represents the position in the list of the active reserves
        uint8 id;
    }

    struct ReserveConfigurationMap {
        //bit 0-15: LTV
        //bit 16-31: Liq. threshold
        //bit 32-47: Liq. bonus
        //bit 48-55: Decimals
        //bit 56: Reserve is active
        //bit 57: reserve is frozen
        //bit 58: borrowing is enabled
        //bit 59: stable rate borrowing enabled
        //bit 60-63: reserved
        //bit 64-79: reserve factor
        uint256 data;
    }

    struct UserConfigurationMap {
        uint256 data;
    }

    enum InterestRateMode {NONE, STABLE, VARIABLE}
}


library SupportStructs {
    struct CalcMaxDebtLocalVars {
        uint256 availableLiquidity;
        uint256 totalStableDebt;
        uint256 totalVariableDebt;
        uint256 totalDebt;
        uint256 utilizationRate;
        uint256 totalLiquidity;
        uint256 targetUtilizationRate;
        uint256 maxProtocolDebt;
    }

    struct IrsVars {
        uint256 optimalRate;
        uint256 baseRate;
        uint256 slope1;
        uint256 slope2;
    }
}

struct StrategyParams {
    uint256 performanceFee;
    uint256 activation;
    uint256 debtRatio;
    uint256 minDebtPerHarvest;
    uint256 maxDebtPerHarvest;
    uint256 lastReport;
    uint256 totalDebt;
    uint256 totalGain;
    uint256 totalLoss;
}

// Part: IAaveIncentivesController

interface IAaveIncentivesController {
    /**
     * @dev Returns the total of rewards of an user, already accrued + not yet accrued
     * @param user The address of the user
     * @return The rewards
     **/
    function getRewardsBalance(address[] calldata assets, address user)
        external
        view
        returns (uint256);

    /**
     * @dev Claims reward for an user, on all the assets of the lending pool, accumulating the pending rewards
     * @param amount Amount of rewards to claim
     * @param to Address that will be receiving the rewards
     * @return Rewards claimed
     **/
    function claimRewards(
        address[] calldata assets,
        uint256 amount,
        address to
    ) external returns (uint256);

    /**
     * @dev Claims reward for an user on behalf, on all the assets of the lending pool, accumulating the pending rewards. The caller must
     * be whitelisted via "allowClaimOnBehalf" function by the RewardsAdmin role manager
     * @param amount Amount of rewards to claim
     * @param user Address to check and claim rewards
     * @param to Address that will be receiving the rewards
     * @return Rewards claimed
     **/
    function claimRewardsOnBehalf(
        address[] calldata assets,
        uint256 amount,
        address user,
        address to
    ) external returns (uint256);

    /**
     * @dev returns the unclaimed rewards of the user
     * @param user the address of the user
     * @return the unclaimed user rewards
     */
    function getUserUnclaimedRewards(address user)
        external
        view
        returns (uint256);

    /**
     * @dev for backward compatibility with previous implementation of the Incentives controller
     */
    function REWARD_TOKEN() external view returns (address);

    function getDistributionEnd() external view returns (uint256);

    function getAssetData(address asset)
        external
        view
        returns (
            uint256,
            uint256,
            uint256
        );
}

// Part: ILendingPoolAddressesProvider

/**
 * @title LendingPoolAddressesProvider contract
 * @dev Main registry of addresses part of or connected to the protocol, including permissioned roles
 * - Acting also as factory of proxies and admin of those, so with right to change its implementations
 * - Owned by the Aave Governance
 * @author Aave
 **/
interface ILendingPoolAddressesProvider {
    event MarketIdSet(string newMarketId);
    event LendingPoolUpdated(address indexed newAddress);
    event ConfigurationAdminUpdated(address indexed newAddress);
    event EmergencyAdminUpdated(address indexed newAddress);
    event LendingPoolConfiguratorUpdated(address indexed newAddress);
    event LendingPoolCollateralManagerUpdated(address indexed newAddress);
    event PriceOracleUpdated(address indexed newAddress);
    event LendingRateOracleUpdated(address indexed newAddress);
    event ProxyCreated(bytes32 id, address indexed newAddress);
    event AddressSet(bytes32 id, address indexed newAddress, bool hasProxy);

    function getMarketId() external view returns (string memory);

    function setMarketId(string calldata marketId) external;

    function setAddress(bytes32 id, address newAddress) external;

    function setAddressAsProxy(bytes32 id, address impl) external;

    function getAddress(bytes32 id) external view returns (address);

    function getLendingPool() external view returns (address);

    function setLendingPoolImpl(address pool) external;

    function getLendingPoolConfigurator() external view returns (address);

    function setLendingPoolConfiguratorImpl(address configurator) external;

    function getLendingPoolCollateralManager() external view returns (address);

    function setLendingPoolCollateralManager(address manager) external;

    function getPoolAdmin() external view returns (address);

    function setPoolAdmin(address admin) external;

    function getEmergencyAdmin() external view returns (address);

    function setEmergencyAdmin(address admin) external;

    function getPriceOracle() external view returns (address);

    function setPriceOracle(address priceOracle) external;

    function getLendingRateOracle() external view returns (address);

    function setLendingRateOracle(address lendingRateOracle) external;
}

// Part: IOptionalERC20

interface IOptionalERC20 {
    function name() external view returns (string memory);

    function symbol() external view returns (string memory);

    function decimals() external view returns (uint8);
}

// Part: IPriceOracle

interface IPriceOracle {
    function getAssetPrice(address _asset) external view returns (uint256);

    function getAssetsPrices(address[] calldata _assets)
        external
        view
        returns (uint256[] memory);

    function getSourceOfAsset(address _asset) external view returns (address);

    function getFallbackOracle() external view returns (address);
}

// Part: IReserveInterestRateStrategy

/**
 * @title IReserveInterestRateStrategyInterface interface
 * @dev Interface for the calculation of the interest rates
 * @author Aave
 */
interface IReserveInterestRateStrategy {
    function OPTIMAL_UTILIZATION_RATE() external view returns (uint256);

    function EXCESS_UTILIZATION_RATE() external view returns (uint256);

    function variableRateSlope1() external view returns (uint256);

    function variableRateSlope2() external view returns (uint256);

    function baseVariableBorrowRate() external view returns (uint256);

    function getMaxVariableBorrowRate() external view returns (uint256);

    function calculateInterestRates(
        address reserve,
        uint256 utilizationRate,
        uint256 totalStableDebt,
        uint256 totalVariableDebt,
        uint256 averageStableBorrowRate,
        uint256 reserveFactor
    )
        external
        view
        returns (
            uint256 liquidityRate,
            uint256 stableBorrowRate,
            uint256 variableBorrowRate
        );
}

// Part: IScaledBalanceToken

interface IScaledBalanceToken {
    /**
     * @dev Returns the scaled balance of the user. The scaled balance is the sum of all the
     * updated stored balance divided by the reserve's liquidity index at the moment of the update
     * @param user The user whose balance is calculated
     * @return The scaled balance of the user
     **/
    function scaledBalanceOf(address user) external view returns (uint256);

    /**
     * @dev Returns the scaled balance of the user and the scaled total supply.
     * @param user The address of the user
     * @return The scaled balance of the user
     * @return The scaled balance and the scaled total supply
     **/
    function getScaledUserBalanceAndSupply(address user)
        external
        view
        returns (uint256, uint256);

    /**
     * @dev Returns the scaled total supply of the variable debt token. Represents sum(debt/index)
     * @return The scaled total supply
     **/
    function scaledTotalSupply() external view returns (uint256);
}

// Part: IStakedAave

interface IStakedAave {
    function stake(address to, uint256 amount) external;

    function redeem(address to, uint256 amount) external;

    function cooldown() external;

    function claimRewards(address to, uint256 amount) external;

    function getTotalRewardsBalance(address) external view returns (uint256);

    function COOLDOWN_SECONDS() external view returns (uint256);

    function stakersCooldowns(address) external view returns (uint256);

    function UNSTAKE_WINDOW() external view returns (uint256);
}

// Part: ISwap

interface ISwap {
    function swapExactTokensForTokens(
        uint256,
        uint256,
        address[] calldata,
        address,
        uint256
    ) external returns (uint256[] memory amounts);

    function swapTokensForExactTokens(
        uint256,
        uint256,
        address[] calldata,
        address,
        uint256
    ) external returns (uint256[] memory amounts);

    function getAmountsOut(uint256 amountIn, address[] memory path)
        external
        view
        returns (uint256[] memory amounts);
}

// Part: OpenZeppelin/openzeppelin-contracts@3.1.0/Address

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

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

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

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain`call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
      return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
        return _functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        return _functionCallWithValue(target, data, value, errorMessage);
    }

    function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) {
        require(isContract(target), "Address: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

// Part: OpenZeppelin/openzeppelin-contracts@3.1.0/IERC20

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

// Part: OpenZeppelin/openzeppelin-contracts@3.1.0/Math

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow, so we distribute
        return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
    }
}

// Part: OpenZeppelin/openzeppelin-contracts@3.1.0/SafeMath

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

        return c;
    }

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

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

        return c;
    }

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

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

        return c;
    }

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

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

        return c;
    }

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

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

// Part: WadRayMath

/**
 * @title WadRayMath library
 * @author Aave
 * @dev Provides mul and div function for wads (decimal numbers with 18 digits precision) and rays (decimals with 27 digits)
 **/

library WadRayMath {
    uint256 internal constant WAD = 1e18;
    uint256 internal constant halfWAD = WAD / 2;

    uint256 internal constant RAY = 1e27;
    uint256 internal constant halfRAY = RAY / 2;

    uint256 internal constant WAD_RAY_RATIO = 1e9;

    /**
     * @return One ray, 1e27
     **/
    function ray() internal pure returns (uint256) {
        return RAY;
    }

    /**
     * @return One wad, 1e18
     **/

    function wad() internal pure returns (uint256) {
        return WAD;
    }

    /**
     * @return Half ray, 1e27/2
     **/
    function halfRay() internal pure returns (uint256) {
        return halfRAY;
    }

    /**
     * @return Half ray, 1e18/2
     **/
    function halfWad() internal pure returns (uint256) {
        return halfWAD;
    }

    /**
     * @dev Multiplies two wad, rounding half up to the nearest wad
     * @param a Wad
     * @param b Wad
     * @return The result of a*b, in wad
     **/
    function wadMul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0 || b == 0) {
            return 0;
        }

        require(a <= (type(uint256).max - halfWAD) / b);

        return (a * b + halfWAD) / WAD;
    }

    /**
     * @dev Divides two wad, rounding half up to the nearest wad
     * @param a Wad
     * @param b Wad
     * @return The result of a/b, in wad
     **/
    function wadDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0);
        uint256 halfB = b / 2;

        require(a <= (type(uint256).max - halfB) / WAD);

        return (a * WAD + halfB) / b;
    }

    /**
     * @dev Multiplies two ray, rounding half up to the nearest ray
     * @param a Ray
     * @param b Ray
     * @return The result of a*b, in ray
     **/
    function rayMul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0 || b == 0) {
            return 0;
        }

        require(a <= (type(uint256).max - halfRAY) / b);

        return (a * b + halfRAY) / RAY;
    }

    /**
     * @dev Divides two ray, rounding half up to the nearest ray
     * @param a Ray
     * @param b Ray
     * @return The result of a/b, in ray
     **/
    function rayDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0);
        uint256 halfB = b / 2;

        require(a <= (type(uint256).max - halfB) / RAY);

        return (a * RAY + halfB) / b;
    }

    /**
     * @dev Casts ray down to wad
     * @param a Ray
     * @return a casted to wad, rounded half up to the nearest wad
     **/
    function rayToWad(uint256 a) internal pure returns (uint256) {
        uint256 halfRatio = WAD_RAY_RATIO / 2;
        uint256 result = halfRatio + a;
        require(result >= halfRatio);

        return result / WAD_RAY_RATIO;
    }

    /**
     * @dev Converts wad up to ray
     * @param a Wad
     * @return a converted in ray
     **/
    function wadToRay(uint256 a) internal pure returns (uint256) {
        uint256 result = a * WAD_RAY_RATIO;
        require(result / WAD_RAY_RATIO == a);
        return result;
    }
}

// Part: ILendingPool

interface ILendingPool {
    /**
     * @dev Emitted on deposit()
     * @param reserve The address of the underlying asset of the reserve
     * @param user The address initiating the deposit
     * @param onBehalfOf The beneficiary of the deposit, receiving the aTokens
     * @param amount The amount deposited
     * @param referral The referral code used
     **/
    event Deposit(
        address indexed reserve,
        address user,
        address indexed onBehalfOf,
        uint256 amount,
        uint16 indexed referral
    );

    /**
     * @dev Emitted on withdraw()
     * @param reserve The address of the underlyng asset being withdrawn
     * @param user The address initiating the withdrawal, owner of aTokens
     * @param to Address that will receive the underlying
     * @param amount The amount to be withdrawn
     **/
    event Withdraw(
        address indexed reserve,
        address indexed user,
        address indexed to,
        uint256 amount
    );

    /**
     * @dev Emitted on borrow() and flashLoan() when debt needs to be opened
     * @param reserve The address of the underlying asset being borrowed
     * @param user The address of the user initiating the borrow(), receiving the funds on borrow() or just
     * initiator of the transaction on flashLoan()
     * @param onBehalfOf The address that will be getting the debt
     * @param amount The amount borrowed out
     * @param borrowRateMode The rate mode: 1 for Stable, 2 for Variable
     * @param borrowRate The numeric rate at which the user has borrowed
     * @param referral The referral code used
     **/
    event Borrow(
        address indexed reserve,
        address user,
        address indexed onBehalfOf,
        uint256 amount,
        uint256 borrowRateMode,
        uint256 borrowRate,
        uint16 indexed referral
    );

    /**
     * @dev Emitted on repay()
     * @param reserve The address of the underlying asset of the reserve
     * @param user The beneficiary of the repayment, getting his debt reduced
     * @param repayer The address of the user initiating the repay(), providing the funds
     * @param amount The amount repaid
     **/
    event Repay(
        address indexed reserve,
        address indexed user,
        address indexed repayer,
        uint256 amount
    );

    /**
     * @dev Emitted on swapBorrowRateMode()
     * @param reserve The address of the underlying asset of the reserve
     * @param user The address of the user swapping his rate mode
     * @param rateMode The rate mode that the user wants to swap to
     **/
    event Swap(address indexed reserve, address indexed user, uint256 rateMode);

    /**
     * @dev Emitted on setUserUseReserveAsCollateral()
     * @param reserve The address of the underlying asset of the reserve
     * @param user The address of the user enabling the usage as collateral
     **/
    event ReserveUsedAsCollateralEnabled(
        address indexed reserve,
        address indexed user
    );

    /**
     * @dev Emitted on setUserUseReserveAsCollateral()
     * @param reserve The address of the underlying asset of the reserve
     * @param user The address of the user enabling the usage as collateral
     **/
    event ReserveUsedAsCollateralDisabled(
        address indexed reserve,
        address indexed user
    );

    /**
     * @dev Emitted on rebalanceStableBorrowRate()
     * @param reserve The address of the underlying asset of the reserve
     * @param user The address of the user for which the rebalance has been executed
     **/
    event RebalanceStableBorrowRate(
        address indexed reserve,
        address indexed user
    );

    /**
     * @dev Emitted on flashLoan()
     * @param target The address of the flash loan receiver contract
     * @param initiator The address initiating the flash loan
     * @param asset The address of the asset being flash borrowed
     * @param amount The amount flash borrowed
     * @param premium The fee flash borrowed
     * @param referralCode The referral code used
     **/
    event FlashLoan(
        address indexed target,
        address indexed initiator,
        address indexed asset,
        uint256 amount,
        uint256 premium,
        uint16 referralCode
    );

    /**
     * @dev Emitted when the pause is triggered.
     */
    event Paused();

    /**
     * @dev Emitted when the pause is lifted.
     */
    event Unpaused();

    /**
     * @dev Emitted when a borrower is liquidated. This event is emitted by the LendingPool via
     * LendingPoolCollateral manager using a DELEGATECALL
     * This allows to have the events in the generated ABI for LendingPool.
     * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation
     * @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation
     * @param user The address of the borrower getting liquidated
     * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover
     * @param liquidatedCollateralAmount The amount of collateral received by the liiquidator
     * @param liquidator The address of the liquidator
     * @param receiveAToken `true` if the liquidators wants to receive the collateral aTokens, `false` if he wants
     * to receive the underlying collateral asset directly
     **/
    event LiquidationCall(
        address indexed collateralAsset,
        address indexed debtAsset,
        address indexed user,
        uint256 debtToCover,
        uint256 liquidatedCollateralAmount,
        address liquidator,
        bool receiveAToken
    );

    /**
     * @dev Emitted when the state of a reserve is updated. NOTE: This event is actually declared
     * in the ReserveLogic library and emitted in the updateInterestRates() function. Since the function is internal,
     * the event will actually be fired by the LendingPool contract. The event is therefore replicated here so it
     * gets added to the LendingPool ABI
     * @param reserve The address of the underlying asset of the reserve
     * @param liquidityRate The new liquidity rate
     * @param stableBorrowRate The new stable borrow rate
     * @param variableBorrowRate The new variable borrow rate
     * @param liquidityIndex The new liquidity index
     * @param variableBorrowIndex The new variable borrow index
     **/
    event ReserveDataUpdated(
        address indexed reserve,
        uint256 liquidityRate,
        uint256 stableBorrowRate,
        uint256 variableBorrowRate,
        uint256 liquidityIndex,
        uint256 variableBorrowIndex
    );

    /**
     * @dev Deposits an `amount` of underlying asset into the reserve, receiving in return overlying aTokens.
     * - E.g. User deposits 100 USDC and gets in return 100 aUSDC
     * @param asset The address of the underlying asset to deposit
     * @param amount The amount to be deposited
     * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user
     *   wants to receive them on his own wallet, or a different address if the beneficiary of aTokens
     *   is a different wallet
     * @param referralCode Code used to register the integrator originating the operation, for potential rewards.
     *   0 if the action is executed directly by the user, without any middle-man
     **/
    function deposit(
        address asset,
        uint256 amount,
        address onBehalfOf,
        uint16 referralCode
    ) external;

    /**
     * @dev Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned
     * E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC
     * @param asset The address of the underlying asset to withdraw
     * @param amount The underlying amount to be withdrawn
     *   - Send the value type(uint256).max in order to withdraw the whole aToken balance
     * @param to Address that will receive the underlying, same as msg.sender if the user
     *   wants to receive it on his own wallet, or a different address if the beneficiary is a
     *   different wallet
     * @return The final amount withdrawn
     **/
    function withdraw(
        address asset,
        uint256 amount,
        address to
    ) external returns (uint256);

    /**
     * @dev Allows users to borrow a specific `amount` of the reserve underlying asset, provided that the borrower
     * already deposited enough collateral, or he was given enough allowance by a credit delegator on the
     * corresponding debt token (StableDebtToken or VariableDebtToken)
     * - E.g. User borrows 100 USDC passing as `onBehalfOf` his own address, receiving the 100 USDC in his wallet
     *   and 100 stable/variable debt tokens, depending on the `interestRateMode`
     * @param asset The address of the underlying asset to borrow
     * @param amount The amount to be borrowed
     * @param interestRateMode The interest rate mode at which the user wants to borrow: 1 for Stable, 2 for Variable
     * @param referralCode Code used to register the integrator originating the operation, for potential rewards.
     *   0 if the action is executed directly by the user, without any middle-man
     * @param onBehalfOf Address of the user who will receive the debt. Should be the address of the borrower itself
     * calling the function if he wants to borrow against his own collateral, or the address of the credit delegator
     * if he has been given credit delegation allowance
     **/
    function borrow(
        address asset,
        uint256 amount,
        uint256 interestRateMode,
        uint16 referralCode,
        address onBehalfOf
    ) external;

    /**
     * @notice Repays a borrowed `amount` on a specific reserve, burning the equivalent debt tokens owned
     * - E.g. User repays 100 USDC, burning 100 variable/stable debt tokens of the `onBehalfOf` address
     * @param asset The address of the borrowed underlying asset previously borrowed
     * @param amount The amount to repay
     * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode`
     * @param rateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable
     * @param onBehalfOf Address of the user who will get his debt reduced/removed. Should be the address of the
     * user calling the function if he wants to reduce/remove his own debt, or the address of any other
     * other borrower whose debt should be removed
     * @return The final amount repaid
     **/
    function repay(
        address asset,
        uint256 amount,
        uint256 rateMode,
        address onBehalfOf
    ) external returns (uint256);

    /**
     * @dev Allows a borrower to swap his debt between stable and variable mode, or viceversa
     * @param asset The address of the underlying asset borrowed
     * @param rateMode The rate mode that the user wants to swap to
     **/
    function swapBorrowRateMode(address asset, uint256 rateMode) external;

    /**
     * @dev Rebalances the stable interest rate of a user to the current stable rate defined on the reserve.
     * - Users can be rebalanced if the following conditions are satisfied:
     *     1. Usage ratio is above 95%
     *     2. the current deposit APY is below REBALANCE_UP_THRESHOLD * maxVariableBorrowRate, which means that too much has been
     *        borrowed at a stable rate and depositors are not earning enough
     * @param asset The address of the underlying asset borrowed
     * @param user The address of the user to be rebalanced
     **/
    function rebalanceStableBorrowRate(address asset, address user) external;

    /**
     * @dev Allows depositors to enable/disable a specific deposited asset as collateral
     * @param asset The address of the underlying asset deposited
     * @param useAsCollateral `true` if the user wants to use the deposit as collateral, `false` otherwise
     **/
    function setUserUseReserveAsCollateral(address asset, bool useAsCollateral)
        external;

    /**
     * @dev Function to liquidate a non-healthy position collateral-wise, with Health Factor below 1
     * - The caller (liquidator) covers `debtToCover` amount of debt of the user getting liquidated, and receives
     *   a proportionally amount of the `collateralAsset` plus a bonus to cover market risk
     * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation
     * @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation
     * @param user The address of the borrower getting liquidated
     * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover
     * @param receiveAToken `true` if the liquidators wants to receive the collateral aTokens, `false` if he wants
     * to receive the underlying collateral asset directly
     **/
    function liquidationCall(
        address collateralAsset,
        address debtAsset,
        address user,
        uint256 debtToCover,
        bool receiveAToken
    ) external;

    /**
     * @dev Allows smartcontracts to access the liquidity of the pool within one transaction,
     * as long as the amount taken plus a fee is returned.
     * IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept into consideration.
     * For further details please visit https://developers.aave.com
     * @param receiverAddress The address of the contract receiving the funds, implementing the IFlashLoanReceiver interface
     * @param assets The addresses of the assets being flash-borrowed
     * @param amounts The amounts amounts being flash-borrowed
     * @param modes Types of the debt to open if the flash loan is not returned:
     *   0 -> Don't open any debt, just revert if funds can't be transferred from the receiver
     *   1 -> Open debt at stable rate for the value of the amount flash-borrowed to the `onBehalfOf` address
     *   2 -> Open debt at variable rate for the value of the amount flash-borrowed to the `onBehalfOf` address
     * @param onBehalfOf The address  that will receive the debt in the case of using on `modes` 1 or 2
     * @param params Variadic packed params to pass to the receiver as extra information
     * @param referralCode Code used to register the integrator originating the operation, for potential rewards.
     *   0 if the action is executed directly by the user, without any middle-man
     **/
    function flashLoan(
        address receiverAddress,
        address[] calldata assets,
        uint256[] calldata amounts,
        uint256[] calldata modes,
        address onBehalfOf,
        bytes calldata params,
        uint16 referralCode
    ) external;

    /**
     * @dev Returns the user account data across all the reserves
     * @param user The address of the user
     * @return totalCollateralETH the total collateral in ETH of the user
     * @return totalDebtETH the total debt in ETH of the user
     * @return availableBorrowsETH the borrowing power left of the user
     * @return currentLiquidationThreshold the liquidation threshold of the user
     * @return ltv the loan to value of the user
     * @return healthFactor the current health factor of the user
     **/
    function getUserAccountData(address user)
        external
        view
        returns (
            uint256 totalCollateralETH,
            uint256 totalDebtETH,
            uint256 availableBorrowsETH,
            uint256 currentLiquidationThreshold,
            uint256 ltv,
            uint256 healthFactor
        );

    function initReserve(
        address reserve,
        address aTokenAddress,
        address stableDebtAddress,
        address variableDebtAddress,
        address interestRateStrategyAddress
    ) external;

    function setReserveInterestRateStrategyAddress(
        address reserve,
        address rateStrategyAddress
    ) external;

    function setConfiguration(address reserve, uint256 configuration) external;

    /**
     * @dev Returns the configuration of the reserve
     * @param asset The address of the underlying asset of the reserve
     * @return The configuration of the reserve
     **/
    function getConfiguration(address asset)
        external
        view
        returns (DataTypes.ReserveConfigurationMap memory);

    /**
     * @dev Returns the configuration of the user across all the reserves
     * @param user The user address
     * @return The configuration of the user
     **/
    function getUserConfiguration(address user)
        external
        view
        returns (DataTypes.UserConfigurationMap memory);

    /**
     * @dev Returns the normalized income normalized income of the reserve
     * @param asset The address of the underlying asset of the reserve
     * @return The reserve's normalized income
     */
    function getReserveNormalizedIncome(address asset)
        external
        view
        returns (uint256);

    /**
     * @dev Returns the normalized variable debt per unit of asset
     * @param asset The address of the underlying asset of the reserve
     * @return The reserve normalized variable debt
     */
    function getReserveNormalizedVariableDebt(address asset)
        external
        view
        returns (uint256);

    /**
     * @dev Returns the state and configuration of the reserve
     * @param asset The address of the underlying asset of the reserve
     * @return The state of the reserve
     **/
    function getReserveData(address asset)
        external
        view
        returns (DataTypes.ReserveData memory);

    function finalizeTransfer(
        address asset,
        address from,
        address to,
        uint256 amount,
        uint256 balanceFromAfter,
        uint256 balanceToBefore
    ) external;

    function getReservesList() external view returns (address[] memory);

    function getAddressesProvider()
        external
        view
        returns (ILendingPoolAddressesProvider);

    function setPause(bool val) external;

    function paused() external view returns (bool);
}

// Part: IProtocolDataProvider

interface IProtocolDataProvider {
    struct TokenData {
        string symbol;
        address tokenAddress;
    }

    function ADDRESSES_PROVIDER()
        external
        view
        returns (ILendingPoolAddressesProvider);

    function getAllReservesTokens() external view returns (TokenData[] memory);

    function getAllATokens() external view returns (TokenData[] memory);

    function getReserveConfigurationData(address asset)
        external
        view
        returns (
            uint256 decimals,
            uint256 ltv,
            uint256 liquidationThreshold,
            uint256 liquidationBonus,
            uint256 reserveFactor,
            bool usageAsCollateralEnabled,
            bool borrowingEnabled,
            bool stableBorrowRateEnabled,
            bool isActive,
            bool isFrozen
        );

    function getReserveData(address asset)
        external
        view
        returns (
            uint256 availableLiquidity,
            uint256 totalStableDebt,
            uint256 totalVariableDebt,
            uint256 liquidityRate,
            uint256 variableBorrowRate,
            uint256 stableBorrowRate,
            uint256 averageStableBorrowRate,
            uint256 liquidityIndex,
            uint256 variableBorrowIndex,
            uint40 lastUpdateTimestamp
        );

    function getUserReserveData(address asset, address user)
        external
        view
        returns (
            uint256 currentATokenBalance,
            uint256 currentStableDebt,
            uint256 currentVariableDebt,
            uint256 principalStableDebt,
            uint256 scaledVariableDebt,
            uint256 stableBorrowRate,
            uint256 liquidityRate,
            uint40 stableRateLastUpdated,
            bool usageAsCollateralEnabled
        );

    function getReserveTokensAddresses(address asset)
        external
        view
        returns (
            address aTokenAddress,
            address stableDebtTokenAddress,
            address variableDebtTokenAddress
        );
}

// Part: IVariableDebtToken

/**
 * @title IVariableDebtToken
 * @author Aave
 * @notice Defines the basic interface for a variable debt token.
 **/
interface IVariableDebtToken is IERC20, IScaledBalanceToken {
    /**
     * @dev Emitted after the mint action
     * @param from The address performing the mint
     * @param onBehalfOf The address of the user on which behalf minting has been performed
     * @param value The amount to be minted
     * @param index The last index of the reserve
     **/
    event Mint(
        address indexed from,
        address indexed onBehalfOf,
        uint256 value,
        uint256 index
    );

    /**
     * @dev Mints debt token to the `onBehalfOf` address
     * @param user The address receiving the borrowed underlying, being the delegatee in case
     * of credit delegate, or same as `onBehalfOf` otherwise
     * @param onBehalfOf The address receiving the debt tokens
     * @param amount The amount of debt being minted
     * @param index The variable debt index of the reserve
     * @return `true` if the the previous balance of the user is 0
     **/
    function mint(
        address user,
        address onBehalfOf,
        uint256 amount,
        uint256 index
    ) external returns (bool);

    /**
     * @dev Emitted when variable debt is burnt
     * @param user The user which debt has been burned
     * @param amount The amount of debt being burned
     * @param index The index of the user
     **/
    event Burn(address indexed user, uint256 amount, uint256 index);

    /**
     * @dev Burns user variable debt
     * @param user The user which debt is burnt
     * @param index The variable debt index of the reserve
     **/
    function burn(
        address user,
        uint256 amount,
        uint256 index
    ) external;

    /**
     * @dev Returns the address of the incentives controller contract
     **/
    function getIncentivesController()
        external
        view
        returns (IAaveIncentivesController);
}

// Part: IVault

interface IVault is IERC20 {
    function token() external view returns (address);

    function decimals() external view returns (uint256);

    function deposit() external;

    function pricePerShare() external view returns (uint256);

    function withdraw() external returns (uint256);

    function withdraw(uint256 amount) external returns (uint256);

    function withdraw(
        uint256 amount,
        address account,
        uint256 maxLoss
    ) external returns (uint256);

    function availableDepositLimit() external view returns (uint256);
}

// Part: OpenZeppelin/openzeppelin-contracts@3.1.0/SafeERC20

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

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

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

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        // solhint-disable-next-line max-line-length
        require((value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

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

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

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) { // Return data is optional
            // solhint-disable-next-line max-line-length
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

// Part: iearn-finance/yearn-vaults@0.3.5/VaultAPI

interface VaultAPI is IERC20 {
    function name() external view returns (string calldata);

    function symbol() external view returns (string calldata);

    function decimals() external view returns (uint256);

    function apiVersion() external pure returns (string memory);

    function permit(
        address owner,
        address spender,
        uint256 amount,
        uint256 expiry,
        bytes calldata signature
    ) external returns (bool);

    // NOTE: Vyper produces multiple signatures for a given function with "default" args
    function deposit() external returns (uint256);

    function deposit(uint256 amount) external returns (uint256);

    function deposit(uint256 amount, address recipient) external returns (uint256);

    // NOTE: Vyper produces multiple signatures for a given function with "default" args
    function withdraw() external returns (uint256);

    function withdraw(uint256 maxShares) external returns (uint256);

    function withdraw(uint256 maxShares, address recipient) external returns (uint256);

    function token() external view returns (address);

    function strategies(address _strategy) external view returns (StrategyParams memory);

    function pricePerShare() external view returns (uint256);

    function totalAssets() external view returns (uint256);

    function depositLimit() external view returns (uint256);

    function maxAvailableShares() external view returns (uint256);

    /**
     * View how much the Vault would increase this Strategy's borrow limit,
     * based on its present performance (since its last report). Can be used to
     * determine expectedReturn in your Strategy.
     */
    function creditAvailable() external view returns (uint256);

    /**
     * View how much the Vault would like to pull back from the Strategy,
     * based on its present performance (since its last report). Can be used to
     * determine expectedReturn in your Strategy.
     */
    function debtOutstanding() external view returns (uint256);

    /**
     * View how much the Vault expect this Strategy to return at the current
     * block, based on its present performance (since its last report). Can be
     * used to determine expectedReturn in your Strategy.
     */
    function expectedReturn() external view returns (uint256);

    /**
     * This is the main contact point where the Strategy interacts with the
     * Vault. It is critical that this call is handled as intended by the
     * Strategy. Therefore, this function will be called by BaseStrategy to
     * make sure the integration is correct.
     */
    function report(
        uint256 _gain,
        uint256 _loss,
        uint256 _debtPayment
    ) external returns (uint256);

    /**
     * This function should only be used in the scenario where the Strategy is
     * being retired but no migration of the positions are possible, or in the
     * extreme scenario that the Strategy needs to be put into "Emergency Exit"
     * mode in order for it to exit as quickly as possible. The latter scenario
     * could be for any reason that is considered "critical" that the Strategy
     * exits its position as fast as possible, such as a sudden change in
     * market conditions leading to losses, or an imminent failure in an
     * external dependency.
     */
    function revokeStrategy() external;

    /**
     * View the governance address of the Vault to assert privileged functions
     * can only be called by governance. The Strategy serves the Vault, so it
     * is subject to governance defined by the Vault.
     */
    function governance() external view returns (address);

    /**
     * View the management address of the Vault to assert privileged functions
     * can only be called by management. The Strategy serves the Vault, so it
     * is subject to management defined by the Vault.
     */
    function management() external view returns (address);

    /**
     * View the guardian address of the Vault to assert privileged functions
     * can only be called by guardian. The Strategy serves the Vault, so it
     * is subject to guardian defined by the Vault.
     */
    function guardian() external view returns (address);
}

// Part: IInitializableAToken

/**
 * @title IInitializableAToken
 * @notice Interface for the initialize function on AToken
 * @author Aave
 **/
interface IInitializableAToken {
    /**
     * @dev Emitted when an aToken is initialized
     * @param underlyingAsset The address of the underlying asset
     * @param pool The address of the associated lending pool
     * @param treasury The address of the treasury
     * @param incentivesController The address of the incentives controller for this aToken
     * @param aTokenDecimals the decimals of the underlying
     * @param aTokenName the name of the aToken
     * @param aTokenSymbol the symbol of the aToken
     * @param params A set of encoded parameters for additional initialization
     **/
    event Initialized(
        address indexed underlyingAsset,
        address indexed pool,
        address treasury,
        address incentivesController,
        uint8 aTokenDecimals,
        string aTokenName,
        string aTokenSymbol,
        bytes params
    );

    /**
     * @dev Initializes the aToken
     * @param pool The address of the lending pool where this aToken will be used
     * @param treasury The address of the Aave treasury, receiving the fees on this aToken
     * @param underlyingAsset The address of the underlying asset of this aToken (E.g. WETH for aWETH)
     * @param incentivesController The smart contract managing potential incentives distribution
     * @param aTokenDecimals The decimals of the aToken, same as the underlying asset's
     * @param aTokenName The name of the aToken
     * @param aTokenSymbol The symbol of the aToken
     */
    function initialize(
        ILendingPool pool,
        address treasury,
        address underlyingAsset,
        IAaveIncentivesController incentivesController,
        uint8 aTokenDecimals,
        string calldata aTokenName,
        string calldata aTokenSymbol,
        bytes calldata params
    ) external;
}

// Part: iearn-finance/yearn-vaults@0.3.5/BaseStrategy

/**
 * @title Yearn Base Strategy
 * @author yearn.finance
 * @notice
 *  BaseStrategy implements all of the required functionality to interoperate
 *  closely with the Vault contract. This contract should be inherited and the
 *  abstract methods implemented to adapt the Strategy to the particular needs
 *  it has to create a return.
 *
 *  Of special interest is the relationship between `harvest()` and
 *  `vault.report()'. `harvest()` may be called simply because enough time has
 *  elapsed since the last report, and not because any funds need to be moved
 *  or positions adjusted. This is critical so that the Vault may maintain an
 *  accurate picture of the Strategy's performance. See  `vault.report()`,
 *  `harvest()`, and `harvestTrigger()` for further details.
 */
abstract contract BaseStrategy {
    using SafeMath for uint256;
    using SafeERC20 for IERC20;
    string public metadataURI;

    /**
     * @notice
     *  Used to track which version of `StrategyAPI` this Strategy
     *  implements.
     * @dev The Strategy's version must match the Vault's `API_VERSION`.
     * @return A string which holds the current API version of this contract.
     */
    function apiVersion() public pure returns (string memory) {
        return "0.3.5";
    }

    /**
     * @notice This Strategy's name.
     * @dev
     *  You can use this field to manage the "version" of this Strategy, e.g.
     *  `StrategySomethingOrOtherV1`. However, "API Version" is managed by
     *  `apiVersion()` function above.
     * @return This Strategy's name.
     */
    function name() external virtual view returns (string memory);

    /**
     * @notice
     *  The amount (priced in want) of the total assets managed by this strategy should not count
     *  towards Yearn's TVL calculations.
     * @dev
     *  You can override this field to set it to a non-zero value if some of the assets of this
     *  Strategy is somehow delegated inside another part of of Yearn's ecosystem e.g. another Vault.
     *  Note that this value must be strictly less than or equal to the amount provided by
     *  `estimatedTotalAssets()` below, as the TVL calc will be total assets minus delegated assets.
     *  Also note that this value is used to determine the total assets under management by this
     *  strategy, for the purposes of computing the management fee in `Vault`
     * @return
     *  The amount of assets this strategy manages that should not be included in Yearn's Total Value
     *  Locked (TVL) calculation across it's ecosystem.
     */
    function delegatedAssets() external virtual view returns (uint256) {
        return 0;
    }

    VaultAPI public vault;
    address public strategist;
    address public rewards;
    address public keeper;

    IERC20 public want;

    // So indexers can keep track of this
    event Harvested(uint256 profit, uint256 loss, uint256 debtPayment, uint256 debtOutstanding);

    event UpdatedStrategist(address newStrategist);

    event UpdatedKeeper(address newKeeper);

    event UpdatedRewards(address rewards);

    event UpdatedMinReportDelay(uint256 delay);

    event UpdatedMaxReportDelay(uint256 delay);

    event UpdatedProfitFactor(uint256 profitFactor);

    event UpdatedDebtThreshold(uint256 debtThreshold);

    event EmergencyExitEnabled();

    event UpdatedMetadataURI(string metadataURI);

    // The minimum number of seconds between harvest calls. See
    // `setMinReportDelay()` for more details.
    uint256 public minReportDelay;

    // The maximum number of seconds between harvest calls. See
    // `setMaxReportDelay()` for more details.
    uint256 public maxReportDelay;

    // The minimum multiple that `callCost` must be above the credit/profit to
    // be "justifiable". See `setProfitFactor()` for more details.
    uint256 public profitFactor;

    // Use this to adjust the threshold at which running a debt causes a
    // harvest trigger. See `setDebtThreshold()` for more details.
    uint256 public debtThreshold;

    // See note on `setEmergencyExit()`.
    bool public emergencyExit;

    // modifiers
    modifier onlyAuthorized() {
        require(msg.sender == strategist || msg.sender == governance(), "!authorized");
        _;
    }

    modifier onlyStrategist() {
        require(msg.sender == strategist, "!strategist");
        _;
    }

    modifier onlyGovernance() {
        require(msg.sender == governance(), "!authorized");
        _;
    }

    modifier onlyKeepers() {
        require(
            msg.sender == keeper ||
                msg.sender == strategist ||
                msg.sender == governance() ||
                msg.sender == vault.guardian() ||
                msg.sender == vault.management(),
            "!authorized"
        );
        _;
    }

    constructor(address _vault) public {
        _initialize(_vault, msg.sender, msg.sender, msg.sender);
    }

    /**
     * @notice
     *  Initializes the Strategy, this is called only once, when the
     *  contract is deployed.
     * @dev `_vault` should implement `VaultAPI`.
     * @param _vault The address of the Vault responsible for this Strategy.
     */
    function _initialize(
        address _vault,
        address _strategist,
        address _rewards,
        address _keeper
    ) internal {
        require(address(want) == address(0), "Strategy already initialized");

        vault = VaultAPI(_vault);
        want = IERC20(vault.token());
        want.safeApprove(_vault, uint256(-1)); // Give Vault unlimited access (might save gas)
        strategist = _strategist;
        rewards = _rewards;
        keeper = _keeper;

        // initialize variables
        minReportDelay = 0;
        maxReportDelay = 86400;
        profitFactor = 100;
        debtThreshold = 0;

        vault.approve(rewards, uint256(-1)); // Allow rewards to be pulled
    }

    /**
     * @notice
     *  Used to change `strategist`.
     *
     *  This may only be called by governance or the existing strategist.
     * @param _strategist The new address to assign as `strategist`.
     */
    function setStrategist(address _strategist) external onlyAuthorized {
        require(_strategist != address(0));
        strategist = _strategist;
        emit UpdatedStrategist(_strategist);
    }

    /**
     * @notice
     *  Used to change `keeper`.
     *
     *  `keeper` is the only address that may call `tend()` or `harvest()`,
     *  other than `governance()` or `strategist`. However, unlike
     *  `governance()` or `strategist`, `keeper` may *only* call `tend()`
     *  and `harvest()`, and no other authorized functions, following the
     *  principle of least privilege.
     *
     *  This may only be called by governance or the strategist.
     * @param _keeper The new address to assign as `keeper`.
     */
    function setKeeper(address _keeper) external onlyAuthorized {
        require(_keeper != address(0));
        keeper = _keeper;
        emit UpdatedKeeper(_keeper);
    }

    /**
     * @notice
     *  Used to change `rewards`. EOA or smart contract which has the permission
     *  to pull rewards from the vault.
     *
     *  This may only be called by the strategist.
     * @param _rewards The address to use for pulling rewards.
     */
    function setRewards(address _rewards) external onlyStrategist {
        require(_rewards != address(0));
        vault.approve(rewards, 0);
        rewards = _rewards;
        vault.approve(rewards, uint256(-1));
        emit UpdatedRewards(_rewards);
    }

    /**
     * @notice
     *  Used to change `minReportDelay`. `minReportDelay` is the minimum number
     *  of blocks that should pass for `harvest()` to be called.
     *
     *  For external keepers (such as the Keep3r network), this is the minimum
     *  time between jobs to wait. (see `harvestTrigger()`
     *  for more details.)
     *
     *  This may only be called by governance or the strategist.
     * @param _delay The minimum number of seconds to wait between harvests.
     */
    function setMinReportDelay(uint256 _delay) external onlyAuthorized {
        minReportDelay = _delay;
        emit UpdatedMinReportDelay(_delay);
    }

    /**
     * @notice
     *  Used to change `maxReportDelay`. `maxReportDelay` is the maximum number
     *  of blocks that should pass for `harvest()` to be called.
     *
     *  For external keepers (such as the Keep3r network), this is the maximum
     *  time between jobs to wait. (see `harvestTrigger()`
     *  for more details.)
     *
     *  This may only be called by governance or the strategist.
     * @param _delay The maximum number of seconds to wait between harvests.
     */
    function setMaxReportDelay(uint256 _delay) external onlyAuthorized {
        maxReportDelay = _delay;
        emit UpdatedMaxReportDelay(_delay);
    }

    /**
     * @notice
     *  Used to change `profitFactor`. `profitFactor` is used to determine
     *  if it's worthwhile to harvest, given gas costs. (See `harvestTrigger()`
     *  for more details.)
     *
     *  This may only be called by governance or the strategist.
     * @param _profitFactor A ratio to multiply anticipated
     * `harvest()` gas cost against.
     */
    function setProfitFactor(uint256 _profitFactor) external onlyAuthorized {
        profitFactor = _profitFactor;
        emit UpdatedProfitFactor(_profitFactor);
    }

    /**
     * @notice
     *  Sets how far the Strategy can go into loss without a harvest and report
     *  being required.
     *
     *  By default this is 0, meaning any losses would cause a harvest which
     *  will subsequently report the loss to the Vault for tracking. (See
     *  `harvestTrigger()` for more details.)
     *
     *  This may only be called by governance or the strategist.
     * @param _debtThreshold How big of a loss this Strategy may carry without
     * being required to report to the Vault.
     */
    function setDebtThreshold(uint256 _debtThreshold) external onlyAuthorized {
        debtThreshold = _debtThreshold;
        emit UpdatedDebtThreshold(_debtThreshold);
    }

    /**
     * @notice
     *  Used to change `metadataURI`. `metadataURI` is used to store the URI
     * of the file describing the strategy.
     *
     *  This may only be called by governance or the strategist.
     * @param _metadataURI The URI that describe the strategy.
     */
    function setMetadataURI(string calldata _metadataURI) external onlyAuthorized {
        metadataURI = _metadataURI;
        emit UpdatedMetadataURI(_metadataURI);
    }

    /**
     * Resolve governance address from Vault contract, used to make assertions
     * on protected functions in the Strategy.
     */
    function governance() internal view returns (address) {
        return vault.governance();
    }

    /**
     * @notice
     *  Provide an accurate estimate for the total amount of assets
     *  (principle + return) that this Strategy is currently managing,
     *  denominated in terms of `want` tokens.
     *
     *  This total should be "realizable" e.g. the total value that could
     *  *actually* be obtained from this Strategy if it were to divest its
     *  entire position based on current on-chain conditions.
     * @dev
     *  Care must be taken in using this function, since it relies on external
     *  systems, which could be manipulated by the attacker to give an inflated
     *  (or reduced) value produced by this function, based on current on-chain
     *  conditions (e.g. this function is possible to influence through
     *  flashloan attacks, oracle manipulations, or other DeFi attack
     *  mechanisms).
     *
     *  It is up to governance to use this function to correctly order this
     *  Strategy relative to its peers in the withdrawal queue to minimize
     *  losses for the Vault based on sudden withdrawals. This value should be
     *  higher than the total debt of the Strategy and higher than its expected
     *  value to be "safe".
     * @return The estimated total assets in this Strategy.
     */
    function estimatedTotalAssets() public virtual view returns (uint256);

    /*
     * @notice
     *  Provide an indication of whether this strategy is currently "active"
     *  in that it is managing an active position, or will manage a position in
     *  the future. This should correlate to `harvest()` activity, so that Harvest
     *  events can be tracked externally by indexing agents.
     * @return True if the strategy is actively managing a position.
     */
    function isActive() public view returns (bool) {
        return vault.strategies(address(this)).debtRatio > 0 || estimatedTotalAssets() > 0;
    }

    /**
     * Perform any Strategy unwinding or other calls necessary to capture the
     * "free return" this Strategy has generated since the last time its core
     * position(s) were adjusted. Examples include unwrapping extra rewards.
     * This call is only used during "normal operation" of a Strategy, and
     * should be optimized to minimize losses as much as possible.
     *
     * This method returns any realized profits and/or realized losses
     * incurred, and should return the total amounts of profits/losses/debt
     * payments (in `want` tokens) for the Vault's accounting (e.g.
     * `want.balanceOf(this) >= _debtPayment + _profit - _loss`).
     *
     * `_debtOutstanding` will be 0 if the Strategy is not past the configured
     * debt limit, otherwise its value will be how far past the debt limit
     * the Strategy is. The Strategy's debt limit is configured in the Vault.
     *
     * NOTE: `_debtPayment` should be less than or equal to `_debtOutstanding`.
     *       It is okay for it to be less than `_debtOutstanding`, as that
     *       should only used as a guide for how much is left to pay back.
     *       Payments should be made to minimize loss from slippage, debt,
     *       withdrawal fees, etc.
     *
     * See `vault.debtOutstanding()`.
     */
    function prepareReturn(uint256 _debtOutstanding)
        internal
        virtual
        returns (
            uint256 _profit,
            uint256 _loss,
            uint256 _debtPayment
        );

    /**
     * Perform any adjustments to the core position(s) of this Strategy given
     * what change the Vault made in the "investable capital" available to the
     * Strategy. Note that all "free capital" in the Strategy after the report
     * was made is available for reinvestment. Also note that this number
     * could be 0, and you should handle that scenario accordingly.
     *
     * See comments regarding `_debtOutstanding` on `prepareReturn()`.
     */
    function adjustPosition(uint256 _debtOutstanding) internal virtual;

    /**
     * Liquidate up to `_amountNeeded` of `want` of this strategy's positions,
     * irregardless of slippage. Any excess will be re-invested with `adjustPosition()`.
     * This function should return the amount of `want` tokens made available by the
     * liquidation. If there is a difference between them, `_loss` indicates whether the
     * difference is due to a realized loss, or if there is some other sitution at play
     * (e.g. locked funds) where the amount made available is less than what is needed.
     * This function is used during emergency exit instead of `prepareReturn()` to
     * liquidate all of the Strategy's positions back to the Vault.
     *
     * NOTE: The invariant `_liquidatedAmount + _loss <= _amountNeeded` should always be maintained
     */
    function liquidatePosition(uint256 _amountNeeded) internal virtual returns (uint256 _liquidatedAmount, uint256 _loss);

    /**
     * @notice
     *  Provide a signal to the keeper that `tend()` should be called. The
     *  keeper will provide the estimated gas cost that they would pay to call
     *  `tend()`, and this function should use that estimate to make a
     *  determination if calling it is "worth it" for the keeper. This is not
     *  the only consideration into issuing this trigger, for example if the
     *  position would be negatively affected if `tend()` is not called
     *  shortly, then this can return `true` even if the keeper might be
     *  "at a loss" (keepers are always reimbursed by Yearn).
     * @dev
     *  `callCost` must be priced in terms of `want`.
     *
     *  This call and `harvestTrigger()` should never return `true` at the same
     *  time.
     * @param callCost The keeper's estimated cast cost to call `tend()`.
     * @return `true` if `tend()` should be called, `false` otherwise.
     */
    function tendTrigger(uint256 callCost) public virtual view returns (bool) {
        // We usually don't need tend, but if there are positions that need
        // active maintainence, overriding this function is how you would
        // signal for that.
        return false;
    }

    /**
     * @notice
     *  Adjust the Strategy's position. The purpose of tending isn't to
     *  realize gains, but to maximize yield by reinvesting any returns.
     *
     *  See comments on `adjustPosition()`.
     *
     *  This may only be called by governance, the strategist, or the keeper.
     */
    function tend() external onlyKeepers {
        // Don't take profits with this call, but adjust for better gains
        adjustPosition(vault.debtOutstanding());
    }

    /**
     * @notice
     *  Provide a signal to the keeper that `harvest()` should be called. The
     *  keeper will provide the estimated gas cost that they would pay to call
     *  `harvest()`, and this function should use that estimate to make a
     *  determination if calling it is "worth it" for the keeper. This is not
     *  the only consideration into issuing this trigger, for example if the
     *  position would be negatively affected if `harvest()` is not called
     *  shortly, then this can return `true` even if the keeper might be "at a
     *  loss" (keepers are always reimbursed by Yearn).
     * @dev
     *  `callCost` must be priced in terms of `want`.
     *
     *  This call and `tendTrigger` should never return `true` at the
     *  same time.
     *
     *  See `min/maxReportDelay`, `profitFactor`, `debtThreshold` to adjust the
     *  strategist-controlled parameters that will influence whether this call
     *  returns `true` or not. These parameters will be used in conjunction
     *  with the parameters reported to the Vault (see `params`) to determine
     *  if calling `harvest()` is merited.
     *
     *  It is expected that an external system will check `harvestTrigger()`.
     *  This could be a script run off a desktop or cloud bot (e.g.
     *  https://github.com/iearn-finance/yearn-vaults/blob/master/scripts/keep.py),
     *  or via an integration with the Keep3r network (e.g.
     *  https://github.com/Macarse/GenericKeep3rV2/blob/master/contracts/keep3r/GenericKeep3rV2.sol).
     * @param callCost The keeper's estimated cast cost to call `harvest()`.
     * @return `true` if `harvest()` should be called, `false` otherwise.
     */
    function harvestTrigger(uint256 callCost) public virtual view returns (bool) {
        StrategyParams memory params = vault.strategies(address(this));

        // Should not trigger if Strategy is not activated
        if (params.activation == 0) return false;

        // Should not trigger if we haven't waited long enough since previous harvest
        if (block.timestamp.sub(params.lastReport) < minReportDelay) return false;

        // Should trigger if hasn't been called in a while
        if (block.timestamp.sub(params.lastReport) >= maxReportDelay) return true;

        // If some amount is owed, pay it back
        // NOTE: Since debt is based on deposits, it makes sense to guard against large
        //       changes to the value from triggering a harvest directly through user
        //       behavior. This should ensure reasonable resistance to manipulation
        //       from user-initiated withdrawals as the outstanding debt fluctuates.
        uint256 outstanding = vault.debtOutstanding();
        if (outstanding > debtThreshold) return true;

        // Check for profits and losses
        uint256 total = estimatedTotalAssets();
        // Trigger if we have a loss to report
        if (total.add(debtThreshold) < params.totalDebt) return true;

        uint256 profit = 0;
        if (total > params.totalDebt) profit = total.sub(params.totalDebt); // We've earned a profit!

        // Otherwise, only trigger if it "makes sense" economically (gas cost
        // is <N% of value moved)
        uint256 credit = vault.creditAvailable();
        return (profitFactor.mul(callCost) < credit.add(profit));
    }

    /**
     * @notice
     *  Harvests the Strategy, recognizing any profits or losses and adjusting
     *  the Strategy's position.
     *
     *  In the rare case the Strategy is in emergency shutdown, this will exit
     *  the Strategy's position.
     *
     *  This may only be called by governance, the strategist, or the keeper.
     * @dev
     *  When `harvest()` is called, the Strategy reports to the Vault (via
     *  `vault.report()`), so in some cases `harvest()` must be called in order
     *  to take in profits, to borrow newly available funds from the Vault, or
     *  otherwise adjust its position. In other cases `harvest()` must be
     *  called to report to the Vault on the Strategy's position, especially if
     *  any losses have occurred.
     */
    function harvest() external onlyKeepers {
        uint256 profit = 0;
        uint256 loss = 0;
        uint256 debtOutstanding = vault.debtOutstanding();
        uint256 debtPayment = 0;
        if (emergencyExit) {
            // Free up as much capital as possible
            uint256 totalAssets = estimatedTotalAssets();
            // NOTE: use the larger of total assets or debt outstanding to book losses properly
            (debtPayment, loss) = liquidatePosition(totalAssets > debtOutstanding ? totalAssets : debtOutstanding);
            // NOTE: take up any remainder here as profit
            if (debtPayment > debtOutstanding) {
                profit = debtPayment.sub(debtOutstanding);
                debtPayment = debtOutstanding;
            }
        } else {
            // Free up returns for Vault to pull
            (profit, loss, debtPayment) = prepareReturn(debtOutstanding);
        }

        // Allow Vault to take up to the "harvested" balance of this contract,
        // which is the amount it has earned since the last time it reported to
        // the Vault.
        debtOutstanding = vault.report(profit, loss, debtPayment);

        // Check if free returns are left, and re-invest them
        adjustPosition(debtOutstanding);

        emit Harvested(profit, loss, debtPayment, debtOutstanding);
    }

    /**
     * @notice
     *  Withdraws `_amountNeeded` to `vault`.
     *
     *  This may only be called by the Vault.
     * @param _amountNeeded How much `want` to withdraw.
     * @return _loss Any realized losses
     */
    function withdraw(uint256 _amountNeeded) external returns (uint256 _loss) {
        require(msg.sender == address(vault), "!vault");
        // Liquidate as much as possible to `want`, up to `_amountNeeded`
        uint256 amountFreed;
        (amountFreed, _loss) = liquidatePosition(_amountNeeded);
        // Send it directly back (NOTE: Using `msg.sender` saves some gas here)
        want.safeTransfer(msg.sender, amountFreed);
        // NOTE: Reinvest anything leftover on next `tend`/`harvest`
    }

    /**
     * Do anything necessary to prepare this Strategy for migration, such as
     * transferring any reserve or LP tokens, CDPs, or other tokens or stores of
     * value.
     */
    function prepareMigration(address _newStrategy) internal virtual;

    /**
     * @notice
     *  Transfers all `want` from this Strategy to `_newStrategy`.
     *
     *  This may only be called by governance or the Vault.
     * @dev
     *  The new Strategy's Vault must be the same as this Strategy's Vault.
     * @param _newStrategy The Strategy to migrate to.
     */
    function migrate(address _newStrategy) external {
        require(msg.sender == address(vault) || msg.sender == governance());
        require(BaseStrategy(_newStrategy).vault() == vault);
        prepareMigration(_newStrategy);
        want.safeTransfer(_newStrategy, want.balanceOf(address(this)));
    }

    /**
     * @notice
     *  Activates emergency exit. Once activated, the Strategy will exit its
     *  position upon the next harvest, depositing all funds into the Vault as
     *  quickly as is reasonable given on-chain conditions.
     *
     *  This may only be called by governance or the strategist.
     * @dev
     *  See `vault.setEmergencyShutdown()` and `harvest()` for further details.
     */
    function setEmergencyExit() external onlyAuthorized {
        emergencyExit = true;
        vault.revokeStrategy();

        emit EmergencyExitEnabled();
    }

    /**
     * Override this to add all tokens/tokenized positions this contract
     * manages on a *persistent* basis (e.g. not just for swapping back to
     * want ephemerally).
     *
     * NOTE: Do *not* include `want`, already included in `sweep` below.
     *
     * Example:
     *
     *    function protectedTokens() internal override view returns (address[] memory) {
     *      address[] memory protected = new address[](3);
     *      protected[0] = tokenA;
     *      protected[1] = tokenB;
     *      protected[2] = tokenC;
     *      return protected;
     *    }
     */
    function protectedTokens() internal virtual view returns (address[] memory);

    /**
     * @notice
     *  Removes tokens from this Strategy that are not the type of tokens
     *  managed by this Strategy. This may be used in case of accidentally
     *  sending the wrong kind of token to this Strategy.
     *
     *  Tokens will be sent to `governance()`.
     *
     *  This will fail if an attempt is made to sweep `want`, or any tokens
     *  that are protected by this Strategy.
     *
     *  This may only be called by governance.
     * @dev
     *  Implement `protectedTokens()` to specify any additional tokens that
     *  should be protected from sweeping in addition to `want`.
     * @param _token The token to transfer out of this vault.
     */
    function sweep(address _token) external onlyGovernance {
        require(_token != address(want), "!want");
        require(_token != address(vault), "!shares");

        address[] memory _protectedTokens = protectedTokens();
        for (uint256 i; i < _protectedTokens.length; i++) require(_token != _protectedTokens[i], "!protected");

        IERC20(_token).safeTransfer(governance(), IERC20(_token).balanceOf(address(this)));
    }
}

// Part: IAToken

interface IAToken is IERC20, IScaledBalanceToken, IInitializableAToken {
    /**
     * @dev Emitted after the mint action
     * @param from The address performing the mint
     * @param value The amount being
     * @param index The new liquidity index of the reserve
     **/
    event Mint(address indexed from, uint256 value, uint256 index);

    /**
     * @dev Mints `amount` aTokens to `user`
     * @param user The address receiving the minted tokens
     * @param amount The amount of tokens getting minted
     * @param index The new liquidity index of the reserve
     * @return `true` if the the previous balance of the user was 0
     */
    function mint(
        address user,
        uint256 amount,
        uint256 index
    ) external returns (bool);

    /**
     * @dev Emitted after aTokens are burned
     * @param from The owner of the aTokens, getting them burned
     * @param target The address that will receive the underlying
     * @param value The amount being burned
     * @param index The new liquidity index of the reserve
     **/
    event Burn(
        address indexed from,
        address indexed target,
        uint256 value,
        uint256 index
    );

    /**
     * @dev Emitted during the transfer action
     * @param from The user whose tokens are being transferred
     * @param to The recipient
     * @param value The amount being transferred
     * @param index The new liquidity index of the reserve
     **/
    event BalanceTransfer(
        address indexed from,
        address indexed to,
        uint256 value,
        uint256 index
    );

    /**
     * @dev Burns aTokens from `user` and sends the equivalent amount of underlying to `receiverOfUnderlying`
     * @param user The owner of the aTokens, getting them burned
     * @param receiverOfUnderlying The address that will receive the underlying
     * @param amount The amount being burned
     * @param index The new liquidity index of the reserve
     **/
    function burn(
        address user,
        address receiverOfUnderlying,
        uint256 amount,
        uint256 index
    ) external;

    /**
     * @dev Mints aTokens to the reserve treasury
     * @param amount The amount of tokens getting minted
     * @param index The new liquidity index of the reserve
     */
    function mintToTreasury(uint256 amount, uint256 index) external;

    /**
     * @dev Transfers aTokens in the event of a borrow being liquidated, in case the liquidators reclaims the aToken
     * @param from The address getting liquidated, current owner of the aTokens
     * @param to The recipient
     * @param value The amount of tokens getting transferred
     **/
    function transferOnLiquidation(
        address from,
        address to,
        uint256 value
    ) external;

    /**
     * @dev Transfers the underlying asset to `target`. Used by the LendingPool to transfer
     * assets in borrow(), withdraw() and flashLoan()
     * @param user The recipient of the underlying
     * @param amount The amount getting transferred
     * @return The amount transferred
     **/
    function transferUnderlyingTo(address user, uint256 amount)
        external
        returns (uint256);

    /**
     * @dev Invoked to execute actions on the aToken side after a repayment.
     * @param user The user executing the repayment
     * @param amount The amount getting repaid
     **/
    function handleRepayment(address user, uint256 amount) external;

    /**
     * @dev Returns the address of the incentives controller contract
     **/
    function getIncentivesController()
        external
        view
        returns (IAaveIncentivesController);

    /**
     * @dev Returns the address of the underlying asset of this aToken (E.g. WETH for aWETH)
     **/
    function UNDERLYING_ASSET_ADDRESS() external view returns (address);
}

// File: Strategy.sol

contract Strategy is BaseStrategy {
    using SafeERC20 for IERC20;
    using Address for address;
    using SafeMath for uint256;
    using WadRayMath for uint256;

    bool internal isOriginal = true;
    // max interest rate we can afford to pay for borrowing investment token
    // amount in Ray (1e27 = 100%)
    uint256 public acceptableCostsRay = 1e27;

    // max amount to borrow. used to manually limit amount (for yVault to keep APY)
    uint256 public maxTotalBorrowIT;

    bool public isWantIncentivised;
    bool public isInvestmentTokenIncentivised;

    // if set to true, the strategy will not try to repay debt by selling want
    bool public leaveDebtBehind;

    // Aave's referral code
    uint16 internal referral;

    // NOTE: LTV = Loan-To-Value = debt/collateral

    // Target LTV: ratio up to which which we will borrow
    uint16 public targetLTVMultiplier = 6_000;

    // Warning LTV: ratio at which we will repay
    uint16 public warningLTVMultiplier = 8_000; // 80% of liquidation LTV

    // support
    uint16 internal constant MAX_BPS = 10_000; // 100%
    uint16 internal constant MAX_MULTIPLIER = 9_000; // 90%

    IAToken internal aToken;
    IVariableDebtToken internal variableDebtToken;
    IVault public yVault;
    IERC20 internal investmentToken;

    ISwap internal constant router =
        ISwap(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);

    IStakedAave internal constant stkAave =
        IStakedAave(0x4da27a545c0c5B758a6BA100e3a049001de870f5);

    IProtocolDataProvider internal constant protocolDataProvider =
        IProtocolDataProvider(0x057835Ad21a177dbdd3090bB1CAE03EaCF78Fc6d);

    address internal constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
    address internal constant AAVE = 0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9;

    uint256 internal minThreshold;
    uint256 public maxLoss;
    string internal strategyName;

    constructor(
        address _vault,
        address _yVault,
        bool _isWantIncentivised,
        bool _isInvestmentTokenIncentivised,
        string memory _strategyName
    ) public BaseStrategy(_vault) {
        _initializeThis(
            _yVault,
            _isWantIncentivised,
            _isInvestmentTokenIncentivised,
            _strategyName
        );
    }

    // ----------------- PUBLIC VIEW FUNCTIONS -----------------

    function name() external view override returns (string memory) {
        return strategyName;
    }

    function estimatedTotalAssets() public view override returns (uint256) {
        // not taking into account aave rewards (they are staked and not accesible)
        return
            balanceOfWant() // balance of want
                .add(balanceOfAToken()) // asset suplied as collateral
                .add(
                _fromETH(
                    _toETH(_valueOfInvestment(), address(investmentToken)),
                    address(want)
                )
            ) // current value of assets deposited in vault
                .sub(
                _fromETH(
                    _toETH(balanceOfDebt(), address(investmentToken)),
                    address(want)
                )
            ); // liabilities
    }

    // ----------------- SETTERS -----------------
    // we put all together to save contract bytecode (!)
    function setStrategyParams(
        uint16 _targetLTVMultiplier,
        uint16 _warningLTVMultiplier,
        uint256 _acceptableCostsRay,
        uint16 _aaveReferral,
        uint256 _maxTotalBorrowIT,
        bool _isWantIncentivised,
        bool _isInvestmentTokenIncentivised,
        bool _leaveDebtBehind,
        uint256 _maxLoss
    ) external onlyAuthorized {
        require(
            _warningLTVMultiplier <= MAX_MULTIPLIER &&
                _targetLTVMultiplier <= _warningLTVMultiplier
        );
        targetLTVMultiplier = _targetLTVMultiplier;
        warningLTVMultiplier = _warningLTVMultiplier;
        acceptableCostsRay = _acceptableCostsRay;
        maxTotalBorrowIT = _maxTotalBorrowIT;
        referral = _aaveReferral;
        isWantIncentivised = _isWantIncentivised;
        isInvestmentTokenIncentivised = _isInvestmentTokenIncentivised;
        leaveDebtBehind = _leaveDebtBehind;
        require(maxLoss <= 10_000);
        maxLoss = _maxLoss;
    }

    event Cloned(address indexed clone);

    function cloneAaveLenderBorrower(
        address _vault,
        address _strategist,
        address _rewards,
        address _keeper,
        address _yVault,
        bool _isWantIncentivised,
        bool _isInvestmentTokenIncentivised,
        string memory _strategyName
    ) external returns (address newStrategy) {
        require(isOriginal);
        // Copied from https://github.com/optionality/clone-factory/blob/master/contracts/CloneFactory.sol
        bytes20 addressBytes = bytes20(address(this));
        assembly {
            // EIP-1167 bytecode
            let clone_code := mload(0x40)
            mstore(
                clone_code,
                0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000
            )
            mstore(add(clone_code, 0x14), addressBytes)
            mstore(
                add(clone_code, 0x28),
                0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000
            )
            newStrategy := create(0, clone_code, 0x37)
        }

        Strategy(newStrategy).initialize(
            _vault,
            _strategist,
            _rewards,
            _keeper,
            _yVault,
            _isWantIncentivised,
            _isInvestmentTokenIncentivised,
            _strategyName
        );

        emit Cloned(newStrategy);
    }

    function _initializeThis(
        address _yVault,
        bool _isWantIncentivised,
        bool _isInvestmentTokenIncentivised,
        string memory _strategyName
    ) internal {
        minReportDelay = 24 * 3600;
        maxReportDelay = 10 * 24 * 3600;
        profitFactor = 100;
        // debtThreshold = 0; It's 0 by default.

        yVault = IVault(_yVault);
        investmentToken = IERC20(IVault(_yVault).token());

        (address _aToken, , ) =
            protocolDataProvider.getReserveTokensAddresses(address(want));
        aToken = IAToken(_aToken);

        (, , address _variableDebtToken) =
            protocolDataProvider.getReserveTokensAddresses(
                address(investmentToken)
            );

        variableDebtToken = IVariableDebtToken(_variableDebtToken);
        minThreshold = (10**(yVault.decimals())).div(100); // 0.01 minThreshold
        isWantIncentivised = _isWantIncentivised;
        isInvestmentTokenIncentivised = _isInvestmentTokenIncentivised;

        maxTotalBorrowIT = type(uint256).max; // set to max to avoid limits. this may trigger revert in some parts if not correctly handled

        maxLoss = 1;
        strategyName = _strategyName;
    }

    function initialize(
        address _vault,
        address _strategist,
        address _rewards,
        address _keeper,
        address _yVault,
        bool _isWantIncentivised,
        bool _isInvestmentTokenIncentivised,
        string memory _strategyName
    ) public {
        _initialize(_vault, _strategist, _rewards, _keeper);
        require(address(yVault) == address(0));
        _initializeThis(
            _yVault,
            _isWantIncentivised,
            _isInvestmentTokenIncentivised,
            _strategyName
        );
    }

    // ----------------- MAIN STRATEGY FUNCTIONS -----------------
    function prepareReturn(uint256 _debtOutstanding)
        internal
        override
        returns (
            uint256 _profit,
            uint256 _loss,
            uint256 _debtPayment
        )
    {
        uint256 balanceInit = balanceOfWant();
        // claim rewards from Aave's Liquidity Mining Program
        _claimRewards();

        // claim rewards from yVault
        _takeVaultProfit();

        // claim interest from lending
        _takeLendingProfit();

        uint256 balanceOfWant = balanceOfWant();

        if (balanceOfWant > balanceInit) {
            _profit = balanceOfWant.sub(balanceInit);
        }

        // if the vault is claiming repayment of debt
        if (_debtOutstanding > 0) {
            uint256 _amountFreed = 0;
            (_amountFreed, _loss) = liquidatePosition(_debtOutstanding);
            _debtPayment = Math.min(_debtOutstanding, _amountFreed);
            if (_loss > 0) {
                _profit = 0;
            }
        }
    }

    function adjustPosition(uint256 _debtOutstanding) internal override {
        uint256 wantBalance = balanceOfWant();

        // if we have enough want to deposit more into Aave, we do
        // NOTE: we do not skip the rest of the function if we don't as it may need to repay or take on more debt
        if (wantBalance > _debtOutstanding) {
            uint256 amountToDeposit = wantBalance.sub(_debtOutstanding);
            _depositToAave(amountToDeposit);
        }

        // NOTE: debt + collateral calcs are done in ETH
        (
            uint256 totalCollateralETH,
            uint256 totalDebtETH,
            uint256 availableBorrowsETH,
            uint256 currentLiquidationThreshold,
            ,

        ) = _getAaveUserAccountData();

        // if there is no want deposited into aave, don't do nothing
        // this means no debt is borrowed from aave too
        if (totalCollateralETH == 0) {
            return;
        }

        uint256 currentLTV = totalDebtETH.mul(MAX_BPS).div(totalCollateralETH);
        uint256 targetLTV = _getTargetLTV(currentLiquidationThreshold); // 60% under liquidation Threshold
        uint256 warningLTV = _getWarningLTV(currentLiquidationThreshold); // 80% under liquidation Threshold

        // decide in which range we are and act accordingly:
        // SUBOPTIMAL(borrow) (e.g. from 0 to 60% liqLTV)
        // HEALTHY(do nothing) (e.g. from 60% to 80% liqLTV)
        // UNHEALTHY(repay) (e.g. from 80% to 100% liqLTV)

        // we use our target cost of capital to calculate how much debt we can take on / how much debt we need to repay
        // in order to bring costs back to an acceptable range
        // currentProtocolDebt => total amount of debt taken by all Aave's borrowers
        // maxProtocolDebt => amount of total debt at which the cost of capital is equal to our acceptable costs
        // if the current protocol debt is higher than the max protocol debt, we will repay debt
        (uint256 currentProtocolDebt, uint256 maxProtocolDebt) =
            _calculateMaxDebt();

        if (targetLTV > currentLTV && currentProtocolDebt < maxProtocolDebt) {
            // SUBOPTIMAL RATIO: our current Loan-to-Value is lower than what we want
            // AND costs are lower than our max acceptable costs

            // we need to take on more debt
            uint256 targetDebtETH =
                totalCollateralETH.mul(targetLTV).div(MAX_BPS);

            uint256 amountToBorrowETH = targetDebtETH.sub(totalDebtETH); // safe bc we checked ratios
            amountToBorrowETH = Math.min(
                availableBorrowsETH,
                amountToBorrowETH
            );

            // cap the amount of debt we are taking according to our acceptable costs
            // if with the new loan we are increasing our cost of capital over what is healthy
            if (currentProtocolDebt.add(amountToBorrowETH) > maxProtocolDebt) {
                // Can't underflow because it's checked in the previous if condition
                amountToBorrowETH = maxProtocolDebt.sub(currentProtocolDebt);
            }

            uint256 maxTotalBorrowETH =
                _toETH(maxTotalBorrowIT, address(investmentToken));
            if (totalDebtETH.add(amountToBorrowETH) > maxTotalBorrowETH) {
                amountToBorrowETH = maxTotalBorrowETH > totalDebtETH
                    ? maxTotalBorrowETH.sub(totalDebtETH)
                    : 0;
            }

            // convert to InvestmentToken
            uint256 amountToBorrowIT =
                _fromETH(amountToBorrowETH, address(investmentToken));

            if (amountToBorrowIT > 0) {
                _lendingPool().borrow(
                    address(investmentToken),
                    amountToBorrowIT,
                    2,
                    referral,
                    address(this)
                );
            }

            _depositInYVault();
        } else if (
            currentLTV > warningLTV || currentProtocolDebt > maxProtocolDebt
        ) {
            // UNHEALTHY RATIO
            // we may be in this case if the current cost of capital is higher than our max cost of capital
            // we repay debt to set it to targetLTV
            uint256 targetDebtETH =
                targetLTV.mul(totalCollateralETH).div(MAX_BPS);
            uint256 amountToRepayETH =
                targetDebtETH < totalDebtETH
                    ? totalDebtETH.sub(targetDebtETH)
                    : 0;

            if (maxProtocolDebt == 0) {
                amountToRepayETH = totalDebtETH;
            } else if (currentProtocolDebt > maxProtocolDebt) {
                amountToRepayETH = Math.max(
                    amountToRepayETH,
                    currentProtocolDebt.sub(maxProtocolDebt)
                );
            }

            uint256 amountToRepayIT =
                _fromETH(amountToRepayETH, address(investmentToken));
            uint256 withdrawnIT = _withdrawFromYVault(amountToRepayIT); // we withdraw from investmentToken vault
            _repayInvestmentTokenDebt(withdrawnIT); // we repay the investmentToken debt with Aave
        }
    }

    function liquidatePosition(uint256 _amountNeeded)
        internal
        override
        returns (uint256 _liquidatedAmount, uint256 _loss)
    {
        uint256 balance = balanceOfWant();
        // if we have enough want to take care of the liquidatePosition without actually liquidating positons
        if (balance >= _amountNeeded) {
            return (_amountNeeded, 0);
        }

        // NOTE: amountNeeded is in want
        // NOTE: repayment amount is in investmentToken
        // NOTE: collateral and debt calcs are done in ETH (always, see Aave docs)

        // We first repay whatever we need to repay to keep healthy ratios
        uint256 amountToRepayIT = _calculateAmountToRepay(_amountNeeded);
        uint256 withdrawnIT = _withdrawFromYVault(amountToRepayIT); // we withdraw from investmentToken vault
        _repayInvestmentTokenDebt(withdrawnIT); // we repay the investmentToken debt with Aave

        // it will return the free amount of want
        _withdrawWantFromAave(_amountNeeded);

        balance = balanceOfWant();
        // we check if we withdrew less than expected AND should buy investmentToken with want (realising losses)
        if (
            _amountNeeded > balance &&
            balanceOfDebt() > 0 && // still some debt remaining
            balanceOfInvestmentToken().add(_valueOfInvestment()) == 0 && // but no capital to repay
            !leaveDebtBehind // if set to true, the strategy will not try to repay debt by selling want
        ) {
            // using this part of code will result in losses but it is necessary to unlock full collateral in case of wind down
            // we calculate how much want we need to fulfill the want request
            uint256 remainingAmountWant = _amountNeeded.sub(balance);
            // then calculate how much InvestmentToken we need to unlock collateral
            amountToRepayIT = _calculateAmountToRepay(remainingAmountWant);

            // we buy investmentToken with Want
            _buyInvestmentTokenWithWant(amountToRepayIT);

            // we repay debt to actually unlock collateral
            // after this, balanceOfDebt should be 0
            _repayInvestmentTokenDebt(amountToRepayIT);

            // then we try withdraw once more
            _withdrawWantFromAave(remainingAmountWant);
        }

        uint256 totalAssets = balanceOfWant();
        if (_amountNeeded > totalAssets) {
            _liquidatedAmount = totalAssets;
            _loss = _amountNeeded.sub(totalAssets);
        } else {
            _liquidatedAmount = _amountNeeded;
        }
    }

    function delegatedAssets() external view override returns (uint256) {
        // returns total debt borrowed in want (which is the delegatedAssets)
        return
            _fromETH(
                _toETH(balanceOfDebt(), address(investmentToken)),
                address(want)
            );
    }

    function prepareMigration(address _newStrategy) internal override {
        // nothing to do since debt cannot be migrated
    }

    function harvestTrigger(uint256 callCost)
        public
        view
        override
        returns (bool)
    {
        // we harvest if:
        // 1. stakedAave is ready to be converted to Aave and sold

        return
            _checkCooldown() ||
            super.harvestTrigger(_fromETH(callCost, address(want)));
    }

    function tendTrigger(uint256 callCost) public view override returns (bool) {
        // we adjust position if:
        // 1. LTV ratios are not in the HEALTHY range (either we take on more debt or repay debt)
        // 2. costs are not acceptable and we need to repay debt

        (
            uint256 totalCollateralETH,
            uint256 totalDebtETH,
            ,
            uint256 currentLiquidationThreshold,
            ,

        ) = _getAaveUserAccountData();

        uint256 currentLTV = totalDebtETH.mul(MAX_BPS).div(totalCollateralETH);
        uint256 targetLTV = _getTargetLTV(currentLiquidationThreshold);
        uint256 warningLTV = _getWarningLTV(currentLiquidationThreshold);
        (uint256 currentProtocolDebt, uint256 maxProtocolDebt) =
            _calculateMaxDebt();

        if (
            (currentLTV < targetLTV &&
                currentProtocolDebt < maxProtocolDebt &&
                targetLTV.sub(currentLTV) > 100) || // WE NEED TO TAKE ON MORE DEBT
            (currentLTV > warningLTV || currentProtocolDebt > maxProtocolDebt) // WE NEED TO REPAY DEBT BECAUSE OF UNHEALTHY RATIO OR BORROWING COSTS
        ) {
            return true;
        }

        // no call to super.tendTrigger as it would return false
        return false;
    }

    // ----------------- INTERNAL FUNCTIONS SUPPORT -----------------

    function _withdrawFromYVault(uint256 _amountIT) internal returns (uint256) {
        if (_amountIT == 0) {
            return 0;
        }
        // no need to check allowance bc the contract == token
        uint256 balancePrior = balanceOfInvestmentToken();
        uint256 sharesToWithdraw =
            Math.min(
                _investmentTokenToYShares(_amountIT),
                yVault.balanceOf(address(this))
            );
        yVault.withdraw(sharesToWithdraw, address(this), maxLoss);
        return balanceOfInvestmentToken().sub(balancePrior);
    }

    function _repayInvestmentTokenDebt(uint256 amount) internal {
        if (amount == 0) {
            return;
        }

        // we cannot pay more than loose balance
        uint256 balance = balanceOfInvestmentToken();
        amount = Math.min(amount, balance);
        // we cannot pay more than we owe
        amount = Math.min(balanceOfDebt(), amount);

        _checkAllowance(
            address(_lendingPool()),
            address(investmentToken),
            amount
        );

        if (amount > 0) {
            _lendingPool().repay(
                address(investmentToken),
                amount,
                uint256(2),
                address(this)
            );
        }
    }

    function _depositInYVault() internal {
        uint256 balanceIT = balanceOfInvestmentToken();
        if (balanceIT > 0) {
            _checkAllowance(
                address(yVault),
                address(investmentToken),
                balanceIT
            );
            yVault.deposit();
        }
    }

    function _claimRewards() internal {
        if (isInvestmentTokenIncentivised || isWantIncentivised) {
            // redeem AAVE from stkAave
            uint256 stkAaveBalance =
                IERC20(address(stkAave)).balanceOf(address(this));
            if (stkAaveBalance > 0 && _checkCooldown()) {
                stkAave.redeem(address(this), stkAaveBalance);
            }

            // claim AAVE rewards
            stkAave.claimRewards(address(this), type(uint256).max);

            // sell AAVE for want
            // a minimum balance of 0.01 AAVE is required
            uint256 aaveBalance = IERC20(AAVE).balanceOf(address(this));
            if (aaveBalance > 1e15) {
                _sellAAVEForWant(aaveBalance);
            }

            // claim rewards
            // only add to assets those assets that are incentivised
            address[] memory assets;
            if (isInvestmentTokenIncentivised && isWantIncentivised) {
                assets = new address[](2);
                assets[0] = address(aToken);
                assets[1] = address(variableDebtToken);
            } else if (isInvestmentTokenIncentivised) {
                assets = new address[](1);
                assets[0] = address(variableDebtToken);
            } else if (isWantIncentivised) {
                assets = new address[](1);
                assets[0] = address(aToken);
            }

            _incentivesController().claimRewards(
                assets,
                type(uint256).max,
                address(this)
            );

            // request start of cooldown period
            if (IERC20(address(stkAave)).balanceOf(address(this)) > 0) {
                stkAave.cooldown();
            }
        }
    }

    function _takeLendingProfit() internal {
        uint256 depositedWant = vault.strategies(address(this)).totalDebt;
        uint256 currentWantInAave = balanceOfAToken();

        if (currentWantInAave > depositedWant) {
            uint256 toWithdraw = currentWantInAave.sub(depositedWant);
            _withdrawWantFromAave(toWithdraw);
        }
    }

    //withdraw an amount including any want balance
    function _withdrawWantFromAave(uint256 amount) internal {
        uint256 balanceUnderlying = balanceOfAToken();
        if (amount > balanceUnderlying) {
            amount = balanceUnderlying;
        }

        uint256 maxWithdrawal =
            Math.min(_maxWithdrawal(), want.balanceOf(address(aToken)));

        uint256 toWithdraw = Math.min(amount, maxWithdrawal);
        if (toWithdraw > 0) {
            _checkAllowance(
                address(_lendingPool()),
                address(aToken),
                toWithdraw
            );
            _lendingPool().withdraw(address(want), toWithdraw, address(this));
        }
    }

    function _maxWithdrawal() internal view returns (uint256) {
        (uint256 totalCollateralETH, uint256 totalDebtETH, , , uint256 ltv, ) =
            _getAaveUserAccountData();
        uint256 minCollateralETH =
            ltv > 0 ? totalDebtETH.mul(MAX_BPS).div(ltv) : totalCollateralETH;
        if (minCollateralETH > totalCollateralETH) {
            return 0;
        }
        return
            _fromETH(totalCollateralETH.sub(minCollateralETH), address(want));
    }

    function _calculateAmountToRepay(uint256 amount)
        internal
        view
        returns (uint256)
    {
        if (amount == 0) {
            return 0;
        }

        // we check if the collateral that we are withdrawing leaves us in a risky range, we then take action
        (
            uint256 totalCollateralETH,
            uint256 totalDebtETH,
            ,
            uint256 currentLiquidationThreshold,
            ,

        ) = _getAaveUserAccountData();

        uint256 amountToWithdrawETH = _toETH(amount, address(want));
        // calculate the collateral that we are leaving after withdrawing
        uint256 newCollateral =
            totalCollateralETH > amountToWithdrawETH
                ? totalCollateralETH.sub(amountToWithdrawETH)
                : 0;

        uint256 ltvAfterWithdrawal =
            newCollateral > 0
                ? totalDebtETH.mul(MAX_BPS).div(newCollateral)
                : type(uint256).max;

        // check if the new LTV is in UNHEALTHY range
        // remember that if balance > _amountNeeded, ltvAfterWithdrawal == 0 (0 risk)
        // this is not true but the effect will be the same
        uint256 warningLTV = _getWarningLTV(currentLiquidationThreshold);

        if (ltvAfterWithdrawal <= warningLTV) {
            // no need of repaying debt because the LTV is ok
            return 0;
        } else if (ltvAfterWithdrawal == type(uint256).max) {
            // we are withdrawing 100% of collateral so we need to repay full debt
            return _fromETH(totalDebtETH, address(investmentToken));
        }

        uint256 targetLTV = _getTargetLTV(currentLiquidationThreshold);
        // WARNING: this only works for a single collateral asset, otherwise liquidationThreshold might change depending on the collateral being withdrawn
        // e.g. we have USDC + WBTC as collateral, end liquidationThreshold will be different depending on which asset we withdraw
        uint256 newTargetDebt = targetLTV.mul(newCollateral).div(MAX_BPS);

        // if newTargetDebt is higher, we don't need to repay anything
        if (newTargetDebt > totalDebtETH) {
            return 0;
        }

        return
            _fromETH(
                totalDebtETH.sub(newTargetDebt) < minThreshold
                    ? totalDebtETH
                    : totalDebtETH.sub(newTargetDebt),
                address(investmentToken)
            );
    }

    function _depositToAave(uint256 amount) internal {
        if (amount == 0) {
            return;
        }

        ILendingPool lp = _lendingPool();
        _checkAllowance(address(lp), address(want), amount);
        lp.deposit(address(want), amount, address(this), referral);
    }

    function _checkCooldown() internal view returns (bool) {
        if (!isWantIncentivised && !isInvestmentTokenIncentivised) {
            return false;
        }

        uint256 cooldownStartTimestamp =
            IStakedAave(stkAave).stakersCooldowns(address(this));
        uint256 COOLDOWN_SECONDS = IStakedAave(stkAave).COOLDOWN_SECONDS();
        uint256 UNSTAKE_WINDOW = IStakedAave(stkAave).UNSTAKE_WINDOW();
        if (block.timestamp >= cooldownStartTimestamp.add(COOLDOWN_SECONDS)) {
            return
                block.timestamp.sub(
                    cooldownStartTimestamp.add(COOLDOWN_SECONDS)
                ) <=
                UNSTAKE_WINDOW ||
                cooldownStartTimestamp == 0;
        }

        return false;
    }

    function _checkAllowance(
        address _contract,
        address _token,
        uint256 _amount
    ) internal {
        if (IERC20(_token).allowance(address(this), _contract) < _amount) {
            IERC20(_token).safeApprove(_contract, 0);
            IERC20(_token).safeApprove(_contract, type(uint256).max);
        }
    }

    function _takeVaultProfit() internal {
        uint256 _debt = balanceOfDebt();
        uint256 _valueInVault = _valueOfInvestment();
        if (_debt >= _valueInVault) {
            return;
        }

        uint256 profit = _valueInVault.sub(_debt);
        uint256 ySharesToWithdraw = _investmentTokenToYShares(profit);
        if (ySharesToWithdraw > 0) {
            yVault.withdraw(ySharesToWithdraw, address(this), maxLoss);
            _sellInvestmentForWant(balanceOfInvestmentToken());
        }
    }

    // ----------------- INTERNAL CALCS -----------------
    function _calculateMaxDebt()
        internal
        view
        returns (uint256 currentProtocolDebt, uint256 maxProtocolDebt)
    {
        // This function is used to calculate the maximum amount of debt that the protocol can take
        // to keep the cost of capital lower than the set acceptableCosts
        // This maxProtocolDebt will be used to decide if capital costs are acceptable or not
        // and to repay required debt to keep the rates below acceptable costs

        // Hack to avoid the stack too deep compiler error.
        SupportStructs.CalcMaxDebtLocalVars memory vars;
        DataTypes.ReserveData memory reserveData =
            _lendingPool().getReserveData(address(investmentToken));
        IReserveInterestRateStrategy irs =
            IReserveInterestRateStrategy(
                reserveData.interestRateStrategyAddress
            );

        (
            vars.availableLiquidity, // = total supply - total stable debt - total variable debt
            vars.totalStableDebt, // total debt paying stable interest rates
            vars.totalVariableDebt, // total debt paying stable variable rates
            ,
            ,
            ,
            ,
            ,
            ,

        ) = protocolDataProvider.getReserveData(address(investmentToken));

        vars.totalDebt = vars.totalStableDebt.add(vars.totalVariableDebt);
        vars.totalLiquidity = vars.availableLiquidity.add(vars.totalDebt);
        vars.utilizationRate = vars.totalDebt == 0
            ? 0
            : vars.totalDebt.rayDiv(vars.totalLiquidity);

        // Aave's Interest Rate Strategy Parameters (see docs)
        SupportStructs.IrsVars memory irsVars;
        irsVars.optimalRate = irs.OPTIMAL_UTILIZATION_RATE();
        irsVars.baseRate = irs.baseVariableBorrowRate(); // minimum cost of capital with 0 % of utilisation rate
        irsVars.slope1 = irs.variableRateSlope1(); // rate of increase of cost of debt up to Optimal Utilisation Rate
        irsVars.slope2 = irs.variableRateSlope2(); // rate of increase of cost of debt above Optimal Utilisation Rate

        // acceptableCosts should always be > baseVariableBorrowRate
        // If it's not this will revert since the strategist set the wrong
        // acceptableCosts value
        if (
            vars.utilizationRate < irsVars.optimalRate &&
            acceptableCostsRay < irsVars.baseRate.add(irsVars.slope1)
        ) {
            // we solve Aave's Interest Rates equation for sub optimal utilisation rates
            // IR = BASERATE + SLOPE1 * CURRENT_UTIL_RATE / OPTIMAL_UTIL_RATE
            vars.targetUtilizationRate = (
                acceptableCostsRay.sub(irsVars.baseRate)
            )
                .rayMul(irsVars.optimalRate)
                .rayDiv(irsVars.slope1);
        } else {
            // Special case where protocol is above utilization rate but we want
            // a lower interest rate than (base + slope1)
            if (acceptableCostsRay < irsVars.baseRate.add(irsVars.slope1)) {
                return (_toETH(vars.totalDebt, address(investmentToken)), 0);
            }

            // we solve Aave's Interest Rates equation for utilisation rates above optimal U
            // IR = BASERATE + SLOPE1 + SLOPE2 * (CURRENT_UTIL_RATE - OPTIMAL_UTIL_RATE) / (1-OPTIMAL_UTIL_RATE)
            vars.targetUtilizationRate = (
                acceptableCostsRay.sub(irsVars.baseRate.add(irsVars.slope1))
            )
                .rayMul(uint256(1e27).sub(irsVars.optimalRate))
                .rayDiv(irsVars.slope2)
                .add(irsVars.optimalRate);
        }

        vars.maxProtocolDebt = vars
            .totalLiquidity
            .rayMul(vars.targetUtilizationRate)
            .rayDiv(1e27);

        return (
            _toETH(vars.totalDebt, address(investmentToken)),
            _toETH(vars.maxProtocolDebt, address(investmentToken))
        );
    }

    function balanceOfWant() internal view returns (uint256) {
        return want.balanceOf(address(this));
    }

    function balanceOfInvestmentToken() internal view returns (uint256) {
        return investmentToken.balanceOf(address(this));
    }

    function balanceOfAToken() internal view returns (uint256) {
        return aToken.balanceOf(address(this));
    }

    function balanceOfDebt() internal view returns (uint256) {
        return variableDebtToken.balanceOf(address(this));
    }

    function _valueOfInvestment() internal view returns (uint256) {
        return
            yVault.balanceOf(address(this)).mul(yVault.pricePerShare()).div(
                10**yVault.decimals()
            );
    }

    function _investmentTokenToYShares(uint256 amount)
        internal
        view
        returns (uint256)
    {
        return amount.mul(10**yVault.decimals()).div(yVault.pricePerShare());
    }

    function _getAaveUserAccountData()
        internal
        view
        returns (
            uint256 totalCollateralETH,
            uint256 totalDebtETH,
            uint256 availableBorrowsETH,
            uint256 currentLiquidationThreshold,
            uint256 ltv,
            uint256 healthFactor
        )
    {
        return _lendingPool().getUserAccountData(address(this));
    }

    function _getTargetLTV(uint256 liquidationThreshold)
        internal
        view
        returns (uint256)
    {
        return
            liquidationThreshold.mul(uint256(targetLTVMultiplier)).div(MAX_BPS);
    }

    function _getWarningLTV(uint256 liquidationThreshold)
        internal
        view
        returns (uint256)
    {
        return
            liquidationThreshold.mul(uint256(warningLTVMultiplier)).div(
                MAX_BPS
            );
    }

    // ----------------- TOKEN CONVERSIONS -----------------
    function getTokenOutPath(address _token_in, address _token_out)
        internal
        pure
        returns (address[] memory _path)
    {
        bool is_weth =
            _token_in == address(WETH) || _token_out == address(WETH);
        _path = new address[](is_weth ? 2 : 3);
        _path[0] = _token_in;

        if (is_weth) {
            _path[1] = _token_out;
        } else {
            _path[1] = address(WETH);
            _path[2] = _token_out;
        }
    }

    function _sellAAVEForWant(uint256 _amount) internal {
        if (_amount == 0) {
            return;
        }

        _checkAllowance(address(router), address(AAVE), _amount);
        router.swapExactTokensForTokens(
            _amount,
            0,
            getTokenOutPath(address(AAVE), address(want)),
            address(this),
            now
        );
    }

    function _sellInvestmentForWant(uint256 _amount) internal {
        if (_amount == 0) {
            return;
        }

        // NOTE: 1:1
        if (address(want) == address(investmentToken)) {
            return;
        }

        _checkAllowance(address(router), address(investmentToken), _amount);
        router.swapExactTokensForTokens(
            _amount,
            0,
            getTokenOutPath(address(investmentToken), address(want)),
            address(this),
            now
        );
    }

    function _buyInvestmentTokenWithWant(uint256 _amount) internal {
        if (_amount == 0) {
            return;
        }

        if (address(investmentToken) == address(want)) {
            return;
        }

        _checkAllowance(address(router), address(want), _amount);
        router.swapTokensForExactTokens(
            _amount,
            type(uint256).max,
            getTokenOutPath(address(want), address(investmentToken)),
            address(this),
            now
        );
    }

    function _toETH(uint256 _amount, address asset)
        internal
        view
        returns (uint256)
    {
        if (
            _amount == 0 ||
            _amount == type(uint256).max ||
            address(asset) == address(WETH) // 1:1 change
        ) {
            return _amount;
        }

        return
            _amount.mul(_priceOracle().getAssetPrice(asset)).div(
                uint256(10)**uint256(IOptionalERC20(asset).decimals())
            );
    }

    function _fromETH(uint256 _amount, address asset)
        internal
        view
        returns (uint256)
    {
        if (
            _amount == 0 ||
            _amount == type(uint256).max ||
            address(asset) == address(WETH) // 1:1 change
        ) {
            return _amount;
        }

        return
            _amount
                .mul(uint256(10)**uint256(IOptionalERC20(asset).decimals()))
                .div(_priceOracle().getAssetPrice(asset));
    }

    // ----------------- INTERNAL SUPPORT GETTERS -----------------

    function _lendingPool() internal view returns (ILendingPool lendingPool) {
        lendingPool = ILendingPool(
            protocolDataProvider.ADDRESSES_PROVIDER().getLendingPool()
        );
    }

    function _priceOracle() internal view returns (IPriceOracle) {
        return
            IPriceOracle(
                protocolDataProvider.ADDRESSES_PROVIDER().getPriceOracle()
            );
    }

    function _incentivesController()
        internal
        view
        returns (IAaveIncentivesController)
    {
        if (isWantIncentivised) {
            return aToken.getIncentivesController();
        } else if (isInvestmentTokenIncentivised) {
            return variableDebtToken.getIncentivesController();
        } else {
            return IAaveIncentivesController(0);
        }
    }

    function protectedTokens()
        internal
        view
        override
        returns (address[] memory)
    {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"address","name":"_yVault","type":"address"},{"internalType":"bool","name":"_isWantIncentivised","type":"bool"},{"internalType":"bool","name":"_isInvestmentTokenIncentivised","type":"bool"},{"internalType":"string","name":"_strategyName","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"clone","type":"address"}],"name":"Cloned","type":"event"},{"anonymous":false,"inputs":[],"name":"EmergencyExitEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"profit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"loss","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtPayment","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtOutstanding","type":"uint256"}],"name":"Harvested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"debtThreshold","type":"uint256"}],"name":"UpdatedDebtThreshold","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newKeeper","type":"address"}],"name":"UpdatedKeeper","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"delay","type":"uint256"}],"name":"UpdatedMaxReportDelay","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"metadataURI","type":"string"}],"name":"UpdatedMetadataURI","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"delay","type":"uint256"}],"name":"UpdatedMinReportDelay","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"profitFactor","type":"uint256"}],"name":"UpdatedProfitFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"rewards","type":"address"}],"name":"UpdatedRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newStrategist","type":"address"}],"name":"UpdatedStrategist","type":"event"},{"inputs":[],"name":"acceptableCostsRay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"apiVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"address","name":"_strategist","type":"address"},{"internalType":"address","name":"_rewards","type":"address"},{"internalType":"address","name":"_keeper","type":"address"},{"internalType":"address","name":"_yVault","type":"address"},{"internalType":"bool","name":"_isWantIncentivised","type":"bool"},{"internalType":"bool","name":"_isInvestmentTokenIncentivised","type":"bool"},{"internalType":"string","name":"_strategyName","type":"string"}],"name":"cloneAaveLenderBorrower","outputs":[{"internalType":"address","name":"newStrategy","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"debtThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"delegatedAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"emergencyExit","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"estimatedTotalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"harvest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"callCost","type":"uint256"}],"name":"harvestTrigger","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"address","name":"_strategist","type":"address"},{"internalType":"address","name":"_rewards","type":"address"},{"internalType":"address","name":"_keeper","type":"address"},{"internalType":"address","name":"_yVault","type":"address"},{"internalType":"bool","name":"_isWantIncentivised","type":"bool"},{"internalType":"bool","name":"_isInvestmentTokenIncentivised","type":"bool"},{"internalType":"string","name":"_strategyName","type":"string"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isInvestmentTokenIncentivised","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isWantIncentivised","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keeper","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"leaveDebtBehind","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxLoss","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxReportDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxTotalBorrowIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metadataURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newStrategy","type":"address"}],"name":"migrate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"minReportDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"profitFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewards","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_debtThreshold","type":"uint256"}],"name":"setDebtThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setEmergencyExit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_keeper","type":"address"}],"name":"setKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_delay","type":"uint256"}],"name":"setMaxReportDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_metadataURI","type":"string"}],"name":"setMetadataURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_delay","type":"uint256"}],"name":"setMinReportDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_profitFactor","type":"uint256"}],"name":"setProfitFactor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rewards","type":"address"}],"name":"setRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_strategist","type":"address"}],"name":"setStrategist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_targetLTVMultiplier","type":"uint16"},{"internalType":"uint16","name":"_warningLTVMultiplier","type":"uint16"},{"internalType":"uint256","name":"_acceptableCostsRay","type":"uint256"},{"internalType":"uint16","name":"_aaveReferral","type":"uint16"},{"internalType":"uint256","name":"_maxTotalBorrowIT","type":"uint256"},{"internalType":"bool","name":"_isWantIncentivised","type":"bool"},{"internalType":"bool","name":"_isInvestmentTokenIncentivised","type":"bool"},{"internalType":"bool","name":"_leaveDebtBehind","type":"bool"},{"internalType":"uint256","name":"_maxLoss","type":"uint256"}],"name":"setStrategyParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"strategist","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"sweep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"targetLTVMultiplier","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tend","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"callCost","type":"uint256"}],"name":"tendTrigger","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"contract VaultAPI","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"want","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"warningLTVMultiplier","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountNeeded","type":"uint256"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"_loss","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"yVault","outputs":[{"internalType":"contract IVault","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

6080604052600a805461010061ff00199091161790556b033b2e3c9fd0803ce8000000600b55600d805461ffff60281b191666177000000000001761ffff60381b1916681f40000000000000001790553480156200005c57600080fd5b5060405162006a7138038062006a718339810160408190526200007f9162000a42565b846200008e81338080620000a8565b506200009d848484846200028d565b505050505062000d8c565b6005546001600160a01b031615620000dd5760405162461bcd60e51b8152600401620000d49062000c04565b60405180910390fd5b600180546001600160a01b0319166001600160a01b03868116919091179182905560408051637e062a3560e11b81529051929091169163fc0c546a91600480820192602092909190829003018186803b1580156200013a57600080fd5b505afa1580156200014f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001759190620009d1565b600580546001600160a01b0319166001600160a01b039283161790819055620001af911685600019620005af602090811b62001b0717901c565b600280546001600160a01b038086166001600160a01b0319928316179092556003805485841690831617908190556004805485851693169290921782556000600681905562015180600755606460085560095560015460405163095ea7b360e01b81529084169363095ea7b393620002309390911691600019910162000bb6565b602060405180830381600087803b1580156200024b57600080fd5b505af115801562000260573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000286919062000b28565b5050505050565b62015180600655620d2f006007556064600855600f80546001600160a01b0319166001600160a01b03861690811790915560408051637e062a3560e11b8152905163fc0c546a91600480820192602092909190829003018186803b158015620002f557600080fd5b505afa1580156200030a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003309190620009d1565b601080546001600160a01b0319166001600160a01b039283161790556005546040516334924edb60e21b815260009273057835ad21a177dbdd3090bb1cae03eacf78fc6d9263d2493b6c926200038e92919091169060040162000b88565b60606040518083038186803b158015620003a757600080fd5b505afa158015620003bc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003e29190620009ef565b5050600d80546001600160a01b03808416690100000000000000000002600160481b600160e81b0319909216919091179091556010546040516334924edb60e21b815292935060009273057835ad21a177dbdd3090bb1cae03eacf78fc6d9263d2493b6c92620004589291169060040162000b88565b60606040518083038186803b1580156200047157600080fd5b505afa15801562000486573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004ac9190620009ef565b600e80546001600160a01b0319166001600160a01b0383811691909117909155600f546040805163313ce56760e01b815290519396506200056895506064945091169163313ce56791600480820192602092909190829003018186803b1580156200051657600080fd5b505afa1580156200052b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000551919062000b51565b600a0a620006bd60201b62001c061790919060201c565b601155600d805460ff19168615151761ff00191661010086151502179055600019600c5560016012558251620005a69060139060208601906200090c565b50505050505050565b8015806200063e5750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e90620005e8903090869060040162000b9c565b60206040518083038186803b1580156200060157600080fd5b505afa15801562000616573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200063c919062000b51565b155b6200065d5760405162461bcd60e51b8152600401620000d49062000cbc565b620006b88363095ea7b360e01b84846040516024016200067f92919062000bb6565b60408051808303601f190181529190526020810180516001600160e01b0319939093166001600160e01b03938416179052906200071016565b505050565b60006200070783836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250620007ac60201b60201c565b90505b92915050565b60606200076c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316620007e760201b62001c4f179092919060201c565b805190915015620006b857808060200190518101906200078d919062000b28565b620006b85760405162461bcd60e51b8152600401620000d49062000c72565b60008183620007d05760405162461bcd60e51b8152600401620000d4919062000bcf565b506000838581620007dd57fe5b0495945050505050565b6060620007f8848460008562000800565b949350505050565b60606200080d85620008d2565b6200082c5760405162461bcd60e51b8152600401620000d49062000c3b565b60006060866001600160a01b031685876040516200084b919062000b6a565b60006040518083038185875af1925050503d80600081146200088a576040519150601f19603f3d011682016040523d82523d6000602084013e6200088f565b606091505b50915091508115620008a5579150620007f89050565b805115620008b65780518082602001fd5b8360405162461bcd60e51b8152600401620000d4919062000bcf565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590620007f8575050151592915050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200094f57805160ff19168380011785556200097f565b828001600101855582156200097f579182015b828111156200097f57825182559160200191906001019062000962565b506200098d92915062000991565b5090565b5b808211156200098d576000815560010162000992565b80516001600160a01b03811681146200070a57600080fd5b805180151581146200070a57600080fd5b600060208284031215620009e3578081fd5b620007078383620009a8565b60008060006060848603121562000a04578182fd5b835162000a118162000d73565b602085015190935062000a248162000d73565b604085015190925062000a378162000d73565b809150509250925092565b600080600080600060a0868803121562000a5a578081fd5b62000a668787620009a8565b945062000a778760208801620009a8565b935062000a888760408801620009c0565b925062000a998760608801620009c0565b60808701519092506001600160401b038082111562000ab6578283fd5b818801915088601f83011262000aca578283fd5b81518181111562000ad9578384fd5b62000aee601f8201601f191660200162000d19565b915080825289602082850101111562000b05578384fd5b62000b1881602084016020860162000d40565b5080925050509295509295909350565b60006020828403121562000b3a578081fd5b8151801515811462000b4a578182fd5b9392505050565b60006020828403121562000b63578081fd5b5051919050565b6000825162000b7e81846020870162000d40565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03929092168252602082015260400190565b600060208252825180602084015262000bf081604085016020870162000d40565b601f01601f19169190910160400192915050565b6020808252601c908201527f537472617465677920616c726561647920696e697469616c697a656400000000604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b60208082526036908201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60408201527f20746f206e6f6e2d7a65726f20616c6c6f77616e636500000000000000000000606082015260800190565b6040518181016001600160401b038111828210171562000d3857600080fd5b604052919050565b60005b8381101562000d5d57818101518382015260200162000d43565b8381111562000d6d576000848401525b50505050565b6001600160a01b038116811462000d8957600080fd5b50565b615cd58062000d9c6000396000f3fe608060405234801561001057600080fd5b50600436106102745760003560e01c8063748747e611610151578063c7b9d530116100c3578063ec38a86211610087578063ec38a86214610484578063ed882c2b14610497578063efbb5cb0146104aa578063f017c92f146104b2578063fbfa77cf146104c5578063fcf2d0ad146104cd57610274565b8063c7b9d53014610446578063ce5494bb14610459578063da769c471461046c578063db67e35e14610474578063dfccfbd91461047c57610274565b80638e6350e2116101155780638e6350e21461040b5780638e72e31b1461041357806391397ab41461041b57806395e80c501461042e5780639ec5a89414610436578063aced16611461043e57610274565b8063748747e6146103b7578063750521f5146103ca578063758463f0146103dd5780637e80295b146103f05780638cdfe1661461040357610274565b806328b7ccf7116101ea5780634641257d116101ae5780634641257d146103645780635641ec031461036c5780635783fe39146103745780636353f8221461037c578063650d18801461039157806369aa6128146103a457610274565b806328b7ccf7146103265780632e1a7d4d1461032e57806333303f8e1461034157806339a172a814610349578063440368a31461035c57610274565b80631d12f28b1161023c5780631d12f28b146102dc5780631f1fcd51146102f15780631fe4a6861461030657806322f3e2d41461030e5780632582941014610316578063276f53771461031e57610274565b806301681a621461027957806303ee438c1461028e57806306fdde03146102ac5780630f969b87146102b45780631166f15e146102c7575b600080fd5b61028c6102873660046150e6565b6104d5565b005b610296610674565b6040516102a391906158fe565b60405180910390f35b610296610702565b61028c6102c23660046155ac565b610799565b6102cf610826565b6040516102a391906158c4565b6102e461082f565b6040516102a39190615b74565b6102f9610835565b6040516102a39190615746565b6102f9610844565b6102cf610853565b6102966108f5565b6102e4610914565b6102e461091a565b6102e461033c3660046155ac565b610920565b6102f961097b565b61028c6103573660046155ac565b61098a565b61028c610a0c565b61028c610c35565b6102cf610f9f565b6102e4610fa8565b610384610fae565b6040516102a39190615b65565b6102cf61039f3660046155ac565b610fbf565b6102f96103b236600461516a565b611084565b61028c6103c53660046150e6565b611193565b61028c6103d8366004615329565b61123e565b61028c6103eb36600461550f565b6112d5565b61028c6103fe36600461516a565b61141a565b6102e4611452565b6102e4611458565b61038461148a565b61028c6104293660046155ac565b61149d565b6102e461151f565b6102f9611525565b6102f9611534565b61028c6104543660046150e6565b611543565b61028c6104673660046150e6565b6115ee565b6102cf61175f565b6102e461176e565b6102cf611774565b61028c6104923660046150e6565b611782565b6102cf6104a53660046155ac565b611919565b6102e461194f565b61028c6104c03660046155ac565b611992565b6102f9611a14565b61028c611a23565b6104dd611c66565b6001600160a01b0316336001600160a01b0316146105165760405162461bcd60e51b815260040161050d90615a7c565b60405180910390fd5b6005546001600160a01b03828116911614156105445760405162461bcd60e51b815260040161050d90615936565b6001546001600160a01b03828116911614156105725760405162461bcd60e51b815260040161050d90615a24565b606061057c611ce3565b905060005b81518110156105d75781818151811061059657fe5b60200260200101516001600160a01b0316836001600160a01b031614156105cf5760405162461bcd60e51b815260040161050d90615aeb565b600101610581565b506106706105e3611c66565b6040516370a0823160e01b81526001600160a01b038516906370a082319061060f903090600401615746565b60206040518083038186803b15801561062757600080fd5b505afa15801561063b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061065f91906155c4565b6001600160a01b0385169190611ce8565b5050565b6000805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156106fa5780601f106106cf576101008083540402835291602001916106fa565b820191906000526020600020905b8154815290600101906020018083116106dd57829003601f168201915b505050505081565b60138054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561078e5780601f106107635761010080835404028352916020019161078e565b820191906000526020600020905b81548152906001019060200180831161077157829003601f168201915b505050505090505b90565b6002546001600160a01b03163314806107ca57506107b5611c66565b6001600160a01b0316336001600160a01b0316145b6107e65760405162461bcd60e51b815260040161050d90615a7c565b60098190556040517fa68ba126373d04c004c5748c300c9fca12bd444b3d4332e261f3bd2bac4a86009061081b908390615b74565b60405180910390a150565b600d5460ff1681565b60095481565b6005546001600160a01b031681565b6002546001600160a01b031681565b6001546040516339ebf82360e01b815260009182916001600160a01b03909116906339ebf82390610888903090600401615746565b6101206040518083038186803b1580156108a157600080fd5b505afa1580156108b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d99190615491565b6040015111806108f0575060006108ee61194f565b115b905090565b604080518082019091526005815264302e332e3560d81b602082015290565b600c5481565b60075481565b6001546000906001600160a01b0316331461094d5760405162461bcd60e51b815260040161050d90615a04565b600061095883611d07565b600554909350909150610975906001600160a01b03163383611ce8565b50919050565b600f546001600160a01b031681565b6002546001600160a01b03163314806109bb57506109a6611c66565b6001600160a01b0316336001600160a01b0316145b6109d75760405162461bcd60e51b815260040161050d90615a7c565b60068190556040517fbb2c369a0355a34b02ab5fce0643150c87e1c8dfe7c918d465591879f57948b19061081b908390615b74565b6004546001600160a01b0316331480610a2f57506002546001600160a01b031633145b80610a525750610a3d611c66565b6001600160a01b0316336001600160a01b0316145b80610af35750600160009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b158015610aa657600080fd5b505afa158015610aba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ade9190615102565b6001600160a01b0316336001600160a01b0316145b80610b945750600160009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b158015610b4757600080fd5b505afa158015610b5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7f9190615102565b6001600160a01b0316336001600160a01b0316145b610bb05760405162461bcd60e51b815260040161050d90615a7c565b6001546040805163bf3759b560e01b81529051610c33926001600160a01b03169163bf3759b5916004808301926020929190829003018186803b158015610bf657600080fd5b505afa158015610c0a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c2e91906155c4565b611e18565b565b6004546001600160a01b0316331480610c5857506002546001600160a01b031633145b80610c7b5750610c66611c66565b6001600160a01b0316336001600160a01b0316145b80610d1c5750600160009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b158015610ccf57600080fd5b505afa158015610ce3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d079190615102565b6001600160a01b0316336001600160a01b0316145b80610dbd5750600160009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b158015610d7057600080fd5b505afa158015610d84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da89190615102565b6001600160a01b0316336001600160a01b0316145b610dd95760405162461bcd60e51b815260040161050d90615a7c565b6000806000600160009054906101000a90046001600160a01b03166001600160a01b031663bf3759b56040518163ffffffff1660e01b815260040160206040518083038186803b158015610e2c57600080fd5b505afa158015610e40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e6491906155c4565b600a5490915060009060ff1615610eba576000610e7f61194f565b9050610e98838211610e915783610e93565b815b611d07565b9450915082821115610eb457610eae82846120bb565b94508291505b50610ecb565b610ec3826120fd565b919550935090505b6001546040516328766ebf60e21b81526001600160a01b039091169063a1d9bafc90610eff90879087908690600401615bd8565b602060405180830381600087803b158015610f1957600080fd5b505af1158015610f2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5191906155c4565b9150610f5c82611e18565b7f4c0f499ffe6befa0ca7c826b0916cf87bea98de658013e76938489368d60d50984848385604051610f919493929190615bee565b60405180910390a150505050565b600a5460ff1681565b60125481565b600d54600160381b900461ffff1681565b600080600080610fcd61217d565b5050935050925092506000610ffb84610ff561271061ffff168661221c90919063ffffffff16565b90611c06565b9050600061100883612256565b905060006110158461227c565b90506000806110226122a0565b91509150838510801561103457508082105b80156110495750606461104785876120bb565b115b8061105c57508285118061105c57508082115b156110725760019850505050505050505061107f565b6000985050505050505050505b919050565b600a54600090610100900460ff1661109b57600080fd5b604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81523060601b601482018190526e5af43d82803e903d91602b57fd5bf360881b6028830152906037816000f0604051637e80295b60e01b81529093506001600160a01b0384169150637e80295b90611120908d908d908d908d908d908d908d908d90600401615774565b600060405180830381600087803b15801561113a57600080fd5b505af115801561114e573d6000803e3d6000fd5b50506040516001600160a01b03851692507f783540fb4221a3238720dc7038937d0d79982bcf895274aa6ad179f82cf0d53c9150600090a25098975050505050505050565b6002546001600160a01b03163314806111c457506111af611c66565b6001600160a01b0316336001600160a01b0316145b6111e05760405162461bcd60e51b815260040161050d90615a7c565b6001600160a01b0381166111f357600080fd5b600480546001600160a01b0319166001600160a01b0383161790556040517f2f202ddb4a2e345f6323ed90f8fc8559d770a7abbbeee84dde8aca3351fe71549061081b908390615746565b6002546001600160a01b031633148061126f575061125a611c66565b6001600160a01b0316336001600160a01b0316145b61128b5760405162461bcd60e51b815260040161050d90615a7c565b61129760008383614e26565b507f300e67d5a415b6d015a471d9c7b95dd58f3e8290af965e84e0f845de2996dda682826040516112c99291906158cf565b60405180910390a15050565b6002546001600160a01b031633148061130657506112f1611c66565b6001600160a01b0316336001600160a01b0316145b6113225760405162461bcd60e51b815260040161050d90615a7c565b61232861ffff89161180159061134057508761ffff168961ffff1611155b61134957600080fd5b88600d60056101000a81548161ffff021916908361ffff16021790555087600d60076101000a81548161ffff021916908361ffff16021790555086600b8190555084600c8190555085600d60036101000a81548161ffff021916908361ffff16021790555083600d60006101000a81548160ff02191690831515021790555082600d60016101000a81548160ff02191690831515021790555081600d60026101000a81548160ff021916908315150217905550612710601254111561140d57600080fd5b6012555050505050505050565b611426888888886127a3565b600f546001600160a01b03161561143c57600080fd5b61144884848484612964565b5050505050505050565b60085481565b60006108f0611479611468612c70565b6010546001600160a01b0316612cf1565b6005546001600160a01b0316612e3b565b600d5465010000000000900461ffff1681565b6002546001600160a01b03163314806114ce57506114b9611c66565b6001600160a01b0316336001600160a01b0316145b6114ea5760405162461bcd60e51b815260040161050d90615a7c565b60088190556040517fd94596337df4c2f0f44d30a7fc5db1c7bb60d9aca4185ed77c6fd96eb45ec2989061081b908390615b74565b60065481565b6003546001600160a01b031681565b6004546001600160a01b031681565b6002546001600160a01b0316331480611574575061155f611c66565b6001600160a01b0316336001600160a01b0316145b6115905760405162461bcd60e51b815260040161050d90615a7c565b6001600160a01b0381166115a357600080fd5b600280546001600160a01b0319166001600160a01b0383161790556040517f352ececae6d7d1e6d26bcf2c549dfd55be1637e9b22dc0cf3b71ddb36097a6b49061081b908390615746565b6001546001600160a01b031633148061161f575061160a611c66565b6001600160a01b0316336001600160a01b0316145b61162857600080fd5b6001546040805163fbfa77cf60e01b815290516001600160a01b039283169284169163fbfa77cf916004808301926020929190829003018186803b15801561166f57600080fd5b505afa158015611683573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116a79190615102565b6001600160a01b0316146116ba57600080fd5b6116c38161175c565b6005546040516370a0823160e01b815261175c9183916001600160a01b03909116906370a08231906116f9903090600401615746565b60206040518083038186803b15801561171157600080fd5b505afa158015611725573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061174991906155c4565b6005546001600160a01b03169190611ce8565b50565b600d5462010000900460ff1681565b600b5481565b600d54610100900460ff1681565b6002546001600160a01b031633146117ac5760405162461bcd60e51b815260040161050d90615911565b6001600160a01b0381166117bf57600080fd5b60015460035460405163095ea7b360e01b81526001600160a01b039283169263095ea7b3926117f6929116906000906004016157c9565b602060405180830381600087803b15801561181057600080fd5b505af1158015611824573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611848919061530d565b50600380546001600160a01b0319166001600160a01b03838116919091179182905560015460405163095ea7b360e01b81529082169263095ea7b39261189792911690600019906004016157c9565b602060405180830381600087803b1580156118b157600080fd5b505af11580156118c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118e9919061530d565b507fafbb66abf8f3b719799940473a4052a3717cdd8e40fb6c8a3faadab316b1a0698160405161081b9190615746565b6000611923612f85565b806119495750600554611949906119449084906001600160a01b0316612e3b565b613192565b92915050565b60006108f0611962611479611468612c70565b61198c61197361147961146861340a565b61198661197e6135a7565b6119866135df565b90613610565b906120bb565b6002546001600160a01b03163314806119c357506119ae611c66565b6001600160a01b0316336001600160a01b0316145b6119df5760405162461bcd60e51b815260040161050d90615a7c565b60078190556040517f5430e11864ad7aa9775b07d12657fe52df9aa2ba734355bd8ef8747be2c800c59061081b908390615b74565b6001546001600160a01b031681565b6002546001600160a01b0316331480611a545750611a3f611c66565b6001600160a01b0316336001600160a01b0316145b611a705760405162461bcd60e51b815260040161050d90615a7c565b600a805460ff19166001908117909155546040805163507257cd60e11b815290516001600160a01b039092169163a0e4af9a9160048082019260009290919082900301818387803b158015611ac457600080fd5b505af1158015611ad8573d6000803e3d6000fd5b50506040517f97e963041e952738788b9d4871d854d282065b8f90a464928d6528f2e9a4fd0b925060009150a1565b801580611b8f5750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e90611b3d903090869060040161575a565b60206040518083038186803b158015611b5557600080fd5b505afa158015611b69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b8d91906155c4565b155b611bab5760405162461bcd60e51b815260040161050d90615b0f565b611c018363095ea7b360e01b8484604051602401611bca9291906157c9565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613635565b505050565b6000611c4883836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506136c4565b9392505050565b6060611c5e84846000856136fb565b949350505050565b60015460408051635aa6e67560e01b815290516000926001600160a01b031691635aa6e675916004808301926020929190829003018186803b158015611cab57600080fd5b505afa158015611cbf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108f09190615102565b606090565b611c018363a9059cbb60e01b8484604051602401611bca9291906157c9565b6000806000611d146135df565b9050838110611d2a578360009250925050611e13565b6000611d35856137bf565b90506000611d4282613917565b9050611d4d81613a5c565b611d5686613b46565b611d5e6135df565b92508286118015611d7657506000611d74612c70565b115b8015611d925750611d90611d8861340a565b611986613c77565b155b8015611da75750600d5462010000900460ff16155b15611de2576000611db887856120bb565b9050611dc3816137bf565b9250611dce83613ca8565b611dd783613a5c565b611de081613b46565b505b6000611dec6135df565b905080871115611e0a57945084611e0387826120bb565b9450611e0e565b8695505b505050505b915091565b6000611e226135df565b905081811115611e45576000611e3882846120bb565b9050611e4381613db2565b505b600080600080611e5361217d565b505093509350935093508360001415611e7057505050505061175c565b6000611e8285610ff58661271061221c565b90506000611e8f83612256565b90506000611e9c8461227c565b9050600080611ea96122a0565b915091508484118015611ebb57508082105b1561200b576000611ed2612710610ff58c8861221c565b90506000611ee0828b6120bb565b9050611eec8982613e5e565b905082611ef98583613610565b1115611f0c57611f0983856120bb565b90505b600c54601054600091611f27916001600160a01b0316612cf1565b905080611f348c84613610565b1115611f55578a8111611f48576000611f52565b611f52818c6120bb565b91505b601054600090611f6f9084906001600160a01b0316612e3b565b90508015611ffa57611f7f613e74565b601054600d5460405163a415bcad60e01b81526001600160a01b039384169363a415bcad93611fc7939116918691600291630100000090910461ffff16903090600401615832565b600060405180830381600087803b158015611fe157600080fd5b505af1158015611ff5573d6000803e3d6000fd5b505050505b612002613f33565b505050506120ae565b8285118061201857508082115b156120ae57600061202f612710610ff5878d61221c565b9050600089821061204157600061204b565b61204b8a836120bb565b905082612059575088612077565b82841115612077576120748161206f86866120bb565b613fc6565b90505b6010546000906120919083906001600160a01b0316612e3b565b9050600061209e82613917565b90506120a981613a5c565b505050505b5050505050505050505050565b6000611c4883836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613fd6565b60008060008061210b6135df565b9050612115614002565b61211d61452c565b61212561460b565b600061212f6135df565b9050818111156121465761214381836120bb565b94505b851561217457600061215787611d07565b955090506121658782613e5e565b9350841561217257600095505b505b50509193909250565b60008060008060008061218e613e74565b6001600160a01b031663bf92857c306040518263ffffffff1660e01b81526004016121b99190615746565b60c06040518083038186803b1580156121d157600080fd5b505afa1580156121e5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061220991906155dc565b949b939a50919850965094509092509050565b60008261222b57506000611949565b8282028284828161223857fe5b0414611c485760405162461bcd60e51b815260040161050d906159c3565b600d546000906119499061271090610ff590859065010000000000900461ffff1661221c565b600d546000906119499061271090610ff5908590600160381b900461ffff1661221c565b6000806122ab614ea4565b6122b3614ee9565b6122bb613e74565b6010546040516335ea6a7560e01b81526001600160a01b03928316926335ea6a75926122ec92911690600401615746565b6101806040518083038186803b15801561230557600080fd5b505afa158015612319573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061233d9190615396565b6101408101516010546040516335ea6a7560e01b8152929350909173057835ad21a177dbdd3090bb1cae03eacf78fc6d916335ea6a759161238a916001600160a01b031690600401615746565b6101406040518083038186803b1580156123a357600080fd5b505afa1580156123b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123db9190615625565b5050505060408901849052505050602086018290529185526123fc91613610565b60608401819052835161240e91613610565b60a08401526060830151156124355760a08301516060840151612430916146be565b612438565b60005b6080840152612445614f54565b816001600160a01b031663a15f30ac6040518163ffffffff1660e01b815260040160206040518083038186803b15801561247e57600080fd5b505afa158015612492573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124b691906155c4565b816000018181525050816001600160a01b031663b25895446040518163ffffffff1660e01b815260040160206040518083038186803b1580156124f857600080fd5b505afa15801561250c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061253091906155c4565b816020018181525050816001600160a01b0316637b832f586040518163ffffffff1660e01b815260040160206040518083038186803b15801561257257600080fd5b505afa158015612586573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125aa91906155c4565b816040018181525050816001600160a01b03166365614f816040518163ffffffff1660e01b815260040160206040518083038186803b1580156125ec57600080fd5b505afa158015612600573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061262491906155c4565b60608201528051608085015110801561265057506040810151602082015161264b91613610565b600b54105b156126945761268a8160400151612684836000015161267e8560200151600b546120bb90919063ffffffff16565b9061470c565b906146be565b60c0850152612730565b604081015160208201516126a791613610565b600b5410156126da5760608401516010546126cb91906001600160a01b0316612cf1565b6000955095505050505061279f565b8051606082015161272a9190611986906126846127036b033b2e3c9fd0803ce8000000856120bb565b61267e6127218860400151896020015161361090919063ffffffff16565b600b54906120bb565b60c08501525b61275b6b033b2e3c9fd0803ce80000006126848660c001518760a0015161470c90919063ffffffff16565b60e0850152606084015160105461277b91906001600160a01b0316612cf1565b60e085015160105461279691906001600160a01b0316612cf1565b95509550505050505b9091565b6005546001600160a01b0316156127cc5760405162461bcd60e51b815260040161050d9061598c565b600180546001600160a01b0319166001600160a01b03868116919091179182905560408051637e062a3560e11b81529051929091169163fc0c546a91600480820192602092909190829003018186803b15801561282857600080fd5b505afa15801561283c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128609190615102565b600580546001600160a01b0319166001600160a01b03928316179081905561288c911685600019611b07565b600280546001600160a01b038086166001600160a01b0319928316179092556003805485841690831617908190556004805485851693169290921782556000600681905562015180600755606460085560095560015460405163095ea7b360e01b81529084169363095ea7b39361290b939091169160001991016157c9565b602060405180830381600087803b15801561292557600080fd5b505af1158015612939573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061295d919061530d565b5050505050565b62015180600655620d2f006007556064600855600f80546001600160a01b0319166001600160a01b03861690811790915560408051637e062a3560e11b8152905163fc0c546a91600480820192602092909190829003018186803b1580156129cb57600080fd5b505afa1580156129df573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a039190615102565b601080546001600160a01b0319166001600160a01b039283161790556005546040516334924edb60e21b815260009273057835ad21a177dbdd3090bb1cae03eacf78fc6d9263d2493b6c92612a5f929190911690600401615746565b60606040518083038186803b158015612a7757600080fd5b505afa158015612a8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aaf919061511e565b5050600d80546001600160a01b03808416600160481b027fffffff0000000000000000000000000000000000000000ffffffffffffffffff909216919091179091556010546040516334924edb60e21b815292935060009273057835ad21a177dbdd3090bb1cae03eacf78fc6d9263d2493b6c92612b3292911690600401615746565b60606040518083038186803b158015612b4a57600080fd5b505afa158015612b5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b82919061511e565b600e80546001600160a01b0319166001600160a01b0383811691909117909155600f546040805163313ce56760e01b81529051939650612c2b95506064945091169163313ce56791600480820192602092909190829003018186803b158015612bea57600080fd5b505afa158015612bfe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c2291906155c4565b600a0a90611c06565b601155600d805460ff19168615151761ff00191661010086151502179055600019600c5560016012558251612c67906013906020860190614f7c565b50505050505050565b600e546040516370a0823160e01b81526000916001600160a01b0316906370a0823190612ca1903090600401615746565b60206040518083038186803b158015612cb957600080fd5b505afa158015612ccd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108f091906155c4565b6000821580612d01575060001983145b80612d2857506001600160a01b03821673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2145b15612d34575081611949565b611c48826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015612d7057600080fd5b505afa158015612d84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612da891906156a0565b60ff16600a0a610ff5612db961476b565b6001600160a01b031663b3596f07866040518263ffffffff1660e01b8152600401612de49190615746565b60206040518083038186803b158015612dfc57600080fd5b505afa158015612e10573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e3491906155c4565b869061221c565b6000821580612e4b575060001983145b80612e7257506001600160a01b03821673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2145b15612e7e575081611949565b611c48612e8961476b565b6001600160a01b031663b3596f07846040518263ffffffff1660e01b8152600401612eb49190615746565b60206040518083038186803b158015612ecc57600080fd5b505afa158015612ee0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f0491906155c4565b610ff5846001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015612f4057600080fd5b505afa158015612f54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f7891906156a0565b869060ff16600a0a61221c565b600d5460009060ff16158015612fa35750600d54610100900460ff16155b15612fb057506000610796565b60405163091030c360e01b8152600090734da27a545c0c5b758a6ba100e3a049001de870f59063091030c390612fea903090600401615746565b60206040518083038186803b15801561300257600080fd5b505afa158015613016573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061303a91906155c4565b90506000734da27a545c0c5b758a6ba100e3a049001de870f56001600160a01b03166372b49d636040518163ffffffff1660e01b815260040160206040518083038186803b15801561308b57600080fd5b505afa15801561309f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130c391906155c4565b90506000734da27a545c0c5b758a6ba100e3a049001de870f56001600160a01b031663359c4a966040518163ffffffff1660e01b815260040160206040518083038186803b15801561311457600080fd5b505afa158015613128573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061314c91906155c4565b90506131588383613610565b4210613188578061317361316c8585613610565b42906120bb565b11158061317e575082155b9350505050610796565b6000935050505090565b600061319c614fea565b6001546040516339ebf82360e01b81526001600160a01b03909116906339ebf823906131cc903090600401615746565b6101206040518083038186803b1580156131e557600080fd5b505afa1580156131f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061321d9190615491565b905080602001516000141561323657600091505061107f565b60065460a08201516132499042906120bb565b101561325957600091505061107f565b60075460a082015161326c9042906120bb565b1061327b57600191505061107f565b6001546040805163bf3759b560e01b815290516000926001600160a01b03169163bf3759b5916004808301926020929190829003018186803b1580156132c057600080fd5b505afa1580156132d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132f891906155c4565b905060095481111561330f5760019250505061107f565b600061331961194f565b90508260c001516133356009548361361090919063ffffffff16565b1015613347576001935050505061107f565b60008360c001518211156133685760c08401516133659083906120bb565b90505b6001546040805163112c1f9b60e01b815290516000926001600160a01b03169163112c1f9b916004808301926020929190829003018186803b1580156133ad57600080fd5b505afa1580156133c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133e591906155c4565b90506133f18183613610565b6008546133fe908961221c565b10979650505050505050565b60006108f0600f60009054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561345d57600080fd5b505afa158015613471573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061349591906155c4565b600a0a610ff5600f60009054906101000a90046001600160a01b03166001600160a01b03166399530b066040518163ffffffff1660e01b815260040160206040518083038186803b1580156134e957600080fd5b505afa1580156134fd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061352191906155c4565b600f546040516370a0823160e01b81526001600160a01b03909116906370a0823190613551903090600401615746565b60206040518083038186803b15801561356957600080fd5b505afa15801561357d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135a191906155c4565b9061221c565b600d546040516370a0823160e01b8152600091600160481b90046001600160a01b0316906370a0823190612ca1903090600401615746565b6005546040516370a0823160e01b81526000916001600160a01b0316906370a0823190612ca1903090600401615746565b600082820183811015611c485760405162461bcd60e51b815260040161050d90615955565b606061368a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611c4f9092919063ffffffff16565b805190915015611c0157808060200190518101906136a8919061530d565b611c015760405162461bcd60e51b815260040161050d90615aa1565b600081836136e55760405162461bcd60e51b815260040161050d91906158fe565b5060008385816136f157fe5b0495945050505050565b60606137068561482a565b6137225760405162461bcd60e51b815260040161050d90615a45565b60006060866001600160a01b0316858760405161373f919061572a565b60006040518083038185875af1925050503d806000811461377c576040519150601f19603f3d011682016040523d82523d6000602084013e613781565b606091505b50915091508115613795579150611c5e9050565b8051156137a55780518082602001fd5b8360405162461bcd60e51b815260040161050d91906158fe565b6000816137ce5750600061107f565b60008060006137db61217d565b5050600554939650919450909250600091613801915087906001600160a01b0316612cf1565b9050600081851161381357600061381d565b61381d85836120bb565b9050600080821161383057600019613840565b61384082610ff58761271061221c565b9050600061384d8561227c565b905080821161386657600097505050505050505061107f565b600019821415613895576010546138879087906001600160a01b0316612e3b565b97505050505050505061107f565b60006138a086612256565b905060006138b4612710610ff5848861221c565b9050878111156138d0576000995050505050505050505061107f565b601154613908906138e18a846120bb565b106138f5576138f089836120bb565b6138f7565b885b6010546001600160a01b0316612e3b565b9b9a5050505050505050505050565b6000816139265750600061107f565b6000613930613c77565b905060006139c561394085614863565b600f546040516370a0823160e01b81526001600160a01b03909116906370a0823190613970903090600401615746565b60206040518083038186803b15801561398857600080fd5b505afa15801561399c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139c091906155c4565b613e5e565b600f54601254604051631cc6d2f960e31b81529293506001600160a01b039091169163e63697c8916139fd9185913091600401615b7d565b602060405180830381600087803b158015613a1757600080fd5b505af1158015613a2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a4f91906155c4565b50611c5e8261198c613c77565b80613a665761175c565b6000613a70613c77565b9050613a7c8282613e5e565b9150613a8f613a89612c70565b83613e5e565b9150613aae613a9c613e74565b6010546001600160a01b031684614976565b811561067057613abc613e74565b60105460405163573ade8160e01b81526001600160a01b039283169263573ade8192613af49291169086906002903090600401615866565b602060405180830381600087803b158015613b0e57600080fd5b505af1158015613b22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c0191906155c4565b6000613b506135a7565b905080821115613b5e578091505b6000613ba8613b6b614a27565b600554600d546040516370a0823160e01b81526001600160a01b03928316926370a082319261397092600160481b90910490911690600401615746565b90506000613bb68483613e5e565b90508015613c7157613be2613bc9613e74565b600d54600160481b90046001600160a01b031683614976565b613bea613e74565b600554604051631a4ca37b60e21b81526001600160a01b03928316926369328dec92613c1f92911690859030906004016157e2565b602060405180830381600087803b158015613c3957600080fd5b505af1158015613c4d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061295d91906155c4565b50505050565b6010546040516370a0823160e01b81526000916001600160a01b0316906370a0823190612ca1903090600401615746565b80613cb25761175c565b6005546010546001600160a01b0390811691161415613cd05761175c565b600554613cfc90737a250d5630b4cf539739df2c5dacb4c659f2488d906001600160a01b031683614976565b600554601054737a250d5630b4cf539739df2c5dacb4c659f2488d91638803dbee91849160001991613d3a916001600160a01b039081169116614a8a565b30426040518663ffffffff1660e01b8152600401613d5c959493929190615b9c565b600060405180830381600087803b158015613d7657600080fd5b505af1158015613d8a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526106709190810190615278565b80613dbc5761175c565b6000613dc6613e74565b600554909150613de19082906001600160a01b031684614976565b600554600d5460405163e8eda9df60e01b81526001600160a01b038085169363e8eda9df93613e289391909216918791309161ffff63010000009091041690600401615805565b600060405180830381600087803b158015613e4257600080fd5b505af1158015613e56573d6000803e3d6000fd5b505050505050565b6000818310613e6d5781611c48565b5090919050565b600073057835ad21a177dbdd3090bb1cae03eacf78fc6d6001600160a01b0316630542975c6040518163ffffffff1660e01b815260040160206040518083038186803b158015613ec357600080fd5b505afa158015613ed7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613efb9190615102565b6001600160a01b0316630261bf8b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611cab57600080fd5b6000613f3d613c77565b9050801561175c57600f54601054613f62916001600160a01b03908116911683614976565b600f60009054906101000a90046001600160a01b03166001600160a01b031663d0e30db06040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613fb257600080fd5b505af115801561295d573d6000803e3d6000fd5b600081831015613e6d5781611c48565b60008184841115613ffa5760405162461bcd60e51b815260040161050d91906158fe565b505050900390565b600d54610100900460ff168061401a5750600d5460ff165b15610c33576040516370a0823160e01b8152600090734da27a545c0c5b758a6ba100e3a049001de870f5906370a0823190614059903090600401615746565b60206040518083038186803b15801561407157600080fd5b505afa158015614085573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140a991906155c4565b90506000811180156140be57506140be612f85565b1561412f576040516301e9a69560e41b8152734da27a545c0c5b758a6ba100e3a049001de870f590631e9a6950906140fc90309085906004016157c9565b600060405180830381600087803b15801561411657600080fd5b505af115801561412a573d6000803e3d6000fd5b505050505b6040516309a99b4f60e41b8152734da27a545c0c5b758a6ba100e3a049001de870f590639a99b4f09061416a903090600019906004016157c9565b600060405180830381600087803b15801561418457600080fd5b505af1158015614198573d6000803e3d6000fd5b50506040516370a0823160e01b815260009250737fc66500c84a76ad7e9c93437bfc5ac33e2ddae991506370a08231906141d6903090600401615746565b60206040518083038186803b1580156141ee57600080fd5b505afa158015614202573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061422691906155c4565b905066038d7ea4c680008111156142405761424081614c0b565b600d54606090610100900460ff16801561425c5750600d5460ff165b156142f4576040805160028082526060820183529091602083019080368337019050509050600d60099054906101000a90046001600160a01b0316816000815181106142a457fe5b6001600160a01b039283166020918202929092010152600e548251911690829060019081106142cf57fe5b60200260200101906001600160a01b031690816001600160a01b0316815250506143ad565b600d54610100900460ff161561433e5760408051600180825281830190925290602080830190803683375050600e5482519293506001600160a01b0316918391506000906142cf57fe5b600d5460ff16156143ad576040805160018082528183019092529060208083019080368337019050509050600d60099054906101000a90046001600160a01b03168160008151811061438c57fe5b60200260200101906001600160a01b031690816001600160a01b0316815250505b6143b5614c94565b6001600160a01b0316633111e7b382600019306040518463ffffffff1660e01b81526004016143e693929190615891565b602060405180830381600087803b15801561440057600080fd5b505af1158015614414573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061443891906155c4565b506040516370a0823160e01b8152600090734da27a545c0c5b758a6ba100e3a049001de870f5906370a0823190614473903090600401615746565b60206040518083038186803b15801561448b57600080fd5b505afa15801561449f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144c391906155c4565b1115611c0157734da27a545c0c5b758a6ba100e3a049001de870f56001600160a01b031663787a08a66040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561451857600080fd5b505af1158015612c67573d6000803e3d6000fd5b6000614536612c70565b9050600061454261340a565b9050808210614552575050610c33565b600061455e82846120bb565b9050600061456b82614863565b90508015613c7157600f54601254604051631cc6d2f960e31b81526001600160a01b039092169163e63697c8916145a89185913091600401615b7d565b602060405180830381600087803b1580156145c257600080fd5b505af11580156145d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145fa91906155c4565b50613c71614606613c77565b614d95565b6001546040516339ebf82360e01b81526000916001600160a01b0316906339ebf8239061463c903090600401615746565b6101206040518083038186803b15801561465557600080fd5b505afa158015614669573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061468d9190615491565b60c001519050600061469d6135a7565b9050818111156106705760006146b382846120bb565b9050611c0181613b46565b6000816146ca57600080fd5b600282046b033b2e3c9fd0803ce80000008119048411156146ea57600080fd5b82816b033b2e3c9fd0803ce80000008602018161470357fe5b04949350505050565b6000821580614719575081155b1561472657506000611949565b816b019d971e4fe8401e74000000198161473c57fe5b0483111561474957600080fd5b506b033b2e3c9fd0803ce800000091026b019d971e4fe8401e74000000010490565b600073057835ad21a177dbdd3090bb1cae03eacf78fc6d6001600160a01b0316630542975c6040518163ffffffff1660e01b815260040160206040518083038186803b1580156147ba57600080fd5b505afa1580156147ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147f29190615102565b6001600160a01b031663fca513a86040518163ffffffff1660e01b815260040160206040518083038186803b158015611cab57600080fd5b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590611c5e575050151592915050565b6000611949600f60009054906101000a90046001600160a01b03166001600160a01b03166399530b066040518163ffffffff1660e01b815260040160206040518083038186803b1580156148b657600080fd5b505afa1580156148ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148ee91906155c4565b600f546040805163313ce56760e01b81529051610ff5926001600160a01b03169163313ce567916004808301926020929190829003018186803b15801561493457600080fd5b505afa158015614948573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061496c91906155c4565b8590600a0a61221c565b604051636eb1769f60e11b815281906001600160a01b0384169063dd62ed3e906149a6903090889060040161575a565b60206040518083038186803b1580156149be57600080fd5b505afa1580156149d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149f691906155c4565b1015611c0157614a116001600160a01b038316846000611b07565b611c016001600160a01b03831684600019611b07565b600080600080614a3561217d565b5094505050925092506000808211614a4d5783614a5d565b614a5d82610ff58561271061221c565b905083811115614a74576000945050505050610796565b614a8161147985836120bb565b94505050505090565b606060006001600160a01b03841673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21480614ad557506001600160a01b03831673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2145b905080614ae3576003614ae6565b60025b60ff1667ffffffffffffffff81118015614aff57600080fd5b50604051908082528060200260200182016040528015614b29578160200160208202803683370190505b5091508382600081518110614b3a57fe5b60200260200101906001600160a01b031690816001600160a01b0316815250508015614b93578282600181518110614b6e57fe5b60200260200101906001600160a01b031690816001600160a01b031681525050614c04565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc282600181518110614bb557fe5b60200260200101906001600160a01b031690816001600160a01b0316815250508282600281518110614be357fe5b60200260200101906001600160a01b031690816001600160a01b0316815250505b5092915050565b80614c155761175c565b614c48737a250d5630b4cf539739df2c5dacb4c659f2488d737fc66500c84a76ad7e9c93437bfc5ac33e2ddae983614976565b600554737a250d5630b4cf539739df2c5dacb4c659f2488d906338ed1739908390600090613d3a90737fc66500c84a76ad7e9c93437bfc5ac33e2ddae9906001600160a01b0316614a8a565b600d5460009060ff1615614d2f57600d60099054906101000a90046001600160a01b03166001600160a01b03166375d264136040518163ffffffff1660e01b815260040160206040518083038186803b158015614cf057600080fd5b505afa158015614d04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614d289190615102565b9050610796565b600d54610100900460ff1615614d8d57600e60009054906101000a90046001600160a01b03166001600160a01b03166375d264136040518163ffffffff1660e01b815260040160206040518083038186803b158015614cf057600080fd5b506000610796565b80614d9f5761175c565b6010546005546001600160a01b0390811691161415614dbd5761175c565b601054614de990737a250d5630b4cf539739df2c5dacb4c659f2488d906001600160a01b031683614976565b601054600554737a250d5630b4cf539739df2c5dacb4c659f2488d916338ed1739918491600091613d3a916001600160a01b039081169116614a8a565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10614e675782800160ff19823516178555614e94565b82800160010185558215614e94579182015b82811115614e94578235825591602001919060010190614e79565b50614ea0929150615036565b5090565b60405180610100016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b604051806101800160405280614efd61504b565b815260006020820181905260408201819052606082018190526080820181905260a0820181905260c0820181905260e082018190526101008201819052610120820181905261014082018190526101609091015290565b6040518060800160405280600081526020016000815260200160008152602001600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10614fbd57805160ff1916838001178555614e94565b82800160010185558215614e94579182015b82811115614e94578251825591602001919060010190614fcf565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b5b80821115614ea05760008155600101615037565b6040518060200160405280600081525090565b805161194981615c7c565b60006020828403121561507a578081fd5b6150846020615c09565b9151825250919050565b80516fffffffffffffffffffffffffffffffff8116811461194957600080fd5b803561ffff8116811461194957600080fd5b805164ffffffffff8116811461194957600080fd5b805160ff8116811461194957600080fd5b6000602082840312156150f7578081fd5b8135611c4881615c7c565b600060208284031215615113578081fd5b8151611c4881615c7c565b600080600060608486031215615132578182fd5b835161513d81615c7c565b602085015190935061514e81615c7c565b604085015190925061515f81615c7c565b809150509250925092565b600080600080600080600080610100898b031215615186578384fd5b883561519181615c7c565b97506020898101356151a281615c7c565b975060408a01356151b281615c7c565b965060608a01356151c281615c7c565b955060808a01356151d281615c7c565b945060a08a01356151e281615c91565b935060c08a01356151f281615c91565b925060e08a013567ffffffffffffffff8082111561520e578384fd5b818c0191508c601f830112615221578384fd5b81358181111561522f578485fd5b615241601f8201601f19168501615c09565b91508082528d84828501011115615256578485fd5b8084840185840137810190920192909252979a96995094975092959194909350565b6000602080838503121561528a578182fd5b825167ffffffffffffffff8111156152a0578283fd5b8301601f810185136152b0578283fd5b80516152c36152be82615c30565b615c09565b81815283810190838501858402850186018910156152df578687fd5b8694505b838510156153015780518352600194909401939185019185016152e3565b50979650505050505050565b60006020828403121561531e578081fd5b8151611c4881615c91565b6000806020838503121561533b578182fd5b823567ffffffffffffffff80821115615352578384fd5b818501915085601f830112615365578384fd5b813581811115615373578485fd5b866020828501011115615384578485fd5b60209290920196919550909350505050565b60006101808083850312156153a9578182fd5b6153b281615c09565b90506153be8484615069565b81526153cd846020850161508e565b60208201526153df846040850161508e565b60408201526153f1846060850161508e565b6060820152615403846080850161508e565b60808201526154158460a0850161508e565b60a08201526154278460c085016150c0565b60c08201526154398460e0850161505e565b60e082015261010061544d8582860161505e565b908201526101206154608585830161505e565b908201526101406154738585830161505e565b90820152610160615486858583016150d5565b908201529392505050565b60006101208083850312156154a4578182fd5b6154ad81615c09565b9050825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152508091505092915050565b60008060008060008060008060006101208a8c03121561552d578283fd5b6155378b8b6150ae565b98506155468b60208c016150ae565b975060408a0135965061555c8b60608c016150ae565b955060808a0135945060a08a013561557381615c91565b935060c08a013561558381615c91565b925060e08a013561559381615c91565b809250506101008a013590509295985092959850929598565b6000602082840312156155bd578081fd5b5035919050565b6000602082840312156155d5578081fd5b5051919050565b60008060008060008060c087890312156155f4578384fd5b865195506020870151945060408701519350606087015192506080870151915060a087015190509295509295509295565b6000806000806000806000806000806101408b8d031215615644578384fd5b8a51995060208b0151985060408b0151975060608b0151965060808b0151955060a08b0151945060c08b0151935060e08b015192506101008b0151915061568f8c6101208d016150c0565b90509295989b9194979a5092959850565b6000602082840312156156b1578081fd5b611c4883836150d5565b6000815180845260208085019450808401835b838110156156f35781516001600160a01b0316875295820195908201906001016156ce565b509495945050505050565b60008151808452615716816020860160208601615c50565b601f01601f19169290920160200192915050565b6000825161573c818460208701615c50565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b0389811682528881166020830152878116604083015286811660608301528516608082015283151560a082015282151560c082015261010060e08201819052600090613908838201856156fe565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b6001600160a01b03948516815260208101939093529216604082015261ffff909116606082015260800190565b6001600160a01b0395861681526020810194909452604084019290925261ffff166060830152909116608082015260a00190565b6001600160a01b03948516815260208101939093526040830191909152909116606082015260800190565b6000606082526158a460608301866156bb565b6020830194909452506001600160a01b0391909116604090910152919050565b901515815260200190565b60006020825282602083015282846040840137818301604090810191909152601f909201601f19160101919050565b600060208252611c4860208301846156fe565b6020808252600b908201526a085cdd1c985d1959da5cdd60aa1b604082015260600190565b602080825260059082015264085dd85b9d60da1b604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252601c908201527f537472617465677920616c726561647920696e697469616c697a656400000000604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b602080825260069082015265085d985d5b1d60d21b604082015260600190565b6020808252600790820152662173686172657360c81b604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252600b908201526a08585d5d1a1bdc9a5e995960aa1b604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b6020808252600a9082015269085c1c9bdd1958dd195960b21b604082015260600190565b60208082526036908201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60408201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b606082015260800190565b61ffff91909116815260200190565b90815260200190565b9283526001600160a01b03919091166020830152604082015260600190565b600086825285602083015260a06040830152615bbb60a08301866156bb565b6001600160a01b0394909416606083015250608001529392505050565b9283526020830191909152604082015260600190565b93845260208401929092526040830152606082015260800190565b60405181810167ffffffffffffffff81118282101715615c2857600080fd5b604052919050565b600067ffffffffffffffff821115615c46578081fd5b5060209081020190565b60005b83811015615c6b578181015183820152602001615c53565b83811115613c715750506000910152565b6001600160a01b038116811461175c57600080fd5b801515811461175c57600080fdfea2646970667358221220460c7cd5f0aeda40e31c72f4074859c1262fb4a2a9ad221809da26623a4c1b8d64736f6c634300060c0033000000000000000000000000a696a63cc78dffa1a63e9e50587c197387ff6c7e0000000000000000000000005f18c75abdae578b483e5f43f12a39cf75b973a90000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000001a416176654c656e64657257425443426f72726f77657255534443000000000000

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102745760003560e01c8063748747e611610151578063c7b9d530116100c3578063ec38a86211610087578063ec38a86214610484578063ed882c2b14610497578063efbb5cb0146104aa578063f017c92f146104b2578063fbfa77cf146104c5578063fcf2d0ad146104cd57610274565b8063c7b9d53014610446578063ce5494bb14610459578063da769c471461046c578063db67e35e14610474578063dfccfbd91461047c57610274565b80638e6350e2116101155780638e6350e21461040b5780638e72e31b1461041357806391397ab41461041b57806395e80c501461042e5780639ec5a89414610436578063aced16611461043e57610274565b8063748747e6146103b7578063750521f5146103ca578063758463f0146103dd5780637e80295b146103f05780638cdfe1661461040357610274565b806328b7ccf7116101ea5780634641257d116101ae5780634641257d146103645780635641ec031461036c5780635783fe39146103745780636353f8221461037c578063650d18801461039157806369aa6128146103a457610274565b806328b7ccf7146103265780632e1a7d4d1461032e57806333303f8e1461034157806339a172a814610349578063440368a31461035c57610274565b80631d12f28b1161023c5780631d12f28b146102dc5780631f1fcd51146102f15780631fe4a6861461030657806322f3e2d41461030e5780632582941014610316578063276f53771461031e57610274565b806301681a621461027957806303ee438c1461028e57806306fdde03146102ac5780630f969b87146102b45780631166f15e146102c7575b600080fd5b61028c6102873660046150e6565b6104d5565b005b610296610674565b6040516102a391906158fe565b60405180910390f35b610296610702565b61028c6102c23660046155ac565b610799565b6102cf610826565b6040516102a391906158c4565b6102e461082f565b6040516102a39190615b74565b6102f9610835565b6040516102a39190615746565b6102f9610844565b6102cf610853565b6102966108f5565b6102e4610914565b6102e461091a565b6102e461033c3660046155ac565b610920565b6102f961097b565b61028c6103573660046155ac565b61098a565b61028c610a0c565b61028c610c35565b6102cf610f9f565b6102e4610fa8565b610384610fae565b6040516102a39190615b65565b6102cf61039f3660046155ac565b610fbf565b6102f96103b236600461516a565b611084565b61028c6103c53660046150e6565b611193565b61028c6103d8366004615329565b61123e565b61028c6103eb36600461550f565b6112d5565b61028c6103fe36600461516a565b61141a565b6102e4611452565b6102e4611458565b61038461148a565b61028c6104293660046155ac565b61149d565b6102e461151f565b6102f9611525565b6102f9611534565b61028c6104543660046150e6565b611543565b61028c6104673660046150e6565b6115ee565b6102cf61175f565b6102e461176e565b6102cf611774565b61028c6104923660046150e6565b611782565b6102cf6104a53660046155ac565b611919565b6102e461194f565b61028c6104c03660046155ac565b611992565b6102f9611a14565b61028c611a23565b6104dd611c66565b6001600160a01b0316336001600160a01b0316146105165760405162461bcd60e51b815260040161050d90615a7c565b60405180910390fd5b6005546001600160a01b03828116911614156105445760405162461bcd60e51b815260040161050d90615936565b6001546001600160a01b03828116911614156105725760405162461bcd60e51b815260040161050d90615a24565b606061057c611ce3565b905060005b81518110156105d75781818151811061059657fe5b60200260200101516001600160a01b0316836001600160a01b031614156105cf5760405162461bcd60e51b815260040161050d90615aeb565b600101610581565b506106706105e3611c66565b6040516370a0823160e01b81526001600160a01b038516906370a082319061060f903090600401615746565b60206040518083038186803b15801561062757600080fd5b505afa15801561063b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061065f91906155c4565b6001600160a01b0385169190611ce8565b5050565b6000805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156106fa5780601f106106cf576101008083540402835291602001916106fa565b820191906000526020600020905b8154815290600101906020018083116106dd57829003601f168201915b505050505081565b60138054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561078e5780601f106107635761010080835404028352916020019161078e565b820191906000526020600020905b81548152906001019060200180831161077157829003601f168201915b505050505090505b90565b6002546001600160a01b03163314806107ca57506107b5611c66565b6001600160a01b0316336001600160a01b0316145b6107e65760405162461bcd60e51b815260040161050d90615a7c565b60098190556040517fa68ba126373d04c004c5748c300c9fca12bd444b3d4332e261f3bd2bac4a86009061081b908390615b74565b60405180910390a150565b600d5460ff1681565b60095481565b6005546001600160a01b031681565b6002546001600160a01b031681565b6001546040516339ebf82360e01b815260009182916001600160a01b03909116906339ebf82390610888903090600401615746565b6101206040518083038186803b1580156108a157600080fd5b505afa1580156108b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d99190615491565b6040015111806108f0575060006108ee61194f565b115b905090565b604080518082019091526005815264302e332e3560d81b602082015290565b600c5481565b60075481565b6001546000906001600160a01b0316331461094d5760405162461bcd60e51b815260040161050d90615a04565b600061095883611d07565b600554909350909150610975906001600160a01b03163383611ce8565b50919050565b600f546001600160a01b031681565b6002546001600160a01b03163314806109bb57506109a6611c66565b6001600160a01b0316336001600160a01b0316145b6109d75760405162461bcd60e51b815260040161050d90615a7c565b60068190556040517fbb2c369a0355a34b02ab5fce0643150c87e1c8dfe7c918d465591879f57948b19061081b908390615b74565b6004546001600160a01b0316331480610a2f57506002546001600160a01b031633145b80610a525750610a3d611c66565b6001600160a01b0316336001600160a01b0316145b80610af35750600160009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b158015610aa657600080fd5b505afa158015610aba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ade9190615102565b6001600160a01b0316336001600160a01b0316145b80610b945750600160009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b158015610b4757600080fd5b505afa158015610b5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7f9190615102565b6001600160a01b0316336001600160a01b0316145b610bb05760405162461bcd60e51b815260040161050d90615a7c565b6001546040805163bf3759b560e01b81529051610c33926001600160a01b03169163bf3759b5916004808301926020929190829003018186803b158015610bf657600080fd5b505afa158015610c0a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c2e91906155c4565b611e18565b565b6004546001600160a01b0316331480610c5857506002546001600160a01b031633145b80610c7b5750610c66611c66565b6001600160a01b0316336001600160a01b0316145b80610d1c5750600160009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b158015610ccf57600080fd5b505afa158015610ce3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d079190615102565b6001600160a01b0316336001600160a01b0316145b80610dbd5750600160009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b158015610d7057600080fd5b505afa158015610d84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da89190615102565b6001600160a01b0316336001600160a01b0316145b610dd95760405162461bcd60e51b815260040161050d90615a7c565b6000806000600160009054906101000a90046001600160a01b03166001600160a01b031663bf3759b56040518163ffffffff1660e01b815260040160206040518083038186803b158015610e2c57600080fd5b505afa158015610e40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e6491906155c4565b600a5490915060009060ff1615610eba576000610e7f61194f565b9050610e98838211610e915783610e93565b815b611d07565b9450915082821115610eb457610eae82846120bb565b94508291505b50610ecb565b610ec3826120fd565b919550935090505b6001546040516328766ebf60e21b81526001600160a01b039091169063a1d9bafc90610eff90879087908690600401615bd8565b602060405180830381600087803b158015610f1957600080fd5b505af1158015610f2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5191906155c4565b9150610f5c82611e18565b7f4c0f499ffe6befa0ca7c826b0916cf87bea98de658013e76938489368d60d50984848385604051610f919493929190615bee565b60405180910390a150505050565b600a5460ff1681565b60125481565b600d54600160381b900461ffff1681565b600080600080610fcd61217d565b5050935050925092506000610ffb84610ff561271061ffff168661221c90919063ffffffff16565b90611c06565b9050600061100883612256565b905060006110158461227c565b90506000806110226122a0565b91509150838510801561103457508082105b80156110495750606461104785876120bb565b115b8061105c57508285118061105c57508082115b156110725760019850505050505050505061107f565b6000985050505050505050505b919050565b600a54600090610100900460ff1661109b57600080fd5b604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81523060601b601482018190526e5af43d82803e903d91602b57fd5bf360881b6028830152906037816000f0604051637e80295b60e01b81529093506001600160a01b0384169150637e80295b90611120908d908d908d908d908d908d908d908d90600401615774565b600060405180830381600087803b15801561113a57600080fd5b505af115801561114e573d6000803e3d6000fd5b50506040516001600160a01b03851692507f783540fb4221a3238720dc7038937d0d79982bcf895274aa6ad179f82cf0d53c9150600090a25098975050505050505050565b6002546001600160a01b03163314806111c457506111af611c66565b6001600160a01b0316336001600160a01b0316145b6111e05760405162461bcd60e51b815260040161050d90615a7c565b6001600160a01b0381166111f357600080fd5b600480546001600160a01b0319166001600160a01b0383161790556040517f2f202ddb4a2e345f6323ed90f8fc8559d770a7abbbeee84dde8aca3351fe71549061081b908390615746565b6002546001600160a01b031633148061126f575061125a611c66565b6001600160a01b0316336001600160a01b0316145b61128b5760405162461bcd60e51b815260040161050d90615a7c565b61129760008383614e26565b507f300e67d5a415b6d015a471d9c7b95dd58f3e8290af965e84e0f845de2996dda682826040516112c99291906158cf565b60405180910390a15050565b6002546001600160a01b031633148061130657506112f1611c66565b6001600160a01b0316336001600160a01b0316145b6113225760405162461bcd60e51b815260040161050d90615a7c565b61232861ffff89161180159061134057508761ffff168961ffff1611155b61134957600080fd5b88600d60056101000a81548161ffff021916908361ffff16021790555087600d60076101000a81548161ffff021916908361ffff16021790555086600b8190555084600c8190555085600d60036101000a81548161ffff021916908361ffff16021790555083600d60006101000a81548160ff02191690831515021790555082600d60016101000a81548160ff02191690831515021790555081600d60026101000a81548160ff021916908315150217905550612710601254111561140d57600080fd5b6012555050505050505050565b611426888888886127a3565b600f546001600160a01b03161561143c57600080fd5b61144884848484612964565b5050505050505050565b60085481565b60006108f0611479611468612c70565b6010546001600160a01b0316612cf1565b6005546001600160a01b0316612e3b565b600d5465010000000000900461ffff1681565b6002546001600160a01b03163314806114ce57506114b9611c66565b6001600160a01b0316336001600160a01b0316145b6114ea5760405162461bcd60e51b815260040161050d90615a7c565b60088190556040517fd94596337df4c2f0f44d30a7fc5db1c7bb60d9aca4185ed77c6fd96eb45ec2989061081b908390615b74565b60065481565b6003546001600160a01b031681565b6004546001600160a01b031681565b6002546001600160a01b0316331480611574575061155f611c66565b6001600160a01b0316336001600160a01b0316145b6115905760405162461bcd60e51b815260040161050d90615a7c565b6001600160a01b0381166115a357600080fd5b600280546001600160a01b0319166001600160a01b0383161790556040517f352ececae6d7d1e6d26bcf2c549dfd55be1637e9b22dc0cf3b71ddb36097a6b49061081b908390615746565b6001546001600160a01b031633148061161f575061160a611c66565b6001600160a01b0316336001600160a01b0316145b61162857600080fd5b6001546040805163fbfa77cf60e01b815290516001600160a01b039283169284169163fbfa77cf916004808301926020929190829003018186803b15801561166f57600080fd5b505afa158015611683573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116a79190615102565b6001600160a01b0316146116ba57600080fd5b6116c38161175c565b6005546040516370a0823160e01b815261175c9183916001600160a01b03909116906370a08231906116f9903090600401615746565b60206040518083038186803b15801561171157600080fd5b505afa158015611725573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061174991906155c4565b6005546001600160a01b03169190611ce8565b50565b600d5462010000900460ff1681565b600b5481565b600d54610100900460ff1681565b6002546001600160a01b031633146117ac5760405162461bcd60e51b815260040161050d90615911565b6001600160a01b0381166117bf57600080fd5b60015460035460405163095ea7b360e01b81526001600160a01b039283169263095ea7b3926117f6929116906000906004016157c9565b602060405180830381600087803b15801561181057600080fd5b505af1158015611824573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611848919061530d565b50600380546001600160a01b0319166001600160a01b03838116919091179182905560015460405163095ea7b360e01b81529082169263095ea7b39261189792911690600019906004016157c9565b602060405180830381600087803b1580156118b157600080fd5b505af11580156118c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118e9919061530d565b507fafbb66abf8f3b719799940473a4052a3717cdd8e40fb6c8a3faadab316b1a0698160405161081b9190615746565b6000611923612f85565b806119495750600554611949906119449084906001600160a01b0316612e3b565b613192565b92915050565b60006108f0611962611479611468612c70565b61198c61197361147961146861340a565b61198661197e6135a7565b6119866135df565b90613610565b906120bb565b6002546001600160a01b03163314806119c357506119ae611c66565b6001600160a01b0316336001600160a01b0316145b6119df5760405162461bcd60e51b815260040161050d90615a7c565b60078190556040517f5430e11864ad7aa9775b07d12657fe52df9aa2ba734355bd8ef8747be2c800c59061081b908390615b74565b6001546001600160a01b031681565b6002546001600160a01b0316331480611a545750611a3f611c66565b6001600160a01b0316336001600160a01b0316145b611a705760405162461bcd60e51b815260040161050d90615a7c565b600a805460ff19166001908117909155546040805163507257cd60e11b815290516001600160a01b039092169163a0e4af9a9160048082019260009290919082900301818387803b158015611ac457600080fd5b505af1158015611ad8573d6000803e3d6000fd5b50506040517f97e963041e952738788b9d4871d854d282065b8f90a464928d6528f2e9a4fd0b925060009150a1565b801580611b8f5750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e90611b3d903090869060040161575a565b60206040518083038186803b158015611b5557600080fd5b505afa158015611b69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b8d91906155c4565b155b611bab5760405162461bcd60e51b815260040161050d90615b0f565b611c018363095ea7b360e01b8484604051602401611bca9291906157c9565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613635565b505050565b6000611c4883836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506136c4565b9392505050565b6060611c5e84846000856136fb565b949350505050565b60015460408051635aa6e67560e01b815290516000926001600160a01b031691635aa6e675916004808301926020929190829003018186803b158015611cab57600080fd5b505afa158015611cbf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108f09190615102565b606090565b611c018363a9059cbb60e01b8484604051602401611bca9291906157c9565b6000806000611d146135df565b9050838110611d2a578360009250925050611e13565b6000611d35856137bf565b90506000611d4282613917565b9050611d4d81613a5c565b611d5686613b46565b611d5e6135df565b92508286118015611d7657506000611d74612c70565b115b8015611d925750611d90611d8861340a565b611986613c77565b155b8015611da75750600d5462010000900460ff16155b15611de2576000611db887856120bb565b9050611dc3816137bf565b9250611dce83613ca8565b611dd783613a5c565b611de081613b46565b505b6000611dec6135df565b905080871115611e0a57945084611e0387826120bb565b9450611e0e565b8695505b505050505b915091565b6000611e226135df565b905081811115611e45576000611e3882846120bb565b9050611e4381613db2565b505b600080600080611e5361217d565b505093509350935093508360001415611e7057505050505061175c565b6000611e8285610ff58661271061221c565b90506000611e8f83612256565b90506000611e9c8461227c565b9050600080611ea96122a0565b915091508484118015611ebb57508082105b1561200b576000611ed2612710610ff58c8861221c565b90506000611ee0828b6120bb565b9050611eec8982613e5e565b905082611ef98583613610565b1115611f0c57611f0983856120bb565b90505b600c54601054600091611f27916001600160a01b0316612cf1565b905080611f348c84613610565b1115611f55578a8111611f48576000611f52565b611f52818c6120bb565b91505b601054600090611f6f9084906001600160a01b0316612e3b565b90508015611ffa57611f7f613e74565b601054600d5460405163a415bcad60e01b81526001600160a01b039384169363a415bcad93611fc7939116918691600291630100000090910461ffff16903090600401615832565b600060405180830381600087803b158015611fe157600080fd5b505af1158015611ff5573d6000803e3d6000fd5b505050505b612002613f33565b505050506120ae565b8285118061201857508082115b156120ae57600061202f612710610ff5878d61221c565b9050600089821061204157600061204b565b61204b8a836120bb565b905082612059575088612077565b82841115612077576120748161206f86866120bb565b613fc6565b90505b6010546000906120919083906001600160a01b0316612e3b565b9050600061209e82613917565b90506120a981613a5c565b505050505b5050505050505050505050565b6000611c4883836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613fd6565b60008060008061210b6135df565b9050612115614002565b61211d61452c565b61212561460b565b600061212f6135df565b9050818111156121465761214381836120bb565b94505b851561217457600061215787611d07565b955090506121658782613e5e565b9350841561217257600095505b505b50509193909250565b60008060008060008061218e613e74565b6001600160a01b031663bf92857c306040518263ffffffff1660e01b81526004016121b99190615746565b60c06040518083038186803b1580156121d157600080fd5b505afa1580156121e5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061220991906155dc565b949b939a50919850965094509092509050565b60008261222b57506000611949565b8282028284828161223857fe5b0414611c485760405162461bcd60e51b815260040161050d906159c3565b600d546000906119499061271090610ff590859065010000000000900461ffff1661221c565b600d546000906119499061271090610ff5908590600160381b900461ffff1661221c565b6000806122ab614ea4565b6122b3614ee9565b6122bb613e74565b6010546040516335ea6a7560e01b81526001600160a01b03928316926335ea6a75926122ec92911690600401615746565b6101806040518083038186803b15801561230557600080fd5b505afa158015612319573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061233d9190615396565b6101408101516010546040516335ea6a7560e01b8152929350909173057835ad21a177dbdd3090bb1cae03eacf78fc6d916335ea6a759161238a916001600160a01b031690600401615746565b6101406040518083038186803b1580156123a357600080fd5b505afa1580156123b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123db9190615625565b5050505060408901849052505050602086018290529185526123fc91613610565b60608401819052835161240e91613610565b60a08401526060830151156124355760a08301516060840151612430916146be565b612438565b60005b6080840152612445614f54565b816001600160a01b031663a15f30ac6040518163ffffffff1660e01b815260040160206040518083038186803b15801561247e57600080fd5b505afa158015612492573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124b691906155c4565b816000018181525050816001600160a01b031663b25895446040518163ffffffff1660e01b815260040160206040518083038186803b1580156124f857600080fd5b505afa15801561250c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061253091906155c4565b816020018181525050816001600160a01b0316637b832f586040518163ffffffff1660e01b815260040160206040518083038186803b15801561257257600080fd5b505afa158015612586573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125aa91906155c4565b816040018181525050816001600160a01b03166365614f816040518163ffffffff1660e01b815260040160206040518083038186803b1580156125ec57600080fd5b505afa158015612600573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061262491906155c4565b60608201528051608085015110801561265057506040810151602082015161264b91613610565b600b54105b156126945761268a8160400151612684836000015161267e8560200151600b546120bb90919063ffffffff16565b9061470c565b906146be565b60c0850152612730565b604081015160208201516126a791613610565b600b5410156126da5760608401516010546126cb91906001600160a01b0316612cf1565b6000955095505050505061279f565b8051606082015161272a9190611986906126846127036b033b2e3c9fd0803ce8000000856120bb565b61267e6127218860400151896020015161361090919063ffffffff16565b600b54906120bb565b60c08501525b61275b6b033b2e3c9fd0803ce80000006126848660c001518760a0015161470c90919063ffffffff16565b60e0850152606084015160105461277b91906001600160a01b0316612cf1565b60e085015160105461279691906001600160a01b0316612cf1565b95509550505050505b9091565b6005546001600160a01b0316156127cc5760405162461bcd60e51b815260040161050d9061598c565b600180546001600160a01b0319166001600160a01b03868116919091179182905560408051637e062a3560e11b81529051929091169163fc0c546a91600480820192602092909190829003018186803b15801561282857600080fd5b505afa15801561283c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128609190615102565b600580546001600160a01b0319166001600160a01b03928316179081905561288c911685600019611b07565b600280546001600160a01b038086166001600160a01b0319928316179092556003805485841690831617908190556004805485851693169290921782556000600681905562015180600755606460085560095560015460405163095ea7b360e01b81529084169363095ea7b39361290b939091169160001991016157c9565b602060405180830381600087803b15801561292557600080fd5b505af1158015612939573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061295d919061530d565b5050505050565b62015180600655620d2f006007556064600855600f80546001600160a01b0319166001600160a01b03861690811790915560408051637e062a3560e11b8152905163fc0c546a91600480820192602092909190829003018186803b1580156129cb57600080fd5b505afa1580156129df573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a039190615102565b601080546001600160a01b0319166001600160a01b039283161790556005546040516334924edb60e21b815260009273057835ad21a177dbdd3090bb1cae03eacf78fc6d9263d2493b6c92612a5f929190911690600401615746565b60606040518083038186803b158015612a7757600080fd5b505afa158015612a8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aaf919061511e565b5050600d80546001600160a01b03808416600160481b027fffffff0000000000000000000000000000000000000000ffffffffffffffffff909216919091179091556010546040516334924edb60e21b815292935060009273057835ad21a177dbdd3090bb1cae03eacf78fc6d9263d2493b6c92612b3292911690600401615746565b60606040518083038186803b158015612b4a57600080fd5b505afa158015612b5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b82919061511e565b600e80546001600160a01b0319166001600160a01b0383811691909117909155600f546040805163313ce56760e01b81529051939650612c2b95506064945091169163313ce56791600480820192602092909190829003018186803b158015612bea57600080fd5b505afa158015612bfe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c2291906155c4565b600a0a90611c06565b601155600d805460ff19168615151761ff00191661010086151502179055600019600c5560016012558251612c67906013906020860190614f7c565b50505050505050565b600e546040516370a0823160e01b81526000916001600160a01b0316906370a0823190612ca1903090600401615746565b60206040518083038186803b158015612cb957600080fd5b505afa158015612ccd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108f091906155c4565b6000821580612d01575060001983145b80612d2857506001600160a01b03821673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2145b15612d34575081611949565b611c48826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015612d7057600080fd5b505afa158015612d84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612da891906156a0565b60ff16600a0a610ff5612db961476b565b6001600160a01b031663b3596f07866040518263ffffffff1660e01b8152600401612de49190615746565b60206040518083038186803b158015612dfc57600080fd5b505afa158015612e10573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e3491906155c4565b869061221c565b6000821580612e4b575060001983145b80612e7257506001600160a01b03821673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2145b15612e7e575081611949565b611c48612e8961476b565b6001600160a01b031663b3596f07846040518263ffffffff1660e01b8152600401612eb49190615746565b60206040518083038186803b158015612ecc57600080fd5b505afa158015612ee0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f0491906155c4565b610ff5846001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015612f4057600080fd5b505afa158015612f54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f7891906156a0565b869060ff16600a0a61221c565b600d5460009060ff16158015612fa35750600d54610100900460ff16155b15612fb057506000610796565b60405163091030c360e01b8152600090734da27a545c0c5b758a6ba100e3a049001de870f59063091030c390612fea903090600401615746565b60206040518083038186803b15801561300257600080fd5b505afa158015613016573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061303a91906155c4565b90506000734da27a545c0c5b758a6ba100e3a049001de870f56001600160a01b03166372b49d636040518163ffffffff1660e01b815260040160206040518083038186803b15801561308b57600080fd5b505afa15801561309f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130c391906155c4565b90506000734da27a545c0c5b758a6ba100e3a049001de870f56001600160a01b031663359c4a966040518163ffffffff1660e01b815260040160206040518083038186803b15801561311457600080fd5b505afa158015613128573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061314c91906155c4565b90506131588383613610565b4210613188578061317361316c8585613610565b42906120bb565b11158061317e575082155b9350505050610796565b6000935050505090565b600061319c614fea565b6001546040516339ebf82360e01b81526001600160a01b03909116906339ebf823906131cc903090600401615746565b6101206040518083038186803b1580156131e557600080fd5b505afa1580156131f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061321d9190615491565b905080602001516000141561323657600091505061107f565b60065460a08201516132499042906120bb565b101561325957600091505061107f565b60075460a082015161326c9042906120bb565b1061327b57600191505061107f565b6001546040805163bf3759b560e01b815290516000926001600160a01b03169163bf3759b5916004808301926020929190829003018186803b1580156132c057600080fd5b505afa1580156132d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132f891906155c4565b905060095481111561330f5760019250505061107f565b600061331961194f565b90508260c001516133356009548361361090919063ffffffff16565b1015613347576001935050505061107f565b60008360c001518211156133685760c08401516133659083906120bb565b90505b6001546040805163112c1f9b60e01b815290516000926001600160a01b03169163112c1f9b916004808301926020929190829003018186803b1580156133ad57600080fd5b505afa1580156133c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133e591906155c4565b90506133f18183613610565b6008546133fe908961221c565b10979650505050505050565b60006108f0600f60009054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561345d57600080fd5b505afa158015613471573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061349591906155c4565b600a0a610ff5600f60009054906101000a90046001600160a01b03166001600160a01b03166399530b066040518163ffffffff1660e01b815260040160206040518083038186803b1580156134e957600080fd5b505afa1580156134fd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061352191906155c4565b600f546040516370a0823160e01b81526001600160a01b03909116906370a0823190613551903090600401615746565b60206040518083038186803b15801561356957600080fd5b505afa15801561357d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135a191906155c4565b9061221c565b600d546040516370a0823160e01b8152600091600160481b90046001600160a01b0316906370a0823190612ca1903090600401615746565b6005546040516370a0823160e01b81526000916001600160a01b0316906370a0823190612ca1903090600401615746565b600082820183811015611c485760405162461bcd60e51b815260040161050d90615955565b606061368a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611c4f9092919063ffffffff16565b805190915015611c0157808060200190518101906136a8919061530d565b611c015760405162461bcd60e51b815260040161050d90615aa1565b600081836136e55760405162461bcd60e51b815260040161050d91906158fe565b5060008385816136f157fe5b0495945050505050565b60606137068561482a565b6137225760405162461bcd60e51b815260040161050d90615a45565b60006060866001600160a01b0316858760405161373f919061572a565b60006040518083038185875af1925050503d806000811461377c576040519150601f19603f3d011682016040523d82523d6000602084013e613781565b606091505b50915091508115613795579150611c5e9050565b8051156137a55780518082602001fd5b8360405162461bcd60e51b815260040161050d91906158fe565b6000816137ce5750600061107f565b60008060006137db61217d565b5050600554939650919450909250600091613801915087906001600160a01b0316612cf1565b9050600081851161381357600061381d565b61381d85836120bb565b9050600080821161383057600019613840565b61384082610ff58761271061221c565b9050600061384d8561227c565b905080821161386657600097505050505050505061107f565b600019821415613895576010546138879087906001600160a01b0316612e3b565b97505050505050505061107f565b60006138a086612256565b905060006138b4612710610ff5848861221c565b9050878111156138d0576000995050505050505050505061107f565b601154613908906138e18a846120bb565b106138f5576138f089836120bb565b6138f7565b885b6010546001600160a01b0316612e3b565b9b9a5050505050505050505050565b6000816139265750600061107f565b6000613930613c77565b905060006139c561394085614863565b600f546040516370a0823160e01b81526001600160a01b03909116906370a0823190613970903090600401615746565b60206040518083038186803b15801561398857600080fd5b505afa15801561399c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139c091906155c4565b613e5e565b600f54601254604051631cc6d2f960e31b81529293506001600160a01b039091169163e63697c8916139fd9185913091600401615b7d565b602060405180830381600087803b158015613a1757600080fd5b505af1158015613a2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a4f91906155c4565b50611c5e8261198c613c77565b80613a665761175c565b6000613a70613c77565b9050613a7c8282613e5e565b9150613a8f613a89612c70565b83613e5e565b9150613aae613a9c613e74565b6010546001600160a01b031684614976565b811561067057613abc613e74565b60105460405163573ade8160e01b81526001600160a01b039283169263573ade8192613af49291169086906002903090600401615866565b602060405180830381600087803b158015613b0e57600080fd5b505af1158015613b22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c0191906155c4565b6000613b506135a7565b905080821115613b5e578091505b6000613ba8613b6b614a27565b600554600d546040516370a0823160e01b81526001600160a01b03928316926370a082319261397092600160481b90910490911690600401615746565b90506000613bb68483613e5e565b90508015613c7157613be2613bc9613e74565b600d54600160481b90046001600160a01b031683614976565b613bea613e74565b600554604051631a4ca37b60e21b81526001600160a01b03928316926369328dec92613c1f92911690859030906004016157e2565b602060405180830381600087803b158015613c3957600080fd5b505af1158015613c4d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061295d91906155c4565b50505050565b6010546040516370a0823160e01b81526000916001600160a01b0316906370a0823190612ca1903090600401615746565b80613cb25761175c565b6005546010546001600160a01b0390811691161415613cd05761175c565b600554613cfc90737a250d5630b4cf539739df2c5dacb4c659f2488d906001600160a01b031683614976565b600554601054737a250d5630b4cf539739df2c5dacb4c659f2488d91638803dbee91849160001991613d3a916001600160a01b039081169116614a8a565b30426040518663ffffffff1660e01b8152600401613d5c959493929190615b9c565b600060405180830381600087803b158015613d7657600080fd5b505af1158015613d8a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526106709190810190615278565b80613dbc5761175c565b6000613dc6613e74565b600554909150613de19082906001600160a01b031684614976565b600554600d5460405163e8eda9df60e01b81526001600160a01b038085169363e8eda9df93613e289391909216918791309161ffff63010000009091041690600401615805565b600060405180830381600087803b158015613e4257600080fd5b505af1158015613e56573d6000803e3d6000fd5b505050505050565b6000818310613e6d5781611c48565b5090919050565b600073057835ad21a177dbdd3090bb1cae03eacf78fc6d6001600160a01b0316630542975c6040518163ffffffff1660e01b815260040160206040518083038186803b158015613ec357600080fd5b505afa158015613ed7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613efb9190615102565b6001600160a01b0316630261bf8b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611cab57600080fd5b6000613f3d613c77565b9050801561175c57600f54601054613f62916001600160a01b03908116911683614976565b600f60009054906101000a90046001600160a01b03166001600160a01b031663d0e30db06040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613fb257600080fd5b505af115801561295d573d6000803e3d6000fd5b600081831015613e6d5781611c48565b60008184841115613ffa5760405162461bcd60e51b815260040161050d91906158fe565b505050900390565b600d54610100900460ff168061401a5750600d5460ff165b15610c33576040516370a0823160e01b8152600090734da27a545c0c5b758a6ba100e3a049001de870f5906370a0823190614059903090600401615746565b60206040518083038186803b15801561407157600080fd5b505afa158015614085573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140a991906155c4565b90506000811180156140be57506140be612f85565b1561412f576040516301e9a69560e41b8152734da27a545c0c5b758a6ba100e3a049001de870f590631e9a6950906140fc90309085906004016157c9565b600060405180830381600087803b15801561411657600080fd5b505af115801561412a573d6000803e3d6000fd5b505050505b6040516309a99b4f60e41b8152734da27a545c0c5b758a6ba100e3a049001de870f590639a99b4f09061416a903090600019906004016157c9565b600060405180830381600087803b15801561418457600080fd5b505af1158015614198573d6000803e3d6000fd5b50506040516370a0823160e01b815260009250737fc66500c84a76ad7e9c93437bfc5ac33e2ddae991506370a08231906141d6903090600401615746565b60206040518083038186803b1580156141ee57600080fd5b505afa158015614202573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061422691906155c4565b905066038d7ea4c680008111156142405761424081614c0b565b600d54606090610100900460ff16801561425c5750600d5460ff165b156142f4576040805160028082526060820183529091602083019080368337019050509050600d60099054906101000a90046001600160a01b0316816000815181106142a457fe5b6001600160a01b039283166020918202929092010152600e548251911690829060019081106142cf57fe5b60200260200101906001600160a01b031690816001600160a01b0316815250506143ad565b600d54610100900460ff161561433e5760408051600180825281830190925290602080830190803683375050600e5482519293506001600160a01b0316918391506000906142cf57fe5b600d5460ff16156143ad576040805160018082528183019092529060208083019080368337019050509050600d60099054906101000a90046001600160a01b03168160008151811061438c57fe5b60200260200101906001600160a01b031690816001600160a01b0316815250505b6143b5614c94565b6001600160a01b0316633111e7b382600019306040518463ffffffff1660e01b81526004016143e693929190615891565b602060405180830381600087803b15801561440057600080fd5b505af1158015614414573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061443891906155c4565b506040516370a0823160e01b8152600090734da27a545c0c5b758a6ba100e3a049001de870f5906370a0823190614473903090600401615746565b60206040518083038186803b15801561448b57600080fd5b505afa15801561449f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144c391906155c4565b1115611c0157734da27a545c0c5b758a6ba100e3a049001de870f56001600160a01b031663787a08a66040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561451857600080fd5b505af1158015612c67573d6000803e3d6000fd5b6000614536612c70565b9050600061454261340a565b9050808210614552575050610c33565b600061455e82846120bb565b9050600061456b82614863565b90508015613c7157600f54601254604051631cc6d2f960e31b81526001600160a01b039092169163e63697c8916145a89185913091600401615b7d565b602060405180830381600087803b1580156145c257600080fd5b505af11580156145d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145fa91906155c4565b50613c71614606613c77565b614d95565b6001546040516339ebf82360e01b81526000916001600160a01b0316906339ebf8239061463c903090600401615746565b6101206040518083038186803b15801561465557600080fd5b505afa158015614669573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061468d9190615491565b60c001519050600061469d6135a7565b9050818111156106705760006146b382846120bb565b9050611c0181613b46565b6000816146ca57600080fd5b600282046b033b2e3c9fd0803ce80000008119048411156146ea57600080fd5b82816b033b2e3c9fd0803ce80000008602018161470357fe5b04949350505050565b6000821580614719575081155b1561472657506000611949565b816b019d971e4fe8401e74000000198161473c57fe5b0483111561474957600080fd5b506b033b2e3c9fd0803ce800000091026b019d971e4fe8401e74000000010490565b600073057835ad21a177dbdd3090bb1cae03eacf78fc6d6001600160a01b0316630542975c6040518163ffffffff1660e01b815260040160206040518083038186803b1580156147ba57600080fd5b505afa1580156147ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147f29190615102565b6001600160a01b031663fca513a86040518163ffffffff1660e01b815260040160206040518083038186803b158015611cab57600080fd5b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590611c5e575050151592915050565b6000611949600f60009054906101000a90046001600160a01b03166001600160a01b03166399530b066040518163ffffffff1660e01b815260040160206040518083038186803b1580156148b657600080fd5b505afa1580156148ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148ee91906155c4565b600f546040805163313ce56760e01b81529051610ff5926001600160a01b03169163313ce567916004808301926020929190829003018186803b15801561493457600080fd5b505afa158015614948573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061496c91906155c4565b8590600a0a61221c565b604051636eb1769f60e11b815281906001600160a01b0384169063dd62ed3e906149a6903090889060040161575a565b60206040518083038186803b1580156149be57600080fd5b505afa1580156149d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149f691906155c4565b1015611c0157614a116001600160a01b038316846000611b07565b611c016001600160a01b03831684600019611b07565b600080600080614a3561217d565b5094505050925092506000808211614a4d5783614a5d565b614a5d82610ff58561271061221c565b905083811115614a74576000945050505050610796565b614a8161147985836120bb565b94505050505090565b606060006001600160a01b03841673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21480614ad557506001600160a01b03831673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2145b905080614ae3576003614ae6565b60025b60ff1667ffffffffffffffff81118015614aff57600080fd5b50604051908082528060200260200182016040528015614b29578160200160208202803683370190505b5091508382600081518110614b3a57fe5b60200260200101906001600160a01b031690816001600160a01b0316815250508015614b93578282600181518110614b6e57fe5b60200260200101906001600160a01b031690816001600160a01b031681525050614c04565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc282600181518110614bb557fe5b60200260200101906001600160a01b031690816001600160a01b0316815250508282600281518110614be357fe5b60200260200101906001600160a01b031690816001600160a01b0316815250505b5092915050565b80614c155761175c565b614c48737a250d5630b4cf539739df2c5dacb4c659f2488d737fc66500c84a76ad7e9c93437bfc5ac33e2ddae983614976565b600554737a250d5630b4cf539739df2c5dacb4c659f2488d906338ed1739908390600090613d3a90737fc66500c84a76ad7e9c93437bfc5ac33e2ddae9906001600160a01b0316614a8a565b600d5460009060ff1615614d2f57600d60099054906101000a90046001600160a01b03166001600160a01b03166375d264136040518163ffffffff1660e01b815260040160206040518083038186803b158015614cf057600080fd5b505afa158015614d04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614d289190615102565b9050610796565b600d54610100900460ff1615614d8d57600e60009054906101000a90046001600160a01b03166001600160a01b03166375d264136040518163ffffffff1660e01b815260040160206040518083038186803b158015614cf057600080fd5b506000610796565b80614d9f5761175c565b6010546005546001600160a01b0390811691161415614dbd5761175c565b601054614de990737a250d5630b4cf539739df2c5dacb4c659f2488d906001600160a01b031683614976565b601054600554737a250d5630b4cf539739df2c5dacb4c659f2488d916338ed1739918491600091613d3a916001600160a01b039081169116614a8a565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10614e675782800160ff19823516178555614e94565b82800160010185558215614e94579182015b82811115614e94578235825591602001919060010190614e79565b50614ea0929150615036565b5090565b60405180610100016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b604051806101800160405280614efd61504b565b815260006020820181905260408201819052606082018190526080820181905260a0820181905260c0820181905260e082018190526101008201819052610120820181905261014082018190526101609091015290565b6040518060800160405280600081526020016000815260200160008152602001600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10614fbd57805160ff1916838001178555614e94565b82800160010185558215614e94579182015b82811115614e94578251825591602001919060010190614fcf565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b5b80821115614ea05760008155600101615037565b6040518060200160405280600081525090565b805161194981615c7c565b60006020828403121561507a578081fd5b6150846020615c09565b9151825250919050565b80516fffffffffffffffffffffffffffffffff8116811461194957600080fd5b803561ffff8116811461194957600080fd5b805164ffffffffff8116811461194957600080fd5b805160ff8116811461194957600080fd5b6000602082840312156150f7578081fd5b8135611c4881615c7c565b600060208284031215615113578081fd5b8151611c4881615c7c565b600080600060608486031215615132578182fd5b835161513d81615c7c565b602085015190935061514e81615c7c565b604085015190925061515f81615c7c565b809150509250925092565b600080600080600080600080610100898b031215615186578384fd5b883561519181615c7c565b97506020898101356151a281615c7c565b975060408a01356151b281615c7c565b965060608a01356151c281615c7c565b955060808a01356151d281615c7c565b945060a08a01356151e281615c91565b935060c08a01356151f281615c91565b925060e08a013567ffffffffffffffff8082111561520e578384fd5b818c0191508c601f830112615221578384fd5b81358181111561522f578485fd5b615241601f8201601f19168501615c09565b91508082528d84828501011115615256578485fd5b8084840185840137810190920192909252979a96995094975092959194909350565b6000602080838503121561528a578182fd5b825167ffffffffffffffff8111156152a0578283fd5b8301601f810185136152b0578283fd5b80516152c36152be82615c30565b615c09565b81815283810190838501858402850186018910156152df578687fd5b8694505b838510156153015780518352600194909401939185019185016152e3565b50979650505050505050565b60006020828403121561531e578081fd5b8151611c4881615c91565b6000806020838503121561533b578182fd5b823567ffffffffffffffff80821115615352578384fd5b818501915085601f830112615365578384fd5b813581811115615373578485fd5b866020828501011115615384578485fd5b60209290920196919550909350505050565b60006101808083850312156153a9578182fd5b6153b281615c09565b90506153be8484615069565b81526153cd846020850161508e565b60208201526153df846040850161508e565b60408201526153f1846060850161508e565b6060820152615403846080850161508e565b60808201526154158460a0850161508e565b60a08201526154278460c085016150c0565b60c08201526154398460e0850161505e565b60e082015261010061544d8582860161505e565b908201526101206154608585830161505e565b908201526101406154738585830161505e565b90820152610160615486858583016150d5565b908201529392505050565b60006101208083850312156154a4578182fd5b6154ad81615c09565b9050825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152508091505092915050565b60008060008060008060008060006101208a8c03121561552d578283fd5b6155378b8b6150ae565b98506155468b60208c016150ae565b975060408a0135965061555c8b60608c016150ae565b955060808a0135945060a08a013561557381615c91565b935060c08a013561558381615c91565b925060e08a013561559381615c91565b809250506101008a013590509295985092959850929598565b6000602082840312156155bd578081fd5b5035919050565b6000602082840312156155d5578081fd5b5051919050565b60008060008060008060c087890312156155f4578384fd5b865195506020870151945060408701519350606087015192506080870151915060a087015190509295509295509295565b6000806000806000806000806000806101408b8d031215615644578384fd5b8a51995060208b0151985060408b0151975060608b0151965060808b0151955060a08b0151945060c08b0151935060e08b015192506101008b0151915061568f8c6101208d016150c0565b90509295989b9194979a5092959850565b6000602082840312156156b1578081fd5b611c4883836150d5565b6000815180845260208085019450808401835b838110156156f35781516001600160a01b0316875295820195908201906001016156ce565b509495945050505050565b60008151808452615716816020860160208601615c50565b601f01601f19169290920160200192915050565b6000825161573c818460208701615c50565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b0389811682528881166020830152878116604083015286811660608301528516608082015283151560a082015282151560c082015261010060e08201819052600090613908838201856156fe565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b6001600160a01b03948516815260208101939093529216604082015261ffff909116606082015260800190565b6001600160a01b0395861681526020810194909452604084019290925261ffff166060830152909116608082015260a00190565b6001600160a01b03948516815260208101939093526040830191909152909116606082015260800190565b6000606082526158a460608301866156bb565b6020830194909452506001600160a01b0391909116604090910152919050565b901515815260200190565b60006020825282602083015282846040840137818301604090810191909152601f909201601f19160101919050565b600060208252611c4860208301846156fe565b6020808252600b908201526a085cdd1c985d1959da5cdd60aa1b604082015260600190565b602080825260059082015264085dd85b9d60da1b604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252601c908201527f537472617465677920616c726561647920696e697469616c697a656400000000604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b602080825260069082015265085d985d5b1d60d21b604082015260600190565b6020808252600790820152662173686172657360c81b604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252600b908201526a08585d5d1a1bdc9a5e995960aa1b604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b6020808252600a9082015269085c1c9bdd1958dd195960b21b604082015260600190565b60208082526036908201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60408201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b606082015260800190565b61ffff91909116815260200190565b90815260200190565b9283526001600160a01b03919091166020830152604082015260600190565b600086825285602083015260a06040830152615bbb60a08301866156bb565b6001600160a01b0394909416606083015250608001529392505050565b9283526020830191909152604082015260600190565b93845260208401929092526040830152606082015260800190565b60405181810167ffffffffffffffff81118282101715615c2857600080fd5b604052919050565b600067ffffffffffffffff821115615c46578081fd5b5060209081020190565b60005b83811015615c6b578181015183820152602001615c53565b83811115613c715750506000910152565b6001600160a01b038116811461175c57600080fd5b801515811461175c57600080fdfea2646970667358221220460c7cd5f0aeda40e31c72f4074859c1262fb4a2a9ad221809da26623a4c1b8d64736f6c634300060c0033

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

000000000000000000000000a696a63cc78dffa1a63e9e50587c197387ff6c7e0000000000000000000000005f18c75abdae578b483e5f43f12a39cf75b973a90000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000001a416176654c656e64657257425443426f72726f77657255534443000000000000

-----Decoded View---------------
Arg [0] : _vault (address): 0xA696a63cc78DfFa1a63E9E50587C197387FF6C7E
Arg [1] : _yVault (address): 0x5f18C75AbDAe578b483E5F43f12a39cF75b973a9
Arg [2] : _isWantIncentivised (bool): True
Arg [3] : _isInvestmentTokenIncentivised (bool): True
Arg [4] : _strategyName (string): AaveLenderWBTCBorrowerUSDC

-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 000000000000000000000000a696a63cc78dffa1a63e9e50587c197387ff6c7e
Arg [1] : 0000000000000000000000005f18c75abdae578b483e5f43f12a39cf75b973a9
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [4] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [5] : 000000000000000000000000000000000000000000000000000000000000001a
Arg [6] : 416176654c656e64657257425443426f72726f77657255534443000000000000


Deployed Bytecode Sourcemap

94889:38457:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;90419:444;;;;;;:::i;:::-;;:::i;:::-;;64243:25;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;97324:101;;;:::i;73565:175::-;;;;;;:::i;:::-;;:::i;95391:30::-;;;:::i;:::-;;;;;;;:::i;67433:28::-;;;:::i;:::-;;;;;;;:::i;66181:18::-;;;:::i;:::-;;;;;;;:::i;66090:25::-;;;:::i;76238:148::-;;;:::i;64553:91::-;;;:::i;95351:31::-;;;:::i;67069:29::-;;;:::i;86999:515::-;;;;;;:::i;:::-;;:::i;96163:20::-;;;:::i;71614:154::-;;;;;;:::i;:::-;;:::i;80991:170::-;;;:::i;85384:1371::-;;;:::i;67512:25::-;;;:::i;96791:22::-;;;:::i;95869:42::-;;;:::i;:::-;;;;;;;:::i;112438:1316::-;;;;;;:::i;:::-;;:::i;99365:1378::-;;;;;;:::i;:::-;;:::i;70371:174::-;;;;;;:::i;:::-;;:::i;74043:171::-;;;;;;:::i;:::-;;:::i;98300:1013::-;;;;;;:::i;:::-;;:::i;102002:572::-;;;;;;:::i;:::-;;:::i;67255:27::-;;;:::i;111632:309::-;;;:::i;95769:41::-;;;:::i;72839:169::-;;;;;;:::i;:::-;;:::i;66918:29::-;;;:::i;66122:22::-;;;:::i;66151:21::-;;;:::i;69615:202::-;;;;;;:::i;:::-;;:::i;88105:311::-;;;;;;:::i;:::-;;:::i;95558:27::-;;;:::i;95217:40::-;;;:::i;95428:41::-;;;:::i;70834:263::-;;;;;;:::i;:::-;;:::i;112087:343::-;;;;;;:::i;:::-;;:::i;97433:749::-;;;:::i;72285:154::-;;;;;;:::i;:::-;;:::i;66062:21::-;;;:::i;88845:164::-;;;:::i;90419:444::-;67879:12;:10;:12::i;:::-;-1:-1:-1;;;;;67865:26:0;:10;-1:-1:-1;;;;;67865:26:0;;67857:50;;;;-1:-1:-1;;;67857:50:0;;;;;;;:::i;:::-;;;;;;;;;90511:4:::1;::::0;-1:-1:-1;;;;;90493:23:0;;::::1;90511:4:::0;::::1;90493:23;;90485:41;;;;-1:-1:-1::0;;;90485:41:0::1;;;;;;;:::i;:::-;90563:5;::::0;-1:-1:-1;;;;;90545:24:0;;::::1;90563:5:::0;::::1;90545:24;;90537:44;;;;-1:-1:-1::0;;;90537:44:0::1;;;;;;;:::i;:::-;90594:33;90630:17;:15;:17::i;:::-;90594:53;;90663:9;90658:102;90678:16;:23;90674:1;:27;90658:102;;;90726:16;90743:1;90726:19;;;;;;;;;;;;;;-1:-1:-1::0;;;;;90716:29:0::1;:6;-1:-1:-1::0;;;;;90716:29:0::1;;;90708:52;;;;-1:-1:-1::0;;;90708:52:0::1;;;;;;;:::i;:::-;90703:3;;90658:102;;;;90773:82;90801:12;:10;:12::i;:::-;90815:39;::::0;-1:-1:-1;;;90815:39:0;;-1:-1:-1;;;;;90815:24:0;::::1;::::0;::::1;::::0;:39:::1;::::0;90848:4:::1;::::0;90815:39:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;90773:27:0;::::1;::::0;:82;:27:::1;:82::i;:::-;67918:1;90419:444:::0;:::o;64243:25::-;;;;;;;;;;;;;;;-1:-1:-1;;64243:25:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;97324:101::-;97405:12;97398:19;;;;;;;;-1:-1:-1;;97398:19:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;97372:13;;97398:19;;97405:12;;97398:19;;97405:12;97398:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;97324:101;;:::o;73565:175::-;67623:10;;-1:-1:-1;;;;;67623:10:0;67609;:24;;:54;;;67651:12;:10;:12::i;:::-;-1:-1:-1;;;;;67637:26:0;:10;-1:-1:-1;;;;;67637:26:0;;67609:54;67601:78;;;;-1:-1:-1;;;67601:78:0;;;;;;;:::i;:::-;73650:13:::1;:30:::0;;;73696:36:::1;::::0;::::1;::::0;::::1;::::0;73666:14;;73696:36:::1;:::i;:::-;;;;;;;;73565:175:::0;:::o;95391:30::-;;;;;;:::o;67433:28::-;;;;:::o;66181:18::-;;;-1:-1:-1;;;;;66181:18:0;;:::o;66090:25::-;;;-1:-1:-1;;;;;66090:25:0;;:::o;76238:148::-;76303:5;;:31;;-1:-1:-1;;;76303:31:0;;76279:4;;;;-1:-1:-1;;;;;76303:5:0;;;;:16;;:31;;76328:4;;76303:31;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:41;;;:45;:75;;;;76377:1;76352:22;:20;:22::i;:::-;:26;76303:75;76296:82;;76238:148;:::o;64553:91::-;64622:14;;;;;;;;;;;;-1:-1:-1;;;64622:14:0;;;;64553:91;:::o;95351:31::-;;;;:::o;67069:29::-;;;;:::o;86999:515::-;87114:5;;87058:13;;-1:-1:-1;;;;;87114:5:0;87092:10;:28;87084:47;;;;-1:-1:-1;;;87084:47:0;;;;;;;:::i;:::-;87217:19;87270:32;87288:13;87270:17;:32::i;:::-;87394:4;;87247:55;;-1:-1:-1;87247:55:0;;-1:-1:-1;87394:42:0;;-1:-1:-1;;;;;87394:4:0;87412:10;87247:55;87394:17;:42::i;:::-;86999:515;;;;:::o;96163:20::-;;;-1:-1:-1;;;;;96163:20:0;;:::o;71614:154::-;67623:10;;-1:-1:-1;;;;;67623:10:0;67609;:24;;:54;;;67651:12;:10;:12::i;:::-;-1:-1:-1;;;;;67637:26:0;:10;-1:-1:-1;;;;;67637:26:0;;67609:54;67601:78;;;;-1:-1:-1;;;67601:78:0;;;;;;;:::i;:::-;71692:14:::1;:23:::0;;;71731:29:::1;::::0;::::1;::::0;::::1;::::0;71709:6;;71731:29:::1;:::i;80991:170::-:0;68005:6;;-1:-1:-1;;;;;68005:6:0;67991:10;:20;;:65;;-1:-1:-1;68046:10:0;;-1:-1:-1;;;;;68046:10:0;68032;:24;67991:65;:112;;;;68091:12;:10;:12::i;:::-;-1:-1:-1;;;;;68077:26:0;:10;-1:-1:-1;;;;;68077:26:0;;67991:112;:163;;;;68138:5;;;;;;;;;-1:-1:-1;;;;;68138:5:0;-1:-1:-1;;;;;68138:14:0;;:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;68124:30:0;:10;-1:-1:-1;;;;;68124:30:0;;67991:163;:216;;;;68189:5;;;;;;;;;-1:-1:-1;;;;;68189:5:0;-1:-1:-1;;;;;68189:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;68175:32:0;:10;-1:-1:-1;;;;;68175:32:0;;67991:216;67969:277;;;;-1:-1:-1;;;67969:277:0;;;;;;;:::i;:::-;81129:5:::1;::::0;:23:::1;::::0;;-1:-1:-1;;;81129:23:0;;;;81114:39:::1;::::0;-1:-1:-1;;;;;81129:5:0::1;::::0;:21:::1;::::0;:23:::1;::::0;;::::1;::::0;::::1;::::0;;;;;;;;:5;:23;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;81114:14;:39::i;:::-;80991:170::o:0;85384:1371::-;68005:6;;-1:-1:-1;;;;;68005:6:0;67991:10;:20;;:65;;-1:-1:-1;68046:10:0;;-1:-1:-1;;;;;68046:10:0;68032;:24;67991:65;:112;;;;68091:12;:10;:12::i;:::-;-1:-1:-1;;;;;68077:26:0;:10;-1:-1:-1;;;;;68077:26:0;;67991:112;:163;;;;68138:5;;;;;;;;;-1:-1:-1;;;;;68138:5:0;-1:-1:-1;;;;;68138:14:0;;:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;68124:30:0;:10;-1:-1:-1;;;;;68124:30:0;;67991:163;:216;;;;68189:5;;;;;;;;;-1:-1:-1;;;;;68189:5:0;-1:-1:-1;;;;;68189:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;68175:32:0;:10;-1:-1:-1;;;;;68175:32:0;;67991:216;67969:277;;;;-1:-1:-1;;;67969:277:0;;;;;;;:::i;:::-;85435:14:::1;85464:12:::0;85491:23:::1;85517:5;;;;;;;;;-1:-1:-1::0;;;;;85517:5:0::1;-1:-1:-1::0;;;;;85517:21:0::1;;:23;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;85589:13;::::0;85491:49;;-1:-1:-1;85551:19:0::1;::::0;85589:13:::1;;85585:731;;;85671:19;85693:22;:20;:22::i;:::-;85671:44;;85849:80;85881:15;85867:11;:29;:61;;85913:15;85867:61;;;85899:11;85867:61;85849:17;:80::i;:::-;85827:102:::0;-1:-1:-1;85827:102:0;-1:-1:-1;86007:29:0;;::::1;86003:159;;;86066:32;:11:::0;86082:15;86066::::1;:32::i;:::-;86057:41;;86131:15;86117:29;;86003:159;85585:731;;;;86274:30;86288:15;86274:13;:30::i;:::-;86244:60:::0;;-1:-1:-1;86244:60:0;-1:-1:-1;86244:60:0;-1:-1:-1;85585:731:0::1;86530:5;::::0;:39:::1;::::0;-1:-1:-1;;;86530:39:0;;-1:-1:-1;;;;;86530:5:0;;::::1;::::0;:12:::1;::::0;:39:::1;::::0;86543:6;;86551:4;;86557:11;;86530:39:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;86512:57;;86645:31;86660:15;86645:14;:31::i;:::-;86694:53;86704:6;86712:4;86718:11;86731:15;86694:53;;;;;;;;;:::i;:::-;;;;;;;;68257:1;;;;85384:1371::o:0;67512:25::-;;;;;;:::o;96791:22::-;;;;:::o;95869:42::-;;;-1:-1:-1;;;95869:42:0;;;;;:::o;112438:1316::-;112507:4;112741:26;112782:20;112832:35;112899:25;:23;:25::i;:::-;112726:198;;;;;;;;;112937:18;112958:49;112988:18;112958:25;95997:6;112958:25;;:12;:16;;:25;;;;:::i;:::-;:29;;:49::i;:::-;112937:70;;113018:17;113038:42;113052:27;113038:13;:42::i;:::-;113018:62;;113091:18;113112:43;113127:27;113112:14;:43::i;:::-;113091:64;;113167:27;113196:23;113236:19;:17;:19::i;:::-;113166:89;;;;113300:9;113287:10;:22;:80;;;;;113352:15;113330:19;:37;113287:80;:132;;;;-1:-1:-1;113416:3:0;113388:25;:9;113402:10;113388:13;:25::i;:::-;:31;113287:132;113286:249;;;;113483:10;113470;:23;:64;;;;113519:15;113497:19;:37;113470:64;113268:388;;;113640:4;113633:11;;;;;;;;;;;;113268:388;113741:5;113734:12;;;;;;;;;;112438:1316;;;;:::o;99365:1378::-;99716:10;;99676:19;;99716:10;;;;;99708:19;;;;;;99984:4;99978:11;-1:-1:-1;;;100003:135:0;;99885:4;99869:22;;100175:4;100159:21;;100152:43;;;-1:-1:-1;;;100250:4:0;100234:21;;100209:146;99869:22;100406:4;99978:11;99846:20;100384:27;100434:264;;-1:-1:-1;;;100434:264:0;;100369:42;;-1:-1:-1;;;;;;100434:32:0;;;-1:-1:-1;100434:32:0;;:264;;100481:6;;100502:11;;100528:8;;100551:7;;100573;;100595:19;;100629:30;;100674:13;;100434:264;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;100716:19:0;;-1:-1:-1;;;;;100716:19:0;;;-1:-1:-1;100716:19:0;;-1:-1:-1;100716:19:0;;;99365:1378;;;;;;;;;;;:::o;70371:174::-;67623:10;;-1:-1:-1;;;;;67623:10:0;67609;:24;;:54;;;67651:12;:10;:12::i;:::-;-1:-1:-1;;;;;67637:26:0;:10;-1:-1:-1;;;;;67637:26:0;;67609:54;67601:78;;;;-1:-1:-1;;;67601:78:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;70450:21:0;::::1;70442:30;;;::::0;::::1;;70483:6;:16:::0;;-1:-1:-1;;;;;;70483:16:0::1;-1:-1:-1::0;;;;;70483:16:0;::::1;;::::0;;70515:22:::1;::::0;::::1;::::0;::::1;::::0;70483:16;;70515:22:::1;:::i;74043:171::-:0;67623:10;;-1:-1:-1;;;;;67623:10:0;67609;:24;;:54;;;67651:12;:10;:12::i;:::-;-1:-1:-1;;;;;67637:26:0;:10;-1:-1:-1;;;;;67637:26:0;;67609:54;67601:78;;;;-1:-1:-1;;;67601:78:0;;;;;;;:::i;:::-;74132:26:::1;:11;74146:12:::0;;74132:26:::1;:::i;:::-;;74174:32;74193:12;;74174:32;;;;;;;:::i;:::-;;;;;;;;74043:171:::0;;:::o;98300:1013::-;67623:10;;-1:-1:-1;;;;;67623:10:0;67609;:24;;:54;;;67651:12;:10;:12::i;:::-;-1:-1:-1;;;;;67637:26:0;:10;-1:-1:-1;;;;;67637:26:0;;67609:54;67601:78;;;;-1:-1:-1;;;67601:78:0;;;;;;;:::i;:::-;96060:5:::1;98713:39;::::0;::::1;;::::0;::::1;::::0;:105:::1;;;98797:21;98773:45;;:20;:45;;;;98713:105;98691:138;;;::::0;::::1;;98862:20;98840:19;;:42;;;;;;;;;;;;;;;;;;98916:21;98893:20;;:44;;;;;;;;;;;;;;;;;;98969:19;98948:18;:40;;;;99018:17;98999:16;:36;;;;99057:13;99046:8;;:24;;;;;;;;;;;;;;;;;;99102:19;99081:18;;:40;;;;;;;;;;;;;;;;;;99164:30;99132:29;;:62;;;;;;;;;;;;;;;;;;99223:16;99205:15;;:34;;;;;;;;;;;;;;;;;;99269:6;99258:7;;:17;;99250:26;;;::::0;::::1;;99287:7;:18:::0;-1:-1:-1;;;;;;;;98300:1013:0:o;102002:572::-;102300:51;102312:6;102320:11;102333:8;102343:7;102300:11;:51::i;:::-;102378:6;;-1:-1:-1;;;;;102378:6:0;102370:29;102362:38;;;;;;102411:155;102441:7;102463:19;102497:30;102542:13;102411:15;:155::i;:::-;102002:572;;;;;;;;:::o;67255:27::-;;;;:::o;111632:309::-;111691:7;111810:123;111837:49;111844:15;:13;:15::i;:::-;111869;;-1:-1:-1;;;;;111869:15:0;111837:6;:49::i;:::-;111913:4;;-1:-1:-1;;;;;111913:4:0;111810:8;:123::i;95769:41::-;;;;;;;;;:::o;72839:169::-;67623:10;;-1:-1:-1;;;;;67623:10:0;67609;:24;;:54;;;67651:12;:10;:12::i;:::-;-1:-1:-1;;;;;67637:26:0;:10;-1:-1:-1;;;;;67637:26:0;;67609:54;67601:78;;;;-1:-1:-1;;;67601:78:0;;;;;;;:::i;:::-;72922:12:::1;:28:::0;;;72966:34:::1;::::0;::::1;::::0;::::1;::::0;72937:13;;72966:34:::1;:::i;66918:29::-:0;;;;:::o;66122:22::-;;;-1:-1:-1;;;;;66122:22:0;;:::o;66151:21::-;;;-1:-1:-1;;;;;66151:21:0;;:::o;69615:202::-;67623:10;;-1:-1:-1;;;;;67623:10:0;67609;:24;;:54;;;67651:12;:10;:12::i;:::-;-1:-1:-1;;;;;67637:26:0;:10;-1:-1:-1;;;;;67637:26:0;;67609:54;67601:78;;;;-1:-1:-1;;;67601:78:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;69702:25:0;::::1;69694:34;;;::::0;::::1;;69739:10;:24:::0;;-1:-1:-1;;;;;;69739:24:0::1;-1:-1:-1::0;;;;;69739:24:0;::::1;;::::0;;69779:30:::1;::::0;::::1;::::0;::::1;::::0;69739:24;;69779:30:::1;:::i;88105:311::-:0;88194:5;;-1:-1:-1;;;;;88194:5:0;88172:10;:28;;:58;;;88218:12;:10;:12::i;:::-;-1:-1:-1;;;;;88204:26:0;:10;-1:-1:-1;;;;;88204:26:0;;88172:58;88164:67;;;;;;88288:5;;88250:34;;;-1:-1:-1;;;88250:34:0;;;;-1:-1:-1;;;;;88288:5:0;;;;88250:32;;;;;:34;;;;;;;;;;;;;;:32;:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;88250:43:0;;88242:52;;;;;;88305:30;88322:12;88305:16;:30::i;:::-;88378:4;;:29;;-1:-1:-1;;;88378:29:0;;88346:62;;88364:12;;-1:-1:-1;;;;;88378:4:0;;;;:14;;:29;;88401:4;;88378:29;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;88346:4;;-1:-1:-1;;;;;88346:4:0;;:62;:17;:62::i;:::-;88105:311;:::o;95558:27::-;;;;;;;;;:::o;95217:40::-;;;;:::o;95428:41::-;;;;;;;;;:::o;70834:263::-;67766:10;;-1:-1:-1;;;;;67766:10:0;67752;:24;67744:48;;;;-1:-1:-1;;;67744:48:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;70915:22:0;::::1;70907:31;;;::::0;::::1;;70949:5;::::0;70963:7:::1;::::0;70949:25:::1;::::0;-1:-1:-1;;;70949:25:0;;-1:-1:-1;;;;;70949:5:0;;::::1;::::0;:13:::1;::::0;:25:::1;::::0;70963:7;::::1;::::0;70949:5:::1;::::0;:25:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;70985:7:0::1;:18:::0;;-1:-1:-1;;;;;;70985:18:0::1;-1:-1:-1::0;;;;;70985:18:0;;::::1;::::0;;;::::1;::::0;;;;-1:-1:-1;71014:5:0;:35:::1;::::0;-1:-1:-1;;;71014:35:0;;:5;;::::1;::::0;:13:::1;::::0;:35:::1;::::0;71028:7;::::1;::::0;-1:-1:-1;;71045:2:0;71014:35:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;71065:24;71080:8;71065:24;;;;;;:::i;112087:343::-:0;112195:4;112334:16;:14;:16::i;:::-;:88;;;-1:-1:-1;112415:4:0;;112367:55;;112388:33;;112397:8;;-1:-1:-1;;;;;112415:4:0;112388:8;:33::i;:::-;112367:20;:55::i;:::-;112314:108;112087:343;-1:-1:-1;;112087:343:0:o;97433:749::-;97495:7;97620:539;98009:135;98040:49;98047:15;:13;:15::i;98009:135::-;97620:302;97767:140;97798:54;97805:20;:18;:20::i;97767:140::-;97620:75;97677:17;:15;:17::i;:::-;97620:15;:13;:15::i;:::-;:56;;:75::i;:302::-;:370;;:539::i;72285:154::-;67623:10;;-1:-1:-1;;;;;67623:10:0;67609;:24;;:54;;;67651:12;:10;:12::i;:::-;-1:-1:-1;;;;;67637:26:0;:10;-1:-1:-1;;;;;67637:26:0;;67609:54;67601:78;;;;-1:-1:-1;;;67601:78:0;;;;;;;:::i;:::-;72363:14:::1;:23:::0;;;72402:29:::1;::::0;::::1;::::0;::::1;::::0;72380:6;;72402:29:::1;:::i;66062:21::-:0;;;-1:-1:-1;;;;;66062:21:0;;:::o;88845:164::-;67623:10;;-1:-1:-1;;;;;67623:10:0;67609;:24;;:54;;;67651:12;:10;:12::i;:::-;-1:-1:-1;;;;;67637:26:0;:10;-1:-1:-1;;;;;67637:26:0;;67609:54;67601:78;;;;-1:-1:-1;;;67601:78:0;;;;;;;:::i;:::-;88908:13:::1;:20:::0;;-1:-1:-1;;88908:20:0::1;88924:4;88908:20:::0;;::::1;::::0;;;88939:5;:22:::1;::::0;;-1:-1:-1;;;88939:22:0;;;;-1:-1:-1;;;;;88939:5:0;;::::1;::::0;:20:::1;::::0;:22:::1;::::0;;::::1;::::0;88908:13:::1;::::0;88939:22;;;;;;;;88908:13;88939:5;:22;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;88979:22:0::1;::::0;::::1;::::0;-1:-1:-1;88979:22:0;;-1:-1:-1;88979:22:0::1;88845:164::o:0;54467:622::-;54837:10;;;54836:62;;-1:-1:-1;54853:39:0;;-1:-1:-1;;;54853:39:0;;-1:-1:-1;;;;;54853:15:0;;;;;:39;;54877:4;;54884:7;;54853:39;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:44;54836:62;54828:152;;;;-1:-1:-1;;;54828:152:0;;;;;;;:::i;:::-;54991:90;55011:5;55041:22;;;55065:7;55074:5;55018:62;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;55018:62:0;;;;;;;;;;;;;;-1:-1:-1;;;;;55018:62:0;-1:-1:-1;;;;;;55018:62:0;;;;;;;;;;54991:19;:90::i;:::-;54467:622;;;:::o;24049:132::-;24107:7;24134:39;24138:1;24141;24134:39;;;;;;;;;;;;;;;;;:3;:39::i;:::-;24127:46;24049:132;-1:-1:-1;;;24049:132:0:o;14877:196::-;14980:12;15012:53;15035:6;15043:4;15049:1;15052:12;15012:22;:53::i;:::-;15005:60;14877:196;-1:-1:-1;;;;14877:196:0:o;74368:98::-;74440:5;;:18;;;-1:-1:-1;;;74440:18:0;;;;74413:7;;-1:-1:-1;;;;;74440:5:0;;:16;;:18;;;;;;;;;;;;;;:5;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;133223:120::-;133318:16;133223:120;:::o;53808:177::-;53891:86;53911:5;53941:23;;;53966:2;53970:5;53918:58;;;;;;;;;:::i;108971:2653::-;109075:25;109102:13;109133:15;109151;:13;:15::i;:::-;109133:33;;109303:13;109292:7;:24;109288:82;;109341:13;109356:1;109333:25;;;;;;;109288:82;109643:23;109669:38;109693:13;109669:23;:38::i;:::-;109643:64;;109718:19;109740:36;109760:15;109740:19;:36::i;:::-;109718:58;;109829:38;109855:11;109829:25;:38::i;:::-;109978:36;110000:13;109978:21;:36::i;:::-;110037:15;:13;:15::i;:::-;110027:25;;110212:7;110196:13;:23;:59;;;;;110254:1;110236:15;:13;:15::i;:::-;:19;110196:59;:162;;;;;110301:52;110332:20;:18;:20::i;:::-;110301:26;:24;:26::i;:52::-;:57;110196:162;:222;;;;-1:-1:-1;110403:15:0;;;;;;;110402:16;110196:222;110178:1169;;;110728:27;110758:26;:13;110776:7;110758:17;:26::i;:::-;110728:56;;110902:44;110926:19;110902:23;:44::i;:::-;110884:62;;111012:44;111040:15;111012:27;:44::i;:::-;111187:42;111213:15;111187:25;:42::i;:::-;111293;111315:19;111293:21;:42::i;:::-;110178:1169;;111359:19;111381:15;:13;:15::i;:::-;111359:37;;111427:11;111411:13;:27;111407:210;;;111475:11;-1:-1:-1;111475:11:0;111509:30;:13;111475:11;111509:17;:30::i;:::-;111501:38;;111407:210;;;111592:13;111572:33;;111407:210;108971:2653;;;;;;;;:::o;103684:5279::-;103763:19;103785:15;:13;:15::i;:::-;103763:37;;104014:16;104000:11;:30;103996:168;;;104047:23;104073:33;:11;104089:16;104073:15;:33::i;:::-;104047:59;;104121:31;104136:15;104121:14;:31::i;:::-;103996:168;;104249:26;104290:20;104325:27;104367:35;104434:25;:23;:25::i;:::-;104234:225;;;;;;;;;;104603:18;104625:1;104603:23;104599:62;;;104643:7;;;;;;;104599:62;104673:18;104694:49;104724:18;104694:25;:12;95997:6;104694:16;:25::i;:49::-;104673:70;;104754:17;104774:42;104788:27;104774:13;:42::i;:::-;104754:62;;104862:18;104883:43;104898:27;104883:14;:43::i;:::-;104862:64;;105703:27;105732:23;105772:19;:17;:19::i;:::-;105702:89;;;;105820:10;105808:9;:22;:63;;;;;105856:15;105834:19;:37;105808:63;105804:3152;;;106088:21;106129:46;95997:6;106129:33;:18;106152:9;106129:22;:33::i;:46::-;106088:87;-1:-1:-1;106192:25:0;106220:31;106088:87;106238:12;106220:17;:31::i;:::-;106192:59;;106315:97;106342:19;106380:17;106315:8;:97::i;:::-;106295:117;-1:-1:-1;106661:15:0;106616:42;:19;106295:117;106616:23;:42::i;:::-;:60;106612:247;;;106803:40;:15;106823:19;106803;:40::i;:::-;106783:60;;106612:247;106927:16;;106953:15;;106875:25;;106920:50;;-1:-1:-1;;;;;106953:15:0;106920:6;:50::i;:::-;106875:95;-1:-1:-1;106875:95:0;106989:35;:12;107006:17;106989:16;:35::i;:::-;:55;106985:232;;;107105:12;107085:17;:32;:116;;107200:1;107085:116;;;107141:35;:17;107163:12;107141:21;:35::i;:::-;107065:136;;106985:232;107356:15;;107276:24;;107320:53;;107329:17;;-1:-1:-1;;;;;107356:15:0;107320:8;:53::i;:::-;107276:97;-1:-1:-1;107394:20:0;;107390:278;;107435:14;:12;:14::i;:::-;107487:15;;107589:8;;107435:217;;-1:-1:-1;;;107435:217:0;;-1:-1:-1;;;;;107435:21:0;;;;;;:217;;107487:15;;;107526:16;;107565:1;;107589:8;;;;;;;107628:4;;107435:217;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;107390:278;107684:18;:16;:18::i;:::-;105804:3152;;;;;;;107751:10;107738;:23;:64;;;;107787:15;107765:19;:37;107738:64;107720:1236;;;108023:21;108064:46;95997:6;108064:33;:9;108078:18;108064:13;:33::i;:46::-;108023:87;;108125:24;108185:12;108169:13;:28;:108;;108276:1;108169:108;;;108221:31;:12;108238:13;108221:16;:31::i;:::-;108125:152;-1:-1:-1;108298:20:0;108294:324;;-1:-1:-1;108358:12:0;108294:324;;;108418:15;108396:19;:37;108392:226;;;108473:129;108504:16;108543:40;:19;108567:15;108543:23;:40::i;:::-;108473:8;:129::i;:::-;108454:148;;108392:226;108712:15;;108634:23;;108677:52;;108686:16;;-1:-1:-1;;;;;108712:15:0;108677:8;:52::i;:::-;108634:95;;108744:19;108766:36;108786:15;108766:19;:36::i;:::-;108744:58;;108859:38;108885:11;108859:25;:38::i;:::-;107720:1236;;;;;103684:5279;;;;;;;;;;;:::o;22212:136::-;22270:7;22297:43;22301:1;22304;22297:43;;;;;;;;;;;;;;;;;:3;:43::i;102650:1026::-;102767:15;102797:13;102825:20;102873:19;102895:15;:13;:15::i;:::-;102873:37;;102984:15;:13;:15::i;:::-;103050:18;:16;:18::i;:::-;103121:20;:18;:20::i;:::-;103154:21;103178:15;:13;:15::i;:::-;103154:39;;103226:11;103210:13;:27;103206:100;;;103264:30;:13;103282:11;103264:17;:30::i;:::-;103254:40;;103206:100;103377:20;;103373:296;;103414:20;103477:35;103495:16;103477:17;:35::i;:::-;103453:59;-1:-1:-1;103453:59:0;-1:-1:-1;103542:40:0;103551:16;103453:59;103542:8;:40::i;:::-;103527:55;-1:-1:-1;103601:9:0;;103597:61;;103641:1;103631:11;;103597:61;103373:296;;102650:1026;;;;;;;:::o;128377:404::-;128476:26;128517:20;128552:27;128594:35;128644:11;128670:20;128725:14;:12;:14::i;:::-;-1:-1:-1;;;;;128725:33:0;;128767:4;128725:48;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;128718:55;;;;-1:-1:-1;128718:55:0;;-1:-1:-1;128718:55:0;-1:-1:-1;128718:55:0;-1:-1:-1;128718:55:0;;-1:-1:-1;128377:404:0;-1:-1:-1;128377:404:0:o;23102:471::-;23160:7;23405:6;23401:47;;-1:-1:-1;23435:1:0;23428:8;;23401:47;23472:5;;;23476:1;23472;:5;:1;23496:5;;;;;:10;23488:56;;;;-1:-1:-1;;;23488:56:0;;;;;;;:::i;128789:223::-;128970:19;;128892:7;;128937:67;;95997:6;;128937:54;;:20;;128970:19;;;128937:67;128970:19;128937:24;:54::i;129020:257::-;129202:20;;129124:7;;129169:100;;95997:6;;129169:55;;:20;;-1:-1:-1;;;129202:20:0;;129169:100;129202:20;129169:24;:55::i;123405:4008::-;123484:27;123513:23;123968:47;;:::i;:::-;124026:40;;:::i;:::-;124082:14;:12;:14::i;:::-;124120:15;;124082:55;;-1:-1:-1;;;124082:55:0;;-1:-1:-1;;;;;124082:29:0;;;;;;:55;;124120:15;;;124082:55;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;124243:39;;;;124717:15;;124673:61;;-1:-1:-1;;;124673:61:0;;124026:111;;-1:-1:-1;124243:39:0;;96537:42;;124673:35;;:61;;-1:-1:-1;;;;;124717:15:0;;124673:61;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;124501:22:0;;;124310:424;;;-1:-1:-1;;;124423:20:0;;;124310:424;;;;;;124764:48;;:24;:48::i;:::-;124747:14;;;:65;;;124845:23;;:43;;:27;:43::i;:::-;124823:19;;;:65;124922:14;;;;:19;:94;;124996:19;;;;124974:14;;;;:42;;:21;:42::i;:::-;124922:94;;;124957:1;124922:94;124899:20;;;:117;125093:37;;:::i;:::-;125163:3;-1:-1:-1;;;;;125163:28:0;;:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;125141:7;:19;;:52;;;;;125223:3;-1:-1:-1;;;;;125223:26:0;;:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;125204:7;:16;;:47;;;;;125335:3;-1:-1:-1;;;;;125335:22:0;;:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;125318:7;:14;;:41;;;;;125454:3;-1:-1:-1;;;;;125454:22:0;;:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;125437:14;;;:41;125779:19;;125756:20;;;;:42;:116;;;;-1:-1:-1;125857:14:0;;;;125836:16;;;;:36;;:20;:36::i;:::-;125815:18;;:57;125756:116;125738:1360;;;126097:161;126243:7;:14;;;126097:120;126197:7;:19;;;126116:40;126139:7;:16;;;126116:18;;:22;;:40;;;;:::i;:::-;126097:99;;:120::i;:::-;:145;;:161::i;:::-;126068:26;;;:190;125738:1360;;;126478:14;;;;126457:16;;;;:36;;:20;:36::i;:::-;126436:18;;:57;126432:158;;;126529:14;;;;126553:15;;126522:48;;126529:14;-1:-1:-1;;;;;126553:15:0;126522:6;:48::i;:::-;126572:1;126514:60;;;;;;;;;;126432:158;127066:19;;127028:14;;;;126843:243;;127066:19;126843:200;;:159;126963:38;126971:4;127066:19;126963:17;:38::i;:::-;126862:60;126885:36;126906:7;:14;;;126885:7;:16;;;:20;;:36;;;;:::i;:::-;126862:18;;;:22;:60::i;126843:243::-;126814:26;;;:272;125738:1360;127133:109;127237:4;127133:82;127188:4;:26;;;127133:4;:33;;;:54;;:82;;;;:::i;:109::-;127110:20;;;:132;127284:14;;;;127308:15;;127277:48;;127284:14;-1:-1:-1;;;;;127308:15:0;127277:6;:48::i;:::-;127347:20;;;;127377:15;;127340:54;;127347:20;-1:-1:-1;;;;;127377:15:0;127340:6;:54::i;:::-;127255:150;;;;;;;;123405:4008;;;:::o;68655:727::-;68827:4;;-1:-1:-1;;;;;68827:4:0;68819:27;68811:68;;;;-1:-1:-1;;;68811:68:0;;;;;;;:::i;:::-;68892:5;:24;;-1:-1:-1;;;;;;68892:24:0;-1:-1:-1;;;;;68892:24:0;;;;;;;;;;;68941:13;;;-1:-1:-1;;;68941:13:0;;;;:5;;;;;:11;;:13;;;;;;;;;;;;;;;:5;:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;68927:4;:28;;-1:-1:-1;;;;;;68927:28:0;-1:-1:-1;;;;;68927:28:0;;;;;;;;68966:37;;:4;68983:6;-1:-1:-1;;68966:16:0;:37::i;:::-;69062:10;:24;;-1:-1:-1;;;;;69062:24:0;;;-1:-1:-1;;;;;;69062:24:0;;;;;;;69097:7;:18;;;;;;;;;;;;;69126:6;:16;;;;;;;;;;;;;69062:10;69188:14;:18;;;69234:5;69217:14;:22;69265:3;69250:12;:18;69279:13;:17;69062:24;69309:5;:35;;-1:-1:-1;;;69309:35:0;;:5;;;;:13;;:35;;69323:7;;;;-1:-1:-1;;;69309:35:0;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;68655:727;;;;:::o;100751:1243::-;100965:9;100948:14;:26;101002:14;100985;:31;101042:3;101027:12;:18;101108:6;:24;;-1:-1:-1;;;;;;101108:24:0;-1:-1:-1;;;;;101108:24:0;;;;;;;;101168:23;;;-1:-1:-1;;;101168:23:0;;;;:21;;:23;;;;;;;;;;;;;;;101108:24;101168:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;101143:15;:49;;-1:-1:-1;;;;;;101143:49:0;-1:-1:-1;;;;;101143:49:0;;;;;;101297:4;;101242:61;;-1:-1:-1;;;101242:61:0;;-1:-1:-1;;96537:42:0;;101242:46;;:61;;101297:4;;;;;101242:61;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;101314:6:0;:25;;-1:-1:-1;;;;;101314:25:0;;;-1:-1:-1;;;101314:25:0;;;;;;;;;;;;101473:15;;101400:104;;-1:-1:-1;;;101400:104:0;;101205:98;;-1:-1:-1;;;96537:42:0;;101400:46;;:104;;101473:15;;;101400:104;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;101517:17;:58;;-1:-1:-1;;;;;;101517:58:0;-1:-1:-1;;;;;101517:58:0;;;;;;;;;;101607:6;;:17;;;-1:-1:-1;;;101607:17:0;;;;101517:58;;-1:-1:-1;101601:34:0;;-1:-1:-1;101631:3:0;;-1:-1:-1;101607:6:0;;;:15;;:17;;;;;;;;;;;;;;;:6;:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;101602:2;:23;;101601:29;:34::i;:::-;101586:12;:49;101667:18;:40;;-1:-1:-1;;101667:40:0;;;;;-1:-1:-1;;101718:62:0;101667:40;101718:62;;;;;;;-1:-1:-1;;101793:16:0;:36;-1:-1:-1;101936:7:0;:11;101958:28;;;;:12;;:28;;;;;:::i;:::-;;100751:1243;;;;;;:::o;127807:125::-;127882:17;;:42;;-1:-1:-1;;;127882:42:0;;127855:7;;-1:-1:-1;;;;;127882:17:0;;:27;;:42;;127918:4;;127882:42;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;131305:493::-;131403:7;131446:12;;;:57;;;-1:-1:-1;;131475:7:0;:28;131446:57;:105;;;-1:-1:-1;;;;;;131520:31:0;;96622:42;131520:31;131446:105;131428:190;;;-1:-1:-1;131599:7:0;131592:14;;131428:190;131650:140;131757:5;-1:-1:-1;;;;;131742:30:0;;:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;131734:41;;131729:2;131721:54;131650:48;131662:14;:12;:14::i;:::-;-1:-1:-1;;;;;131662:28:0;;131691:5;131662:35;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;131650:7;;:11;:48::i;131806:499::-;131906:7;131949:12;;;:57;;;-1:-1:-1;;131978:7:0;:28;131949:57;:105;;;-1:-1:-1;;;;;;132023:31:0;;96622:42;132023:31;131949:105;131931:190;;;-1:-1:-1;132102:7:0;132095:14;;131931:190;132153:144;132261:14;:12;:14::i;:::-;-1:-1:-1;;;;;132261:28:0;;132290:5;132261:35;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;132153:85;132219:5;-1:-1:-1;;;;;132204:30:0;;:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;132153:7;;132196:41;;132191:2;132183:54;132153:29;:85::i;121679:775::-;121750:18;;121728:4;;121750:18;;121749:19;:53;;;;-1:-1:-1;121773:29:0;;;;;;;121772:30;121749:53;121745:98;;;-1:-1:-1;121826:5:0;121819:12;;121745:98;121901:52;;-1:-1:-1;;;121901:52:0;;121855:30;;96391:42;;121901:37;;:52;;121947:4;;121901:52;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;121855:98;;121964:24;96391:42;-1:-1:-1;;;;;121991:37:0;;:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;121964:66;;122041:22;96391:42;-1:-1:-1;;;;;122066:35:0;;:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;122041:62;-1:-1:-1;122137:44:0;:22;122164:16;122137:26;:44::i;:::-;122118:15;:63;122114:308;;122348:14;122222:105;122264:44;:22;122291:16;122264:26;:44::i;:::-;122222:15;;:19;:105::i;:::-;:140;;:188;;;-1:-1:-1;122383:27:0;;122222:188;122198:212;;;;;;;122114:308;122441:5;122434:12;;;;;121679:775;:::o;82901:1677::-;82972:4;82989:28;;:::i;:::-;83020:5;;:31;;-1:-1:-1;;;83020:31:0;;-1:-1:-1;;;;;83020:5:0;;;;:16;;:31;;83045:4;;83020:31;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;82989:62;;83128:6;:17;;;83149:1;83128:22;83124:40;;;83159:5;83152:12;;;;;83124:40;83309:14;;83288:17;;;;83268:38;;:15;;:19;:38::i;:::-;:55;83264:73;;;83332:5;83325:12;;;;;83264:73;83456:14;;83434:17;;;;83414:38;;:15;;:19;:38::i;:::-;:56;83410:73;;83479:4;83472:11;;;;;83410:73;83913:5;;:23;;;-1:-1:-1;;;83913:23:0;;;;83891:19;;-1:-1:-1;;;;;83913:5:0;;:21;;:23;;;;;;;;;;;;;;:5;:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;83891:45;;83965:13;;83951:11;:27;83947:44;;;83987:4;83980:11;;;;;;83947:44;84045:13;84061:22;:20;:22::i;:::-;84045:38;;84173:6;:16;;;84146:24;84156:13;;84146:5;:9;;:24;;;;:::i;:::-;:43;84142:60;;;84198:4;84191:11;;;;;;;84142:60;84215:14;84256:6;:16;;;84248:5;:24;84244:66;;;84293:16;;;;84283:27;;:5;;:9;:27::i;:::-;84274:36;;84244:66;84480:5;;:23;;;-1:-1:-1;;;84480:23:0;;;;84463:14;;-1:-1:-1;;;;;84480:5:0;;:21;;:23;;;;;;;;;;;;;;:5;:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;84463:40;-1:-1:-1;84551:18:0;84463:40;84562:6;84551:10;:18::i;:::-;84522:12;;:26;;84539:8;84522:16;:26::i;:::-;:47;;82901:1677;-1:-1:-1;;;;;;;82901:1677:0:o;127940:219::-;127993:7;128033:118;128119:6;;;;;;;;;-1:-1:-1;;;;;128119:6:0;-1:-1:-1;;;;;128119:15:0;;:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;128115:2;:21;128033:59;128069:6;;;;;;;;;-1:-1:-1;;;;;128069:6:0;-1:-1:-1;;;;;128069:20:0;;:22;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;128033:6;;:31;;-1:-1:-1;;;128033:31:0;;-1:-1:-1;;;;;128033:6:0;;;;:16;;:31;;128058:4;;128033:31;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:35;;:59::i;127683:116::-;127760:6;;:31;;-1:-1:-1;;;127760:31:0;;127733:7;;-1:-1:-1;;;127760:6:0;;-1:-1:-1;;;;;127760:6:0;;:16;;:31;;127785:4;;127760:31;;;:::i;127421:112::-;127496:4;;:29;;-1:-1:-1;;;127496:29:0;;127469:7;;-1:-1:-1;;;;;127496:4:0;;:14;;:29;;127519:4;;127496:29;;;:::i;21748:181::-;21806:7;21838:5;;;21862:6;;;;21854:46;;;;-1:-1:-1;;;21854:46:0;;;;;;;:::i;56113:761::-;56537:23;56563:69;56591:4;56563:69;;;;;;;;;;;;;;;;;56571:5;-1:-1:-1;;;;;56563:27:0;;;:69;;;;;:::i;:::-;56647:17;;56537:95;;-1:-1:-1;56647:21:0;56643:224;;56789:10;56778:30;;;;;;;;;;;;:::i;:::-;56770:85;;;;-1:-1:-1;;;56770:85:0;;;;;;;:::i;24677:278::-;24763:7;24798:12;24791:5;24783:28;;;;-1:-1:-1;;;24783:28:0;;;;;;;;:::i;:::-;;24822:9;24838:1;24834;:5;;;;;;;24677:278;-1:-1:-1;;;;;24677:278:0:o;16254:979::-;16384:12;16417:18;16428:6;16417:10;:18::i;:::-;16409:60;;;;-1:-1:-1;;;16409:60:0;;;;;;;:::i;:::-;16543:12;16557:23;16584:6;-1:-1:-1;;;;;16584:11:0;16604:8;16615:4;16584:36;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;16542:78;;;;16635:7;16631:595;;;16666:10;-1:-1:-1;16659:17:0;;-1:-1:-1;16659:17:0;16631:595;16780:17;;:21;16776:439;;17043:10;17037:17;17104:15;17091:10;17087:2;17083:19;17076:44;16991:148;17186:12;17179:20;;-1:-1:-1;;;17179:20:0;;;;;;;;:::i;118881:2489::-;118980:7;119009:11;119005:52;;-1:-1:-1;119044:1:0;119037:8;;119005:52;119195:26;119236:20;119286:35;119353:25;:23;:25::i;:::-;-1:-1:-1;;119444:4:0;;119180:198;;-1:-1:-1;119180:198:0;;-1:-1:-1;119180:198:0;;-1:-1:-1;119391:27:0;;119421:29;;-1:-1:-1;119428:6:0;;-1:-1:-1;;;;;119444:4:0;119421:6;:29::i;:::-;119391:59;;119536:21;119594:19;119573:18;:40;:124;;119696:1;119573:124;;;119633:43;:18;119656:19;119633:22;:43::i;:::-;119536:161;;119710:26;119768:1;119752:13;:17;:118;;-1:-1:-1;;119752:118:0;;;119789:44;119819:13;119789:25;:12;95997:6;119789:16;:25::i;:44::-;119710:160;;120086:18;120107:43;120122:27;120107:14;:43::i;:::-;120086:64;;120189:10;120167:18;:32;120163:353;;120286:1;120279:8;;;;;;;;;;;120163:353;-1:-1:-1;;120309:18:0;:39;120305:211;;;120487:15;;120456:48;;120465:12;;-1:-1:-1;;;;;120487:15:0;120456:8;:48::i;:::-;120449:55;;;;;;;;;;;120305:211;120528:17;120548:42;120562:27;120548:13;:42::i;:::-;120528:62;-1:-1:-1;120889:21:0;120913:41;95997:6;120913:28;120528:62;120927:13;120913;:28::i;:41::-;120889:65;;121059:12;121043:13;:28;121039:69;;;121095:1;121088:8;;;;;;;;;;;;;121039:69;121201:12;;121140:222;;121167:31;:12;121184:13;121167:16;:31::i;:::-;:46;:137;;121273:31;:12;121290:13;121273:16;:31::i;:::-;121167:137;;;121237:12;121167:137;121331:15;;-1:-1:-1;;;;;121331:15:0;121140:8;:222::i;:::-;121120:242;118881:2489;-1:-1:-1;;;;;;;;;;;118881:2489:0:o;113835:581::-;113901:7;113925:14;113921:55;;-1:-1:-1;113963:1:0;113956:8;;113921:55;114050:20;114073:26;:24;:26::i;:::-;114050:49;;114110:24;114150:128;114177:36;114203:9;114177:25;:36::i;:::-;114232:6;;:31;;-1:-1:-1;;;114232:31:0;;-1:-1:-1;;;;;114232:6:0;;;;:16;;:31;;114257:4;;114232:31;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;114150:8;:128::i;:::-;114289:6;;114338:7;;114289:57;;-1:-1:-1;;;114289:57:0;;114110:168;;-1:-1:-1;;;;;;114289:6:0;;;;:15;;:57;;114110:168;;114331:4;;114289:57;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;114364:44;114395:12;114364:26;:24;:26::i;114424:732::-;114499:11;114495:50;;114527:7;;114495:50;114607:15;114625:26;:24;:26::i;:::-;114607:44;;114671:25;114680:6;114688:7;114671:8;:25::i;:::-;114662:34;;114759:33;114768:15;:13;:15::i;:::-;114785:6;114759:8;:33::i;:::-;114750:42;;114805:124;114843:14;:12;:14::i;:::-;114881:15;;-1:-1:-1;;;;;114881:15:0;114912:6;114805:15;:124::i;:::-;114946:10;;114942:207;;114973:14;:12;:14::i;:::-;115020:15;;114973:164;;-1:-1:-1;;;114973:164:0;;-1:-1:-1;;;;;114973:20:0;;;;;;:164;;115020:15;;;115055:6;;115088:1;;115117:4;;114973:164;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;117717:661::-;117784:25;117812:17;:15;:17::i;:::-;117784:45;;117853:17;117844:6;:26;117840:85;;;117896:17;117887:26;;117840:85;117937:21;117974:59;117983:16;:14;:16::i;:::-;118001:4;;118024:6;;118001:31;;-1:-1:-1;;;118001:31:0;;-1:-1:-1;;;;;118001:4:0;;;;:14;;:31;;-1:-1:-1;;;118024:6:0;;;;;;;118001:31;;;:::i;117974:59::-;117937:96;;118046:18;118067:31;118076:6;118084:13;118067:8;:31::i;:::-;118046:52;-1:-1:-1;118113:14:0;;118109:262;;118144:135;118186:14;:12;:14::i;:::-;118228:6;;-1:-1:-1;;;118228:6:0;;-1:-1:-1;;;;;118228:6:0;118254:10;118144:15;:135::i;:::-;118294:14;:12;:14::i;:::-;118326:4;;118294:65;;-1:-1:-1;;;118294:65:0;;-1:-1:-1;;;;;118294:23:0;;;;;;:65;;118326:4;;;118333:10;;118353:4;;118294:65;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;118109:262::-;117717:661;;;;:::o;127541:134::-;127627:15;;:40;;-1:-1:-1;;;127627:40:0;;127600:7;;-1:-1:-1;;;;;127627:15:0;;:25;;:40;;127661:4;;127627:40;;;:::i;130780:517::-;130858:12;130854:51;;130887:7;;130854:51;130957:4;;130929:15;;-1:-1:-1;;;;;130929:15:0;;;130957:4;;130921:41;130917:80;;;130979:7;;130917:80;131050:4;;131009:56;;96278:42;;-1:-1:-1;;;;;131050:4:0;131057:7;131009:15;:56::i;:::-;131200:4;;131215:15;;96278:42;;131076:31;;131122:7;;-1:-1:-1;;131144:17:0;131176:56;;-1:-1:-1;;;;;131200:4:0;;;;131215:15;131176;:56::i;:::-;131255:4;131275:3;131076:213;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;131076:213:0;;;;;;;;;;;;:::i;121378:293::-;121442:11;121438:50;;121470:7;;121438:50;121500:15;121518:14;:12;:14::i;:::-;121580:4;;121500:32;;-1:-1:-1;121543:51:0;;121500:32;;-1:-1:-1;;;;;121580:4:0;121587:6;121543:15;:51::i;:::-;121624:4;;121654:8;;121605:58;;-1:-1:-1;;;121605:58:0;;-1:-1:-1;;;;;121605:10:0;;;;;;:58;;121624:4;;;;;121631:6;;121647:4;;121654:8;;;;;;;121605:58;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;121378:293;;:::o;20420:106::-;20478:7;20509:1;20505;:5;:13;;20517:1;20505:13;;;-1:-1:-1;20513:1:0;;20420:106;-1:-1:-1;20420:106:0:o;132384:202::-;132431:24;96537:42;-1:-1:-1;;;;;132509:39:0;;:41;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;132509:56:0;;:58;;;;;;;;;;;;;;;;;;;;;;;;;;;;;115164:324;115212:17;115232:26;:24;:26::i;:::-;115212:46;-1:-1:-1;115273:13:0;;115269:212;;115345:6;;115379:15;;115303:135;;-1:-1:-1;;;;;115345:6:0;;;;115379:15;115414:9;115303:15;:135::i;:::-;115453:6;;;;;;;;;-1:-1:-1;;;;;115453:6:0;-1:-1:-1;;;;;115453:14:0;;:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;20237:107;20295:7;20327:1;20322;:6;;:14;;20335:1;20322:14;;22651:192;22737:7;22773:12;22765:6;;;;22757:29;;;;-1:-1:-1;;;22757:29:0;;;;;;;;:::i;:::-;-1:-1:-1;;;22809:5:0;;;22651:192::o;115496:1790::-;115545:29;;;;;;;;:51;;-1:-1:-1;115578:18:0;;;;115545:51;115541:1738;;;115696:49;;-1:-1:-1;;;115696:49:0;;115654:22;;96391:42;;115696:34;;:49;;115739:4;;115696:49;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;115654:91;;115781:1;115764:14;:18;:38;;;;;115786:16;:14;:16::i;:::-;115760:124;;;115823:45;;-1:-1:-1;;;115823:45:0;;96391:42;;115823:14;;:45;;115846:4;;115853:14;;115823:45;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;115760:124;115935:54;;-1:-1:-1;;;115935:54:0;;96391:42;;115935:20;;:54;;115964:4;;-1:-1:-1;;115971:17:0;115935:54;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;116122:37:0;;-1:-1:-1;;;116122:37:0;;116100:19;;-1:-1:-1;96704:42:0;;-1:-1:-1;116122:22:0;;:37;;116153:4;;116122:37;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;116100:59;;116192:4;116178:11;:18;116174:88;;;116217:29;116234:11;116217:16;:29::i;:::-;116420;;116378:23;;116420:29;;;;;:51;;;;-1:-1:-1;116453:18:0;;;;116420:51;116416:514;;;116501:16;;;116515:1;116501:16;;;;;;;;;;;;;;;;;;;;-1:-1:-1;116501:16:0;116492:25;;116556:6;;;;;;;;;-1:-1:-1;;;;;116556:6:0;116536;116543:1;116536:9;;;;;;;;-1:-1:-1;;;;;116536:27:0;;;:9;;;;;;;;;:27;116602:17;;116582:9;;116602:17;;;116582:6;;116602:17;;116582:9;;;;;;;;;;;:38;-1:-1:-1;;;;;116582:38:0;;;-1:-1:-1;;;;;116582:38:0;;;;;116416:514;;;116646:29;;;;;;;116642:288;;;116705:16;;;116719:1;116705:16;;;;;;;;;;;;;;;;;;;-1:-1:-1;;116760:17:0;;116740:9;;;;-1:-1:-1;;;;;;116760:17:0;;116740:9;;-1:-1:-1;116760:17:0;;116740:9;;;116642:288;116804:18;;;;116800:130;;;116852:16;;;116866:1;116852:16;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;116852:16:0;116843:25;;116907:6;;;;;;;;;-1:-1:-1;;;;;116907:6:0;116887;116894:1;116887:9;;;;;;;;;;;;;:27;-1:-1:-1;;;;;116887:27:0;;;-1:-1:-1;;;;;116887:27:0;;;;;116800:130;116946:23;:21;:23::i;:::-;-1:-1:-1;;;;;116946:36:0;;117001:6;-1:-1:-1;;117070:4:0;116946:144;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;117160:49:0;;-1:-1:-1;;;117160:49:0;;117212:1;;96391:42;;117160:34;;:49;;117203:4;;117160:49;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:53;117156:112;;;96391:42;-1:-1:-1;;;;;117234:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;122812:526;122860:13;122876:15;:13;:15::i;:::-;122860:31;;122902:21;122926:20;:18;:20::i;:::-;122902:44;;122970:13;122961:5;:22;122957:61;;123000:7;;;;122957:61;123030:14;123047:24;:13;123065:5;123047:17;:24::i;:::-;123030:41;;123082:25;123110:33;123136:6;123110:25;:33::i;:::-;123082:61;-1:-1:-1;123158:21:0;;123154:177;;123196:6;;123246:7;;123196:58;;-1:-1:-1;;;123196:58:0;;-1:-1:-1;;;;;123196:6:0;;;;:15;;:58;;123212:17;;123239:4;;123196:58;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;123269:50;123292:26;:24;:26::i;:::-;123269:22;:50::i;117294:362::-;117368:5;;:31;;-1:-1:-1;;;117368:31:0;;117344:21;;-1:-1:-1;;;;;117368:5:0;;:16;;:31;;117393:4;;117368:31;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:41;;;117344:65;;117420:25;117448:17;:15;:17::i;:::-;117420:45;;117502:13;117482:17;:33;117478:171;;;117532:18;117553:36;:17;117575:13;117553:21;:36::i;:::-;117532:57;;117604:33;117626:10;117604:21;:33::i;28682:237::-;28743:7;28771:6;28763:15;;;;;;28809:1;28805:5;;26570:4;28837:25;;28836:33;28831:38;;;28823:47;;;;;;28910:1;28901:5;26570:4;28891:1;:7;:15;28890:21;;;;;;;28682:237;-1:-1:-1;;;;28682:237:0:o;28257:248::-;28318:7;28342:6;;;:16;;-1:-1:-1;28352:6:0;;28342:16;28338:57;;;-1:-1:-1;28382:1:0;28375:8;;28338:57;28452:1;-1:-1:-1;;28452:1:0;28420:33;;;;;28415:1;:38;;28407:47;;;;;;-1:-1:-1;26570:4:0;28475:5;;26617:7;28475:15;28474:23;;28257:248::o;132594:204::-;132641:12;96537:42;-1:-1:-1;;;;;132717:39:0;;:41;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;132717:56:0;;:58;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11762:619;11822:4;12290:20;;12133:66;12330:23;;;;;;:42;;-1:-1:-1;;12357:15:0;;;11762:619;-1:-1:-1;;11762:619:0:o;128167:202::-;128268:7;128300:61;128338:6;;;;;;;;;-1:-1:-1;;;;;128338:6:0;-1:-1:-1;;;;;128338:20:0;;:22;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;128315:6;;:17;;;-1:-1:-1;;;128315:17:0;;;;128300:33;;-1:-1:-1;;;;;128315:6:0;;:15;;:17;;;;;;;;;;;;;;:6;:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;128300:6;;128311:2;:21;128300:10;:33::i;122462:342::-;122597:50;;-1:-1:-1;;;122597:50:0;;122650:7;;-1:-1:-1;;;;;122597:24:0;;;;;:50;;122630:4;;122637:9;;122597:50;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:60;122593:204;;;122674:40;-1:-1:-1;;;;;122674:26:0;;122701:9;122712:1;122674:26;:40::i;:::-;122729:56;-1:-1:-1;;;;;122729:26:0;;122756:9;-1:-1:-1;;122729:26:0;:56::i;118386:487::-;118435:7;118456:26;118484:20;118510:11;118540:25;:23;:25::i;:::-;118455:110;;;;;;;;;118576:24;118622:1;118616:3;:7;:65;;118663:18;118616:65;;;118626:34;118656:3;118626:25;:12;95997:6;118626:16;:25::i;:34::-;118576:105;;118715:18;118696:16;:37;118692:78;;;118757:1;118750:8;;;;;;;;118692:78;118800:65;118809:40;:18;118832:16;118809:22;:40::i;118800:65::-;118780:85;;;;;;118386:487;:::o;129347:493::-;129461:22;129501:12;-1:-1:-1;;;;;129529:26:0;;96622:42;129529:26;;:57;;-1:-1:-1;;;;;;129559:27:0;;96622:42;129559:27;129529:57;129501:85;;129619:7;:15;;129633:1;129619:15;;;129629:1;129619:15;129605:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;129605:30:0;;129597:38;;129657:9;129646:5;129652:1;129646:8;;;;;;;;;;;;;:20;-1:-1:-1;;;;;129646:20:0;;;-1:-1:-1;;;;;129646:20:0;;;;;129683:7;129679:154;;;129718:10;129707:5;129713:1;129707:8;;;;;;;;;;;;;:21;-1:-1:-1;;;;;129707:21:0;;;-1:-1:-1;;;;;129707:21:0;;;;;129679:154;;;96622:42;129761:5;129767:1;129761:8;;;;;;;;;;;;;:24;-1:-1:-1;;;;;129761:24:0;;;-1:-1:-1;;;;;129761:24:0;;;;;129811:10;129800:5;129806:1;129800:8;;;;;;;;;;;;;:21;-1:-1:-1;;;;;129800:21:0;;;-1:-1:-1;;;;;129800:21:0;;;;;129679:154;129347:493;;;;;:::o;129848:387::-;129915:12;129911:51;;129944:7;;129911:51;129974:56;96278:42;96704;130022:7;129974:15;:56::i;:::-;130164:4;;96278:42;;130041:31;;130087:7;;130109:1;;130125:45;;96704:42;;-1:-1:-1;;;;;130164:4:0;130125:15;:45::i;132806:409::-;132936:18;;132889:25;;132936:18;;132932:276;;;132978:6;;;;;;;;;-1:-1:-1;;;;;132978:6:0;-1:-1:-1;;;;;132978:30:0;;:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;132971:39;;;;132932:276;133032:29;;;;;;;133028:180;;;133085:17;;;;;;;;;-1:-1:-1;;;;;133085:17:0;-1:-1:-1;;;;;133085:41:0;;:43;;;;;;;;;;;;;;;;;;;;;;;;;;;;;133028:180;-1:-1:-1;133194:1:0;133161:35;;130243:529;130316:12;130312:51;;130345:7;;130312:51;130426:15;;130409:4;;-1:-1:-1;;;;;130409:4:0;;;130426:15;;130401:41;130397:80;;;130459:7;;130397:80;130530:15;;130489:67;;96278:42;;-1:-1:-1;;;;;130530:15:0;130548:7;130489:15;:67::i;:::-;130675:15;;130701:4;;96278:42;;130567:31;;130613:7;;130635:1;;130651:56;;-1:-1:-1;;;;;130675:15:0;;;;130701:4;130651:15;:56::i;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;142:134::-;220:13;;238:33;220:13;238:33;:::i;2752:359::-;;2891:4;2879:9;2874:3;2870:19;2866:30;2863:2;;;-1:-1;;2899:12;2863:2;2927:20;2891:4;2927:20;:::i;:::-;7636:13;;3004:86;;-1:-1;2918:29;2857:254;-1:-1;2857:254::o;7145:134::-;7223:13;;43324:34;43313:46;;46350:35;;46340:2;;46399:1;;46389:12;7286:128;7352:20;;43443:6;43432:18;;46473:34;;46463:2;;46521:1;;46511:12;7699:132;7776:13;;43741:12;43730:24;;46719:34;;46709:2;;46767:1;;46757:12;7838:130;7914:13;;43837:4;43826:16;;46840:33;;46830:2;;46887:1;;46877:12;7975:241;;8079:2;8067:9;8058:7;8054:23;8050:32;8047:2;;;-1:-1;;8085:12;8047:2;85:6;72:20;97:33;124:5;97:33;:::i;8223:263::-;;8338:2;8326:9;8317:7;8313:23;8309:32;8306:2;;;-1:-1;;8344:12;8306:2;226:6;220:13;238:33;265:5;238:33;:::i;8493:535::-;;;;8642:2;8630:9;8621:7;8617:23;8613:32;8610:2;;;-1:-1;;8648:12;8610:2;226:6;220:13;238:33;265:5;238:33;:::i;:::-;8811:2;8861:22;;220:13;8700:74;;-1:-1;238:33;220:13;238:33;:::i;:::-;8930:2;8980:22;;220:13;8819:74;;-1:-1;238:33;220:13;238:33;:::i;:::-;8938:74;;;;8604:424;;;;;:::o;9035:1215::-;;;;;;;;;9262:3;9250:9;9241:7;9237:23;9233:33;9230:2;;;-1:-1;;9269:12;9230:2;85:6;72:20;97:33;124:5;97:33;:::i;:::-;9321:63;-1:-1;9421:2;9460:22;;;72:20;97:33;72:20;97:33;:::i;:::-;9429:63;-1:-1;9529:2;9568:22;;72:20;97:33;72:20;97:33;:::i;:::-;9537:63;-1:-1;9637:2;9676:22;;72:20;97:33;72:20;97:33;:::i;:::-;9645:63;-1:-1;9745:3;9785:22;;72:20;97:33;72:20;97:33;:::i;:::-;9754:63;-1:-1;9854:3;9891:22;;1095:20;1120:30;1095:20;1120:30;:::i;:::-;9863:60;-1:-1;9960:3;9997:22;;1095:20;1120:30;1095:20;1120:30;:::i;:::-;9969:60;-1:-1;10094:3;10079:19;;10066:33;10119:18;10108:30;;;10105:2;;;-1:-1;;10141:12;10105:2;10217:6;10206:9;10202:22;;;2357:3;2350:4;2342:6;2338:17;2334:27;2324:2;;-1:-1;;2365:12;2324:2;2412:6;2399:20;10119:18;41301:6;41298:30;41295:2;;;-1:-1;;41331:12;41295:2;2434:65;41404:9;41385:17;;-1:-1;;41381:33;41462:15;;2434:65;:::i;:::-;2425:74;;2519:6;2512:5;2505:21;2623:3;9421:2;2614:6;2547;2605:16;;2602:25;2599:2;;;-1:-1;;2630:12;2599:2;45049:6;9421:2;2547:6;2543:17;9421:2;2581:5;2577:16;45026:30;45087:16;;;;;45080:27;;;;9224:1026;;;;-1:-1;9224:1026;;-1:-1;9224:1026;;;;;;-1:-1;9224:1026::o;10257:392::-;;10397:2;;10385:9;10376:7;10372:23;10368:32;10365:2;;;-1:-1;;10403:12;10365:2;10454:17;10448:24;10492:18;10484:6;10481:30;10478:2;;;-1:-1;;10514:12;10478:2;10601:22;;422:4;410:17;;406:27;-1:-1;396:2;;-1:-1;;437:12;396:2;477:6;471:13;499:80;514:64;571:6;514:64;:::i;:::-;499:80;:::i;:::-;607:21;;;664:14;;;;639:17;;;753;;;744:27;;;;741:36;-1:-1;738:2;;;-1:-1;;780:12;738:2;-1:-1;806:10;;800:217;825:6;822:1;819:13;800:217;;;7636:13;;893:61;;847:1;840:9;;;;;968:14;;;;996;;800:217;;;-1:-1;10534:99;10359:290;-1:-1;;;;;;;10359:290::o;10656:257::-;;10768:2;10756:9;10747:7;10743:23;10739:32;10736:2;;;-1:-1;;10774:12;10736:2;1243:6;1237:13;1255:30;1279:5;1255:30;:::i;11904:367::-;;;12028:2;12016:9;12007:7;12003:23;11999:32;11996:2;;;-1:-1;;12034:12;11996:2;12092:17;12079:31;12130:18;;12122:6;12119:30;12116:2;;;-1:-1;;12152:12;12116:2;12238:6;12227:9;12223:22;;;2024:3;2017:4;2009:6;2005:17;2001:27;1991:2;;-1:-1;;2032:12;1991:2;2075:6;2062:20;12130:18;2094:6;2091:30;2088:2;;;-1:-1;;2124:12;2088:2;2219:3;12028:2;2199:17;2160:6;2185:32;;2182:41;2179:2;;;-1:-1;;2226:12;2179:2;12028;2156:17;;;;;12172:83;;-1:-1;11990:281;;-1:-1;;;;11990:281::o;12278:318::-;;12420:3;;12408:9;12399:7;12395:23;12391:33;12388:2;;;-1:-1;;12427:12;12388:2;3318:22;12420:3;3318:22;:::i;:::-;3309:31;;3431:99;3526:3;3502:22;3431:99;:::i;:::-;3413:16;3406:125;3635:60;3691:3;3602:2;3671:9;3667:22;3635:60;:::i;:::-;3602:2;3621:5;3617:16;3610:86;3805:60;3861:3;3772:2;3841:9;3837:22;3805:60;:::i;:::-;3772:2;3791:5;3787:16;3780:86;3976:60;4032:3;3943:2;4012:9;4008:22;3976:60;:::i;:::-;3943:2;3962:5;3958:16;3951:86;4153:60;4209:3;4119;4189:9;4185:22;4153:60;:::i;:::-;4119:3;4139:5;4135:16;4128:86;4328:60;4384:3;4294;4364:9;4360:22;4328:60;:::i;:::-;4294:3;4314:5;4310:16;4303:86;4499:59;4554:3;4465;4534:9;4530:22;4499:59;:::i;:::-;4465:3;4485:5;4481:16;4474:85;4663:60;4719:3;4629;4699:9;4695:22;4663:60;:::i;:::-;4629:3;4649:5;4645:16;4638:86;4803:3;4839:60;4895:3;4803;4875:9;4871:22;4839:60;:::i;:::-;4819:18;;;4812:88;4981:3;5017:60;5073:3;5049:22;;;5017:60;:::i;:::-;4997:18;;;4990:88;5162:3;5198:60;5254:3;5230:22;;;5198:60;:::i;:::-;5178:18;;;5171:88;5318:3;5354:58;5408:3;5384:22;;;5354:58;:::i;:::-;5334:18;;;5327:86;5338:5;12382:214;-1:-1;;;12382:214::o;12603:324::-;;12748:3;;12736:9;12727:7;12723:23;12719:33;12716:2;;;-1:-1;;12755:12;12716:2;5637:22;12748:3;5637:22;:::i;:::-;5628:31;;5783:22;7636:13;5733:16;5726:86;5879:2;5948:9;5944:22;7636:13;5879:2;5898:5;5894:16;5887:86;6039:2;6108:9;6104:22;7636:13;6039:2;6058:5;6054:16;6047:86;6207:2;6276:9;6272:22;7636:13;6207:2;6226:5;6222:16;6215:86;6375:3;6445:9;6441:22;7636:13;6375:3;6395:5;6391:16;6384:86;6537:3;6607:9;6603:22;7636:13;6537:3;6557:5;6553:16;6546:86;6698:3;6768:9;6764:22;7636:13;6698:3;6718:5;6714:16;6707:86;6859:3;6929:9;6925:22;7636:13;6859:3;6879:5;6875:16;6868:86;7020:3;;7092:9;7088:22;7636:13;7020:3;7040:5;7036:18;7029:88;;12807:104;;;;12710:217;;;;:::o;12934:1223::-;;;;;;;;;;13162:3;13150:9;13141:7;13137:23;13133:33;13130:2;;;-1:-1;;13169:12;13130:2;13231:52;13275:7;13251:22;13231:52;:::i;:::-;13221:62;;13338:52;13382:7;13320:2;13362:9;13358:22;13338:52;:::i;:::-;13328:62;;13427:2;13470:9;13466:22;7488:20;13435:63;;13553:52;13597:7;13535:2;13577:9;13573:22;13553:52;:::i;:::-;13543:62;;13642:3;13686:9;13682:22;7488:20;13651:63;;13751:3;13792:9;13788:22;1095:20;1120:30;1144:5;1120:30;:::i;:::-;13760:60;-1:-1;13857:3;13894:22;;1095:20;1120:30;1095:20;1120:30;:::i;:::-;13866:60;-1:-1;13963:3;14000:22;;1095:20;1120:30;1095:20;1120:30;:::i;:::-;13972:60;;;;14069:3;14113:9;14109:22;7488:20;14078:63;;13124:1033;;;;;;;;;;;:::o;14164:241::-;;14268:2;14256:9;14247:7;14243:23;14239:32;14236:2;;;-1:-1;;14274:12;14236:2;-1:-1;7488:20;;14230:175;-1:-1;14230:175::o;14412:263::-;;14527:2;14515:9;14506:7;14502:23;14498:32;14495:2;;;-1:-1;;14533:12;14495:2;-1:-1;7636:13;;14489:186;-1:-1;14489:186::o;14682:946::-;;;;;;;14882:3;14870:9;14861:7;14857:23;14853:33;14850:2;;;-1:-1;;14889:12;14850:2;7642:6;7636:13;14941:74;;15052:2;15106:9;15102:22;7636:13;15060:74;;15171:2;15225:9;15221:22;7636:13;15179:74;;15290:2;15344:9;15340:22;7636:13;15298:74;;15409:3;15464:9;15460:22;7636:13;15418:74;;15529:3;15584:9;15580:22;7636:13;15538:74;;14844:784;;;;;;;;:::o;15635:1492::-;;;;;;;;;;;15902:3;15890:9;15881:7;15877:23;15873:33;15870:2;;;-1:-1;;15909:12;15870:2;7642:6;7636:13;15961:74;;16072:2;16126:9;16122:22;7636:13;16080:74;;16191:2;16245:9;16241:22;7636:13;16199:74;;16310:2;16364:9;16360:22;7636:13;16318:74;;16429:3;16484:9;16480:22;7636:13;16438:74;;16549:3;16604:9;16600:22;7636:13;16558:74;;16669:3;16724:9;16720:22;7636:13;16678:74;;16789:3;16844:9;16840:22;7636:13;16798:74;;16909:3;16964:9;16960:22;7636:13;16918:74;;17048:63;17103:7;17029:3;17083:9;17079:22;17048:63;:::i;:::-;17038:73;;15864:1263;;;;;;;;;;;;;:::o;17134:259::-;;17247:2;17235:9;17226:7;17222:23;17218:32;17215:2;;;-1:-1;;17253:12;17215:2;17315:62;17369:7;17345:22;17315:62;:::i;17843:690::-;;18036:5;41755:12;42299:6;42294:3;42287:19;42336:4;;42331:3;42327:14;18048:93;;42336:4;18212:5;41609:14;-1:-1;18251:260;18276:6;18273:1;18270:13;18251:260;;;18337:13;;-1:-1;;;;;43524:54;17643:37;;17554:14;;;;42142;;;;43324:34;18291:9;18251:260;;;-1:-1;18517:10;;17967:566;-1:-1;;;;;17967:566::o;20137:347::-;;20282:5;41755:12;42299:6;42294:3;42287:19;20376:52;20421:6;42336:4;42331:3;42327:14;42336:4;20402:5;20398:16;20376:52;:::i;:::-;41404:9;45466:14;-1:-1;;45462:28;20440:39;;;;42336:4;20440:39;;20229:255;-1:-1;;20229:255::o;24807:271::-;;18812:5;41755:12;18923:52;18968:6;18963:3;18956:4;18949:5;18945:16;18923:52;:::i;:::-;18987:16;;;;;24941:137;-1:-1;;24941:137::o;25085:222::-;-1:-1;;;;;43524:54;;;;17643:37;;25212:2;25197:18;;25183:124::o;25314:333::-;-1:-1;;;;;43524:54;;;17643:37;;43524:54;;25633:2;25618:18;;17643:37;25469:2;25454:18;;25440:207::o;25654:1068::-;-1:-1;;;;;43524:54;;;17643:37;;43524:54;;;26150:2;26135:18;;17643:37;43524:54;;;26233:2;26218:18;;17643:37;43524:54;;;26316:2;26301:18;;17643:37;43524:54;;26399:3;26384:19;;17643:37;42844:13;;42837:21;43535:42;26462:19;;18606:34;42844:13;;42837:21;26555:3;26540:19;;18606:34;25985:3;26593;26578:19;;26571:49;;;25654:1068;;26634:78;25970:19;;;26698:6;26634:78;:::i;26729:349::-;-1:-1;;;;;43524:54;;;;17643:37;;27064:2;27049:18;;19585:58;26892:2;26877:18;;26863:215::o;27425:444::-;-1:-1;;;;;43524:54;;;17643:37;;27772:2;27757:18;;24758:37;;;;43524:54;;;27855:2;27840:18;;17643:37;27608:2;27593:18;;27579:290::o;27876:552::-;-1:-1;;;;;43524:54;;;17643:37;;28250:2;28235:18;;24758:37;;;;43524:54;;28333:2;28318:18;;17643:37;43443:6;43432:18;;;28414:2;28399:18;;24639:36;28085:3;28070:19;;28056:372::o;28435:680::-;-1:-1;;;;;43524:54;;;17643:37;;28845:2;28830:18;;24758:37;;;;28936:2;28921:18;;19585:58;;;;43443:6;43432:18;29017:2;29002:18;;24639:36;43524:54;;;29100:3;29085:19;;17643:37;28680:3;28665:19;;28651:464::o;29122:556::-;-1:-1;;;;;43524:54;;;17643:37;;29498:2;29483:18;;24758:37;;;;29581:2;29566:18;;24758:37;;;;43524:54;;;29664:2;29649:18;;17643:37;29333:3;29318:19;;29304:374::o;29685:592::-;;29918:2;29939:17;29932:47;29993:108;29918:2;29907:9;29903:18;30087:6;29993:108;:::i;:::-;30180:2;30165:18;;24758:37;;;;-1:-1;;;;;;43524:54;;;;30263:2;30248:18;;;17643:37;29985:116;29889:388;-1:-1;29889:388::o;30284:210::-;42844:13;;42837:21;18606:34;;30405:2;30390:18;;30376:118::o;31280:330::-;;31437:2;31458:17;31451:47;42299:6;31437:2;31426:9;31422:18;42287:19;45049:6;45044:3;42327:14;31426:9;42327:14;45026:30;45087:16;;;42327:14;45087:16;;;45080:27;;;;41404:9;45466:14;;;-1:-1;;45462:28;20084:39;;;31408:202;-1:-1;31408:202::o;31617:310::-;;31764:2;31785:17;31778:47;31839:78;31764:2;31753:9;31749:18;31903:6;31839:78;:::i;31934:416::-;32134:2;32148:47;;;20716:2;32119:18;;;42287:19;-1:-1;;;42327:14;;;20732:34;20785:12;;;32105:245::o;32357:416::-;32557:2;32571:47;;;21036:1;32542:18;;;42287:19;-1:-1;;;42327:14;;;21051:28;21098:12;;;32528:245::o;32780:416::-;32980:2;32994:47;;;21349:2;32965:18;;;42287:19;21385:29;42327:14;;;21365:50;21434:12;;;32951:245::o;33203:416::-;33403:2;33417:47;;;21685:2;33388:18;;;42287:19;21721:30;42327:14;;;21701:51;21771:12;;;33374:245::o;33626:416::-;33826:2;33840:47;;;22022:2;33811:18;;;42287:19;22058:34;42327:14;;;22038:55;-1:-1;;;22113:12;;;22106:25;22150:12;;;33797:245::o;34049:416::-;34249:2;34263:47;;;22401:1;34234:18;;;42287:19;-1:-1;;;42327:14;;;22416:29;22464:12;;;34220:245::o;34472:416::-;34672:2;34686:47;;;22715:1;34657:18;;;42287:19;-1:-1;;;42327:14;;;22730:30;22779:12;;;34643:245::o;34895:416::-;35095:2;35109:47;;;23030:2;35080:18;;;42287:19;23066:31;42327:14;;;23046:52;23117:12;;;35066:245::o;35318:416::-;35518:2;35532:47;;;23368:2;35503:18;;;42287:19;-1:-1;;;42327:14;;;23384:34;23437:12;;;35489:245::o;35741:416::-;35941:2;35955:47;;;23688:2;35926:18;;;42287:19;23724:34;42327:14;;;23704:55;-1:-1;;;23779:12;;;23772:34;23825:12;;;35912:245::o;36164:416::-;36364:2;36378:47;;;24076:2;36349:18;;;42287:19;-1:-1;;;42327:14;;;24092:33;24144:12;;;36335:245::o;36587:416::-;36787:2;36801:47;;;24395:2;36772:18;;;42287:19;24431:34;42327:14;;;24411:55;-1:-1;;;24486:12;;;24479:46;24544:12;;;36758:245::o;37010:218::-;43443:6;43432:18;;;;24639:36;;37135:2;37120:18;;37106:122::o;37235:222::-;24758:37;;;37362:2;37347:18;;37333:124::o;37464:444::-;24758:37;;;-1:-1;;;;;43524:54;;;;37811:2;37796:18;;17643:37;37894:2;37879:18;;24758:37;37647:2;37632:18;;37618:290::o;37915:832::-;;24788:5;24765:3;24758:37;44808:24;38385:2;38374:9;38370:18;19585:58;38212:3;38422:2;38411:9;38407:18;38400:48;38462:108;38212:3;38201:9;38197:19;38556:6;38462:108;:::i;:::-;-1:-1;;;;;43524:54;;;;38649:2;38634:18;;17643:37;-1:-1;38732:3;38717:19;24758:37;38454:116;38183:564;-1:-1;;;38183:564::o;39577:444::-;24758:37;;;39924:2;39909:18;;24758:37;;;;40007:2;39992:18;;24758:37;39760:2;39745:18;;39731:290::o;40028:556::-;24758:37;;;40404:2;40389:18;;24758:37;;;;40487:2;40472:18;;24758:37;40570:2;40555:18;;24758:37;40239:3;40224:19;;40210:374::o;40591:256::-;40653:2;40647:9;40679:17;;;40754:18;40739:34;;40775:22;;;40736:62;40733:2;;;40811:1;;40801:12;40733:2;40653;40820:22;40631:216;;-1:-1;40631:216::o;40854:304::-;;41013:18;41005:6;41002:30;40999:2;;;-1:-1;;41035:12;40999:2;-1:-1;41080:4;41068:17;;;41133:15;;40936:222::o;45122:268::-;45187:1;45194:101;45208:6;45205:1;45202:13;45194:101;;;45275:11;;;45269:18;45256:11;;;45249:39;45230:2;45223:10;45194:101;;;45310:6;45307:1;45304:13;45301:2;;;-1:-1;;45187:1;45357:16;;45350:27;45171:219::o;45503:117::-;-1:-1;;;;;43524:54;;45562:35;;45552:2;;45611:1;;45601:12;45627:111;45708:5;42844:13;42837:21;45686:5;45683:32;45673:2;;45729:1;;45719:12

Swarm Source

ipfs://460c7cd5f0aeda40e31c72f4074859c1262fb4a2a9ad221809da26623a4c1b8d
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.