ETH Price: $3,071.04 (-3.48%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
FeederPool

Compiler Version
v0.8.2+commit.661d1103

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, GNU AGPLv3 license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2021-07-11
*/

pragma solidity 0.8.2;


struct BassetPersonal {
    // Address of the bAsset
    address addr;
    // Address of the bAsset
    address integrator;
    // An ERC20 can charge transfer fee, for example USDT, DGX tokens.
    bool hasTxFee; // takes a byte in storage
    // Status of the bAsset
    BassetStatus status;
}

struct BassetData {
    // 1 Basset * ratio / ratioScale == x Masset (relative value)
    // If ratio == 10e8 then 1 bAsset = 10 mAssets
    // A ratio is divised as 10^(18-tokenDecimals) * measurementMultiple(relative value of 1 base unit)
    uint128 ratio;
    // Amount of the Basset that is held in Collateral
    uint128 vaultBalance;
}

abstract contract IMasset {
    // Mint
    function mint(
        address _input,
        uint256 _inputQuantity,
        uint256 _minOutputQuantity,
        address _recipient
    ) external virtual returns (uint256 mintOutput);

    function mintMulti(
        address[] calldata _inputs,
        uint256[] calldata _inputQuantities,
        uint256 _minOutputQuantity,
        address _recipient
    ) external virtual returns (uint256 mintOutput);

    function getMintOutput(address _input, uint256 _inputQuantity)
        external
        view
        virtual
        returns (uint256 mintOutput);

    function getMintMultiOutput(address[] calldata _inputs, uint256[] calldata _inputQuantities)
        external
        view
        virtual
        returns (uint256 mintOutput);

    // Swaps
    function swap(
        address _input,
        address _output,
        uint256 _inputQuantity,
        uint256 _minOutputQuantity,
        address _recipient
    ) external virtual returns (uint256 swapOutput);

    function getSwapOutput(
        address _input,
        address _output,
        uint256 _inputQuantity
    ) external view virtual returns (uint256 swapOutput);

    // Redemption
    function redeem(
        address _output,
        uint256 _mAssetQuantity,
        uint256 _minOutputQuantity,
        address _recipient
    ) external virtual returns (uint256 outputQuantity);

    function redeemMasset(
        uint256 _mAssetQuantity,
        uint256[] calldata _minOutputQuantities,
        address _recipient
    ) external virtual returns (uint256[] memory outputQuantities);

    function redeemExactBassets(
        address[] calldata _outputs,
        uint256[] calldata _outputQuantities,
        uint256 _maxMassetQuantity,
        address _recipient
    ) external virtual returns (uint256 mAssetRedeemed);

    function getRedeemOutput(address _output, uint256 _mAssetQuantity)
        external
        view
        virtual
        returns (uint256 bAssetOutput);

    function getRedeemExactBassetsOutput(
        address[] calldata _outputs,
        uint256[] calldata _outputQuantities
    ) external view virtual returns (uint256 mAssetAmount);

    // Views
    function getBasket() external view virtual returns (bool, bool);

    function getBasset(address _token)
        external
        view
        virtual
        returns (BassetPersonal memory personal, BassetData memory data);

    function getBassets()
        external
        view
        virtual
        returns (BassetPersonal[] memory personal, BassetData[] memory data);

    function bAssetIndexes(address) external view virtual returns (uint8);

    function getPrice() external view virtual returns (uint256 price, uint256 k);

    // SavingsManager
    function collectInterest() external virtual returns (uint256 swapFeesGained, uint256 newSupply);

    function collectPlatformInterest()
        external
        virtual
        returns (uint256 mintAmount, uint256 newSupply);

    // Admin
    function setCacheSize(uint256 _cacheSize) external virtual;

    function setFees(uint256 _swapFee, uint256 _redemptionFee) external virtual;

    function setTransferFeesFlag(address _bAsset, bool _flag) external virtual;

    function migrateBassets(address[] calldata _bAssets, address _newIntegration) external virtual;
}

// Status of the Basset - has it broken its peg?
enum BassetStatus {
    Default,
    Normal,
    BrokenBelowPeg,
    BrokenAbovePeg,
    Blacklisted,
    Liquidating,
    Liquidated,
    Failed
}

struct BasketState {
    bool undergoingRecol;
    bool failed;
}

struct FeederConfig {
    uint256 supply;
    uint256 a;
    WeightLimits limits;
}

struct InvariantConfig {
    uint256 supply;
    uint256 a;
    WeightLimits limits;
    uint256 recolFee;
}

struct BasicConfig {
    uint256 a;
    WeightLimits limits;
}

struct WeightLimits {
    uint128 min;
    uint128 max;
}

struct AmpData {
    uint64 initialA;
    uint64 targetA;
    uint64 rampStartTime;
    uint64 rampEndTime;
}

struct FeederData {
    uint256 swapFee;
    uint256 redemptionFee;
    uint256 govFee;
    uint256 pendingFees;
    uint256 cacheSize;
    BassetPersonal[] bAssetPersonal;
    BassetData[] bAssetData;
    AmpData ampData;
    WeightLimits weightLimits;
}

struct MassetData {
    uint256 swapFee;
    uint256 redemptionFee;
    uint256 cacheSize;
    uint256 surplus;
    BassetPersonal[] bAssetPersonal;
    BassetData[] bAssetData;
    BasketState basket;
    AmpData ampData;
    WeightLimits weightLimits;
}

struct AssetData {
    uint8 idx;
    uint256 amt;
    BassetPersonal personal;
}

struct Asset {
    uint8 idx;
    address addr;
    bool exists;
}

abstract contract IFeederPool {
    // Mint
    function mint(
        address _input,
        uint256 _inputQuantity,
        uint256 _minOutputQuantity,
        address _recipient
    ) external virtual returns (uint256 mintOutput);

    function mintMulti(
        address[] calldata _inputs,
        uint256[] calldata _inputQuantities,
        uint256 _minOutputQuantity,
        address _recipient
    ) external virtual returns (uint256 mintOutput);

    function getMintOutput(address _input, uint256 _inputQuantity)
        external
        view
        virtual
        returns (uint256 mintOutput);

    function getMintMultiOutput(address[] calldata _inputs, uint256[] calldata _inputQuantities)
        external
        view
        virtual
        returns (uint256 mintOutput);

    // Swaps
    function swap(
        address _input,
        address _output,
        uint256 _inputQuantity,
        uint256 _minOutputQuantity,
        address _recipient
    ) external virtual returns (uint256 swapOutput);

    function getSwapOutput(
        address _input,
        address _output,
        uint256 _inputQuantity
    ) external view virtual returns (uint256 swapOutput);

    // Redemption
    function redeem(
        address _output,
        uint256 _fpTokenQuantity,
        uint256 _minOutputQuantity,
        address _recipient
    ) external virtual returns (uint256 outputQuantity);

    function redeemProportionately(
        uint256 _fpTokenQuantity,
        uint256[] calldata _minOutputQuantities,
        address _recipient
    ) external virtual returns (uint256[] memory outputQuantities);

    function redeemExactBassets(
        address[] calldata _outputs,
        uint256[] calldata _outputQuantities,
        uint256 _maxMassetQuantity,
        address _recipient
    ) external virtual returns (uint256 mAssetRedeemed);

    function getRedeemOutput(address _output, uint256 _fpTokenQuantity)
        external
        view
        virtual
        returns (uint256 bAssetOutput);

    function getRedeemExactBassetsOutput(
        address[] calldata _outputs,
        uint256[] calldata _outputQuantities
    ) external view virtual returns (uint256 mAssetAmount);

    // Views
    function mAsset() external view virtual returns (address);

    function getPrice() public view virtual returns (uint256 price, uint256 k);

    function getConfig() external view virtual returns (FeederConfig memory config);

    function getBasset(address _token)
        external
        view
        virtual
        returns (BassetPersonal memory personal, BassetData memory data);

    function getBassets()
        external
        view
        virtual
        returns (BassetPersonal[] memory personal, BassetData[] memory data);

    // SavingsManager
    function collectPlatformInterest()
        external
        virtual
        returns (uint256 mintAmount, uint256 newSupply);

    function collectPendingFees() external virtual;
}

/**
 * @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) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 0;
    }

    /**
     * @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");
        require(isContract(target), "Address: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{ value: value }(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.staticcall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
        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);
            }
        }
    }
}

abstract contract Initializable {

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

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

    /**
     * @dev Modifier to protect an initializer function from being invoked twice.
     */
    modifier initializer() {
        require(_initializing || !_initialized, "Initializable: contract is already initialized");

        bool isTopLevelCall = !_initializing;
        if (isTopLevelCall) {
            _initializing = true;
            _initialized = true;
        }

        _;

        if (isTopLevelCall) {
            _initializing = false;
        }
    }
}

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

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

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

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);
}

contract ERC205 is Context, IERC20 {
    mapping (address => uint256) private _balances;

    mapping (address => mapping (address => uint256)) private _allowances;

    uint256 private _totalSupply;

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual override returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `recipient` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
        _transfer(_msgSender(), recipient, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        _approve(_msgSender(), spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * Requirements:
     *
     * - `sender` and `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     * - the caller must have allowance for ``sender``'s tokens of at least
     * `amount`.
     */
    function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
        _transfer(sender, recipient, amount);

        uint256 currentAllowance = _allowances[sender][_msgSender()];
        require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
        _approve(sender, _msgSender(), currentAllowance - amount);

        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        uint256 currentAllowance = _allowances[_msgSender()][spender];
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        _approve(_msgSender(), spender, currentAllowance - subtractedValue);

        return true;
    }

    /**
     * @dev Moves tokens `amount` from `sender` to `recipient`.
     *
     * This is internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `sender` cannot be the zero address.
     * - `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     */
    function _transfer(address sender, address recipient, uint256 amount) internal virtual {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");

        uint256 senderBalance = _balances[sender];
        require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
        _balances[sender] = senderBalance - amount;
        _balances[recipient] += amount;

        emit Transfer(sender, recipient, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        _totalSupply += amount;
        _balances[account] += amount;
        emit Transfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        _balances[account] = accountBalance - amount;
        _totalSupply -= amount;

        emit Transfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(address owner, address spender, uint256 amount) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }
}

abstract contract InitializableERC20Detailed is IERC20 {
    string private _name;
    string private _symbol;
    uint8 private _decimals;

    /**
     * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of
     * these values are immutable: they can only be set once during
     * construction.
     * @notice To avoid variable shadowing appended `Arg` after arguments name.
     */
    function _initialize(
        string memory nameArg,
        string memory symbolArg,
        uint8 decimalsArg
    ) internal {
        _name = nameArg;
        _symbol = symbolArg;
        _decimals = decimalsArg;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5,05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei.
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view returns (uint8) {
        return _decimals;
    }
}

abstract contract InitializableToken is ERC205, InitializableERC20Detailed {
    /**
     * @dev Initialization function for implementing contract
     * @notice To avoid variable shadowing appended `Arg` after arguments name.
     */
    function _initialize(string memory _nameArg, string memory _symbolArg) internal {
        InitializableERC20Detailed._initialize(_nameArg, _symbolArg, 18);
    }
}

contract ModuleKeys {
    // Governance
    // ===========
    // keccak256("Governance");
    bytes32 internal constant KEY_GOVERNANCE =
        0x9409903de1e6fd852dfc61c9dacb48196c48535b60e25abf92acc92dd689078d;
    //keccak256("Staking");
    bytes32 internal constant KEY_STAKING =
        0x1df41cd916959d1163dc8f0671a666ea8a3e434c13e40faef527133b5d167034;
    //keccak256("ProxyAdmin");
    bytes32 internal constant KEY_PROXY_ADMIN =
        0x96ed0203eb7e975a4cbcaa23951943fa35c5d8288117d50c12b3d48b0fab48d1;

    // mStable
    // =======
    // keccak256("OracleHub");
    bytes32 internal constant KEY_ORACLE_HUB =
        0x8ae3a082c61a7379e2280f3356a5131507d9829d222d853bfa7c9fe1200dd040;
    // keccak256("Manager");
    bytes32 internal constant KEY_MANAGER =
        0x6d439300980e333f0256d64be2c9f67e86f4493ce25f82498d6db7f4be3d9e6f;
    //keccak256("Recollateraliser");
    bytes32 internal constant KEY_RECOLLATERALISER =
        0x39e3ed1fc335ce346a8cbe3e64dd525cf22b37f1e2104a755e761c3c1eb4734f;
    //keccak256("MetaToken");
    bytes32 internal constant KEY_META_TOKEN =
        0xea7469b14936af748ee93c53b2fe510b9928edbdccac3963321efca7eb1a57a2;
    // keccak256("SavingsManager");
    bytes32 internal constant KEY_SAVINGS_MANAGER =
        0x12fe936c77a1e196473c4314f3bed8eeac1d757b319abb85bdda70df35511bf1;
    // keccak256("Liquidator");
    bytes32 internal constant KEY_LIQUIDATOR =
        0x1e9cb14d7560734a61fa5ff9273953e971ff3cd9283c03d8346e3264617933d4;
    // keccak256("InterestValidator");
    bytes32 internal constant KEY_INTEREST_VALIDATOR =
        0xc10a28f028c7f7282a03c90608e38a4a646e136e614e4b07d119280c5f7f839f;
}

interface INexus {
    function governor() external view returns (address);

    function getModule(bytes32 key) external view returns (address);

    function proposeModule(bytes32 _key, address _addr) external;

    function cancelProposedModule(bytes32 _key) external;

    function acceptProposedModule(bytes32 _key) external;

    function acceptProposedModules(bytes32[] calldata _keys) external;

    function requestLockModule(bytes32 _key) external;

    function cancelLockModule(bytes32 _key) external;

    function lockModule(bytes32 _key) external;
}

abstract contract ImmutableModule is ModuleKeys {
    INexus public immutable nexus;

    /**
     * @dev Initialization function for upgradable proxy contracts
     * @param _nexus Nexus contract address
     */
    constructor(address _nexus) {
        require(_nexus != address(0), "Nexus address is zero");
        nexus = INexus(_nexus);
    }

    /**
     * @dev Modifier to allow function calls only from the Governor.
     */
    modifier onlyGovernor() {
        _onlyGovernor();
        _;
    }

    function _onlyGovernor() internal view {
        require(msg.sender == _governor(), "Only governor can execute");
    }

    /**
     * @dev Modifier to allow function calls only from the Governance.
     *      Governance is either Governor address or Governance address.
     */
    modifier onlyGovernance() {
        require(
            msg.sender == _governor() || msg.sender == _governance(),
            "Only governance can execute"
        );
        _;
    }

    /**
     * @dev Returns Governor address from the Nexus
     * @return Address of Governor Contract
     */
    function _governor() internal view returns (address) {
        return nexus.governor();
    }

    /**
     * @dev Returns Governance Module address from the Nexus
     * @return Address of the Governance (Phase 2)
     */
    function _governance() internal view returns (address) {
        return nexus.getModule(KEY_GOVERNANCE);
    }

    /**
     * @dev Return SavingsManager Module address from the Nexus
     * @return Address of the SavingsManager Module contract
     */
    function _savingsManager() internal view returns (address) {
        return nexus.getModule(KEY_SAVINGS_MANAGER);
    }

    /**
     * @dev Return Recollateraliser Module address from the Nexus
     * @return  Address of the Recollateraliser Module contract (Phase 2)
     */
    function _recollateraliser() internal view returns (address) {
        return nexus.getModule(KEY_RECOLLATERALISER);
    }

    /**
     * @dev Return Recollateraliser Module address from the Nexus
     * @return  Address of the Recollateraliser Module contract (Phase 2)
     */
    function _liquidator() internal view returns (address) {
        return nexus.getModule(KEY_LIQUIDATOR);
    }

    /**
     * @dev Return ProxyAdmin Module address from the Nexus
     * @return Address of the ProxyAdmin Module contract
     */
    function _proxyAdmin() internal view returns (address) {
        return nexus.getModule(KEY_PROXY_ADMIN);
    }
}

abstract contract PausableModule is ImmutableModule {
    /**
     * @dev Emitted when the pause is triggered by Governor
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by Governor
     */
    event Unpaused(address account);

    bool internal _paused = false;

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

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

    /**
     * @dev Initializes the contract in unpaused state.
     * Hooks into the Module to give the Governor ability to pause
     * @param _nexus Nexus contract address
     */
    constructor(address _nexus) ImmutableModule(_nexus) {
        _paused = false;
    }

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

    /**
     * @dev Called by the Governor to pause, triggers stopped state.
     */
    function pause() external onlyGovernor whenNotPaused {
        _paused = true;
        emit Paused(msg.sender);
    }

    /**
     * @dev Called by Governor to unpause, returns to normal state.
     */
    function unpause() external onlyGovernor whenPaused {
        _paused = false;
        emit Unpaused(msg.sender);
    }
}

contract InitializableReentrancyGuard {
    bool private _notEntered;

    function _initializeReentrancyGuard() internal {
        // Storing an initial non-zero value makes deployment a bit more
        // expensive, but in exchange the refund on every call to nonReentrant
        // will be lower in amount. Since refunds are capped to a percetange of
        // the total transaction's gas, it is best to keep them low in cases
        // like this one, to increase the likelihood of the full refund coming
        // into effect.
        _notEntered = true;
    }

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

        // Any calls to nonReentrant after this point will fail
        _notEntered = false;

        _;

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

interface IBasicToken {
    function decimals() external view returns (uint8);
}

library SafeCast {
    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        require(value < 2**128, "SafeCast: value doesn\'t fit in 128 bits");
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        require(value < 2**64, "SafeCast: value doesn\'t fit in 64 bits");
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        require(value < 2**32, "SafeCast: value doesn\'t fit in 32 bits");
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        require(value < 2**16, "SafeCast: value doesn\'t fit in 16 bits");
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits.
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        require(value < 2**8, "SafeCast: value doesn\'t fit in 8 bits");
        return uint8(value);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        require(value >= 0, "SafeCast: value must be positive");
        return uint256(value);
    }

    /**
     * @dev Returns the downcasted int128 from int256, reverting on
     * overflow (when the input is less than smallest int128 or
     * greater than largest int128).
     *
     * Counterpart to Solidity's `int128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     *
     * _Available since v3.1._
     */
    function toInt128(int256 value) internal pure returns (int128) {
        require(value >= -2**127 && value < 2**127, "SafeCast: value doesn\'t fit in 128 bits");
        return int128(value);
    }

    /**
     * @dev Returns the downcasted int64 from int256, reverting on
     * overflow (when the input is less than smallest int64 or
     * greater than largest int64).
     *
     * Counterpart to Solidity's `int64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     *
     * _Available since v3.1._
     */
    function toInt64(int256 value) internal pure returns (int64) {
        require(value >= -2**63 && value < 2**63, "SafeCast: value doesn\'t fit in 64 bits");
        return int64(value);
    }

    /**
     * @dev Returns the downcasted int32 from int256, reverting on
     * overflow (when the input is less than smallest int32 or
     * greater than largest int32).
     *
     * Counterpart to Solidity's `int32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     *
     * _Available since v3.1._
     */
    function toInt32(int256 value) internal pure returns (int32) {
        require(value >= -2**31 && value < 2**31, "SafeCast: value doesn\'t fit in 32 bits");
        return int32(value);
    }

    /**
     * @dev Returns the downcasted int16 from int256, reverting on
     * overflow (when the input is less than smallest int16 or
     * greater than largest int16).
     *
     * Counterpart to Solidity's `int16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     *
     * _Available since v3.1._
     */
    function toInt16(int256 value) internal pure returns (int16) {
        require(value >= -2**15 && value < 2**15, "SafeCast: value doesn\'t fit in 16 bits");
        return int16(value);
    }

    /**
     * @dev Returns the downcasted int8 from int256, reverting on
     * overflow (when the input is less than smallest int8 or
     * greater than largest int8).
     *
     * Counterpart to Solidity's `int8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits.
     *
     * _Available since v3.1._
     */
    function toInt8(int256 value) internal pure returns (int8) {
        require(value >= -2**7 && value < 2**7, "SafeCast: value doesn\'t fit in 8 bits");
        return int8(value);
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        require(value < 2**255, "SafeCast: value doesn't fit in an int256");
        return int256(value);
    }
}

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */

library SafeERC20 {
    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) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _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");
        }
    }
}

library StableMath {
    /**
     * @dev Scaling unit for use in specific calculations,
     * where 1 * 10**18, or 1e18 represents a unit '1'
     */
    uint256 private constant FULL_SCALE = 1e18;

    /**
     * @dev Token Ratios are used when converting between units of bAsset, mAsset and MTA
     * Reasoning: Takes into account token decimals, and difference in base unit (i.e. grams to Troy oz for gold)
     * bAsset ratio unit for use in exact calculations,
     * where (1 bAsset unit * bAsset.ratio) / ratioScale == x mAsset unit
     */
    uint256 private constant RATIO_SCALE = 1e8;

    /**
     * @dev Provides an interface to the scaling unit
     * @return Scaling unit (1e18 or 1 * 10**18)
     */
    function getFullScale() internal pure returns (uint256) {
        return FULL_SCALE;
    }

    /**
     * @dev Provides an interface to the ratio unit
     * @return Ratio scale unit (1e8 or 1 * 10**8)
     */
    function getRatioScale() internal pure returns (uint256) {
        return RATIO_SCALE;
    }

    /**
     * @dev Scales a given integer to the power of the full scale.
     * @param x   Simple uint256 to scale
     * @return    Scaled value a to an exact number
     */
    function scaleInteger(uint256 x) internal pure returns (uint256) {
        return x * FULL_SCALE;
    }

    /***************************************
              PRECISE ARITHMETIC
    ****************************************/

    /**
     * @dev Multiplies two precise units, and then truncates by the full scale
     * @param x     Left hand input to multiplication
     * @param y     Right hand input to multiplication
     * @return      Result after multiplying the two inputs and then dividing by the shared
     *              scale unit
     */
    function mulTruncate(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulTruncateScale(x, y, FULL_SCALE);
    }

    /**
     * @dev Multiplies two precise units, and then truncates by the given scale. For example,
     * when calculating 90% of 10e18, (10e18 * 9e17) / 1e18 = (9e36) / 1e18 = 9e18
     * @param x     Left hand input to multiplication
     * @param y     Right hand input to multiplication
     * @param scale Scale unit
     * @return      Result after multiplying the two inputs and then dividing by the shared
     *              scale unit
     */
    function mulTruncateScale(
        uint256 x,
        uint256 y,
        uint256 scale
    ) internal pure returns (uint256) {
        // e.g. assume scale = fullScale
        // z = 10e18 * 9e17 = 9e36
        // return 9e36 / 1e18 = 9e18
        return (x * y) / scale;
    }

    /**
     * @dev Multiplies two precise units, and then truncates by the full scale, rounding up the result
     * @param x     Left hand input to multiplication
     * @param y     Right hand input to multiplication
     * @return      Result after multiplying the two inputs and then dividing by the shared
     *              scale unit, rounded up to the closest base unit.
     */
    function mulTruncateCeil(uint256 x, uint256 y) internal pure returns (uint256) {
        // e.g. 8e17 * 17268172638 = 138145381104e17
        uint256 scaled = x * y;
        // e.g. 138145381104e17 + 9.99...e17 = 138145381113.99...e17
        uint256 ceil = scaled + FULL_SCALE - 1;
        // e.g. 13814538111.399...e18 / 1e18 = 13814538111
        return ceil / FULL_SCALE;
    }

    /**
     * @dev Precisely divides two units, by first scaling the left hand operand. Useful
     *      for finding percentage weightings, i.e. 8e18/10e18 = 80% (or 8e17)
     * @param x     Left hand input to division
     * @param y     Right hand input to division
     * @return      Result after multiplying the left operand by the scale, and
     *              executing the division on the right hand input.
     */
    function divPrecisely(uint256 x, uint256 y) internal pure returns (uint256) {
        // e.g. 8e18 * 1e18 = 8e36
        // e.g. 8e36 / 10e18 = 8e17
        return (x * FULL_SCALE) / y;
    }

    /***************************************
                  RATIO FUNCS
    ****************************************/

    /**
     * @dev Multiplies and truncates a token ratio, essentially flooring the result
     *      i.e. How much mAsset is this bAsset worth?
     * @param x     Left hand operand to multiplication (i.e Exact quantity)
     * @param ratio bAsset ratio
     * @return c    Result after multiplying the two inputs and then dividing by the ratio scale
     */
    function mulRatioTruncate(uint256 x, uint256 ratio) internal pure returns (uint256 c) {
        return mulTruncateScale(x, ratio, RATIO_SCALE);
    }

    /**
     * @dev Multiplies and truncates a token ratio, rounding up the result
     *      i.e. How much mAsset is this bAsset worth?
     * @param x     Left hand input to multiplication (i.e Exact quantity)
     * @param ratio bAsset ratio
     * @return      Result after multiplying the two inputs and then dividing by the shared
     *              ratio scale, rounded up to the closest base unit.
     */
    function mulRatioTruncateCeil(uint256 x, uint256 ratio) internal pure returns (uint256) {
        // e.g. How much mAsset should I burn for this bAsset (x)?
        // 1e18 * 1e8 = 1e26
        uint256 scaled = x * ratio;
        // 1e26 + 9.99e7 = 100..00.999e8
        uint256 ceil = scaled + RATIO_SCALE - 1;
        // return 100..00.999e8 / 1e8 = 1e18
        return ceil / RATIO_SCALE;
    }

    /**
     * @dev Precisely divides two ratioed units, by first scaling the left hand operand
     *      i.e. How much bAsset is this mAsset worth?
     * @param x     Left hand operand in division
     * @param ratio bAsset ratio
     * @return c    Result after multiplying the left operand by the scale, and
     *              executing the division on the right hand input.
     */
    function divRatioPrecisely(uint256 x, uint256 ratio) internal pure returns (uint256 c) {
        // e.g. 1e14 * 1e8 = 1e22
        // return 1e22 / 1e12 = 1e10
        return (x * RATIO_SCALE) / ratio;
    }

    /***************************************
                    HELPERS
    ****************************************/

    /**
     * @dev Calculates minimum of two numbers
     * @param x     Left hand input
     * @param y     Right hand input
     * @return      Minimum of the two inputs
     */
    function min(uint256 x, uint256 y) internal pure returns (uint256) {
        return x > y ? y : x;
    }

    /**
     * @dev Calculated maximum of two numbers
     * @param x     Left hand input
     * @param y     Right hand input
     * @return      Maximum of the two inputs
     */
    function max(uint256 x, uint256 y) internal pure returns (uint256) {
        return x > y ? x : y;
    }

    /**
     * @dev Clamps a value to an upper bound
     * @param x           Left hand input
     * @param upperBound  Maximum possible value to return
     * @return            Input x clamped to a maximum value, upperBound
     */
    function clamp(uint256 x, uint256 upperBound) internal pure returns (uint256) {
        return x > upperBound ? upperBound : x;
    }
}

interface IPlatformIntegration {
    /**
     * @dev Deposit the given bAsset to Lending platform
     * @param _bAsset bAsset address
     * @param _amount Amount to deposit
     */
    function deposit(
        address _bAsset,
        uint256 _amount,
        bool isTokenFeeCharged
    ) external returns (uint256 quantityDeposited);

    /**
     * @dev Withdraw given bAsset from Lending platform
     */
    function withdraw(
        address _receiver,
        address _bAsset,
        uint256 _amount,
        bool _hasTxFee
    ) external;

    /**
     * @dev Withdraw given bAsset from Lending platform
     */
    function withdraw(
        address _receiver,
        address _bAsset,
        uint256 _amount,
        uint256 _totalAmount,
        bool _hasTxFee
    ) external;

    /**
     * @dev Withdraw given bAsset from the cache
     */
    function withdrawRaw(
        address _receiver,
        address _bAsset,
        uint256 _amount
    ) external;

    /**
     * @dev Returns the current balance of the given bAsset
     */
    function checkBalance(address _bAsset) external returns (uint256 balance);
}

library FeederManager {
    using SafeERC20 for IERC20;
    using StableMath for uint256;

    event BassetsMigrated(address[] bAssets, address newIntegrator);
    event StartRampA(uint256 currentA, uint256 targetA, uint256 startTime, uint256 rampEndTime);
    event StopRampA(uint256 currentA, uint256 time);

    uint256 private constant MIN_RAMP_TIME = 1 days;
    uint256 private constant MAX_A = 1e6;

    /**
     * @dev Calculates the gains accrued across all lending markets.
     * @param _bAssetPersonal   Basset personal storage array
     * @param _bAssetData       Basset data storage array
     * @return idxs             Array [0,1]
     * @return rawGains         Raw increases in vault Balance
     */
    function calculatePlatformInterest(
        BassetPersonal[] memory _bAssetPersonal,
        BassetData[] storage _bAssetData
    ) external returns (uint8[] memory idxs, uint256[] memory rawGains) {
        // Get basket details
        BassetData[] memory bAssetData_ = _bAssetData;
        uint256 count = bAssetData_.length;
        idxs = new uint8[](count);
        rawGains = new uint256[](count);
        // 1. Calculate rawGains in each bAsset, in comparison to current vault balance
        for (uint256 i = 0; i < count; i++) {
            idxs[i] = uint8(i);
            BassetPersonal memory bPersonal = _bAssetPersonal[i];
            BassetData memory bData = bAssetData_[i];
            // If there is no integration, then nothing can have accrued
            if (bPersonal.integrator == address(0)) continue;
            uint256 lending =
                IPlatformIntegration(bPersonal.integrator).checkBalance(bPersonal.addr);
            uint256 cache = 0;
            if (!bPersonal.hasTxFee) {
                cache = IERC20(bPersonal.addr).balanceOf(bPersonal.integrator);
            }
            uint256 balance = lending + cache;
            uint256 oldVaultBalance = bData.vaultBalance;
            if (balance > oldVaultBalance && bPersonal.status == BassetStatus.Normal) {
                _bAssetData[i].vaultBalance = SafeCast.toUint128(balance);
                uint256 interestDelta = balance - oldVaultBalance;
                rawGains[i] = interestDelta;
            } else {
                rawGains[i] = 0;
            }
        }
    }

    /**
     * @dev Transfers all collateral from one lending market to another - used initially
     *      to handle the migration between Aave V1 and Aave V2. Note - only supports non
     *      tx fee enabled assets. Supports going from no integration to integration, but
     *      not the other way around.
     * @param _bAssetPersonal   Basset data storage array
     * @param _bAssets          Array of basket assets to migrate
     * @param _newIntegration   Address of the new platform integration
     */
    function migrateBassets(
        BassetPersonal[] storage _bAssetPersonal,
        address[] calldata _bAssets,
        address _newIntegration
    ) external {
        uint256 len = _bAssets.length;
        require(len > 0, "Must migrate some bAssets");

        for (uint256 i = 0; i < len; i++) {
            // 1. Check that the bAsset is in the basket
            address bAsset = _bAssets[i];
            uint256 index = _getAssetIndex(_bAssetPersonal, bAsset);
            require(!_bAssetPersonal[index].hasTxFee, "A bAsset has a transfer fee");

            // 2. Withdraw everything from the old platform integration
            address oldAddress = _bAssetPersonal[index].integrator;
            require(oldAddress != _newIntegration, "Must transfer to new integrator");
            (uint256 cache, uint256 lendingBal) = (0, 0);
            if (oldAddress == address(0)) {
                cache = IERC20(bAsset).balanceOf(address(this));
            } else {
                IPlatformIntegration oldIntegration = IPlatformIntegration(oldAddress);
                cache = IERC20(bAsset).balanceOf(address(oldIntegration));
                // 2.1. Withdraw from the lending market
                lendingBal = oldIntegration.checkBalance(bAsset);
                if (lendingBal > 0) {
                    oldIntegration.withdraw(address(this), bAsset, lendingBal, false);
                }
                // 2.2. Withdraw from the cache, if any
                if (cache > 0) {
                    oldIntegration.withdrawRaw(address(this), bAsset, cache);
                }
            }
            uint256 sum = lendingBal + cache;

            // 3. Update the integration address for this bAsset
            _bAssetPersonal[index].integrator = _newIntegration;

            // 4. Deposit everything into the new
            //    This should fail if we did not receive the full amount from the platform withdrawal
            // 4.1. Deposit all bAsset
            IERC20(bAsset).safeTransfer(_newIntegration, sum);
            IPlatformIntegration newIntegration = IPlatformIntegration(_newIntegration);
            if (lendingBal > 0) {
                newIntegration.deposit(bAsset, lendingBal, false);
            }
            // 4.2. Check balances
            uint256 newLendingBal = newIntegration.checkBalance(bAsset);
            uint256 newCache = IERC20(bAsset).balanceOf(address(newIntegration));
            uint256 upperMargin = 10001e14;
            uint256 lowerMargin = 9999e14;

            require(
                newLendingBal >= lendingBal.mulTruncate(lowerMargin) &&
                    newLendingBal <= lendingBal.mulTruncate(upperMargin),
                "Must transfer full amount"
            );
            require(
                newCache >= cache.mulTruncate(lowerMargin) &&
                    newCache <= cache.mulTruncate(upperMargin),
                "Must transfer full amount"
            );
        }

        emit BassetsMigrated(_bAssets, _newIntegration);
    }

    /**
     * @dev Simply gets the asset index by looping through bAssets. Given there are only
     * ever 2 assets, should not be gas intensive.
     */
    function _getAssetIndex(BassetPersonal[] storage _bAssetPersonal, address _asset)
        internal
        view
        returns (uint8 idx)
    {
        uint256 len = _bAssetPersonal.length;
        for (uint8 i = 0; i < len; i++) {
            if (_bAssetPersonal[i].addr == _asset) return i;
        }
        revert("Invalid asset");
    }

    /**
     * @dev Starts changing of the amplification var A
     * @param _targetA      Target A value
     * @param _rampEndTime  Time at which A will arrive at _targetA
     */
    function startRampA(
        AmpData storage _ampData,
        uint256 _targetA,
        uint256 _rampEndTime,
        uint256 _currentA,
        uint256 _precision
    ) external {
        require(
            block.timestamp >= (_ampData.rampStartTime + MIN_RAMP_TIME),
            "Sufficient period of previous ramp has not elapsed"
        );
        require(_rampEndTime >= (block.timestamp + MIN_RAMP_TIME), "Ramp time too short");
        require(_targetA > 0 && _targetA < MAX_A, "A target out of bounds");

        uint256 preciseTargetA = _targetA * _precision;

        if (preciseTargetA > _currentA) {
            require(preciseTargetA <= _currentA * 10, "A target increase too big");
        } else {
            require(preciseTargetA >= _currentA / 10, "A target decrease too big");
        }

        _ampData.initialA = SafeCast.toUint64(_currentA);
        _ampData.targetA = SafeCast.toUint64(preciseTargetA);
        _ampData.rampStartTime = SafeCast.toUint64(block.timestamp);
        _ampData.rampEndTime = SafeCast.toUint64(_rampEndTime);

        emit StartRampA(_currentA, preciseTargetA, block.timestamp, _rampEndTime);
    }

    /**
     * @dev Stops the changing of the amplification var A, setting
     * it to whatever the current value is.
     */
    function stopRampA(AmpData storage _ampData, uint256 _currentA) external {
        require(block.timestamp < _ampData.rampEndTime, "Amplification not changing");

        _ampData.initialA = SafeCast.toUint64(_currentA);
        _ampData.targetA = SafeCast.toUint64(_currentA);
        _ampData.rampStartTime = SafeCast.toUint64(block.timestamp);
        _ampData.rampEndTime = SafeCast.toUint64(block.timestamp);

        emit StopRampA(_currentA, block.timestamp);
    }
}

library Root {
    /**
     * @dev Returns the square root of a given number
     * @param x Input
     * @return y Square root of Input
     */
    function sqrt(uint256 x) internal pure returns (uint256 y) {
        if (x == 0) return 0;
        else {
            uint256 xx = x;
            uint256 r = 1;
            if (xx >= 0x100000000000000000000000000000000) {
                xx >>= 128;
                r <<= 64;
            }
            if (xx >= 0x10000000000000000) {
                xx >>= 64;
                r <<= 32;
            }
            if (xx >= 0x100000000) {
                xx >>= 32;
                r <<= 16;
            }
            if (xx >= 0x10000) {
                xx >>= 16;
                r <<= 8;
            }
            if (xx >= 0x100) {
                xx >>= 8;
                r <<= 4;
            }
            if (xx >= 0x10) {
                xx >>= 4;
                r <<= 2;
            }
            if (xx >= 0x8) {
                r <<= 1;
            }
            r = (r + x / r) >> 1;
            r = (r + x / r) >> 1;
            r = (r + x / r) >> 1;
            r = (r + x / r) >> 1;
            r = (r + x / r) >> 1;
            r = (r + x / r) >> 1;
            r = (r + x / r) >> 1; // Seven iterations should be enough
            uint256 r1 = x / r;
            return uint256(r < r1 ? r : r1);
        }
    }
}

library MassetHelpers {
    using SafeERC20 for IERC20;

    function transferReturnBalance(
        address _sender,
        address _recipient,
        address _bAsset,
        uint256 _qty
    ) internal returns (uint256 receivedQty, uint256 recipientBalance) {
        uint256 balBefore = IERC20(_bAsset).balanceOf(_recipient);
        IERC20(_bAsset).safeTransferFrom(_sender, _recipient, _qty);
        recipientBalance = IERC20(_bAsset).balanceOf(_recipient);
        receivedQty = recipientBalance - balBefore;
    }

    function safeInfiniteApprove(address _asset, address _spender) internal {
        IERC20(_asset).safeApprove(_spender, 0);
        IERC20(_asset).safeApprove(_spender, 2**256 - 1);
    }
}

library FeederLogic {
    using StableMath for uint256;
    using SafeERC20 for IERC20;

    uint256 internal constant A_PRECISION = 100;

    /***************************************
                    MINT
    ****************************************/

    /**
     * @notice Transfers token in, updates internal balances and computes the fpToken output
     * @param _data                 Feeder pool storage state
     * @param _config               Core config for use in the invariant validator
     * @param _input                Data on the bAsset to deposit for the minted fpToken.
     * @param _inputQuantity        Quantity in input token units.
     * @param _minOutputQuantity    Minimum fpToken quantity to be minted. This protects against slippage.
     * @return mintOutput           Quantity of fpToken minted from the deposited bAsset.
     */
    function mint(
        FeederData storage _data,
        FeederConfig calldata _config,
        Asset calldata _input,
        uint256 _inputQuantity,
        uint256 _minOutputQuantity
    ) external returns (uint256 mintOutput) {
        BassetData[] memory cachedBassetData = _data.bAssetData;
        AssetData memory inputData =
            _transferIn(_data, _config, cachedBassetData, _input, _inputQuantity);
        // Validation should be after token transfer, as real input amt is unknown before
        mintOutput = computeMint(cachedBassetData, inputData.idx, inputData.amt, _config);
        require(mintOutput >= _minOutputQuantity, "Mint quantity < min qty");
    }

    /**
     * @notice Transfers tokens in, updates internal balances and computes the fpToken output.
     * Only fAsset & mAsset are supported in this path.
     * @param _data                 Feeder pool storage state
     * @param _config               Core config for use in the invariant validator
     * @param _indices              Non-duplicate addresses of the bAssets to deposit for the minted fpToken.
     * @param _inputQuantities      Quantity of each input in input token units.
     * @param _minOutputQuantity    Minimum fpToken quantity to be minted. This protects against slippage.
     * @return mintOutput           Quantity of fpToken minted from the deposited bAsset.
     */
    function mintMulti(
        FeederData storage _data,
        FeederConfig calldata _config,
        uint8[] calldata _indices,
        uint256[] calldata _inputQuantities,
        uint256 _minOutputQuantity
    ) external returns (uint256 mintOutput) {
        uint256 len = _indices.length;
        uint256[] memory quantitiesDeposited = new uint256[](len);
        // Load bAssets from storage into memory
        BassetData[] memory allBassets = _data.bAssetData;
        uint256 maxCache = _getCacheDetails(_data, _config.supply);
        // Transfer the Bassets to the integrator & update storage
        for (uint256 i = 0; i < len; i++) {
            if (_inputQuantities[i] > 0) {
                uint8 idx = _indices[i];
                BassetData memory bData = allBassets[idx];
                quantitiesDeposited[i] = _depositTokens(
                    _data.bAssetPersonal[idx],
                    bData.ratio,
                    _inputQuantities[i],
                    maxCache
                );

                _data.bAssetData[idx].vaultBalance =
                    bData.vaultBalance +
                    SafeCast.toUint128(quantitiesDeposited[i]);
            }
        }
        // Validate the proposed mint, after token transfer
        mintOutput = computeMintMulti(allBassets, _indices, quantitiesDeposited, _config);
        require(mintOutput >= _minOutputQuantity, "Mint quantity < min qty");
        require(mintOutput > 0, "Zero mAsset quantity");
    }

    /***************************************
                    SWAP
    ****************************************/

    /**
     * @notice Swaps two assets - either internally between fAsset<>mAsset, or between fAsset<>mpAsset by
     * first routing through the mAsset pool.
     * @param _data              Feeder pool storage state
     * @param _config            Core config for use in the invariant validator
     * @param _input             Data on bAsset to deposit
     * @param _output            Data on bAsset to withdraw
     * @param _inputQuantity     Units of input bAsset to swap in
     * @param _minOutputQuantity Minimum quantity of the swap output asset. This protects against slippage
     * @param _recipient         Address to transfer output asset to
     * @return swapOutput        Quantity of output asset returned from swap
     * @return localFee          Fee paid, in fpToken terms
     */
    function swap(
        FeederData storage _data,
        FeederConfig calldata _config,
        Asset calldata _input,
        Asset calldata _output,
        uint256 _inputQuantity,
        uint256 _minOutputQuantity,
        address _recipient
    ) external returns (uint256 swapOutput, uint256 localFee) {
        BassetData[] memory cachedBassetData = _data.bAssetData;

        AssetData memory inputData =
            _transferIn(_data, _config, cachedBassetData, _input, _inputQuantity);
        // 1. [f/mAsset ->][ f/mAsset]               : Y - normal in, SWAP, normal out
        // 3. [mpAsset -> mAsset][ -> fAsset]        : Y - mint in  , SWAP, normal out
        if (_output.exists) {
            (swapOutput, localFee) = _swapLocal(
                _data,
                _config,
                cachedBassetData,
                inputData,
                _output,
                _minOutputQuantity,
                _recipient
            );
        }
        // 2. [fAsset ->][ mAsset][ -> mpAsset]      : Y - normal in, SWAP, mpOut
        else {
            address mAsset = _data.bAssetPersonal[0].addr;
            (swapOutput, localFee) = _swapLocal(
                _data,
                _config,
                cachedBassetData,
                inputData,
                Asset(0, mAsset, true),
                0,
                address(this)
            );
            swapOutput = IMasset(mAsset).redeem(
                _output.addr,
                swapOutput,
                _minOutputQuantity,
                _recipient
            );
        }
    }

    /***************************************
                    REDEEM
    ****************************************/

    /**
     * @notice Burns a specified quantity of the senders fpToken in return for a bAsset. The output amount is derived
     * from the invariant. Supports redemption into either the fAsset, mAsset or assets in the mAsset basket.
     * @param _data              Feeder pool storage state
     * @param _config            Core config for use in the invariant validator
     * @param _output            Data on bAsset to withdraw
     * @param _fpTokenQuantity   Quantity of fpToken to burn
     * @param _minOutputQuantity Minimum bAsset quantity to receive for the burnt fpToken. This protects against slippage.
     * @param _recipient         Address to transfer the withdrawn bAssets to.
     * @return outputQuantity    Quanity of bAsset units received for the burnt fpToken
     * @return localFee          Fee paid, in fpToken terms
     */
    function redeem(
        FeederData storage _data,
        FeederConfig calldata _config,
        Asset calldata _output,
        uint256 _fpTokenQuantity,
        uint256 _minOutputQuantity,
        address _recipient
    ) external returns (uint256 outputQuantity, uint256 localFee) {
        if (_output.exists) {
            (outputQuantity, localFee) = _redeemLocal(
                _data,
                _config,
                _output,
                _fpTokenQuantity,
                _minOutputQuantity,
                _recipient
            );
        } else {
            address mAsset = _data.bAssetPersonal[0].addr;
            (outputQuantity, localFee) = _redeemLocal(
                _data,
                _config,
                Asset(0, mAsset, true),
                _fpTokenQuantity,
                0,
                address(this)
            );
            outputQuantity = IMasset(mAsset).redeem(
                _output.addr,
                outputQuantity,
                _minOutputQuantity,
                _recipient
            );
        }
    }

    /**
     * @dev Credits a recipient with a proportionate amount of bAssets, relative to current vault
     * balance levels and desired fpToken quantity. Burns the fpToken as payment. Only fAsset & mAsset are supported in this path.
     * @param _data                 Feeder pool storage state
     * @param _config               Core config for use in the invariant validator
     * @param _inputQuantity        Quantity of fpToken to redeem
     * @param _minOutputQuantities  Min units of output to receive
     * @param _recipient            Address to credit the withdrawn bAssets
     * @return scaledFee            Fee collected in fpToken terms
     * @return outputs              Array of output asset addresses
     * @return outputQuantities     Array of output asset quantities
     */
    function redeemProportionately(
        FeederData storage _data,
        FeederConfig calldata _config,
        uint256 _inputQuantity,
        uint256[] calldata _minOutputQuantities,
        address _recipient
    )
        external
        returns (
            uint256 scaledFee,
            address[] memory outputs,
            uint256[] memory outputQuantities
        )
    {
        // Calculate mAsset redemption quantities
        scaledFee = _inputQuantity.mulTruncate(_data.redemptionFee);
        // cache = (config.supply - inputQuantity) * 0.2
        uint256 maxCache = _getCacheDetails(_data, _config.supply - _inputQuantity);

        // Load the bAsset data from storage into memory
        BassetData[] memory allBassets = _data.bAssetData;
        uint256 len = allBassets.length;
        outputs = new address[](len);
        outputQuantities = new uint256[](len);
        for (uint256 i = 0; i < len; i++) {
            // Get amount out, proportionate to redemption quantity
            uint256 amountOut =
                (allBassets[i].vaultBalance * (_inputQuantity - scaledFee)) / _config.supply;
            require(amountOut > 1, "Output == 0");
            amountOut -= 1;
            require(amountOut >= _minOutputQuantities[i], "bAsset qty < min qty");
            // Set output in array
            (outputQuantities[i], outputs[i]) = (amountOut, _data.bAssetPersonal[i].addr);
            // Transfer the bAsset to the recipient
            _withdrawTokens(
                amountOut,
                _data.bAssetPersonal[i],
                allBassets[i],
                _recipient,
                maxCache
            );
            // Reduce vaultBalance
            _data.bAssetData[i].vaultBalance =
                allBassets[i].vaultBalance -
                SafeCast.toUint128(amountOut);
        }
    }

    /**
     * @dev Credits a recipient with a certain quantity of selected bAssets, in exchange for burning the
     *      relative fpToken quantity from the sender. Only fAsset & mAsset (0,1) are supported in this path.
     * @param _data                 Feeder pool storage state
     * @param _config               Core config for use in the invariant validator
     * @param _indices              Indices of the bAssets to receive
     * @param _outputQuantities     Units of the bAssets to receive
     * @param _maxInputQuantity     Maximum fpToken quantity to burn for the received bAssets. This protects against slippage.
     * @param _recipient            Address to receive the withdrawn bAssets
     * @return fpTokenQuantity      Quantity of fpToken units to burn as payment
     * @return localFee             Fee collected, in fpToken terms
     */
    function redeemExactBassets(
        FeederData storage _data,
        FeederConfig memory _config,
        uint8[] calldata _indices,
        uint256[] calldata _outputQuantities,
        uint256 _maxInputQuantity,
        address _recipient
    ) external returns (uint256 fpTokenQuantity, uint256 localFee) {
        // Load bAsset data from storage to memory
        BassetData[] memory allBassets = _data.bAssetData;

        // Validate redemption
        uint256 fpTokenRequired =
            computeRedeemExact(allBassets, _indices, _outputQuantities, _config);
        fpTokenQuantity = fpTokenRequired.divPrecisely(1e18 - _data.redemptionFee);
        localFee = fpTokenQuantity - fpTokenRequired;
        require(fpTokenQuantity > 0, "Must redeem some mAssets");
        fpTokenQuantity += 1;
        require(fpTokenQuantity <= _maxInputQuantity, "Redeem mAsset qty > max quantity");

        // Burn the full amount of Masset
        uint256 maxCache = _getCacheDetails(_data, _config.supply - fpTokenQuantity);
        // Transfer the Bassets to the recipient
        for (uint256 i = 0; i < _outputQuantities.length; i++) {
            _withdrawTokens(
                _outputQuantities[i],
                _data.bAssetPersonal[_indices[i]],
                allBassets[_indices[i]],
                _recipient,
                maxCache
            );
            _data.bAssetData[_indices[i]].vaultBalance =
                allBassets[_indices[i]].vaultBalance -
                SafeCast.toUint128(_outputQuantities[i]);
        }
    }

    /***************************************
                FORGING - INTERNAL
    ****************************************/

    /**
     * @dev Transfers an asset in and updates vault balance. Supports fAsset, mAsset and mpAsset.
     * Transferring an mpAsset requires first a mint in the main pool, and consequent depositing of
     * the mAsset.
     */
    function _transferIn(
        FeederData storage _data,
        FeederConfig memory _config,
        BassetData[] memory _cachedBassetData,
        Asset memory _input,
        uint256 _inputQuantity
    ) internal returns (AssetData memory inputData) {
        // fAsset / mAsset transfers
        if (_input.exists) {
            BassetPersonal memory personal = _data.bAssetPersonal[_input.idx];
            uint256 amt =
                _depositTokens(
                    personal,
                    _cachedBassetData[_input.idx].ratio,
                    _inputQuantity,
                    _getCacheDetails(_data, _config.supply)
                );
            inputData = AssetData(_input.idx, amt, personal);
        }
        // mpAsset transfers
        else {
            inputData = _mpMint(
                _data,
                _input,
                _inputQuantity,
                _getCacheDetails(_data, _config.supply)
            );
            require(inputData.amt > 0, "Must mint something from mp");
        }
        _data.bAssetData[inputData.idx].vaultBalance =
            _cachedBassetData[inputData.idx].vaultBalance +
            SafeCast.toUint128(inputData.amt);
    }

    /**
     * @dev Mints an asset in the main mAsset pool. Input asset must be supported by the mAsset
     * or else the call will revert. After minting, check if the balance exceeds the cache upper limit
     * and consequently deposit if necessary.
     */
    function _mpMint(
        FeederData storage _data,
        Asset memory _input,
        uint256 _inputQuantity,
        uint256 _maxCache
    ) internal returns (AssetData memory mAssetData) {
        mAssetData = AssetData(0, 0, _data.bAssetPersonal[0]);
        IERC20(_input.addr).safeTransferFrom(msg.sender, address(this), _inputQuantity);

        address integrator =
            mAssetData.personal.integrator == address(0)
                ? address(this)
                : mAssetData.personal.integrator;

        uint256 balBefore = IERC20(mAssetData.personal.addr).balanceOf(integrator);
        // Mint will revert if the _input.addr is not whitelisted on that mAsset
        IMasset(mAssetData.personal.addr).mint(_input.addr, _inputQuantity, 0, integrator);
        uint256 balAfter = IERC20(mAssetData.personal.addr).balanceOf(integrator);
        mAssetData.amt = balAfter - balBefore;

        // Route the mAsset to platform integration
        if (integrator != address(this)) {
            if (balAfter > _maxCache) {
                uint256 delta = balAfter - (_maxCache / 2);
                IPlatformIntegration(integrator).deposit(mAssetData.personal.addr, delta, false);
            }
        }
    }

    /**
     * @dev Performs a swap between fAsset and mAsset. If the output is an mAsset, do not
     * charge the swap fee.
     */
    function _swapLocal(
        FeederData storage _data,
        FeederConfig memory _config,
        BassetData[] memory _cachedBassetData,
        AssetData memory _inputData,
        Asset memory _output,
        uint256 _minOutputQuantity,
        address _recipient
    ) internal returns (uint256 swapOutput, uint256 scaledFee) {
        // Validate the swap
        (swapOutput, scaledFee) = computeSwap(
            _cachedBassetData,
            _inputData.idx,
            _output.idx,
            _inputData.amt,
            _output.idx == 0 ? 0 : _data.swapFee,
            _config
        );
        require(swapOutput >= _minOutputQuantity, "Output qty < minimum qty");
        require(swapOutput > 0, "Zero output quantity");
        // Settle the swap
        _withdrawTokens(
            swapOutput,
            _data.bAssetPersonal[_output.idx],
            _cachedBassetData[_output.idx],
            _recipient,
            _getCacheDetails(_data, _config.supply)
        );
        // Decrease output bal
        _data.bAssetData[_output.idx].vaultBalance =
            _cachedBassetData[_output.idx].vaultBalance -
            SafeCast.toUint128(swapOutput);
    }

    /**
     * @dev Performs a local redemption into either fAsset or mAsset.
     */
    function _redeemLocal(
        FeederData storage _data,
        FeederConfig memory _config,
        Asset memory _output,
        uint256 _fpTokenQuantity,
        uint256 _minOutputQuantity,
        address _recipient
    ) internal returns (uint256 outputQuantity, uint256 scaledFee) {
        BassetData[] memory allBassets = _data.bAssetData;
        // Subtract the redemption fee
        scaledFee = _fpTokenQuantity.mulTruncate(_data.redemptionFee);
        // Calculate redemption quantities
        outputQuantity = computeRedeem(
            allBassets,
            _output.idx,
            _fpTokenQuantity - scaledFee,
            _config
        );
        require(outputQuantity >= _minOutputQuantity, "bAsset qty < min qty");
        require(outputQuantity > 0, "Output == 0");

        // Transfer the bAssets to the recipient
        _withdrawTokens(
            outputQuantity,
            _data.bAssetPersonal[_output.idx],
            allBassets[_output.idx],
            _recipient,
            _getCacheDetails(_data, _config.supply - _fpTokenQuantity)
        );
        // Set vault balance
        _data.bAssetData[_output.idx].vaultBalance =
            allBassets[_output.idx].vaultBalance -
            SafeCast.toUint128(outputQuantity);
    }

    /**
     * @dev Deposits a given asset to the system. If there is sufficient room for the asset
     * in the cache, then just transfer, otherwise reset the cache to the desired mid level by
     * depositing the delta in the platform
     */
    function _depositTokens(
        BassetPersonal memory _bAsset,
        uint256 _bAssetRatio,
        uint256 _quantity,
        uint256 _maxCache
    ) internal returns (uint256 quantityDeposited) {
        // 0. If integration is 0, short circuit
        if (_bAsset.integrator == address(0)) {
            (uint256 received, ) =
                MassetHelpers.transferReturnBalance(
                    msg.sender,
                    address(this),
                    _bAsset.addr,
                    _quantity
                );
            return received;
        }

        // 1 - Send all to PI, using the opportunity to get the cache balance and net amount transferred
        uint256 cacheBal;
        (quantityDeposited, cacheBal) = MassetHelpers.transferReturnBalance(
            msg.sender,
            _bAsset.integrator,
            _bAsset.addr,
            _quantity
        );

        // 2 - Deposit X if necessary
        // 2.1 - Deposit if xfer fees
        if (_bAsset.hasTxFee) {
            uint256 deposited =
                IPlatformIntegration(_bAsset.integrator).deposit(
                    _bAsset.addr,
                    quantityDeposited,
                    true
                );

            return StableMath.min(deposited, quantityDeposited);
        }
        // 2.2 - Else Deposit X if Cache > %
        // This check is in place to ensure that any token with a txFee is rejected
        require(quantityDeposited == _quantity, "Asset not fully transferred");

        uint256 relativeMaxCache = _maxCache.divRatioPrecisely(_bAssetRatio);

        if (cacheBal > relativeMaxCache) {
            uint256 delta = cacheBal - (relativeMaxCache / 2);
            IPlatformIntegration(_bAsset.integrator).deposit(_bAsset.addr, delta, false);
        }
    }

    /**
     * @dev Withdraws a given asset from its platformIntegration. If there is sufficient liquidity
     * in the cache, then withdraw from there, otherwise withdraw from the lending market and reset the
     * cache to the mid level.
     */
    function _withdrawTokens(
        uint256 _quantity,
        BassetPersonal memory _personal,
        BassetData memory _data,
        address _recipient,
        uint256 _maxCache
    ) internal {
        if (_quantity == 0) return;

        // 1.0 If there is no integrator, send from here
        if (_personal.integrator == address(0)) {
            // If this is part of a cross-swap or cross-redeem, and there is no
            // integrator.. then we don't need to transfer anywhere
            if (_recipient == address(this)) return;
            IERC20(_personal.addr).safeTransfer(_recipient, _quantity);
        }
        // 1.1 If txFee then short circuit - there is no cache
        else if (_personal.hasTxFee) {
            IPlatformIntegration(_personal.integrator).withdraw(
                _recipient,
                _personal.addr,
                _quantity,
                _quantity,
                true
            );
        }
        // 1.2. Else, withdraw from either cache or main vault
        else {
            uint256 cacheBal = IERC20(_personal.addr).balanceOf(_personal.integrator);
            // 2.1 - If balance b in cache, simply withdraw
            if (cacheBal >= _quantity) {
                IPlatformIntegration(_personal.integrator).withdrawRaw(
                    _recipient,
                    _personal.addr,
                    _quantity
                );
            }
            // 2.2 - Else reset the cache to X, or as far as possible
            //       - Withdraw X+b from platform
            //       - Send b to user
            else {
                uint256 relativeMidCache = _maxCache.divRatioPrecisely(_data.ratio) / 2;
                uint256 totalWithdrawal =
                    StableMath.min(
                        relativeMidCache + _quantity - cacheBal,
                        _data.vaultBalance - SafeCast.toUint128(cacheBal)
                    );

                IPlatformIntegration(_personal.integrator).withdraw(
                    _recipient,
                    _personal.addr,
                    _quantity,
                    totalWithdrawal,
                    false
                );
            }
        }
    }

    /**
     * @dev Gets the max cache size, given the supply of fpToken
     * @return maxCache    Max units of any given bAsset that should be held in the cache
     */
    function _getCacheDetails(FeederData storage _data, uint256 _supply)
        internal
        view
        returns (uint256 maxCache)
    {
        maxCache = (_supply * _data.cacheSize) / 1e18;
    }

    /***************************************
                    INVARIANT
    ****************************************/

    /**
     * @notice Compute the amount of fpToken received for minting
     * with `quantity` amount of bAsset index `i`.
     * @param _bAssets      Array of all bAsset Data
     * @param _i            Index of bAsset with which to mint
     * @param _rawInput     Raw amount of bAsset to use in mint
     * @param _config       Generalised FeederConfig stored externally
     * @return mintAmount   Quantity of fpTokens minted
     */
    function computeMint(
        BassetData[] memory _bAssets,
        uint8 _i,
        uint256 _rawInput,
        FeederConfig memory _config
    ) public pure returns (uint256 mintAmount) {
        // 1. Get raw reserves
        (uint256[] memory x, uint256 sum) = _getReserves(_bAssets);
        // 2. Get value of reserves according to invariant
        uint256 k0 = _invariant(x, sum, _config.a);
        uint256 scaledInput = (_rawInput * _bAssets[_i].ratio) / 1e8;
        require(scaledInput > 1e6, "Must add > 1e6 units");
        // 3. Add deposit to x and sum
        x[_i] += scaledInput;
        sum += scaledInput;
        // 4. Finalise mint
        require(_inBounds(x, sum, _config.limits), "Exceeds weight limits");
        mintAmount = _computeMintOutput(x, sum, k0, _config);
    }

    /**
     * @notice Compute the amount of fpToken received for minting
     * with the given array of inputs.
     * @param _bAssets      Array of all bAsset Data
     * @param _indices      Indexes of bAssets with which to mint
     * @param _rawInputs    Raw amounts of bAssets to use in mint
     * @param _config       Generalised FeederConfig stored externally
     * @return mintAmount   Quantity of fpTokens minted
     */
    function computeMintMulti(
        BassetData[] memory _bAssets,
        uint8[] memory _indices,
        uint256[] memory _rawInputs,
        FeederConfig memory _config
    ) public pure returns (uint256 mintAmount) {
        // 1. Get raw reserves
        (uint256[] memory x, uint256 sum) = _getReserves(_bAssets);
        // 2. Get value of reserves according to invariant
        uint256 k0 = _invariant(x, sum, _config.a);
        // 3. Add deposits to x and sum
        uint256 len = _indices.length;
        uint8 idx;
        uint256 scaledInput;
        for (uint256 i = 0; i < len; i++) {
            idx = _indices[i];
            scaledInput = (_rawInputs[i] * _bAssets[idx].ratio) / 1e8;
            x[idx] += scaledInput;
            sum += scaledInput;
        }
        // 4. Finalise mint
        require(_inBounds(x, sum, _config.limits), "Exceeds weight limits");
        mintAmount = _computeMintOutput(x, sum, k0, _config);
    }

    /**
     * @notice Compute the amount of bAsset received for swapping
     * `quantity` amount of index `input_idx` to index `output_idx`.
     * @param _bAssets      Array of all bAsset Data
     * @param _i            Index of bAsset to swap IN
     * @param _o            Index of bAsset to swap OUT
     * @param _rawInput     Raw amounts of input bAsset to input
     * @param _feeRate      Swap fee rate to apply to output
     * @param _config       Generalised FeederConfig stored externally
     * @return bAssetOutputQuantity   Raw bAsset output quantity
     * @return scaledSwapFee          Swap fee collected, in fpToken terms
     */
    function computeSwap(
        BassetData[] memory _bAssets,
        uint8 _i,
        uint8 _o,
        uint256 _rawInput,
        uint256 _feeRate,
        FeederConfig memory _config
    ) public pure returns (uint256 bAssetOutputQuantity, uint256 scaledSwapFee) {
        // 1. Get raw reserves
        (uint256[] memory x, uint256 sum) = _getReserves(_bAssets);
        // 2. Get value of reserves according to invariant
        uint256 k0 = _invariant(x, sum, _config.a);
        // 3. Add deposits to x and sum
        uint256 scaledInput = (_rawInput * _bAssets[_i].ratio) / 1e8;
        require(scaledInput > 1e6, "Must add > 1e6 units");
        x[_i] += scaledInput;
        sum += scaledInput;
        // 4. Calc total fpToken q
        uint256 k1 = _invariant(x, sum, _config.a);
        scaledSwapFee = ((k1 - k0) * _feeRate) / 1e18;
        // 5. Calc output bAsset
        uint256 newOutputReserve = _solveInvariant(x, _config.a, _o, k0 + scaledSwapFee);
        // Convert swap fee to fpToken terms
        // fpFee = fee * s / k
        scaledSwapFee = (scaledSwapFee * _config.supply) / k0;
        uint256 output = x[_o] - newOutputReserve - 1;
        bAssetOutputQuantity = (output * 1e8) / _bAssets[_o].ratio;
        // 6. Check for bounds
        x[_o] -= output;
        sum -= output;
        require(_inBounds(x, sum, _config.limits), "Exceeds weight limits");
    }

    /**
     * @notice Compute the amount of bAsset index `i` received for
     * redeeming `quantity` amount of fpToken.
     * @param _bAssets              Array of all bAsset Data
     * @param _o                    Index of output bAsset
     * @param _netRedeemInput       Net amount of fpToken to redeem
     * @param _config               Generalised FeederConfig stored externally
     * @return rawOutputUnits       Raw bAsset output returned
     */
    function computeRedeem(
        BassetData[] memory _bAssets,
        uint8 _o,
        uint256 _netRedeemInput,
        FeederConfig memory _config
    ) public pure returns (uint256 rawOutputUnits) {
        require(_netRedeemInput > 1e6, "Must redeem > 1e6 units");
        // 1. Get raw reserves
        (uint256[] memory x, uint256 sum) = _getReserves(_bAssets);
        // 2. Get value of reserves according to invariant
        uint256 k0 = _invariant(x, sum, _config.a);
        uint256 kFinal = (k0 * (_config.supply - _netRedeemInput)) / _config.supply + 1;
        // 3. Compute bAsset output
        uint256 newOutputReserve = _solveInvariant(x, _config.a, _o, kFinal);
        uint256 output = x[_o] - newOutputReserve - 1;
        rawOutputUnits = (output * 1e8) / _bAssets[_o].ratio;
        // 4. Check for max weight
        x[_o] -= output;
        sum -= output;
        require(_inBounds(x, sum, _config.limits), "Exceeds weight limits");
    }

    /**
     * @notice Compute the amount of fpToken required to redeem
     * a given selection of bAssets.
     * @param _bAssets          Array of all bAsset Data
     * @param _indices          Indexes of output bAssets
     * @param _rawOutputs       Desired raw bAsset outputs
     * @param _config           Generalised FeederConfig stored externally
     * @return redeemInput      Amount of fpToken required to redeem bAssets
     */
    function computeRedeemExact(
        BassetData[] memory _bAssets,
        uint8[] memory _indices,
        uint256[] memory _rawOutputs,
        FeederConfig memory _config
    ) public pure returns (uint256 redeemInput) {
        // 1. Get raw reserves
        (uint256[] memory x, uint256 sum) = _getReserves(_bAssets);
        // 2. Get value of reserves according to invariant
        uint256 k0 = _invariant(x, sum, _config.a);
        // 3. Sub deposits from x and sum
        uint256 len = _indices.length;
        uint256 ratioed;
        for (uint256 i = 0; i < len; i++) {
            ratioed = (_rawOutputs[i] * _bAssets[_indices[i]].ratio) / 1e8;
            x[_indices[i]] -= ratioed;
            sum -= ratioed;
        }
        require(_inBounds(x, sum, _config.limits), "Exceeds weight limits");
        // 4. Get new value of reserves according to invariant
        uint256 k1 = _invariant(x, sum, _config.a);
        // 5. Total fpToken is the difference between values
        redeemInput = (_config.supply * (k0 - k1)) / k0;
        require(redeemInput > 1e6, "Must redeem > 1e6 units");
    }

    /**
     * @notice Gets the price of the fpToken, and invariant value k
     * @param _bAssets  Array of all bAsset Data
     * @param _config   Generalised FeederConfig stored externally
     * @return price    Price of an fpToken
     * @return k        Total value of basket, k
     */
    function computePrice(BassetData[] memory _bAssets, FeederConfig memory _config)
        public
        pure
        returns (uint256 price, uint256 k)
    {
        (uint256[] memory x, uint256 sum) = _getReserves(_bAssets);
        k = _invariant(x, sum, _config.a);
        price = (1e18 * k) / _config.supply;
    }

    /***************************************
                    INTERNAL
    ****************************************/

    /**
     * @dev Computes the actual mint output after adding mint inputs
     * to the vault balances
     * @param _x            Scaled vaultBalances
     * @param _sum          Sum of vaultBalances, to avoid another loop
     * @param _k            Previous value of invariant, k, before addition
     * @param _config       Generalised FeederConfig stored externally
     * @return mintAmount   Amount of value added to invariant, in fpToken terms
     */
    function _computeMintOutput(
        uint256[] memory _x,
        uint256 _sum,
        uint256 _k,
        FeederConfig memory _config
    ) internal pure returns (uint256 mintAmount) {
        // 1. Get value of reserves according to invariant
        uint256 kFinal = _invariant(_x, _sum, _config.a);
        // 2. Total minted is the difference between values, with respect to total supply
        if (_config.supply == 0) {
            mintAmount = kFinal - _k;
        } else {
            mintAmount = (_config.supply * (kFinal - _k)) / _k;
        }
    }

    /**
     * @dev Simply scaled raw reserve values and returns the sum
     * @param _bAssets  All bAssets
     * @return x        Scaled vault balances
     * @return sum      Sum of scaled vault balances
     */
    function _getReserves(BassetData[] memory _bAssets)
        internal
        pure
        returns (uint256[] memory x, uint256 sum)
    {
        uint256 len = _bAssets.length;
        x = new uint256[](len);
        uint256 r;
        for (uint256 i = 0; i < len; i++) {
            BassetData memory bAsset = _bAssets[i];
            r = (bAsset.vaultBalance * bAsset.ratio) / 1e8;
            x[i] = r;
            sum += r;
        }
    }

    /**
     * @dev Checks that no bAsset reserves exceed max weight
     * @param _x            Scaled bAsset reserves
     * @param _sum          Sum of x, precomputed
     * @param _limits       Config object containing max and min weights
     * @return inBounds     Bool, true if all assets are within bounds
     */
    function _inBounds(
        uint256[] memory _x,
        uint256 _sum,
        WeightLimits memory _limits
    ) internal pure returns (bool inBounds) {
        uint256 len = _x.length;
        inBounds = true;
        uint256 w;
        for (uint256 i = 0; i < len; i++) {
            w = (_x[i] * 1e18) / _sum;
            if (w > _limits.max || w < _limits.min) return false;
        }
    }

    /***************************************
                    INVARIANT
    ****************************************/

    /**
     * @dev Compute the invariant f(x) for a given array of supplies `x`.
     * @param _x        Scaled vault balances
     * @param _sum      Sum of scaled vault balances
     * @param _a        Precise amplification coefficient
     * @return k        Cumulative value of all assets according to the invariant
     */
    function _invariant(
        uint256[] memory _x,
        uint256 _sum,
        uint256 _a
    ) internal pure returns (uint256 k) {
        if (_sum == 0) return 0;

        uint256 var1 = _x[0] * _x[1];
        uint256 var2 = (_a * var1) / (_x[0] + _x[1]) / A_PRECISION;
        // result = 2 * (isqrt(var2**2 + (A + A_PRECISION) * var1 // A_PRECISION) - var2) + 1
        k = 2 * (Root.sqrt((var2**2) + (((_a + A_PRECISION) * var1) / A_PRECISION)) - var2) + 1;
    }

    /**
     * @dev Solves the invariant for _i with respect to target K, given an array of reserves.
     * @param _x        Scaled reserve balances
     * @param _a        Precise amplification coefficient
     * @param _idx      Index of asset for which to solve
     * @param _targetK  Target invariant value K
     * @return y        New reserve of _i
     */
    function _solveInvariant(
        uint256[] memory _x,
        uint256 _a,
        uint8 _idx,
        uint256 _targetK
    ) internal pure returns (uint256 y) {
        require(_idx == 0 || _idx == 1, "Invalid index");

        uint256 x = _idx == 0 ? _x[1] : _x[0];
        uint256 var1 = _a + A_PRECISION;
        uint256 var2 = ((_targetK**2) * A_PRECISION) / var1;
        // var3 = var2 // (4 * x) + k * _a // var1 - x
        uint256 tmp = var2 / (4 * x) + ((_targetK * _a) / var1);
        uint256 var3 = tmp >= x ? tmp - x : x - tmp;
        //  result = (sqrt(var3**2 + var2) + var3) // 2
        y = ((Root.sqrt((var3**2) + var2) + tmp - x) / 2) + 1;
    }
}

// SPDX-License-Identifier: AGPL-3.0-or-later
// External
// Internal
// Libs
/**
 * @title   FeederPool
 * @author  mStable
 * @notice  Base contract for Feeder Pools (fPools). Feeder Pools are combined of 50/50 fAsset and mAsset. This supports
 *          efficient swaps into and out of mAssets and the bAssets in the mAsset basket (a.k.a mpAssets). There is 0
 *          fee to trade from fAsset into mAsset, providing low cost on-ramps into mAssets.
 * @dev     VERSION: 1.0
 *          DATE:    2021-03-01
 */
contract FeederPool is
    IFeederPool,
    Initializable,
    InitializableToken,
    PausableModule,
    InitializableReentrancyGuard
{
    using SafeERC20 for IERC20;
    using StableMath for uint256;

    // Forging Events
    event Minted(
        address indexed minter,
        address recipient,
        uint256 output,
        address input,
        uint256 inputQuantity
    );
    event MintedMulti(
        address indexed minter,
        address recipient,
        uint256 output,
        address[] inputs,
        uint256[] inputQuantities
    );
    event Swapped(
        address indexed swapper,
        address input,
        address output,
        uint256 outputAmount,
        uint256 fee,
        address recipient
    );
    event Redeemed(
        address indexed redeemer,
        address recipient,
        uint256 mAssetQuantity,
        address output,
        uint256 outputQuantity,
        uint256 scaledFee
    );
    event RedeemedMulti(
        address indexed redeemer,
        address recipient,
        uint256 mAssetQuantity,
        address[] outputs,
        uint256[] outputQuantity,
        uint256 scaledFee
    );
    // State Events
    event CacheSizeChanged(uint256 cacheSize);
    event FeesChanged(uint256 swapFee, uint256 redemptionFee, uint256 govFee);
    event WeightLimitsChanged(uint128 min, uint128 max);

    // FeederManager Events
    event BassetsMigrated(address[] bAssets, address newIntegrator);
    event StartRampA(uint256 currentA, uint256 targetA, uint256 startTime, uint256 rampEndTime);
    event StopRampA(uint256 currentA, uint256 time);

    // Constants
    uint256 private constant MAX_FEE = 1e16;
    uint256 private constant A_PRECISION = 100;
    address public immutable override mAsset;

    // Core data storage
    FeederData public data;

    /**
     * @dev Constructor to set immutable bytecode
     * @param _nexus   Nexus address
     * @param _mAsset  Immutable mAsset address
     */
    constructor(address _nexus, address _mAsset) PausableModule(_nexus) {
        mAsset = _mAsset;
    }

    /**
     * @dev Basic initializer. Sets up core state and importantly provides infinite approvals to the mAsset pool
     * to support the cross pool swaps. bAssetData and bAssetPersonal are always ordered [mAsset, fAsset].
     * @param _nameArg     Name of the fPool token (a.k.a. fpToken)
     * @param _symbolArg   Symbol of the fPool token
     * @param _mAsset      Details on the base mAsset
     * @param _fAsset      Details on the attached fAsset
     * @param _mpAssets    Array of bAssets from the mAsset (to approve)
     * @param _config      Starting invariant config
     */
    function initialize(
        string calldata _nameArg,
        string calldata _symbolArg,
        BassetPersonal calldata _mAsset,
        BassetPersonal calldata _fAsset,
        address[] calldata _mpAssets,
        BasicConfig memory _config
    ) public initializer {
        InitializableToken._initialize(_nameArg, _symbolArg);

        _initializeReentrancyGuard();

        require(_mAsset.addr == mAsset, "mAsset incorrect");
        data.bAssetPersonal.push(
            BassetPersonal(_mAsset.addr, _mAsset.integrator, false, BassetStatus.Normal)
        );
        data.bAssetData.push(BassetData(1e8, 0));
        data.bAssetPersonal.push(
            BassetPersonal(_fAsset.addr, _fAsset.integrator, _fAsset.hasTxFee, BassetStatus.Normal)
        );
        data.bAssetData.push(
            BassetData(SafeCast.toUint128(10**(26 - IBasicToken(_fAsset.addr).decimals())), 0)
        );
        for (uint256 i = 0; i < _mpAssets.length; i++) {
            // Call will fail if bAsset does not exist
            IMasset(_mAsset.addr).getBasset(_mpAssets[i]);
            IERC20(_mpAssets[i]).safeApprove(_mAsset.addr, 2**255);
        }

        uint64 startA = SafeCast.toUint64(_config.a * A_PRECISION);
        data.ampData = AmpData(startA, startA, 0, 0);
        data.weightLimits = _config.limits;

        data.swapFee = 4e14;
        data.redemptionFee = 4e14;
        data.cacheSize = 1e17;
        data.govFee = 1e17;
    }

    /**
     * @dev System will be halted during a recollateralisation event
     */
    modifier whenInOperation() {
        _isOperational();
        _;
    }

    // Internal fn for modifier to reduce deployment size
    function _isOperational() internal view {
        require(!_paused || msg.sender == _recollateraliser(), "Unhealthy");
    }

    /**
     * @dev Verifies that the caller is the Interest Validator contract
     */
    modifier onlyInterestValidator() {
        require(nexus.getModule(KEY_INTEREST_VALIDATOR) == msg.sender, "Only validator");
        _;
    }

    /***************************************
                    MINTING
    ****************************************/

    /**
     * @notice Mint fpTokens with a single bAsset. This contract must have approval to spend the senders bAsset.
     * Supports either fAsset, mAsset or mpAsset as input - with mpAssets used to mint mAsset before depositing.
     * @param _input                Address of the bAsset to deposit.
     * @param _inputQuantity        Quantity in input token units.
     * @param _minOutputQuantity    Minimum fpToken quantity to be minted. This protects against slippage.
     * @param _recipient            Receipient of the newly minted fpTokens
     * @return mintOutput           Quantity of fpToken minted from the deposited bAsset.
     */
    function mint(
        address _input,
        uint256 _inputQuantity,
        uint256 _minOutputQuantity,
        address _recipient
    ) external override nonReentrant whenInOperation returns (uint256 mintOutput) {
        require(_recipient != address(0), "Invalid recipient");
        require(_inputQuantity > 0, "Qty==0");

        Asset memory input = _getAsset(_input);

        mintOutput = FeederLogic.mint(
            data,
            _getConfig(),
            input,
            _inputQuantity,
            _minOutputQuantity
        );

        // Mint the fpToken
        _mint(_recipient, mintOutput);
        emit Minted(msg.sender, _recipient, mintOutput, _input, _inputQuantity);
    }

    /**
     * @notice Mint fpTokens with multiple bAssets. This contract must have approval to spend the senders bAssets.
     * Supports only fAsset or mAsset as inputs.
     * @param _inputs               Address of the bAssets to deposit.
     * @param _inputQuantities      Quantity in input token units.
     * @param _minOutputQuantity    Minimum fpToken quantity to be minted. This protects against slippage.
     * @param _recipient            Receipient of the newly minted fpTokens
     * @return mintOutput           Quantity of fpToken minted from the deposited bAssets.
     */
    function mintMulti(
        address[] calldata _inputs,
        uint256[] calldata _inputQuantities,
        uint256 _minOutputQuantity,
        address _recipient
    ) external override nonReentrant whenInOperation returns (uint256 mintOutput) {
        require(_recipient != address(0), "Invalid recipient");
        uint256 len = _inputQuantities.length;
        require(len > 0 && len == _inputs.length, "Input array mismatch");

        uint8[] memory indexes = _getAssets(_inputs);
        mintOutput = FeederLogic.mintMulti(
            data,
            _getConfig(),
            indexes,
            _inputQuantities,
            _minOutputQuantity
        );
        // Mint the fpToken
        _mint(_recipient, mintOutput);
        emit MintedMulti(msg.sender, _recipient, mintOutput, _inputs, _inputQuantities);
    }

    /**
     * @notice Get the projected output of a given mint.
     * @param _input             Address of the bAsset to deposit
     * @param _inputQuantity     Quantity in bAsset units
     * @return mintOutput        Estimated mint output in fpToken terms
     */
    function getMintOutput(address _input, uint256 _inputQuantity)
        external
        view
        override
        returns (uint256 mintOutput)
    {
        require(_inputQuantity > 0, "Qty==0");

        Asset memory input = _getAsset(_input);

        if (input.exists) {
            mintOutput = FeederLogic.computeMint(
                data.bAssetData,
                input.idx,
                _inputQuantity,
                _getConfig()
            );
        } else {
            uint256 estimatedMasset = IMasset(mAsset).getMintOutput(_input, _inputQuantity);
            mintOutput = FeederLogic.computeMint(data.bAssetData, 0, estimatedMasset, _getConfig());
        }
    }

    /**
     * @notice Get the projected output of a given mint
     * @param _inputs            Non-duplicate address array of addresses to bAssets to deposit for the minted mAsset tokens.
     * @param _inputQuantities   Quantity of each bAsset to deposit for the minted fpToken.
     * @return mintOutput        Estimated mint output in fpToken terms
     */
    function getMintMultiOutput(address[] calldata _inputs, uint256[] calldata _inputQuantities)
        external
        view
        override
        returns (uint256 mintOutput)
    {
        uint256 len = _inputQuantities.length;
        require(len > 0 && len == _inputs.length, "Input array mismatch");
        uint8[] memory indexes = _getAssets(_inputs);
        return
            FeederLogic.computeMintMulti(data.bAssetData, indexes, _inputQuantities, _getConfig());
    }

    /***************************************
                    SWAPPING
    ****************************************/

    /**
     * @notice Swaps two assets - either internally between fAsset<>mAsset, or between fAsset<>mpAsset by
     * first routing through the mAsset pool.
     * @param _input             Address of bAsset to deposit
     * @param _output            Address of bAsset to withdraw
     * @param _inputQuantity     Units of input bAsset to swap in
     * @param _minOutputQuantity Minimum quantity of the swap output asset. This protects against slippage
     * @param _recipient         Address to transfer output asset to
     * @return swapOutput        Quantity of output asset returned from swap
     */
    function swap(
        address _input,
        address _output,
        uint256 _inputQuantity,
        uint256 _minOutputQuantity,
        address _recipient
    ) external override nonReentrant whenInOperation returns (uint256 swapOutput) {
        require(_recipient != address(0), "Invalid recipient");
        require(_input != _output, "Invalid pair");
        require(_inputQuantity > 0, "Qty==0");

        Asset memory input = _getAsset(_input);
        Asset memory output = _getAsset(_output);
        require(_pathIsValid(input, output), "Invalid pair");

        uint256 localFee;
        (swapOutput, localFee) = FeederLogic.swap(
            data,
            _getConfig(),
            input,
            output,
            _inputQuantity,
            _minOutputQuantity,
            _recipient
        );

        uint256 govFee = data.govFee;
        if (govFee > 0) {
            data.pendingFees += ((localFee * govFee) / 1e18);
        }

        emit Swapped(msg.sender, input.addr, output.addr, swapOutput, localFee, _recipient);
    }

    /**
     * @notice Determines both if a trade is valid, and the expected fee or output.
     * Swap is valid if it does not result in the input asset exceeding its maximum weight.
     * @param _input             Address of bAsset to deposit
     * @param _output            Address of bAsset to receive
     * @param _inputQuantity     Units of input bAsset to swap
     * @return swapOutput        Quantity of output asset returned from swap
     */
    function getSwapOutput(
        address _input,
        address _output,
        uint256 _inputQuantity
    ) external view override returns (uint256 swapOutput) {
        require(_input != _output, "Invalid pair");
        require(_inputQuantity > 0, "Qty==0");

        Asset memory input = _getAsset(_input);
        Asset memory output = _getAsset(_output);
        require(_pathIsValid(input, output), "Invalid pair");

        // Internal swap between fAsset and mAsset
        if (input.exists && output.exists) {
            (swapOutput, ) = FeederLogic.computeSwap(
                data.bAssetData,
                input.idx,
                output.idx,
                _inputQuantity,
                output.idx == 0 ? 0 : data.swapFee,
                _getConfig()
            );
            return swapOutput;
        }

        // Swapping out of fAsset
        if (input.exists) {
            // Swap into mAsset > Redeem into mpAsset
            (swapOutput, ) = FeederLogic.computeSwap(
                data.bAssetData,
                1,
                0,
                _inputQuantity,
                0,
                _getConfig()
            );
            swapOutput = IMasset(mAsset).getRedeemOutput(_output, swapOutput);
        }
        // Else we are swapping into fAsset
        else {
            // Mint mAsset from mp > Swap into fAsset here
            swapOutput = IMasset(mAsset).getMintOutput(_input, _inputQuantity);
            (swapOutput, ) = FeederLogic.computeSwap(
                data.bAssetData,
                0,
                1,
                swapOutput,
                data.swapFee,
                _getConfig()
            );
        }
    }

    /**
     * @dev Checks if a given swap path is valid. Only fAsset<>mAsset & fAsset<>mpAsset swaps are supported.
     */
    function _pathIsValid(Asset memory _in, Asset memory _out)
        internal
        pure
        returns (bool isValid)
    {
        // mpAsset -> mpAsset
        if (!_in.exists && !_out.exists) return false;
        // f/mAsset -> f/mAsset
        if (_in.exists && _out.exists) return true;
        // fAsset -> mpAsset
        if (_in.exists && _in.idx == 1) return true;
        // mpAsset -> fAsset
        if (_out.exists && _out.idx == 1) return true;
        // Path is into or out of mAsset - just use main pool for this
        return false;
    }

    /***************************************
                    REDEMPTION
    ****************************************/

    /**
     * @notice Burns a specified quantity of the senders fpToken in return for a bAsset. The output amount is derived
     * from the invariant. Supports redemption into either the fAsset, mAsset or assets in the mAsset basket.
     * @param _output            Address of the bAsset to withdraw
     * @param _fpTokenQuantity   Quantity of LP Token to burn
     * @param _minOutputQuantity Minimum bAsset quantity to receive for the burnt fpToken. This protects against slippage.
     * @param _recipient         Address to transfer the withdrawn bAssets to.
     * @return outputQuantity    Quanity of bAsset units received for the burnt fpToken
     */
    function redeem(
        address _output,
        uint256 _fpTokenQuantity,
        uint256 _minOutputQuantity,
        address _recipient
    ) external override nonReentrant whenInOperation returns (uint256 outputQuantity) {
        require(_recipient != address(0), "Invalid recipient");
        require(_fpTokenQuantity > 0, "Qty==0");

        Asset memory output = _getAsset(_output);

        // Get config before burning. Config > Burn > CacheSize
        FeederConfig memory config = _getConfig();
        _burn(msg.sender, _fpTokenQuantity);

        uint256 localFee;
        (outputQuantity, localFee) = FeederLogic.redeem(
            data,
            config,
            output,
            _fpTokenQuantity,
            _minOutputQuantity,
            _recipient
        );

        uint256 govFee = data.govFee;
        if (govFee > 0) {
            data.pendingFees += ((localFee * govFee) / 1e18);
        }

        emit Redeemed(
            msg.sender,
            _recipient,
            _fpTokenQuantity,
            output.addr,
            outputQuantity,
            localFee
        );
    }

    /**
     * @dev Credits a recipient with a proportionate amount of bAssets, relative to current vault
     * balance levels and desired fpToken quantity. Burns the fpToken as payment. Only fAsset & mAsset are supported in this path.
     * @param _inputQuantity        Quantity of fpToken to redeem
     * @param _minOutputQuantities  Min units of output to receive
     * @param _recipient            Address to credit the withdrawn bAssets
     * @return outputQuantities     Array of output asset quantities
     */
    function redeemProportionately(
        uint256 _inputQuantity,
        uint256[] calldata _minOutputQuantities,
        address _recipient
    ) external override nonReentrant whenInOperation returns (uint256[] memory outputQuantities) {
        require(_recipient != address(0), "Invalid recipient");
        require(_inputQuantity > 0, "Qty==0");

        // Get config before burning. Burn > CacheSize
        FeederConfig memory config = _getConfig();
        _burn(msg.sender, _inputQuantity);

        address[] memory outputs;
        uint256 scaledFee;
        (scaledFee, outputs, outputQuantities) = FeederLogic.redeemProportionately(
            data,
            config,
            _inputQuantity,
            _minOutputQuantities,
            _recipient
        );

        uint256 govFee = data.govFee;
        if (govFee > 0) {
            data.pendingFees += ((scaledFee * govFee) / 1e18);
        }

        emit RedeemedMulti(
            msg.sender,
            _recipient,
            _inputQuantity,
            outputs,
            outputQuantities,
            scaledFee
        );
    }

    /**
     * @dev Credits a recipient with a certain quantity of selected bAssets, in exchange for burning the
     *      relative fpToken quantity from the sender. Only fAsset & mAsset (0,1) are supported in this path.
     * @param _outputs              Addresses of the bAssets to receive
     * @param _outputQuantities     Units of the bAssets to receive
     * @param _maxInputQuantity     Maximum fpToken quantity to burn for the received bAssets. This protects against slippage.
     * @param _recipient            Address to receive the withdrawn bAssets
     * @return fpTokenQuantity      Quantity of fpToken units burned as payment
     */
    function redeemExactBassets(
        address[] calldata _outputs,
        uint256[] calldata _outputQuantities,
        uint256 _maxInputQuantity,
        address _recipient
    ) external override nonReentrant whenInOperation returns (uint256 fpTokenQuantity) {
        require(_recipient != address(0), "Invalid recipient");
        uint256 len = _outputQuantities.length;
        require(len > 0 && len == _outputs.length, "Invalid array input");
        require(_maxInputQuantity > 0, "Qty==0");

        uint8[] memory indexes = _getAssets(_outputs);

        uint256 localFee;
        (fpTokenQuantity, localFee) = FeederLogic.redeemExactBassets(
            data,
            _getConfig(),
            indexes,
            _outputQuantities,
            _maxInputQuantity,
            _recipient
        );

        _burn(msg.sender, fpTokenQuantity);
        uint256 govFee = data.govFee;
        if (govFee > 0) {
            data.pendingFees += ((localFee * govFee) / 1e18);
        }

        emit RedeemedMulti(
            msg.sender,
            _recipient,
            fpTokenQuantity,
            _outputs,
            _outputQuantities,
            localFee
        );
    }

    /**
     * @notice Gets the estimated output from a given redeem
     * @param _output            Address of the bAsset to receive
     * @param _fpTokenQuantity   Quantity of fpToken to redeem
     * @return bAssetOutput      Estimated quantity of bAsset units received for the burnt fpTokens
     */
    function getRedeemOutput(address _output, uint256 _fpTokenQuantity)
        external
        view
        override
        returns (uint256 bAssetOutput)
    {
        require(_fpTokenQuantity > 0, "Qty==0");

        Asset memory output = _getAsset(_output);
        uint256 scaledFee = _fpTokenQuantity.mulTruncate(data.redemptionFee);

        bAssetOutput = FeederLogic.computeRedeem(
            data.bAssetData,
            output.exists ? output.idx : 0,
            _fpTokenQuantity - scaledFee,
            _getConfig()
        );
        // Extra step for mpAsset redemption
        if (!output.exists) {
            bAssetOutput = IMasset(mAsset).getRedeemOutput(output.addr, bAssetOutput);
        }
    }

    /**
     * @notice Gets the estimated output from a given redeem
     * @param _outputs           Addresses of the bAsset to receive
     * @param _outputQuantities  Quantities of bAsset to redeem
     * @return fpTokenQuantity   Estimated quantity of fpToken units needed to burn to receive output
     */
    function getRedeemExactBassetsOutput(
        address[] calldata _outputs,
        uint256[] calldata _outputQuantities
    ) external view override returns (uint256 fpTokenQuantity) {
        uint256 len = _outputQuantities.length;
        require(len > 0 && len == _outputs.length, "Invalid array input");

        uint8[] memory indexes = _getAssets(_outputs);

        uint256 mAssetRedeemed =
            FeederLogic.computeRedeemExact(
                data.bAssetData,
                indexes,
                _outputQuantities,
                _getConfig()
            );
        fpTokenQuantity = mAssetRedeemed.divPrecisely(1e18 - data.redemptionFee);
        if (fpTokenQuantity > 0) fpTokenQuantity += 1;
    }

    /***************************************
                    GETTERS
    ****************************************/

    /**
     * @notice Gets the price of the fpToken, and invariant value k
     * @return price    Price of an fpToken
     * @return k        Total value of basket, k
     */
    function getPrice() public view override returns (uint256 price, uint256 k) {
        return FeederLogic.computePrice(data.bAssetData, _getConfig());
    }

    /**
     * @notice Gets all config needed for general InvariantValidator calls
     */
    function getConfig() external view override returns (FeederConfig memory config) {
        return _getConfig();
    }

    /**
     * @notice Get data for a specific bAsset, if it exists
     * @param _bAsset     Address of bAsset
     * @return personal   Struct with personal data
     * @return vaultData  Struct with full bAsset data
     */
    function getBasset(address _bAsset)
        external
        view
        override
        returns (BassetPersonal memory personal, BassetData memory vaultData)
    {
        Asset memory asset = _getAsset(_bAsset);
        require(asset.exists, "Invalid asset");
        personal = data.bAssetPersonal[asset.idx];
        vaultData = data.bAssetData[asset.idx];
    }

    /**
     * @notice Get data for a all bAssets in basket
     * @return personal    Struct[] with full bAsset data
     * @return vaultData   Number of bAssets in the Basket
     */
    function getBassets()
        external
        view
        override
        returns (BassetPersonal[] memory, BassetData[] memory vaultData)
    {
        return (data.bAssetPersonal, data.bAssetData);
    }

    /***************************************
                GETTERS - INTERNAL
    ****************************************/

    /**
     * @dev Checks if a given asset exists in basket and return the index.
     * @return status    Data containing address, index and whether it exists in basket
     */
    function _getAsset(address _asset) internal view returns (Asset memory status) {
        // if input is mAsset then we know the position
        if (_asset == mAsset) return Asset(0, _asset, true);

        // else it exists if the position 1 is _asset
        return Asset(1, _asset, data.bAssetPersonal[1].addr == _asset);
    }

    /**
     * @dev Validates an array of input assets and returns their indexes. Assets must exist
     * in order to be valid, as mintMulti and redeemMulti do not support external bAssets.
     */
    function _getAssets(address[] memory _assets) internal view returns (uint8[] memory indexes) {
        uint256 len = _assets.length;

        indexes = new uint8[](len);

        Asset memory input_;
        for (uint256 i = 0; i < len; i++) {
            input_ = _getAsset(_assets[i]);
            indexes[i] = input_.idx;
            require(input_.exists, "Invalid asset");

            for (uint256 j = i + 1; j < len; j++) {
                require(_assets[i] != _assets[j], "Duplicate asset");
            }
        }
    }

    /**
     * @dev Gets all config needed for general InvariantValidator calls
     */
    function _getConfig() internal view returns (FeederConfig memory) {
        return FeederConfig(totalSupply() + data.pendingFees, _getA(), data.weightLimits);
    }

    /**
     * @dev Gets current amplification var A
     */
    function _getA() internal view returns (uint256) {
        AmpData memory ampData_ = data.ampData;

        uint64 endA = ampData_.targetA;
        uint64 endTime = ampData_.rampEndTime;

        // If still changing, work out based on current timestmap
        if (block.timestamp < endTime) {
            uint64 startA = ampData_.initialA;
            uint64 startTime = ampData_.rampStartTime;

            (uint256 elapsed, uint256 total) = (block.timestamp - startTime, endTime - startTime);

            if (endA > startA) {
                return startA + (((endA - startA) * elapsed) / total);
            } else {
                return startA - (((startA - endA) * elapsed) / total);
            }
        }
        // Else return final value
        else {
            return endA;
        }
    }

    /***************************************
                    YIELD
    ****************************************/

    /**
     * @dev Collects the interest generated from the lending markets, performing a theoretical mint, which
     * is then validated by the interest validator to protect against accidental hyper inflation.
     * @return mintAmount   fpToken units generated from interest collected from lending markets
     * @return newSupply    fpToken total supply after mint
     */
    function collectPlatformInterest()
        external
        override
        onlyInterestValidator
        whenInOperation
        nonReentrant
        returns (uint256 mintAmount, uint256 newSupply)
    {
        (uint8[] memory idxs, uint256[] memory gains) =
            FeederManager.calculatePlatformInterest(data.bAssetPersonal, data.bAssetData);
        // Calculate potential mint amount. This will be validated by the interest validator
        mintAmount = FeederLogic.computeMintMulti(data.bAssetData, idxs, gains, _getConfig());
        newSupply = totalSupply() + data.pendingFees + mintAmount;

        uint256 govFee = data.govFee;
        if (govFee > 0) {
            data.pendingFees += ((mintAmount * govFee) / 1e18);
        }

        // Dummy mint event to catch the collections here
        emit MintedMulti(address(this), msg.sender, 0, new address[](0), gains);
    }

    /**
     * @dev Collects the pending gov fees extracted from swap, redeem and platform interest.
     */
    function collectPendingFees() external override onlyInterestValidator {
        uint256 fees = data.pendingFees;
        if (fees > 1) {
            uint256 mintAmount = fees - 1;
            data.pendingFees = 1;

            _mint(msg.sender, mintAmount);
            emit MintedMulti(
                address(this),
                msg.sender,
                mintAmount,
                new address[](0),
                new uint256[](0)
            );
        }
    }

    /***************************************
                    STATE
    ****************************************/

    /**
     * @dev Sets the MAX cache size for each bAsset. The cache will actually revolve around
     *      _cacheSize * totalSupply / 2 under normal circumstances.
     * @param _cacheSize Maximum percent of total fpToken supply to hold for each bAsset
     */
    function setCacheSize(uint256 _cacheSize) external onlyGovernor {
        require(_cacheSize <= 2e17, "Must be <= 20%");

        data.cacheSize = _cacheSize;

        emit CacheSizeChanged(_cacheSize);
    }

    /**
     * @dev Set the ecosystem fee for sewapping bAssets or redeeming specific bAssets
     * @param _swapFee       Fee calculated in (%/100 * 1e18)
     * @param _redemptionFee Fee calculated in (%/100 * 1e18)
     * @param _govFee        Fee calculated in (%/100 * 1e18)
     */
    function setFees(
        uint256 _swapFee,
        uint256 _redemptionFee,
        uint256 _govFee
    ) external onlyGovernor {
        require(_swapFee <= MAX_FEE, "Swap rate oob");
        require(_redemptionFee <= MAX_FEE, "Redemption rate oob");
        require(_govFee <= 5e17, "Gov fee rate oob");

        data.swapFee = _swapFee;
        data.redemptionFee = _redemptionFee;
        data.govFee = _govFee;

        emit FeesChanged(_swapFee, _redemptionFee, _govFee);
    }

    /**
     * @dev Set the maximum weight across all bAssets
     * @param _min Weight where 100% = 1e18
     * @param _max Weight where 100% = 1e18
     */
    function setWeightLimits(uint128 _min, uint128 _max) external onlyGovernor {
        require(_min <= 3e17 && _max >= 7e17, "Weights oob");

        data.weightLimits = WeightLimits(_min, _max);

        emit WeightLimitsChanged(_min, _max);
    }

    /**
     * @dev Transfers all collateral from one lending market to another - used initially
     *      to handle the migration between Aave V1 and Aave V2. Note - only supports non
     *      tx fee enabled assets. Supports going from no integration to integration, but
     *      not the other way around.
     * @param _bAssets Array of basket assets to migrate
     * @param _newIntegration Address of the new platform integration
     */
    function migrateBassets(address[] calldata _bAssets, address _newIntegration)
        external
        onlyGovernor
    {
        FeederManager.migrateBassets(data.bAssetPersonal, _bAssets, _newIntegration);
    }

    /**
     * @dev Starts changing of the amplification var A
     * @param _targetA      Target A value
     * @param _rampEndTime  Time at which A will arrive at _targetA
     */
    function startRampA(uint256 _targetA, uint256 _rampEndTime) external onlyGovernor {
        FeederManager.startRampA(data.ampData, _targetA, _rampEndTime, _getA(), A_PRECISION);
    }

    /**
     * @dev Stops the changing of the amplification var A, setting
     * it to whatever the current value is.
     */
    function stopRampA() external onlyGovernor {
        FeederManager.stopRampA(data.ampData, _getA());
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_nexus","type":"address"},{"internalType":"address","name":"_mAsset","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"bAssets","type":"address[]"},{"indexed":false,"internalType":"address","name":"newIntegrator","type":"address"}],"name":"BassetsMigrated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"cacheSize","type":"uint256"}],"name":"CacheSizeChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"swapFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"redemptionFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"govFee","type":"uint256"}],"name":"FeesChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"output","type":"uint256"},{"indexed":false,"internalType":"address","name":"input","type":"address"},{"indexed":false,"internalType":"uint256","name":"inputQuantity","type":"uint256"}],"name":"Minted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"output","type":"uint256"},{"indexed":false,"internalType":"address[]","name":"inputs","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"inputQuantities","type":"uint256[]"}],"name":"MintedMulti","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"redeemer","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"mAssetQuantity","type":"uint256"},{"indexed":false,"internalType":"address","name":"output","type":"address"},{"indexed":false,"internalType":"uint256","name":"outputQuantity","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"scaledFee","type":"uint256"}],"name":"Redeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"redeemer","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"mAssetQuantity","type":"uint256"},{"indexed":false,"internalType":"address[]","name":"outputs","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"outputQuantity","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"scaledFee","type":"uint256"}],"name":"RedeemedMulti","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"currentA","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"targetA","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rampEndTime","type":"uint256"}],"name":"StartRampA","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"currentA","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"StopRampA","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"swapper","type":"address"},{"indexed":false,"internalType":"address","name":"input","type":"address"},{"indexed":false,"internalType":"address","name":"output","type":"address"},{"indexed":false,"internalType":"uint256","name":"outputAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"}],"name":"Swapped","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"min","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"max","type":"uint128"}],"name":"WeightLimitsChanged","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collectPendingFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"collectPlatformInterest","outputs":[{"internalType":"uint256","name":"mintAmount","type":"uint256"},{"internalType":"uint256","name":"newSupply","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"data","outputs":[{"internalType":"uint256","name":"swapFee","type":"uint256"},{"internalType":"uint256","name":"redemptionFee","type":"uint256"},{"internalType":"uint256","name":"govFee","type":"uint256"},{"internalType":"uint256","name":"pendingFees","type":"uint256"},{"internalType":"uint256","name":"cacheSize","type":"uint256"},{"components":[{"internalType":"uint64","name":"initialA","type":"uint64"},{"internalType":"uint64","name":"targetA","type":"uint64"},{"internalType":"uint64","name":"rampStartTime","type":"uint64"},{"internalType":"uint64","name":"rampEndTime","type":"uint64"}],"internalType":"struct AmpData","name":"ampData","type":"tuple"},{"components":[{"internalType":"uint128","name":"min","type":"uint128"},{"internalType":"uint128","name":"max","type":"uint128"}],"internalType":"struct WeightLimits","name":"weightLimits","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_bAsset","type":"address"}],"name":"getBasset","outputs":[{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"address","name":"integrator","type":"address"},{"internalType":"bool","name":"hasTxFee","type":"bool"},{"internalType":"enum BassetStatus","name":"status","type":"uint8"}],"internalType":"struct BassetPersonal","name":"personal","type":"tuple"},{"components":[{"internalType":"uint128","name":"ratio","type":"uint128"},{"internalType":"uint128","name":"vaultBalance","type":"uint128"}],"internalType":"struct BassetData","name":"vaultData","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBassets","outputs":[{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"address","name":"integrator","type":"address"},{"internalType":"bool","name":"hasTxFee","type":"bool"},{"internalType":"enum BassetStatus","name":"status","type":"uint8"}],"internalType":"struct BassetPersonal[]","name":"","type":"tuple[]"},{"components":[{"internalType":"uint128","name":"ratio","type":"uint128"},{"internalType":"uint128","name":"vaultBalance","type":"uint128"}],"internalType":"struct BassetData[]","name":"vaultData","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getConfig","outputs":[{"components":[{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"a","type":"uint256"},{"components":[{"internalType":"uint128","name":"min","type":"uint128"},{"internalType":"uint128","name":"max","type":"uint128"}],"internalType":"struct WeightLimits","name":"limits","type":"tuple"}],"internalType":"struct FeederConfig","name":"config","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_inputs","type":"address[]"},{"internalType":"uint256[]","name":"_inputQuantities","type":"uint256[]"}],"name":"getMintMultiOutput","outputs":[{"internalType":"uint256","name":"mintOutput","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_input","type":"address"},{"internalType":"uint256","name":"_inputQuantity","type":"uint256"}],"name":"getMintOutput","outputs":[{"internalType":"uint256","name":"mintOutput","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPrice","outputs":[{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"k","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_outputs","type":"address[]"},{"internalType":"uint256[]","name":"_outputQuantities","type":"uint256[]"}],"name":"getRedeemExactBassetsOutput","outputs":[{"internalType":"uint256","name":"fpTokenQuantity","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_output","type":"address"},{"internalType":"uint256","name":"_fpTokenQuantity","type":"uint256"}],"name":"getRedeemOutput","outputs":[{"internalType":"uint256","name":"bAssetOutput","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_input","type":"address"},{"internalType":"address","name":"_output","type":"address"},{"internalType":"uint256","name":"_inputQuantity","type":"uint256"}],"name":"getSwapOutput","outputs":[{"internalType":"uint256","name":"swapOutput","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_nameArg","type":"string"},{"internalType":"string","name":"_symbolArg","type":"string"},{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"address","name":"integrator","type":"address"},{"internalType":"bool","name":"hasTxFee","type":"bool"},{"internalType":"enum BassetStatus","name":"status","type":"uint8"}],"internalType":"struct BassetPersonal","name":"_mAsset","type":"tuple"},{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"address","name":"integrator","type":"address"},{"internalType":"bool","name":"hasTxFee","type":"bool"},{"internalType":"enum BassetStatus","name":"status","type":"uint8"}],"internalType":"struct BassetPersonal","name":"_fAsset","type":"tuple"},{"internalType":"address[]","name":"_mpAssets","type":"address[]"},{"components":[{"internalType":"uint256","name":"a","type":"uint256"},{"components":[{"internalType":"uint128","name":"min","type":"uint128"},{"internalType":"uint128","name":"max","type":"uint128"}],"internalType":"struct WeightLimits","name":"limits","type":"tuple"}],"internalType":"struct BasicConfig","name":"_config","type":"tuple"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mAsset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_bAssets","type":"address[]"},{"internalType":"address","name":"_newIntegration","type":"address"}],"name":"migrateBassets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_input","type":"address"},{"internalType":"uint256","name":"_inputQuantity","type":"uint256"},{"internalType":"uint256","name":"_minOutputQuantity","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"mintOutput","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_inputs","type":"address[]"},{"internalType":"uint256[]","name":"_inputQuantities","type":"uint256[]"},{"internalType":"uint256","name":"_minOutputQuantity","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"mintMulti","outputs":[{"internalType":"uint256","name":"mintOutput","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nexus","outputs":[{"internalType":"contract INexus","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_output","type":"address"},{"internalType":"uint256","name":"_fpTokenQuantity","type":"uint256"},{"internalType":"uint256","name":"_minOutputQuantity","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"outputQuantity","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_outputs","type":"address[]"},{"internalType":"uint256[]","name":"_outputQuantities","type":"uint256[]"},{"internalType":"uint256","name":"_maxInputQuantity","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"redeemExactBassets","outputs":[{"internalType":"uint256","name":"fpTokenQuantity","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_inputQuantity","type":"uint256"},{"internalType":"uint256[]","name":"_minOutputQuantities","type":"uint256[]"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"redeemProportionately","outputs":[{"internalType":"uint256[]","name":"outputQuantities","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_cacheSize","type":"uint256"}],"name":"setCacheSize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_swapFee","type":"uint256"},{"internalType":"uint256","name":"_redemptionFee","type":"uint256"},{"internalType":"uint256","name":"_govFee","type":"uint256"}],"name":"setFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"_min","type":"uint128"},{"internalType":"uint128","name":"_max","type":"uint128"}],"name":"setWeightLimits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_targetA","type":"uint256"},{"internalType":"uint256","name":"_rampEndTime","type":"uint256"}],"name":"startRampA","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stopRampA","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_input","type":"address"},{"internalType":"address","name":"_output","type":"address"},{"internalType":"uint256","name":"_inputQuantity","type":"uint256"},{"internalType":"uint256","name":"_minOutputQuantity","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"swap","outputs":[{"internalType":"uint256","name":"swapOutput","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60c06040526006805461ff00191690553480156200001c57600080fd5b5060405162005e3d38038062005e3d8339810160408190526200003f91620000e9565b81806001600160a01b0381166200009c5760405162461bcd60e51b815260206004820152601560248201527f4e657875732061646472657373206973207a65726f0000000000000000000000604482015260640160405180910390fd5b6001600160601b0319606091821b81166080526006805461ff001916905592901b90911660a05250620001209050565b80516001600160a01b0381168114620000e457600080fd5b919050565b60008060408385031215620000fc578182fd5b6200010783620000cc565b91506200011760208401620000cc565b90509250929050565b60805160601c60a05160601c615cab62000192600039600081816102ce0152818161097401528181610e6f01528181611c7601528181611d1f01528181611f75015261389501526000818161052401528181612019015281816124840152818161425901526144320152615cab6000f3fe608060405234801561001057600080fd5b50600436106102535760003560e01c806373d4a13a11610146578063a9059cbb116100c3578063c4db7fa011610087578063c4db7fa0146105c7578063cec10c11146105cf578063d5bcb9b5146105e2578063dd62ed3e146105f5578063e5555b8f1461062e578063f74bfe8e1461064157610253565b8063a9059cbb14610559578063aa5d27e91461056c578063af290bd41461057f578063c1db77ec14610592578063c3f909d4146105b257610253565b806398d5fdca1161010a57806398d5fdca146104fc57806398fec3af14610504578063a1c251511461050c578063a3f5c1d21461051f578063a457c2d71461054657610253565b806373d4a13a1461042257806378aa987e146104bc5780637e8901ea146104cf5780638456cb59146104ec57806395d89b41146104f457610253565b8063313ce567116101d457806344e3fa3c1161019857806344e3fa3c146103c55780635c975abb146103d85780636fb3e89c146103e957806370a08231146103fc57806372ea90761461040f57610253565b8063313ce5671461036157806339509351146103765780633e37bcbc146103895780633f4ba83a146103aa57806343bcfab6146103b257610253565b806318160ddd1161021b57806318160ddd146103085780631820783d146103105780631d3ce3981461032557806323b872dd1461033b57806323fb4bd31461034e57610253565b806304de5a731461025857806306fdde031461027e578063095ea7b314610293578063119849cf146102b6578063178d341f146102c9575b600080fd5b61026b610266366004614987565b610654565b6040519081526020015b60405180910390f35b6102866107c9565b60405161027591906155c6565b6102a66102a13660046148bf565b61085c565b6040519015158152602001610275565b61026b6102c43660046148bf565b610873565b6102f07f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610275565b60035461026b565b61032361031e366004614d8e565b610a93565b005b61032d610b1f565b60405161027592919061540e565b6102a6610349366004614821565b610c82565b61032361035c366004614b6f565b610d35565b60065460405160ff9091168152602001610275565b6102a66103843660046148bf565b61149f565b61039c6103973660046147b1565b6114d6565b6040516102759291906156a1565b610323611674565b61026b6103c03660046148ea565b61170b565b6103236103d3366004614eda565b61190b565b6102a6600654610100900460ff1690565b6103236103f7366004614933565b6119a7565b61026b61040a3660046147b1565b611a22565b61026b61041d366004614821565b611a41565b600754600854600954600a54600b5460408051608081018252600e546001600160401b038082168352600160401b82048116602080850191909152600160801b808404831685870152600160c01b90930490911660608401528351808501909452600f546001600160801b038082168652929004909116908301526104a996959493929187565b60405161027597969594939291906158e7565b61026b6104ca3660046148bf565b611e4a565b6104d7611fd5565b60408051928352602083019190915201610275565b610323612309565b61028661239b565b6104d76123aa565b610323612445565b61032361051a366004614d61565b6125e8565b6102f07f000000000000000000000000000000000000000000000000000000000000000081565b6102a66105543660046148bf565b6126d4565b6102a66105673660046148bf565b61276f565b61026b61057a3660046149ef565b61277c565b61026b61058d3660046149ef565b6129e8565b6105a56105a0366004614e89565b612bec565b60405161027591906155b3565b6105ba612da9565b60405161027591906156d1565b610323612dbe565b6103236105dd366004614f1e565b612e40565b61026b6105f0366004614861565b612f7c565b61026b6106033660046147e9565b6001600160a01b03918216600090815260026020908152604080832093909416825291909152205490565b61026b61063c366004614987565b6131d9565b61026b61064f3660046148ea565b61330f565b600081801580159061066557508085145b6106ac5760405162461bcd60e51b8152602060048201526013602482015272125b9d985b1a5908185c9c985e481a5b9c1d5d606a1b60448201526064015b60405180910390fd5b60006106ea8787808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506134b292505050565b90506000732837c77527c37d61d9763f53005211dacb4125de637cdc8e40600d8489896107156136c2565b6040518663ffffffff1660e01b81526004016107359594939291906152ad565b60206040518083038186803b15801561074d57600080fd5b505af4158015610761573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107859190614da6565b6008549091506107a8906107a190670de0b6b3a7640000615b33565b8290613732565b935083156107be576107bb6001856159c5565b93505b505050949350505050565b6060600480546107d890615bc1565b80601f016020809104026020016040519081016040528092919081815260200182805461080490615bc1565b80156108515780601f1061082657610100808354040283529160200191610851565b820191906000526020600020905b81548152906001019060200180831161083457829003601f168201915b505050505090505b90565b6000610869338484613751565b5060015b92915050565b60008082116108945760405162461bcd60e51b81526004016106a39061564a565b600061089f84613876565b905080604001511561094b578051732837c77527c37d61d9763f53005211dacb4125de9063d1be552890600d90866108d56136c2565b6040518563ffffffff1660e01b81526004016108f494939291906153bb565b60206040518083038186803b15801561090c57600080fd5b505af4158015610920573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109449190614da6565b9150610a8c565b60405163119849cf60e01b81526001600160a01b038581166004830152602482018590526000917f00000000000000000000000000000000000000000000000000000000000000009091169063119849cf9060440160206040518083038186803b1580156109b857600080fd5b505afa1580156109cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109f09190614da6565b9050732837c77527c37d61d9763f53005211dacb4125de63d1be5528600d600084610a196136c2565b6040518563ffffffff1660e01b8152600401610a3894939291906153bb565b60206040518083038186803b158015610a5057600080fd5b505af4158015610a64573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a889190614da6565b9250505b5092915050565b610a9b61396f565b6702c68af0bb140000811115610ae45760405162461bcd60e51b815260206004820152600e60248201526d4d757374206265203c3d2032302560901b60448201526064016106a3565b600b8190556040518181527f2f5a6b1defeafd30e7568ea5c176aa0702b0af5b00ba41fa20e58b2c72e8afe79060200160405180910390a150565b6060806007600501600760060181805480602002602001604051908101604052809291908181526020016000905b82821015610c04576000848152602090819020604080516080810182526002860290920180546001600160a01b03908116845260018201549081169484019490945260ff600160a01b8504811615159284019290925291926060840191600160a81b909104166007811115610bd257634e487b7160e01b600052602160045260246000fd5b6007811115610bf157634e487b7160e01b600052602160045260246000fd5b8152505081526020019060010190610b4d565b50505050915080805480602002602001604051908101604052809291908181526020016000905b82821015610c7457600084815260209081902060408051808201909152908401546001600160801b038082168352600160801b9091041681830152825260019092019101610c2b565b505050509050915091509091565b6000610c8f8484846139d9565b6001600160a01b038416600090815260026020908152604080832033845290915290205482811015610d145760405162461bcd60e51b815260206004820152602860248201527f45524332303a207472616e7366657220616d6f756e74206578636565647320616044820152676c6c6f77616e636560c01b60648201526084016106a3565b610d288533610d238685615b33565b613751565b60019150505b9392505050565b600054610100900460ff1680610d4e575060005460ff16155b610db15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016106a3565b600054610100900460ff16158015610ddc576000805460ff1961ff0019909116610100171660011790555b610e4f8a8a8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8e018190048102820181019092528c815292508c91508b9081908401838280828437600092019190915250613bb192505050565b610e656006805462ff0000191662010000179055565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016610e9c60208801886147b1565b6001600160a01b031614610ee55760405162461bcd60e51b815260206004820152601060248201526f1b505cdcd95d081a5b98dbdc9c9958dd60821b60448201526064016106a3565b6040805160808101909152600c9080610f0160208a018a6147b1565b6001600160a01b03168152602001886020016020810190610f2291906147b1565b6001600160a01b0316815260006020820152604001600190528154600181810184556000938452602093849020835160029093020180546001600160a01b039384166001600160a01b031991821617825594840151918101805460408601511515600160a01b0260ff60a01b19949095169616959095179190911691909117808455606083015192939192919060ff60a81b1916600160a81b836007811115610fdb57634e487b7160e01b600052602160045260246000fd5b0217905550506040805180820182526305f5e100815260006020808301828152600d8054600181018255935292517fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb5909201805493516001600160801b03199094166001600160801b03938416178316600160801b9390941692909202929092179055815160808101909252600c92508190611079908901896147b1565b6001600160a01b0316815260200187602001602081019061109a91906147b1565b6001600160a01b031681526020016110b86060890160408a01614b37565b15158152602001600190528154600181810184556000938452602093849020835160029093020180546001600160a01b039384166001600160a01b031991821617825594840151918101805460408601511515600160a01b0260ff60a01b19949095169616959095179190911691909117808455606083015192939192919060ff60a81b1916600160a81b83600781111561116357634e487b7160e01b600052602160045260246000fd5b02179055505060408051808201909152600d91508061121361118860208a018a6147b1565b6001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156111c057600080fd5b505afa1580156111d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111f89190614f49565b61120390601a615b72565b61120e90600a615a43565b613bc1565b6001600160801b03908116825260006020928301819052845460018101865594815282812084519501805494909301518216600160801b029482166001600160801b03199094169390931716929092179091555b838110156113a55761127c60208801886147b1565b6001600160a01b0316633e37bcbc8686848181106112aa57634e487b7160e01b600052603260045260246000fd5b90506020020160208101906112bf91906147b1565b6040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260240160c06040518083038186803b1580156112fe57600080fd5b505afa158015611312573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113369190614ca2565b50611393905061134960208901896147b1565b600160ff1b87878581811061136e57634e487b7160e01b600052603260045260246000fd5b905060200201602081019061138391906147b1565b6001600160a01b03169190613c2a565b8061139d81615bf6565b915050611267565b5060006113c1606484600001516113bc9190615b14565b613d75565b604080516080810182526001600160401b039290921680835260208084018290526000928401839052606090930191909152600e805467ffffffffffffffff191682176fffffffffffffffff00000000000000001916600160401b909202919091176001600160801b03908116909155848201518051600f805492909401516001600160801b0319909216908316178216600160801b91909216021790555066016bcc41e90000600781905560085567016345785d8a0000600b8190556009558015611493576000805461ff00191690555b50505050505050505050565b3360008181526002602090815260408083206001600160a01b03871684529091528120549091610869918590610d239086906159c5565b6114de614596565b604080518082019091526000808252602082015260006114fd84613876565b905080604001516115405760405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a5908185cdcd95d609a1b60448201526064016106a3565b8051600c8054909160ff1690811061156857634e487b7160e01b600052603260045260246000fd5b600091825260209182902060408051608081018252600290930290910180546001600160a01b03908116845260018201549081169484019490945260ff600160a01b8504811615159284019290925291926060840191600160a81b9091041660078111156115e657634e487b7160e01b600052602160045260246000fd5b600781111561160557634e487b7160e01b600052602160045260246000fd5b8152505092506007600601816000015160ff168154811061163657634e487b7160e01b600052603260045260246000fd5b6000918252602091829020604080518082019091529101546001600160801b038082168352600160801b909104169181019190915292949293505050565b61167c61396f565b600654610100900460ff166116ca5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016106a3565b6006805461ff00191690556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1565b60065460009062010000900460ff166117365760405162461bcd60e51b81526004016106a39061566a565b6006805462ff00001916905561174a613dd9565b6001600160a01b0382166117705760405162461bcd60e51b81526004016106a39061561f565b600084116117905760405162461bcd60e51b81526004016106a39061564a565b600061179b86613876565b905060006117a76136c2565b90506117b33387613e40565b60405163f134c4fb60e01b8152600090732837c77527c37d61d9763f53005211dacb4125de9063f134c4fb906117f890600790869088908d908d908d90600401615852565b604080518083038186803b15801561180f57600080fd5b505af4158015611823573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118479190614efb565b6009549195509150801561188a57670de0b6b3a76400006118688284615b14565b61187291906159dd565b600a80546000906118849084906159c5565b90915550505b602084810151604080516001600160a01b038a811682529381018c90529290911690820152606081018690526080810183905233907f105ffcfe6c5fa767ff5a53039fdd9ba80ce97196d4daa0beb1bfbfa0ed838ad89060a0015b60405180910390a250506006805462ff0000191662010000179055509095945050505050565b61191361396f565b7390ae544e8cc76d2867987ee4f5456c02c50abd8b63bd5b0ac6600e8484611939613f8f565b6040516001600160e01b031960e087901b168152600481019490945260248401929092526044830152606482810191909152608482015260a40160006040518083038186803b15801561198b57600080fd5b505af415801561199f573d6000803e3d6000fd5b505050505050565b6119af61396f565b604051637203e78b60e01b81527390ae544e8cc76d2867987ee4f5456c02c50abd8b90637203e78b906119ed90600c908790879087906004016154b1565b60006040518083038186803b158015611a0557600080fd5b505af4158015611a19573d6000803e3d6000fd5b50505050505050565b6001600160a01b0381166000908152600160205260409020545b919050565b6000826001600160a01b0316846001600160a01b03161415611a755760405162461bcd60e51b81526004016106a3906155f9565b60008211611a955760405162461bcd60e51b81526004016106a39061564a565b6000611aa085613876565b90506000611aad85613876565b9050611ab982826140cc565b611ad55760405162461bcd60e51b81526004016106a3906155f9565b81604001518015611ae7575080604001515b15611ba85781518151732837c77527c37d61d9763f53005211dacb4125de9163dce9bf6a91600d91908860ff821615611b2257600754611b25565b60005b611b2d6136c2565b6040518763ffffffff1660e01b8152600401611b4e96959493929190615379565b604080518083038186803b158015611b6557600080fd5b505af4158015611b79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b9d9190614efb565b509250610d2e915050565b816040015115611cf957732837c77527c37d61d9763f53005211dacb4125de63dce9bf6a600d600160008881611bdc6136c2565b6040518763ffffffff1660e01b8152600401611bfd96959493929190615379565b604080518083038186803b158015611c1457600080fd5b505af4158015611c28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c4c9190614efb565b50604051633c554c3f60e11b81526001600160a01b038781166004830152602482018390529194507f0000000000000000000000000000000000000000000000000000000000000000909116906378aa987e9060440160206040518083038186803b158015611cba57600080fd5b505afa158015611cce573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cf29190614da6565b9250611e41565b60405163119849cf60e01b81526001600160a01b038781166004830152602482018690527f0000000000000000000000000000000000000000000000000000000000000000169063119849cf9060440160206040518083038186803b158015611d6157600080fd5b505afa158015611d75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d999190614da6565b9250732837c77527c37d61d9763f53005211dacb4125de63dce9bf6a60076006016000600187600760000154611dcd6136c2565b6040518763ffffffff1660e01b8152600401611dee96959493929190615379565b604080518083038186803b158015611e0557600080fd5b505af4158015611e19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e3d9190614efb565b5092505b50509392505050565b6000808211611e6b5760405162461bcd60e51b81526004016106a39061564a565b6000611e7684613876565b600854909150600090611e8a908590614161565b9050732837c77527c37d61d9763f53005211dacb4125de639e60b1c560076006018460400151611ebb576000611ebe565b84515b611ec88589615b33565b611ed06136c2565b6040518563ffffffff1660e01b8152600401611eef94939291906153bb565b60206040518083038186803b158015611f0757600080fd5b505af4158015611f1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f3f9190614da6565b92508160400151611fcd576020820151604051633c554c3f60e11b81526001600160a01b039182166004820152602481018590527f0000000000000000000000000000000000000000000000000000000000000000909116906378aa987e9060440160206040518083038186803b158015611fb957600080fd5b505afa158015610a64573d6000803e3d6000fd5b505092915050565b6040516385acd64160e01b81527fc10a28f028c7f7282a03c90608e38a4a646e136e614e4b07d119280c5f7f839f6004820152600090819033906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906385acd6419060240160206040518083038186803b15801561205b57600080fd5b505afa15801561206f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061209391906147cd565b6001600160a01b0316146120da5760405162461bcd60e51b815260206004820152600e60248201526d27b7363c903b30b634b230ba37b960911b60448201526064016106a3565b6120e2613dd9565b60065462010000900460ff1661210a5760405162461bcd60e51b81526004016106a39061566a565b6006805462ff000019169055604051630735024560e51b815260009081907390ae544e8cc76d2867987ee4f5456c02c50abd8b9063e6a048a09061215690600c90600d9060040161551f565b60006040518083038186803b15801561216e57600080fd5b505af4158015612182573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526121aa9190810190614a77565b9092509050732837c77527c37d61d9763f53005211dacb4125de637116e818600d84846121d56136c2565b6040518563ffffffff1660e01b81526004016121f49493929190615301565b60206040518083038186803b15801561220c57600080fd5b505af4158015612220573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122449190614da6565b600a54600354919550859161225991906159c5565b61226391906159c5565b60095490935080156122a457670de0b6b3a76400006122828287615b14565b61228c91906159dd565b600a805460009061229e9084906159c5565b90915550505b604080516000808252602082019283905230927f7d3ff197e9071095bd36b627028ef523ecf46fcbf17cbde745a4b65aec88b6bc926122e99233929091908890615190565b60405180910390a250506006805462ff0000191662010000179055509091565b61231161396f565b600654610100900460ff161561235c5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016106a3565b6006805461ff0019166101001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25890602001611701565b6060600580546107d890615bc1565b600080732837c77527c37d61d9763f53005211dacb4125de635dd72f5d600d6123d16136c2565b6040518363ffffffff1660e01b81526004016123ee9291906153ec565b604080518083038186803b15801561240557600080fd5b505af4158015612419573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061243d9190614efb565b915091509091565b6040516385acd64160e01b81527fc10a28f028c7f7282a03c90608e38a4a646e136e614e4b07d119280c5f7f839f600482015233906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906385acd6419060240160206040518083038186803b1580156124c657600080fd5b505afa1580156124da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124fe91906147cd565b6001600160a01b0316146125455760405162461bcd60e51b815260206004820152600e60248201526d27b7363c903b30b634b230ba37b960911b60448201526064016106a3565b600a5460018111156125e557600061255e600183615b33565b6001600a55905061256f3382614176565b307f7d3ff197e9071095bd36b627028ef523ecf46fcbf17cbde745a4b65aec88b6bc338360006040519080825280602002602001820160405280156125be578160200160208202803683370190505b50604080516000815260208101918290526125db94939291615190565b60405180910390a2505b50565b6125f061396f565b670429d069189e0000826001600160801b03161115801561262257506709b6e64a8ec60000816001600160801b031610155b61265c5760405162461bcd60e51b815260206004820152600b60248201526a2bb2b4b3b43a399037b7b160a91b60448201526064016106a3565b6040805180820182526001600160801b038481168083528482166020938401819052600f80546001600160801b0319168317909316600160801b8202179092558351908152918201527f1633022fee8dcf5a3cdeb5f1b49d5b734a3cfef7fc093e30cfdd28ddde8cd136910160405180910390a15050565b3360009081526002602090815260408083206001600160a01b0386168452909152812054828110156127565760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016106a3565b6127653385610d238685615b33565b5060019392505050565b60006108693384846139d9565b60065460009062010000900460ff166127a75760405162461bcd60e51b81526004016106a39061566a565b6006805462ff0000191690556127bb613dd9565b6001600160a01b0382166127e15760405162461bcd60e51b81526004016106a39061561f565b8380158015906127f057508087145b6128325760405162461bcd60e51b8152602060048201526013602482015272125b9d985b1a5908185c9c985e481a5b9c1d5d606a1b60448201526064016106a3565b600084116128525760405162461bcd60e51b81526004016106a39061564a565b60006128908989808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506134b292505050565b90506000732837c77527c37d61d9763f53005211dacb4125de638c913b9460076128b86136c2565b858c8c8c8c6040518863ffffffff1660e01b81526004016128df979695949392919061575f565b604080518083038186803b1580156128f657600080fd5b505af415801561290a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061292e9190614efb565b909450905061293d3385613e40565b600954801561297b57670de0b6b3a76400006129598284615b14565b61296391906159dd565b600a80546000906129759084906159c5565b90915550505b336001600160a01b03167fdf5bf345d5d6eedd0e8667d799d60af65d7127e3b0417e04bef4d954d2a4750e87878e8e8e8e896040516129c09796959493929190615211565b60405180910390a250506006805462ff00001916620100001790555090979650505050505050565b60065460009062010000900460ff16612a135760405162461bcd60e51b81526004016106a39061566a565b6006805462ff000019169055612a27613dd9565b6001600160a01b038216612a4d5760405162461bcd60e51b81526004016106a39061561f565b838015801590612a5c57508087145b612a9f5760405162461bcd60e51b8152602060048201526014602482015273092dce0eae840c2e4e4c2f240dad2e6dac2e8c6d60631b60448201526064016106a3565b6000612add8989808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506134b292505050565b9050732837c77527c37d61d9763f53005211dacb4125de63b4ff6eae6007612b036136c2565b848b8b8b6040518763ffffffff1660e01b8152600401612b289695949392919061570f565b60206040518083038186803b158015612b4057600080fd5b505af4158015612b54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b789190614da6565b9250612b848484614176565b336001600160a01b03167f7d3ff197e9071095bd36b627028ef523ecf46fcbf17cbde745a4b65aec88b6bc85858c8c8c8c604051612bc7969594939291906151c9565b60405180910390a250506006805462ff00001916620100001790559695505050505050565b60065460609062010000900460ff16612c175760405162461bcd60e51b81526004016106a39061566a565b6006805462ff000019169055612c2b613dd9565b6001600160a01b038216612c515760405162461bcd60e51b81526004016106a39061561f565b60008511612c715760405162461bcd60e51b81526004016106a39061564a565b6000612c7b6136c2565b9050612c873387613e40565b60606000732837c77527c37d61d9763f53005211dacb4125de636fdc2ea26007858b8b8b8b6040518763ffffffff1660e01b8152600401612ccd9695949392919061589d565b60006040518083038186803b158015612ce557600080fd5b505af4158015612cf9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612d219190810190614dbe565b6009549096509093509091508015612d6857670de0b6b3a7640000612d468284615b14565b612d5091906159dd565b600a8054600090612d629084906159c5565b90915550505b336001600160a01b03167fdf5bf345d5d6eedd0e8667d799d60af65d7127e3b0417e04bef4d954d2a4750e878b8689876040516118e5959493929190615261565b612db16145be565b612db96136c2565b905090565b612dc661396f565b7390ae544e8cc76d2867987ee4f5456c02c50abd8b63ceb5ad27600e612dea613f8f565b6040516001600160e01b031960e085901b1681526004810192909252602482015260440160006040518083038186803b158015612e2657600080fd5b505af4158015612e3a573d6000803e3d6000fd5b50505050565b612e4861396f565b662386f26fc10000831115612e8f5760405162461bcd60e51b815260206004820152600d60248201526c29bbb0b8103930ba329037b7b160991b60448201526064016106a3565b662386f26fc10000821115612edc5760405162461bcd60e51b81526020600482015260136024820152722932b232b6b83a34b7b7103930ba329037b7b160691b60448201526064016106a3565b6706f05b59d3b20000811115612f275760405162461bcd60e51b815260206004820152601060248201526f23b7bb103332b2903930ba329037b7b160811b60448201526064016106a3565b60078390556008829055600981905560408051848152602081018490529081018290527fe06a46af1c04656f68e4f75cbbb23baa176651c7f99930a378ef9f1616dc2b8c9060600160405180910390a1505050565b60065460009062010000900460ff16612fa75760405162461bcd60e51b81526004016106a39061566a565b6006805462ff000019169055612fbb613dd9565b6001600160a01b038216612fe15760405162461bcd60e51b81526004016106a39061561f565b846001600160a01b0316866001600160a01b031614156130135760405162461bcd60e51b81526004016106a3906155f9565b600084116130335760405162461bcd60e51b81526004016106a39061564a565b600061303e87613876565b9050600061304b87613876565b905061305782826140cc565b6130735760405162461bcd60e51b81526004016106a3906155f9565b6000732837c77527c37d61d9763f53005211dacb4125de635c1ba5f060076130996136c2565b86868c8c8c6040518863ffffffff1660e01b81526004016130c097969594939291906157c1565b604080518083038186803b1580156130d757600080fd5b505af41580156130eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061310f9190614efb565b6009549195509150801561315257670de0b6b3a76400006131308284615b14565b61313a91906159dd565b600a805460009061314c9084906159c5565b90915550505b60208481015184820151604080516001600160a01b03938416815291831693820193909352918201879052606082018490528716608082015233907f1eeaa4acf3c225a4033105c2647625dbb298dec93b14e16253c4231e26c02b1d9060a00160405180910390a250506006805462ff000019166201000017905550909695505050505050565b60008180158015906131ea57508085145b61322d5760405162461bcd60e51b8152602060048201526014602482015273092dce0eae840c2e4e4c2f240dad2e6dac2e8c6d60631b60448201526064016106a3565b600061326b8787808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506134b292505050565b9050732837c77527c37d61d9763f53005211dacb4125de637116e818600d8388886132946136c2565b6040518663ffffffff1660e01b81526004016132b49594939291906152ad565b60206040518083038186803b1580156132cc57600080fd5b505af41580156132e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133049190614da6565b979650505050505050565b60065460009062010000900460ff1661333a5760405162461bcd60e51b81526004016106a39061566a565b6006805462ff00001916905561334e613dd9565b6001600160a01b0382166133745760405162461bcd60e51b81526004016106a39061561f565b600084116133945760405162461bcd60e51b81526004016106a39061564a565b600061339f86613876565b9050732837c77527c37d61d9763f53005211dacb4125de636089efbc60076133c56136c2565b8489896040518663ffffffff1660e01b81526004016133e895949392919061581b565b60206040518083038186803b15801561340057600080fd5b505af4158015613414573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134389190614da6565b91506134448383614176565b604080516001600160a01b0385811682526020820185905288168183015260608101879052905133917f30873c596f54a2e2e09894670d7e1a48b2433c00204f81fbedf557353c36e7c7919081900360800190a2506006805462ff0000191662010000179055949350505050565b8051606090806001600160401b038111156134dd57634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015613506578160200160208202803683370190505b50604080516060810182526000808252602082018190529181018290529193505b828110156136ba5761355f85828151811061355257634e487b7160e01b600052603260045260246000fd5b6020026020010151613876565b9150816000015184828151811061358657634e487b7160e01b600052603260045260246000fd5b602002602001019060ff16908160ff168152505081604001516135db5760405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a5908185cdcd95d609a1b60448201526064016106a3565b60006135e88260016159c5565b90505b838110156136a75785818151811061361357634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b031686838151811061364457634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b031614156136955760405162461bcd60e51b815260206004820152600f60248201526e111d5c1b1a58d85d1948185cdcd95d608a1b60448201526064016106a3565b8061369f81615bf6565b9150506135eb565b50806136b281615bf6565b915050613527565b505050919050565b6136ca6145be565b60405180606001604052806007600301546136e460035490565b6136ee91906159c5565b81526020016136fb613f8f565b815260408051808201909152600f546001600160801b038082168352600160801b9091041660208281019190915290910152905090565b600081613747670de0b6b3a764000085615b14565b610d2e91906159dd565b6001600160a01b0383166137b35760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016106a3565b6001600160a01b0382166138145760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016106a3565b6001600160a01b0383811660008181526002602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b60408051606081018252600080825260208201819052918101919091527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614156138f9575060408051606081018252600081526001600160a01b0383166020820152600191810191909152611a3c565b6040518060600160405280600160ff168152602001836001600160a01b03168152602001836001600160a01b0316600760050160018154811061394c57634e487b7160e01b600052603260045260246000fd5b60009182526020909120600290910201546001600160a01b031614905292915050565b613977614255565b6001600160a01b0316336001600160a01b0316146139d75760405162461bcd60e51b815260206004820152601960248201527f4f6e6c7920676f7665726e6f722063616e20657865637574650000000000000060448201526064016106a3565b565b6001600160a01b038316613a3d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016106a3565b6001600160a01b038216613a9f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016106a3565b6001600160a01b03831660009081526001602052604090205481811015613b175760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016106a3565b613b218282615b33565b6001600160a01b038086166000908152600160205260408082209390935590851681529081208054849290613b579084906159c5565b92505081905550826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051613ba391815260200190565b60405180910390a350505050565b613bbd828260126142e8565b5050565b6000600160801b8210613c265760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b60648201526084016106a3565b5090565b801580613cb35750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b158015613c7957600080fd5b505afa158015613c8d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cb19190614da6565b155b613d1e5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b60648201526084016106a3565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052613d70908490614328565b505050565b6000600160401b8210613c265760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b60648201526084016106a3565b600654610100900460ff161580613e085750613df36143fa565b6001600160a01b0316336001600160a01b0316145b6139d75760405162461bcd60e51b8152602060048201526009602482015268556e6865616c74687960b81b60448201526064016106a3565b6001600160a01b038216613ea05760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016106a3565b6001600160a01b03821660009081526001602052604090205481811015613f145760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016106a3565b613f1e8282615b33565b6001600160a01b03841660009081526001602052604081209190915560038054849290613f4c908490615b33565b90915550506040518281526000906001600160a01b038516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90602001613869565b60408051608081018252600e546001600160401b038082168352600160401b8204811660208401819052600160801b8304821694840194909452600160c01b909104166060820181905260009290428111156140b957825160408401516000806140026001600160401b03841642615b33565b61400c8487615b4a565b6001600160401b031691509150836001600160401b0316866001600160401b0316111561407d57808261403f8689615b4a565b6001600160401b03166140529190615b14565b61405c91906159dd565b61406f906001600160401b0386166159c5565b975050505050505050610859565b80826140898887615b4a565b6001600160401b031661409c9190615b14565b6140a691906159dd565b61406f906001600160401b038616615b33565b506001600160401b031691506108599050565b600082604001511580156140e257508160400151155b156140ef5750600061086d565b82604001518015614101575081604001515b1561410e5750600161086d565b826040015180156141265750826000015160ff166001145b156141335750600161086d565b8160400151801561414b5750816000015160ff166001145b156141585750600161086d565b50600092915050565b6000610d2e8383670de0b6b3a764000061447c565b6001600160a01b0382166141cc5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016106a3565b80600360008282546141de91906159c5565b90915550506001600160a01b0382166000908152600160205260408120805483929061420b9084906159c5565b90915550506040518181526001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b1580156142b057600080fd5b505afa1580156142c4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612db991906147cd565b82516142fb906004906020860190614606565b50815161430f906005906020850190614606565b506006805460ff191660ff929092169190911790555050565b600061437d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661449b9092919063ffffffff16565b805190915015613d70578080602001905181019061439b9190614b53565b613d705760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016106a3565b6040516385acd64160e01b81527f39e3ed1fc335ce346a8cbe3e64dd525cf22b37f1e2104a755e761c3c1eb4734f60048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906385acd6419060240160206040518083038186803b1580156142b057600080fd5b6000816144898486615b14565b61449391906159dd565b949350505050565b6060614493848460008585843b6144f45760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016106a3565b600080866001600160a01b031685876040516145109190615174565b60006040518083038185875af1925050503d806000811461454d576040519150601f19603f3d011682016040523d82523d6000602084013e614552565b606091505b50915091506133048282866060831561456c575081610d2e565b82511561457c5782518084602001fd5b8160405162461bcd60e51b81526004016106a391906155c6565b604080516080810182526000808252602082018190529181018290529060608201905b905290565b604051806060016040528060008152602001600081526020016145b9604051806040016040528060006001600160801b0316815260200160006001600160801b031681525090565b82805461461290615bc1565b90600052602060002090601f016020900481019282614634576000855561467a565b82601f1061464d57805160ff191683800117855561467a565b8280016001018555821561467a579182015b8281111561467a57825182559160200191906001019061465f565b50613c269291505b80821115613c265760008155600101614682565b60008083601f8401126146a7578182fd5b5081356001600160401b038111156146bd578182fd5b60208301915083602080830285010111156146d757600080fd5b9250929050565b600082601f8301126146ee578081fd5b815160206147036146fe836159a2565b615972565b828152818101908583018385028701840188101561471f578586fd5b855b8581101561473d57815184529284019290840190600101614721565b5090979650505050505050565b60008083601f84011261475b578182fd5b5081356001600160401b03811115614771578182fd5b6020830191508360208285010111156146d757600080fd5b60006080828403121561479a578081fd5b50919050565b805160ff81168114611a3c57600080fd5b6000602082840312156147c2578081fd5b8135610d2e81615c3d565b6000602082840312156147de578081fd5b8151610d2e81615c3d565b600080604083850312156147fb578081fd5b823561480681615c3d565b9150602083013561481681615c3d565b809150509250929050565b600080600060608486031215614835578081fd5b833561484081615c3d565b9250602084013561485081615c3d565b929592945050506040919091013590565b600080600080600060a08688031215614878578283fd5b853561488381615c3d565b9450602086013561489381615c3d565b9350604086013592506060860135915060808601356148b181615c3d565b809150509295509295909350565b600080604083850312156148d1578182fd5b82356148dc81615c3d565b946020939093013593505050565b600080600080608085870312156148ff578182fd5b843561490a81615c3d565b93506020850135925060408501359150606085013561492881615c3d565b939692955090935050565b600080600060408486031215614947578081fd5b83356001600160401b0381111561495c578182fd5b61496886828701614696565b909450925050602084013561497c81615c3d565b809150509250925092565b6000806000806040858703121561499c578182fd5b84356001600160401b03808211156149b2578384fd5b6149be88838901614696565b909650945060208701359150808211156149d6578384fd5b506149e387828801614696565b95989497509550505050565b60008060008060008060808789031215614a07578384fd5b86356001600160401b0380821115614a1d578586fd5b614a298a838b01614696565b90985096506020890135915080821115614a41578586fd5b50614a4e89828a01614696565b909550935050604087013591506060870135614a6981615c3d565b809150509295509295509295565b60008060408385031215614a89578182fd5b82516001600160401b0380821115614a9f578384fd5b818501915085601f830112614ab2578384fd5b81516020614ac26146fe836159a2565b82815281810190858301838502870184018b1015614ade578889fd5b8896505b84871015614b0757614af3816147a0565b835260019690960195918301918301614ae2565b5091880151919650909350505080821115614b20578283fd5b50614b2d858286016146de565b9150509250929050565b600060208284031215614b48578081fd5b8135610d2e81615c52565b600060208284031215614b64578081fd5b8151610d2e81615c52565b6000806000806000806000806000898b036101c0811215614b8e578788fd5b8a356001600160401b0380821115614ba457898afd5b614bb08e838f0161474a565b909c509a5060208d0135915080821115614bc857898afd5b614bd48e838f0161474a565b909a509850889150614be98e60408f01614789565b9750614bf88e60c08f01614789565b96506101408d0135915080821115614c0e578586fd5b50614c1b8d828e01614696565b909550935050606061015f1982011215614c33578182fd5b614c3d6040615972565b6101608c01358152604061017f1983011215614c57578283fd5b614c616040615972565b91506101808c0135614c7281615c60565b82526101a08c0135614c8381615c60565b8060208401525081602082015280925050509295985092959850929598565b60008082840360c0811215614cb5578283fd5b6080811215614cc2578283fd5b614ccc6080615972565b8451614cd781615c3d565b81526020850151614ce781615c3d565b60208201526040850151614cfa81615c52565b6040820152606085015160088110614d10578485fd5b606082015292506040607f1982011215614d28578182fd5b50614d336040615972565b6080840151614d4181615c60565b815260a0840151614d5181615c60565b6020820152919491935090915050565b60008060408385031215614d73578182fd5b8235614d7e81615c60565b9150602083013561481681615c60565b600060208284031215614d9f578081fd5b5035919050565b600060208284031215614db7578081fd5b5051919050565b600080600060608486031215614dd2578081fd5b835192506020808501516001600160401b0380821115614df0578384fd5b818701915087601f830112614e03578384fd5b8151614e116146fe826159a2565b81815284810190848601868402860187018c1015614e2d578788fd5b8795505b83861015614e58578051614e4481615c3d565b835260019590950194918601918601614e31565b5060408a01519097509450505080831115614e71578384fd5b5050614e7f868287016146de565b9150509250925092565b60008060008060608587031215614e9e578182fd5b8435935060208501356001600160401b03811115614eba578283fd5b614ec687828801614696565b909450925050604085013561492881615c3d565b60008060408385031215614eec578182fd5b50508035926020909101359150565b60008060408385031215614f0d578182fd5b505080516020909101519092909150565b600080600060608486031215614f32578081fd5b505081359360208301359350604090920135919050565b600060208284031215614f5a578081fd5b610d2e826147a0565b60008284526020808501945082825b85811015614fa0578135614f8581615c3d565b6001600160a01b031687529582019590820190600101614f72565b509495945050505050565b6000815180845260208085019450808401835b83811015614fa05781516001600160a01b031687529582019590820190600101614fbe565b6000815480845260208085019450838352808320835b83811015614fa05781546001600160801b038116885260801c8388015260409096019560019182019101614ff9565b81835260006001600160fb1b03831115615040578081fd5b6020830280836020870137939093016020019283525090919050565b6000815180845260208085019450808401835b83811015614fa05781518752958201959082019060010161506f565b6000815180845260208085019450808401835b83811015614fa057815160ff168752958201959082019060010161509e565b600881106150db57634e487b7160e01b600052602160045260246000fd5b9052565b805160ff1682526020808201516001600160a01b0316908301526040908101511515910152565b60018060a01b03808251168352806020830151166020840152506040810151151560408301526060810151613d7060608401826150bd565b80518252602081015160208301526040810151613d70604084018280516001600160801b03908116835260209182015116910152565b60008251615186818460208701615b95565b9190910192915050565b600060018060a01b0386168252846020830152608060408301526151b76080830185614fab565b8281036060840152613304818561505c565b600060018060a01b0388168252866020830152608060408301526151f1608083018688614f63565b8281036060840152615204818587615028565b9998505050505050505050565b600060018060a01b038916825287602083015260a0604083015261523960a083018789614f63565b828103606084015261524c818688615028565b91505082608083015298975050505050505050565b600060018060a01b038716825285602083015260a0604083015261528860a0830186614fab565b828103606084015261529a818661505c565b9150508260808301529695505050505050565b600060e082526152c060e0830188614fe3565b82810360208401526152d2818861508b565b905082810360408401526152e7818688615028565b9150506152f7606083018461513e565b9695505050505050565b600060e0825261531460e0830187614fe3565b602083820381850152615327828861508b565b84810360408601528651808252828801935090820190845b8181101561535b5784518352938301939183019160010161533f565b5050809350505050615370606083018461513e565b95945050505050565b600061012080835261538d8184018a614fe3565b91505060ff8716602083015260ff8616604083015284606083015283608083015261330460a083018461513e565b600060e082526153ce60e0830187614fe3565b905060ff85166020830152836040830152615370606083018461513e565b600060a082526153ff60a0830185614fe3565b9050610d2e602083018461513e565b60408082528351828201819052600091906020906060850190828801855b828110156154525761543f848351615106565b608093909301929084019060010161542c565b50505084810382860152855180825286830191830190855b818110156154a35761549383855180516001600160801b03908116835260209182015116910152565b928401929185019160010161546a565b509098975050505050505050565b84815260606020808301829052908201849052600090859060808401835b878110156154fd5783356154e281615c3d565b6001600160a01b0316825292820192908201906001016154cf565b506001600160a01b039590951660409490940193909352509195945050505050565b600060408083018184528086548083526060925082860191508785526020808620865b8381101561559f5781546001600160a01b03908116865260018301549081168487015260ff60a082901c81161515898801529061558788880160a883901c84166150bd565b50506080949094019360029190910190600101615542565b505095909501959095525092949350505050565b600060208252610d2e602083018461505c565b60006020825282518060208401526155e5816040850160208701615b95565b601f01601f19169190910160400192915050565b6020808252600c908201526b24b73b30b634b2103830b4b960a11b604082015260600190565b602080825260119082015270125b9d985b1a59081c9958da5c1a595b9d607a1b604082015260600190565b60208082526006908201526505174793d3d360d41b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60c081016156af8285615106565b82516001600160801b03908116608084015260208401511660a0830152610d2e565b600060808201905082518252602083015160208301526040830151610a8c604084018280516001600160801b03908116835260209182015116910152565b6000610100888352615724602084018961513e565b8060a08401526157368184018861508b565b905082810360c084015261574b818688615028565b9150508260e0830152979650505050505050565b6000610120898352615774602084018a61513e565b8060a08401526157868184018961508b565b905082810360c084015261579b818789615028565b60e084019590955250506001600160a01b03919091166101009091015295945050505050565b8781526101c081016157d6602083018961513e565b6157e360a08301886150df565b6157f16101008301876150df565b6101608201949094526101808101929092526001600160a01b03166101a090910152949350505050565b8581526101408101615830602083018761513e565b61583d60a08301866150df565b61010082019390935261012001529392505050565b8681526101608101615867602083018861513e565b61587460a08301876150df565b6101008201949094526101208101929092526001600160a01b0316610140909101529392505050565b60006101008883526158b2602084018961513e565b8660a08401528060c08401526158cb8184018688615028565b91505060018060a01b03831660e0830152979650505050505050565b6000610160820190508882528760208301528660408301528560608301528460808301526001600160401b038085511660a08401528060208601511660c08401528060408601511660e0840152806060860151166101008401525061596661012083018480516001600160801b03908116835260209182015116910152565b98975050505050505050565b604051601f8201601f191681016001600160401b038111828210171561599a5761599a615c27565b604052919050565b60006001600160401b038211156159bb576159bb615c27565b5060209081020190565b600082198211156159d8576159d8615c11565b500190565b6000826159f857634e487b7160e01b81526012600452602481fd5b500490565b80825b6001808611615a0f5750615a3a565b818704821115615a2157615a21615c11565b80861615615a2e57918102915b9490941c938002615a00565b94509492505050565b6000610d2e60001960ff851684600082615a5f57506001610d2e565b81615a6c57506000610d2e565b8160018114615a825760028114615a8c57615ab9565b6001915050610d2e565b60ff841115615a9d57615a9d615c11565b6001841b915084821115615ab357615ab3615c11565b50610d2e565b5060208310610133831016604e8410600b8410161715615aec575081810a83811115615ae757615ae7615c11565b610d2e565b615af984848460016159fd565b808604821115615b0b57615b0b615c11565b02949350505050565b6000816000190483118215151615615b2e57615b2e615c11565b500290565b600082821015615b4557615b45615c11565b500390565b60006001600160401b0383811690831681811015615b6a57615b6a615c11565b039392505050565b600060ff821660ff841680821015615b8c57615b8c615c11565b90039392505050565b60005b83811015615bb0578181015183820152602001615b98565b83811115612e3a5750506000910152565b600281046001821680615bd557607f821691505b6020821081141561479a57634e487b7160e01b600052602260045260246000fd5b6000600019821415615c0a57615c0a615c11565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b03811681146125e557600080fd5b80151581146125e557600080fd5b6001600160801b03811681146125e557600080fdfea2646970667358221220850dd1f167ac97afe719deef338bad5974094486512a857d3b35961d8341c7f664736f6c63430008020033000000000000000000000000afce80b19a8ce13dec0739a1aab7a028d6845eb3000000000000000000000000e2f2a5c287993345a840db3b0845fbc70f5935a5

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102535760003560e01c806373d4a13a11610146578063a9059cbb116100c3578063c4db7fa011610087578063c4db7fa0146105c7578063cec10c11146105cf578063d5bcb9b5146105e2578063dd62ed3e146105f5578063e5555b8f1461062e578063f74bfe8e1461064157610253565b8063a9059cbb14610559578063aa5d27e91461056c578063af290bd41461057f578063c1db77ec14610592578063c3f909d4146105b257610253565b806398d5fdca1161010a57806398d5fdca146104fc57806398fec3af14610504578063a1c251511461050c578063a3f5c1d21461051f578063a457c2d71461054657610253565b806373d4a13a1461042257806378aa987e146104bc5780637e8901ea146104cf5780638456cb59146104ec57806395d89b41146104f457610253565b8063313ce567116101d457806344e3fa3c1161019857806344e3fa3c146103c55780635c975abb146103d85780636fb3e89c146103e957806370a08231146103fc57806372ea90761461040f57610253565b8063313ce5671461036157806339509351146103765780633e37bcbc146103895780633f4ba83a146103aa57806343bcfab6146103b257610253565b806318160ddd1161021b57806318160ddd146103085780631820783d146103105780631d3ce3981461032557806323b872dd1461033b57806323fb4bd31461034e57610253565b806304de5a731461025857806306fdde031461027e578063095ea7b314610293578063119849cf146102b6578063178d341f146102c9575b600080fd5b61026b610266366004614987565b610654565b6040519081526020015b60405180910390f35b6102866107c9565b60405161027591906155c6565b6102a66102a13660046148bf565b61085c565b6040519015158152602001610275565b61026b6102c43660046148bf565b610873565b6102f07f000000000000000000000000e2f2a5c287993345a840db3b0845fbc70f5935a581565b6040516001600160a01b039091168152602001610275565b60035461026b565b61032361031e366004614d8e565b610a93565b005b61032d610b1f565b60405161027592919061540e565b6102a6610349366004614821565b610c82565b61032361035c366004614b6f565b610d35565b60065460405160ff9091168152602001610275565b6102a66103843660046148bf565b61149f565b61039c6103973660046147b1565b6114d6565b6040516102759291906156a1565b610323611674565b61026b6103c03660046148ea565b61170b565b6103236103d3366004614eda565b61190b565b6102a6600654610100900460ff1690565b6103236103f7366004614933565b6119a7565b61026b61040a3660046147b1565b611a22565b61026b61041d366004614821565b611a41565b600754600854600954600a54600b5460408051608081018252600e546001600160401b038082168352600160401b82048116602080850191909152600160801b808404831685870152600160c01b90930490911660608401528351808501909452600f546001600160801b038082168652929004909116908301526104a996959493929187565b60405161027597969594939291906158e7565b61026b6104ca3660046148bf565b611e4a565b6104d7611fd5565b60408051928352602083019190915201610275565b610323612309565b61028661239b565b6104d76123aa565b610323612445565b61032361051a366004614d61565b6125e8565b6102f07f000000000000000000000000afce80b19a8ce13dec0739a1aab7a028d6845eb381565b6102a66105543660046148bf565b6126d4565b6102a66105673660046148bf565b61276f565b61026b61057a3660046149ef565b61277c565b61026b61058d3660046149ef565b6129e8565b6105a56105a0366004614e89565b612bec565b60405161027591906155b3565b6105ba612da9565b60405161027591906156d1565b610323612dbe565b6103236105dd366004614f1e565b612e40565b61026b6105f0366004614861565b612f7c565b61026b6106033660046147e9565b6001600160a01b03918216600090815260026020908152604080832093909416825291909152205490565b61026b61063c366004614987565b6131d9565b61026b61064f3660046148ea565b61330f565b600081801580159061066557508085145b6106ac5760405162461bcd60e51b8152602060048201526013602482015272125b9d985b1a5908185c9c985e481a5b9c1d5d606a1b60448201526064015b60405180910390fd5b60006106ea8787808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506134b292505050565b90506000732837c77527c37d61d9763f53005211dacb4125de637cdc8e40600d8489896107156136c2565b6040518663ffffffff1660e01b81526004016107359594939291906152ad565b60206040518083038186803b15801561074d57600080fd5b505af4158015610761573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107859190614da6565b6008549091506107a8906107a190670de0b6b3a7640000615b33565b8290613732565b935083156107be576107bb6001856159c5565b93505b505050949350505050565b6060600480546107d890615bc1565b80601f016020809104026020016040519081016040528092919081815260200182805461080490615bc1565b80156108515780601f1061082657610100808354040283529160200191610851565b820191906000526020600020905b81548152906001019060200180831161083457829003601f168201915b505050505090505b90565b6000610869338484613751565b5060015b92915050565b60008082116108945760405162461bcd60e51b81526004016106a39061564a565b600061089f84613876565b905080604001511561094b578051732837c77527c37d61d9763f53005211dacb4125de9063d1be552890600d90866108d56136c2565b6040518563ffffffff1660e01b81526004016108f494939291906153bb565b60206040518083038186803b15801561090c57600080fd5b505af4158015610920573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109449190614da6565b9150610a8c565b60405163119849cf60e01b81526001600160a01b038581166004830152602482018590526000917f000000000000000000000000e2f2a5c287993345a840db3b0845fbc70f5935a59091169063119849cf9060440160206040518083038186803b1580156109b857600080fd5b505afa1580156109cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109f09190614da6565b9050732837c77527c37d61d9763f53005211dacb4125de63d1be5528600d600084610a196136c2565b6040518563ffffffff1660e01b8152600401610a3894939291906153bb565b60206040518083038186803b158015610a5057600080fd5b505af4158015610a64573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a889190614da6565b9250505b5092915050565b610a9b61396f565b6702c68af0bb140000811115610ae45760405162461bcd60e51b815260206004820152600e60248201526d4d757374206265203c3d2032302560901b60448201526064016106a3565b600b8190556040518181527f2f5a6b1defeafd30e7568ea5c176aa0702b0af5b00ba41fa20e58b2c72e8afe79060200160405180910390a150565b6060806007600501600760060181805480602002602001604051908101604052809291908181526020016000905b82821015610c04576000848152602090819020604080516080810182526002860290920180546001600160a01b03908116845260018201549081169484019490945260ff600160a01b8504811615159284019290925291926060840191600160a81b909104166007811115610bd257634e487b7160e01b600052602160045260246000fd5b6007811115610bf157634e487b7160e01b600052602160045260246000fd5b8152505081526020019060010190610b4d565b50505050915080805480602002602001604051908101604052809291908181526020016000905b82821015610c7457600084815260209081902060408051808201909152908401546001600160801b038082168352600160801b9091041681830152825260019092019101610c2b565b505050509050915091509091565b6000610c8f8484846139d9565b6001600160a01b038416600090815260026020908152604080832033845290915290205482811015610d145760405162461bcd60e51b815260206004820152602860248201527f45524332303a207472616e7366657220616d6f756e74206578636565647320616044820152676c6c6f77616e636560c01b60648201526084016106a3565b610d288533610d238685615b33565b613751565b60019150505b9392505050565b600054610100900460ff1680610d4e575060005460ff16155b610db15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016106a3565b600054610100900460ff16158015610ddc576000805460ff1961ff0019909116610100171660011790555b610e4f8a8a8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8e018190048102820181019092528c815292508c91508b9081908401838280828437600092019190915250613bb192505050565b610e656006805462ff0000191662010000179055565b6001600160a01b037f000000000000000000000000e2f2a5c287993345a840db3b0845fbc70f5935a516610e9c60208801886147b1565b6001600160a01b031614610ee55760405162461bcd60e51b815260206004820152601060248201526f1b505cdcd95d081a5b98dbdc9c9958dd60821b60448201526064016106a3565b6040805160808101909152600c9080610f0160208a018a6147b1565b6001600160a01b03168152602001886020016020810190610f2291906147b1565b6001600160a01b0316815260006020820152604001600190528154600181810184556000938452602093849020835160029093020180546001600160a01b039384166001600160a01b031991821617825594840151918101805460408601511515600160a01b0260ff60a01b19949095169616959095179190911691909117808455606083015192939192919060ff60a81b1916600160a81b836007811115610fdb57634e487b7160e01b600052602160045260246000fd5b0217905550506040805180820182526305f5e100815260006020808301828152600d8054600181018255935292517fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb5909201805493516001600160801b03199094166001600160801b03938416178316600160801b9390941692909202929092179055815160808101909252600c92508190611079908901896147b1565b6001600160a01b0316815260200187602001602081019061109a91906147b1565b6001600160a01b031681526020016110b86060890160408a01614b37565b15158152602001600190528154600181810184556000938452602093849020835160029093020180546001600160a01b039384166001600160a01b031991821617825594840151918101805460408601511515600160a01b0260ff60a01b19949095169616959095179190911691909117808455606083015192939192919060ff60a81b1916600160a81b83600781111561116357634e487b7160e01b600052602160045260246000fd5b02179055505060408051808201909152600d91508061121361118860208a018a6147b1565b6001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156111c057600080fd5b505afa1580156111d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111f89190614f49565b61120390601a615b72565b61120e90600a615a43565b613bc1565b6001600160801b03908116825260006020928301819052845460018101865594815282812084519501805494909301518216600160801b029482166001600160801b03199094169390931716929092179091555b838110156113a55761127c60208801886147b1565b6001600160a01b0316633e37bcbc8686848181106112aa57634e487b7160e01b600052603260045260246000fd5b90506020020160208101906112bf91906147b1565b6040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260240160c06040518083038186803b1580156112fe57600080fd5b505afa158015611312573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113369190614ca2565b50611393905061134960208901896147b1565b600160ff1b87878581811061136e57634e487b7160e01b600052603260045260246000fd5b905060200201602081019061138391906147b1565b6001600160a01b03169190613c2a565b8061139d81615bf6565b915050611267565b5060006113c1606484600001516113bc9190615b14565b613d75565b604080516080810182526001600160401b039290921680835260208084018290526000928401839052606090930191909152600e805467ffffffffffffffff191682176fffffffffffffffff00000000000000001916600160401b909202919091176001600160801b03908116909155848201518051600f805492909401516001600160801b0319909216908316178216600160801b91909216021790555066016bcc41e90000600781905560085567016345785d8a0000600b8190556009558015611493576000805461ff00191690555b50505050505050505050565b3360008181526002602090815260408083206001600160a01b03871684529091528120549091610869918590610d239086906159c5565b6114de614596565b604080518082019091526000808252602082015260006114fd84613876565b905080604001516115405760405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a5908185cdcd95d609a1b60448201526064016106a3565b8051600c8054909160ff1690811061156857634e487b7160e01b600052603260045260246000fd5b600091825260209182902060408051608081018252600290930290910180546001600160a01b03908116845260018201549081169484019490945260ff600160a01b8504811615159284019290925291926060840191600160a81b9091041660078111156115e657634e487b7160e01b600052602160045260246000fd5b600781111561160557634e487b7160e01b600052602160045260246000fd5b8152505092506007600601816000015160ff168154811061163657634e487b7160e01b600052603260045260246000fd5b6000918252602091829020604080518082019091529101546001600160801b038082168352600160801b909104169181019190915292949293505050565b61167c61396f565b600654610100900460ff166116ca5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016106a3565b6006805461ff00191690556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1565b60065460009062010000900460ff166117365760405162461bcd60e51b81526004016106a39061566a565b6006805462ff00001916905561174a613dd9565b6001600160a01b0382166117705760405162461bcd60e51b81526004016106a39061561f565b600084116117905760405162461bcd60e51b81526004016106a39061564a565b600061179b86613876565b905060006117a76136c2565b90506117b33387613e40565b60405163f134c4fb60e01b8152600090732837c77527c37d61d9763f53005211dacb4125de9063f134c4fb906117f890600790869088908d908d908d90600401615852565b604080518083038186803b15801561180f57600080fd5b505af4158015611823573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118479190614efb565b6009549195509150801561188a57670de0b6b3a76400006118688284615b14565b61187291906159dd565b600a80546000906118849084906159c5565b90915550505b602084810151604080516001600160a01b038a811682529381018c90529290911690820152606081018690526080810183905233907f105ffcfe6c5fa767ff5a53039fdd9ba80ce97196d4daa0beb1bfbfa0ed838ad89060a0015b60405180910390a250506006805462ff0000191662010000179055509095945050505050565b61191361396f565b7390ae544e8cc76d2867987ee4f5456c02c50abd8b63bd5b0ac6600e8484611939613f8f565b6040516001600160e01b031960e087901b168152600481019490945260248401929092526044830152606482810191909152608482015260a40160006040518083038186803b15801561198b57600080fd5b505af415801561199f573d6000803e3d6000fd5b505050505050565b6119af61396f565b604051637203e78b60e01b81527390ae544e8cc76d2867987ee4f5456c02c50abd8b90637203e78b906119ed90600c908790879087906004016154b1565b60006040518083038186803b158015611a0557600080fd5b505af4158015611a19573d6000803e3d6000fd5b50505050505050565b6001600160a01b0381166000908152600160205260409020545b919050565b6000826001600160a01b0316846001600160a01b03161415611a755760405162461bcd60e51b81526004016106a3906155f9565b60008211611a955760405162461bcd60e51b81526004016106a39061564a565b6000611aa085613876565b90506000611aad85613876565b9050611ab982826140cc565b611ad55760405162461bcd60e51b81526004016106a3906155f9565b81604001518015611ae7575080604001515b15611ba85781518151732837c77527c37d61d9763f53005211dacb4125de9163dce9bf6a91600d91908860ff821615611b2257600754611b25565b60005b611b2d6136c2565b6040518763ffffffff1660e01b8152600401611b4e96959493929190615379565b604080518083038186803b158015611b6557600080fd5b505af4158015611b79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b9d9190614efb565b509250610d2e915050565b816040015115611cf957732837c77527c37d61d9763f53005211dacb4125de63dce9bf6a600d600160008881611bdc6136c2565b6040518763ffffffff1660e01b8152600401611bfd96959493929190615379565b604080518083038186803b158015611c1457600080fd5b505af4158015611c28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c4c9190614efb565b50604051633c554c3f60e11b81526001600160a01b038781166004830152602482018390529194507f000000000000000000000000e2f2a5c287993345a840db3b0845fbc70f5935a5909116906378aa987e9060440160206040518083038186803b158015611cba57600080fd5b505afa158015611cce573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cf29190614da6565b9250611e41565b60405163119849cf60e01b81526001600160a01b038781166004830152602482018690527f000000000000000000000000e2f2a5c287993345a840db3b0845fbc70f5935a5169063119849cf9060440160206040518083038186803b158015611d6157600080fd5b505afa158015611d75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d999190614da6565b9250732837c77527c37d61d9763f53005211dacb4125de63dce9bf6a60076006016000600187600760000154611dcd6136c2565b6040518763ffffffff1660e01b8152600401611dee96959493929190615379565b604080518083038186803b158015611e0557600080fd5b505af4158015611e19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e3d9190614efb565b5092505b50509392505050565b6000808211611e6b5760405162461bcd60e51b81526004016106a39061564a565b6000611e7684613876565b600854909150600090611e8a908590614161565b9050732837c77527c37d61d9763f53005211dacb4125de639e60b1c560076006018460400151611ebb576000611ebe565b84515b611ec88589615b33565b611ed06136c2565b6040518563ffffffff1660e01b8152600401611eef94939291906153bb565b60206040518083038186803b158015611f0757600080fd5b505af4158015611f1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f3f9190614da6565b92508160400151611fcd576020820151604051633c554c3f60e11b81526001600160a01b039182166004820152602481018590527f000000000000000000000000e2f2a5c287993345a840db3b0845fbc70f5935a5909116906378aa987e9060440160206040518083038186803b158015611fb957600080fd5b505afa158015610a64573d6000803e3d6000fd5b505092915050565b6040516385acd64160e01b81527fc10a28f028c7f7282a03c90608e38a4a646e136e614e4b07d119280c5f7f839f6004820152600090819033906001600160a01b037f000000000000000000000000afce80b19a8ce13dec0739a1aab7a028d6845eb316906385acd6419060240160206040518083038186803b15801561205b57600080fd5b505afa15801561206f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061209391906147cd565b6001600160a01b0316146120da5760405162461bcd60e51b815260206004820152600e60248201526d27b7363c903b30b634b230ba37b960911b60448201526064016106a3565b6120e2613dd9565b60065462010000900460ff1661210a5760405162461bcd60e51b81526004016106a39061566a565b6006805462ff000019169055604051630735024560e51b815260009081907390ae544e8cc76d2867987ee4f5456c02c50abd8b9063e6a048a09061215690600c90600d9060040161551f565b60006040518083038186803b15801561216e57600080fd5b505af4158015612182573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526121aa9190810190614a77565b9092509050732837c77527c37d61d9763f53005211dacb4125de637116e818600d84846121d56136c2565b6040518563ffffffff1660e01b81526004016121f49493929190615301565b60206040518083038186803b15801561220c57600080fd5b505af4158015612220573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122449190614da6565b600a54600354919550859161225991906159c5565b61226391906159c5565b60095490935080156122a457670de0b6b3a76400006122828287615b14565b61228c91906159dd565b600a805460009061229e9084906159c5565b90915550505b604080516000808252602082019283905230927f7d3ff197e9071095bd36b627028ef523ecf46fcbf17cbde745a4b65aec88b6bc926122e99233929091908890615190565b60405180910390a250506006805462ff0000191662010000179055509091565b61231161396f565b600654610100900460ff161561235c5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016106a3565b6006805461ff0019166101001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25890602001611701565b6060600580546107d890615bc1565b600080732837c77527c37d61d9763f53005211dacb4125de635dd72f5d600d6123d16136c2565b6040518363ffffffff1660e01b81526004016123ee9291906153ec565b604080518083038186803b15801561240557600080fd5b505af4158015612419573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061243d9190614efb565b915091509091565b6040516385acd64160e01b81527fc10a28f028c7f7282a03c90608e38a4a646e136e614e4b07d119280c5f7f839f600482015233906001600160a01b037f000000000000000000000000afce80b19a8ce13dec0739a1aab7a028d6845eb316906385acd6419060240160206040518083038186803b1580156124c657600080fd5b505afa1580156124da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124fe91906147cd565b6001600160a01b0316146125455760405162461bcd60e51b815260206004820152600e60248201526d27b7363c903b30b634b230ba37b960911b60448201526064016106a3565b600a5460018111156125e557600061255e600183615b33565b6001600a55905061256f3382614176565b307f7d3ff197e9071095bd36b627028ef523ecf46fcbf17cbde745a4b65aec88b6bc338360006040519080825280602002602001820160405280156125be578160200160208202803683370190505b50604080516000815260208101918290526125db94939291615190565b60405180910390a2505b50565b6125f061396f565b670429d069189e0000826001600160801b03161115801561262257506709b6e64a8ec60000816001600160801b031610155b61265c5760405162461bcd60e51b815260206004820152600b60248201526a2bb2b4b3b43a399037b7b160a91b60448201526064016106a3565b6040805180820182526001600160801b038481168083528482166020938401819052600f80546001600160801b0319168317909316600160801b8202179092558351908152918201527f1633022fee8dcf5a3cdeb5f1b49d5b734a3cfef7fc093e30cfdd28ddde8cd136910160405180910390a15050565b3360009081526002602090815260408083206001600160a01b0386168452909152812054828110156127565760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016106a3565b6127653385610d238685615b33565b5060019392505050565b60006108693384846139d9565b60065460009062010000900460ff166127a75760405162461bcd60e51b81526004016106a39061566a565b6006805462ff0000191690556127bb613dd9565b6001600160a01b0382166127e15760405162461bcd60e51b81526004016106a39061561f565b8380158015906127f057508087145b6128325760405162461bcd60e51b8152602060048201526013602482015272125b9d985b1a5908185c9c985e481a5b9c1d5d606a1b60448201526064016106a3565b600084116128525760405162461bcd60e51b81526004016106a39061564a565b60006128908989808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506134b292505050565b90506000732837c77527c37d61d9763f53005211dacb4125de638c913b9460076128b86136c2565b858c8c8c8c6040518863ffffffff1660e01b81526004016128df979695949392919061575f565b604080518083038186803b1580156128f657600080fd5b505af415801561290a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061292e9190614efb565b909450905061293d3385613e40565b600954801561297b57670de0b6b3a76400006129598284615b14565b61296391906159dd565b600a80546000906129759084906159c5565b90915550505b336001600160a01b03167fdf5bf345d5d6eedd0e8667d799d60af65d7127e3b0417e04bef4d954d2a4750e87878e8e8e8e896040516129c09796959493929190615211565b60405180910390a250506006805462ff00001916620100001790555090979650505050505050565b60065460009062010000900460ff16612a135760405162461bcd60e51b81526004016106a39061566a565b6006805462ff000019169055612a27613dd9565b6001600160a01b038216612a4d5760405162461bcd60e51b81526004016106a39061561f565b838015801590612a5c57508087145b612a9f5760405162461bcd60e51b8152602060048201526014602482015273092dce0eae840c2e4e4c2f240dad2e6dac2e8c6d60631b60448201526064016106a3565b6000612add8989808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506134b292505050565b9050732837c77527c37d61d9763f53005211dacb4125de63b4ff6eae6007612b036136c2565b848b8b8b6040518763ffffffff1660e01b8152600401612b289695949392919061570f565b60206040518083038186803b158015612b4057600080fd5b505af4158015612b54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b789190614da6565b9250612b848484614176565b336001600160a01b03167f7d3ff197e9071095bd36b627028ef523ecf46fcbf17cbde745a4b65aec88b6bc85858c8c8c8c604051612bc7969594939291906151c9565b60405180910390a250506006805462ff00001916620100001790559695505050505050565b60065460609062010000900460ff16612c175760405162461bcd60e51b81526004016106a39061566a565b6006805462ff000019169055612c2b613dd9565b6001600160a01b038216612c515760405162461bcd60e51b81526004016106a39061561f565b60008511612c715760405162461bcd60e51b81526004016106a39061564a565b6000612c7b6136c2565b9050612c873387613e40565b60606000732837c77527c37d61d9763f53005211dacb4125de636fdc2ea26007858b8b8b8b6040518763ffffffff1660e01b8152600401612ccd9695949392919061589d565b60006040518083038186803b158015612ce557600080fd5b505af4158015612cf9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612d219190810190614dbe565b6009549096509093509091508015612d6857670de0b6b3a7640000612d468284615b14565b612d5091906159dd565b600a8054600090612d629084906159c5565b90915550505b336001600160a01b03167fdf5bf345d5d6eedd0e8667d799d60af65d7127e3b0417e04bef4d954d2a4750e878b8689876040516118e5959493929190615261565b612db16145be565b612db96136c2565b905090565b612dc661396f565b7390ae544e8cc76d2867987ee4f5456c02c50abd8b63ceb5ad27600e612dea613f8f565b6040516001600160e01b031960e085901b1681526004810192909252602482015260440160006040518083038186803b158015612e2657600080fd5b505af4158015612e3a573d6000803e3d6000fd5b50505050565b612e4861396f565b662386f26fc10000831115612e8f5760405162461bcd60e51b815260206004820152600d60248201526c29bbb0b8103930ba329037b7b160991b60448201526064016106a3565b662386f26fc10000821115612edc5760405162461bcd60e51b81526020600482015260136024820152722932b232b6b83a34b7b7103930ba329037b7b160691b60448201526064016106a3565b6706f05b59d3b20000811115612f275760405162461bcd60e51b815260206004820152601060248201526f23b7bb103332b2903930ba329037b7b160811b60448201526064016106a3565b60078390556008829055600981905560408051848152602081018490529081018290527fe06a46af1c04656f68e4f75cbbb23baa176651c7f99930a378ef9f1616dc2b8c9060600160405180910390a1505050565b60065460009062010000900460ff16612fa75760405162461bcd60e51b81526004016106a39061566a565b6006805462ff000019169055612fbb613dd9565b6001600160a01b038216612fe15760405162461bcd60e51b81526004016106a39061561f565b846001600160a01b0316866001600160a01b031614156130135760405162461bcd60e51b81526004016106a3906155f9565b600084116130335760405162461bcd60e51b81526004016106a39061564a565b600061303e87613876565b9050600061304b87613876565b905061305782826140cc565b6130735760405162461bcd60e51b81526004016106a3906155f9565b6000732837c77527c37d61d9763f53005211dacb4125de635c1ba5f060076130996136c2565b86868c8c8c6040518863ffffffff1660e01b81526004016130c097969594939291906157c1565b604080518083038186803b1580156130d757600080fd5b505af41580156130eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061310f9190614efb565b6009549195509150801561315257670de0b6b3a76400006131308284615b14565b61313a91906159dd565b600a805460009061314c9084906159c5565b90915550505b60208481015184820151604080516001600160a01b03938416815291831693820193909352918201879052606082018490528716608082015233907f1eeaa4acf3c225a4033105c2647625dbb298dec93b14e16253c4231e26c02b1d9060a00160405180910390a250506006805462ff000019166201000017905550909695505050505050565b60008180158015906131ea57508085145b61322d5760405162461bcd60e51b8152602060048201526014602482015273092dce0eae840c2e4e4c2f240dad2e6dac2e8c6d60631b60448201526064016106a3565b600061326b8787808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506134b292505050565b9050732837c77527c37d61d9763f53005211dacb4125de637116e818600d8388886132946136c2565b6040518663ffffffff1660e01b81526004016132b49594939291906152ad565b60206040518083038186803b1580156132cc57600080fd5b505af41580156132e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133049190614da6565b979650505050505050565b60065460009062010000900460ff1661333a5760405162461bcd60e51b81526004016106a39061566a565b6006805462ff00001916905561334e613dd9565b6001600160a01b0382166133745760405162461bcd60e51b81526004016106a39061561f565b600084116133945760405162461bcd60e51b81526004016106a39061564a565b600061339f86613876565b9050732837c77527c37d61d9763f53005211dacb4125de636089efbc60076133c56136c2565b8489896040518663ffffffff1660e01b81526004016133e895949392919061581b565b60206040518083038186803b15801561340057600080fd5b505af4158015613414573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134389190614da6565b91506134448383614176565b604080516001600160a01b0385811682526020820185905288168183015260608101879052905133917f30873c596f54a2e2e09894670d7e1a48b2433c00204f81fbedf557353c36e7c7919081900360800190a2506006805462ff0000191662010000179055949350505050565b8051606090806001600160401b038111156134dd57634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015613506578160200160208202803683370190505b50604080516060810182526000808252602082018190529181018290529193505b828110156136ba5761355f85828151811061355257634e487b7160e01b600052603260045260246000fd5b6020026020010151613876565b9150816000015184828151811061358657634e487b7160e01b600052603260045260246000fd5b602002602001019060ff16908160ff168152505081604001516135db5760405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a5908185cdcd95d609a1b60448201526064016106a3565b60006135e88260016159c5565b90505b838110156136a75785818151811061361357634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b031686838151811061364457634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b031614156136955760405162461bcd60e51b815260206004820152600f60248201526e111d5c1b1a58d85d1948185cdcd95d608a1b60448201526064016106a3565b8061369f81615bf6565b9150506135eb565b50806136b281615bf6565b915050613527565b505050919050565b6136ca6145be565b60405180606001604052806007600301546136e460035490565b6136ee91906159c5565b81526020016136fb613f8f565b815260408051808201909152600f546001600160801b038082168352600160801b9091041660208281019190915290910152905090565b600081613747670de0b6b3a764000085615b14565b610d2e91906159dd565b6001600160a01b0383166137b35760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016106a3565b6001600160a01b0382166138145760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016106a3565b6001600160a01b0383811660008181526002602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b60408051606081018252600080825260208201819052918101919091527f000000000000000000000000e2f2a5c287993345a840db3b0845fbc70f5935a56001600160a01b0316826001600160a01b031614156138f9575060408051606081018252600081526001600160a01b0383166020820152600191810191909152611a3c565b6040518060600160405280600160ff168152602001836001600160a01b03168152602001836001600160a01b0316600760050160018154811061394c57634e487b7160e01b600052603260045260246000fd5b60009182526020909120600290910201546001600160a01b031614905292915050565b613977614255565b6001600160a01b0316336001600160a01b0316146139d75760405162461bcd60e51b815260206004820152601960248201527f4f6e6c7920676f7665726e6f722063616e20657865637574650000000000000060448201526064016106a3565b565b6001600160a01b038316613a3d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016106a3565b6001600160a01b038216613a9f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016106a3565b6001600160a01b03831660009081526001602052604090205481811015613b175760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016106a3565b613b218282615b33565b6001600160a01b038086166000908152600160205260408082209390935590851681529081208054849290613b579084906159c5565b92505081905550826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051613ba391815260200190565b60405180910390a350505050565b613bbd828260126142e8565b5050565b6000600160801b8210613c265760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b60648201526084016106a3565b5090565b801580613cb35750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b158015613c7957600080fd5b505afa158015613c8d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cb19190614da6565b155b613d1e5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b60648201526084016106a3565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052613d70908490614328565b505050565b6000600160401b8210613c265760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b60648201526084016106a3565b600654610100900460ff161580613e085750613df36143fa565b6001600160a01b0316336001600160a01b0316145b6139d75760405162461bcd60e51b8152602060048201526009602482015268556e6865616c74687960b81b60448201526064016106a3565b6001600160a01b038216613ea05760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016106a3565b6001600160a01b03821660009081526001602052604090205481811015613f145760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016106a3565b613f1e8282615b33565b6001600160a01b03841660009081526001602052604081209190915560038054849290613f4c908490615b33565b90915550506040518281526000906001600160a01b038516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90602001613869565b60408051608081018252600e546001600160401b038082168352600160401b8204811660208401819052600160801b8304821694840194909452600160c01b909104166060820181905260009290428111156140b957825160408401516000806140026001600160401b03841642615b33565b61400c8487615b4a565b6001600160401b031691509150836001600160401b0316866001600160401b0316111561407d57808261403f8689615b4a565b6001600160401b03166140529190615b14565b61405c91906159dd565b61406f906001600160401b0386166159c5565b975050505050505050610859565b80826140898887615b4a565b6001600160401b031661409c9190615b14565b6140a691906159dd565b61406f906001600160401b038616615b33565b506001600160401b031691506108599050565b600082604001511580156140e257508160400151155b156140ef5750600061086d565b82604001518015614101575081604001515b1561410e5750600161086d565b826040015180156141265750826000015160ff166001145b156141335750600161086d565b8160400151801561414b5750816000015160ff166001145b156141585750600161086d565b50600092915050565b6000610d2e8383670de0b6b3a764000061447c565b6001600160a01b0382166141cc5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016106a3565b80600360008282546141de91906159c5565b90915550506001600160a01b0382166000908152600160205260408120805483929061420b9084906159c5565b90915550506040518181526001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b60007f000000000000000000000000afce80b19a8ce13dec0739a1aab7a028d6845eb36001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b1580156142b057600080fd5b505afa1580156142c4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612db991906147cd565b82516142fb906004906020860190614606565b50815161430f906005906020850190614606565b506006805460ff191660ff929092169190911790555050565b600061437d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661449b9092919063ffffffff16565b805190915015613d70578080602001905181019061439b9190614b53565b613d705760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016106a3565b6040516385acd64160e01b81527f39e3ed1fc335ce346a8cbe3e64dd525cf22b37f1e2104a755e761c3c1eb4734f60048201526000907f000000000000000000000000afce80b19a8ce13dec0739a1aab7a028d6845eb36001600160a01b0316906385acd6419060240160206040518083038186803b1580156142b057600080fd5b6000816144898486615b14565b61449391906159dd565b949350505050565b6060614493848460008585843b6144f45760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016106a3565b600080866001600160a01b031685876040516145109190615174565b60006040518083038185875af1925050503d806000811461454d576040519150601f19603f3d011682016040523d82523d6000602084013e614552565b606091505b50915091506133048282866060831561456c575081610d2e565b82511561457c5782518084602001fd5b8160405162461bcd60e51b81526004016106a391906155c6565b604080516080810182526000808252602082018190529181018290529060608201905b905290565b604051806060016040528060008152602001600081526020016145b9604051806040016040528060006001600160801b0316815260200160006001600160801b031681525090565b82805461461290615bc1565b90600052602060002090601f016020900481019282614634576000855561467a565b82601f1061464d57805160ff191683800117855561467a565b8280016001018555821561467a579182015b8281111561467a57825182559160200191906001019061465f565b50613c269291505b80821115613c265760008155600101614682565b60008083601f8401126146a7578182fd5b5081356001600160401b038111156146bd578182fd5b60208301915083602080830285010111156146d757600080fd5b9250929050565b600082601f8301126146ee578081fd5b815160206147036146fe836159a2565b615972565b828152818101908583018385028701840188101561471f578586fd5b855b8581101561473d57815184529284019290840190600101614721565b5090979650505050505050565b60008083601f84011261475b578182fd5b5081356001600160401b03811115614771578182fd5b6020830191508360208285010111156146d757600080fd5b60006080828403121561479a578081fd5b50919050565b805160ff81168114611a3c57600080fd5b6000602082840312156147c2578081fd5b8135610d2e81615c3d565b6000602082840312156147de578081fd5b8151610d2e81615c3d565b600080604083850312156147fb578081fd5b823561480681615c3d565b9150602083013561481681615c3d565b809150509250929050565b600080600060608486031215614835578081fd5b833561484081615c3d565b9250602084013561485081615c3d565b929592945050506040919091013590565b600080600080600060a08688031215614878578283fd5b853561488381615c3d565b9450602086013561489381615c3d565b9350604086013592506060860135915060808601356148b181615c3d565b809150509295509295909350565b600080604083850312156148d1578182fd5b82356148dc81615c3d565b946020939093013593505050565b600080600080608085870312156148ff578182fd5b843561490a81615c3d565b93506020850135925060408501359150606085013561492881615c3d565b939692955090935050565b600080600060408486031215614947578081fd5b83356001600160401b0381111561495c578182fd5b61496886828701614696565b909450925050602084013561497c81615c3d565b809150509250925092565b6000806000806040858703121561499c578182fd5b84356001600160401b03808211156149b2578384fd5b6149be88838901614696565b909650945060208701359150808211156149d6578384fd5b506149e387828801614696565b95989497509550505050565b60008060008060008060808789031215614a07578384fd5b86356001600160401b0380821115614a1d578586fd5b614a298a838b01614696565b90985096506020890135915080821115614a41578586fd5b50614a4e89828a01614696565b909550935050604087013591506060870135614a6981615c3d565b809150509295509295509295565b60008060408385031215614a89578182fd5b82516001600160401b0380821115614a9f578384fd5b818501915085601f830112614ab2578384fd5b81516020614ac26146fe836159a2565b82815281810190858301838502870184018b1015614ade578889fd5b8896505b84871015614b0757614af3816147a0565b835260019690960195918301918301614ae2565b5091880151919650909350505080821115614b20578283fd5b50614b2d858286016146de565b9150509250929050565b600060208284031215614b48578081fd5b8135610d2e81615c52565b600060208284031215614b64578081fd5b8151610d2e81615c52565b6000806000806000806000806000898b036101c0811215614b8e578788fd5b8a356001600160401b0380821115614ba457898afd5b614bb08e838f0161474a565b909c509a5060208d0135915080821115614bc857898afd5b614bd48e838f0161474a565b909a509850889150614be98e60408f01614789565b9750614bf88e60c08f01614789565b96506101408d0135915080821115614c0e578586fd5b50614c1b8d828e01614696565b909550935050606061015f1982011215614c33578182fd5b614c3d6040615972565b6101608c01358152604061017f1983011215614c57578283fd5b614c616040615972565b91506101808c0135614c7281615c60565b82526101a08c0135614c8381615c60565b8060208401525081602082015280925050509295985092959850929598565b60008082840360c0811215614cb5578283fd5b6080811215614cc2578283fd5b614ccc6080615972565b8451614cd781615c3d565b81526020850151614ce781615c3d565b60208201526040850151614cfa81615c52565b6040820152606085015160088110614d10578485fd5b606082015292506040607f1982011215614d28578182fd5b50614d336040615972565b6080840151614d4181615c60565b815260a0840151614d5181615c60565b6020820152919491935090915050565b60008060408385031215614d73578182fd5b8235614d7e81615c60565b9150602083013561481681615c60565b600060208284031215614d9f578081fd5b5035919050565b600060208284031215614db7578081fd5b5051919050565b600080600060608486031215614dd2578081fd5b835192506020808501516001600160401b0380821115614df0578384fd5b818701915087601f830112614e03578384fd5b8151614e116146fe826159a2565b81815284810190848601868402860187018c1015614e2d578788fd5b8795505b83861015614e58578051614e4481615c3d565b835260019590950194918601918601614e31565b5060408a01519097509450505080831115614e71578384fd5b5050614e7f868287016146de565b9150509250925092565b60008060008060608587031215614e9e578182fd5b8435935060208501356001600160401b03811115614eba578283fd5b614ec687828801614696565b909450925050604085013561492881615c3d565b60008060408385031215614eec578182fd5b50508035926020909101359150565b60008060408385031215614f0d578182fd5b505080516020909101519092909150565b600080600060608486031215614f32578081fd5b505081359360208301359350604090920135919050565b600060208284031215614f5a578081fd5b610d2e826147a0565b60008284526020808501945082825b85811015614fa0578135614f8581615c3d565b6001600160a01b031687529582019590820190600101614f72565b509495945050505050565b6000815180845260208085019450808401835b83811015614fa05781516001600160a01b031687529582019590820190600101614fbe565b6000815480845260208085019450838352808320835b83811015614fa05781546001600160801b038116885260801c8388015260409096019560019182019101614ff9565b81835260006001600160fb1b03831115615040578081fd5b6020830280836020870137939093016020019283525090919050565b6000815180845260208085019450808401835b83811015614fa05781518752958201959082019060010161506f565b6000815180845260208085019450808401835b83811015614fa057815160ff168752958201959082019060010161509e565b600881106150db57634e487b7160e01b600052602160045260246000fd5b9052565b805160ff1682526020808201516001600160a01b0316908301526040908101511515910152565b60018060a01b03808251168352806020830151166020840152506040810151151560408301526060810151613d7060608401826150bd565b80518252602081015160208301526040810151613d70604084018280516001600160801b03908116835260209182015116910152565b60008251615186818460208701615b95565b9190910192915050565b600060018060a01b0386168252846020830152608060408301526151b76080830185614fab565b8281036060840152613304818561505c565b600060018060a01b0388168252866020830152608060408301526151f1608083018688614f63565b8281036060840152615204818587615028565b9998505050505050505050565b600060018060a01b038916825287602083015260a0604083015261523960a083018789614f63565b828103606084015261524c818688615028565b91505082608083015298975050505050505050565b600060018060a01b038716825285602083015260a0604083015261528860a0830186614fab565b828103606084015261529a818661505c565b9150508260808301529695505050505050565b600060e082526152c060e0830188614fe3565b82810360208401526152d2818861508b565b905082810360408401526152e7818688615028565b9150506152f7606083018461513e565b9695505050505050565b600060e0825261531460e0830187614fe3565b602083820381850152615327828861508b565b84810360408601528651808252828801935090820190845b8181101561535b5784518352938301939183019160010161533f565b5050809350505050615370606083018461513e565b95945050505050565b600061012080835261538d8184018a614fe3565b91505060ff8716602083015260ff8616604083015284606083015283608083015261330460a083018461513e565b600060e082526153ce60e0830187614fe3565b905060ff85166020830152836040830152615370606083018461513e565b600060a082526153ff60a0830185614fe3565b9050610d2e602083018461513e565b60408082528351828201819052600091906020906060850190828801855b828110156154525761543f848351615106565b608093909301929084019060010161542c565b50505084810382860152855180825286830191830190855b818110156154a35761549383855180516001600160801b03908116835260209182015116910152565b928401929185019160010161546a565b509098975050505050505050565b84815260606020808301829052908201849052600090859060808401835b878110156154fd5783356154e281615c3d565b6001600160a01b0316825292820192908201906001016154cf565b506001600160a01b039590951660409490940193909352509195945050505050565b600060408083018184528086548083526060925082860191508785526020808620865b8381101561559f5781546001600160a01b03908116865260018301549081168487015260ff60a082901c81161515898801529061558788880160a883901c84166150bd565b50506080949094019360029190910190600101615542565b505095909501959095525092949350505050565b600060208252610d2e602083018461505c565b60006020825282518060208401526155e5816040850160208701615b95565b601f01601f19169190910160400192915050565b6020808252600c908201526b24b73b30b634b2103830b4b960a11b604082015260600190565b602080825260119082015270125b9d985b1a59081c9958da5c1a595b9d607a1b604082015260600190565b60208082526006908201526505174793d3d360d41b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60c081016156af8285615106565b82516001600160801b03908116608084015260208401511660a0830152610d2e565b600060808201905082518252602083015160208301526040830151610a8c604084018280516001600160801b03908116835260209182015116910152565b6000610100888352615724602084018961513e565b8060a08401526157368184018861508b565b905082810360c084015261574b818688615028565b9150508260e0830152979650505050505050565b6000610120898352615774602084018a61513e565b8060a08401526157868184018961508b565b905082810360c084015261579b818789615028565b60e084019590955250506001600160a01b03919091166101009091015295945050505050565b8781526101c081016157d6602083018961513e565b6157e360a08301886150df565b6157f16101008301876150df565b6101608201949094526101808101929092526001600160a01b03166101a090910152949350505050565b8581526101408101615830602083018761513e565b61583d60a08301866150df565b61010082019390935261012001529392505050565b8681526101608101615867602083018861513e565b61587460a08301876150df565b6101008201949094526101208101929092526001600160a01b0316610140909101529392505050565b60006101008883526158b2602084018961513e565b8660a08401528060c08401526158cb8184018688615028565b91505060018060a01b03831660e0830152979650505050505050565b6000610160820190508882528760208301528660408301528560608301528460808301526001600160401b038085511660a08401528060208601511660c08401528060408601511660e0840152806060860151166101008401525061596661012083018480516001600160801b03908116835260209182015116910152565b98975050505050505050565b604051601f8201601f191681016001600160401b038111828210171561599a5761599a615c27565b604052919050565b60006001600160401b038211156159bb576159bb615c27565b5060209081020190565b600082198211156159d8576159d8615c11565b500190565b6000826159f857634e487b7160e01b81526012600452602481fd5b500490565b80825b6001808611615a0f5750615a3a565b818704821115615a2157615a21615c11565b80861615615a2e57918102915b9490941c938002615a00565b94509492505050565b6000610d2e60001960ff851684600082615a5f57506001610d2e565b81615a6c57506000610d2e565b8160018114615a825760028114615a8c57615ab9565b6001915050610d2e565b60ff841115615a9d57615a9d615c11565b6001841b915084821115615ab357615ab3615c11565b50610d2e565b5060208310610133831016604e8410600b8410161715615aec575081810a83811115615ae757615ae7615c11565b610d2e565b615af984848460016159fd565b808604821115615b0b57615b0b615c11565b02949350505050565b6000816000190483118215151615615b2e57615b2e615c11565b500290565b600082821015615b4557615b45615c11565b500390565b60006001600160401b0383811690831681811015615b6a57615b6a615c11565b039392505050565b600060ff821660ff841680821015615b8c57615b8c615c11565b90039392505050565b60005b83811015615bb0578181015183820152602001615b98565b83811115612e3a5750506000910152565b600281046001821680615bd557607f821691505b6020821081141561479a57634e487b7160e01b600052602260045260246000fd5b6000600019821415615c0a57615c0a615c11565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b03811681146125e557600080fd5b80151581146125e557600080fd5b6001600160801b03811681146125e557600080fdfea2646970667358221220850dd1f167ac97afe719deef338bad5974094486512a857d3b35961d8341c7f664736f6c63430008020033

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

000000000000000000000000afce80b19a8ce13dec0739a1aab7a028d6845eb3000000000000000000000000e2f2a5c287993345a840db3b0845fbc70f5935a5

-----Decoded View---------------
Arg [0] : _nexus (address): 0xAFcE80b19A8cE13DEc0739a1aaB7A028d6845Eb3
Arg [1] : _mAsset (address): 0xe2f2a5C287993345a840Db3B0845fbC70f5935a5

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000afce80b19a8ce13dec0739a1aab7a028d6845eb3
Arg [1] : 000000000000000000000000e2f2a5c287993345a840db3b0845fbc70f5935a5


Deployed Bytecode Sourcemap

105283:31633:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;126686:739;;;;;;:::i;:::-;;:::i;:::-;;;37064:25:1;;;37052:2;37037:18;126686:739:0;;;;;;;;28911:83;;;:::i;:::-;;;;;;;:::i;22467:169::-;;;;;;:::i;:::-;;:::i;:::-;;;36891:14:1;;36884:22;36866:41;;36854:2;36839:18;22467:169:0;36821:92:1;113400:711:0;;;;;;:::i;:::-;;:::i;107069:40::-;;;;;;;;-1:-1:-1;;;;;20896:32:1;;;20878:51;;20866:2;20851:18;107069:40:0;20833:102:1;21420:108:0;21508:12;;21420:108;;134166:214;;;;;;:::i;:::-;;:::i;:::-;;128934:215;;;:::i;:::-;;;;;;;;:::i;23118:422::-;;;;;;:::i;:::-;;:::i;108047:1483::-;;;;;;:::i;:::-;;:::i;29763:83::-;29829:9;;29763:83;;29829:9;;;;59746:36:1;;59734:2;59719:18;29763:83:0;59701:87:1;23949:215:0;;;;;;:::i;:::-;;:::i;128358:378::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;36717:122::-;;;:::i;120560:1157::-;;;;;;:::i;:::-;;:::i;136481:185::-;;;;;;:::i;:::-;;:::i;36326:80::-;;36391:7;;;;;;;;36326:80;136068:218;;;;;;:::i;:::-;;:::i;21591:127::-;;;;;;:::i;:::-;;:::i;117294:1749::-;;;;;;:::i;:::-;;:::i;107144:22::-;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;107144:22:0;;;;;-1:-1:-1;;;107144:22:0;;;;;;;;;;;;-1:-1:-1;;;107144:22:0;;;;;;;;;-1:-1:-1;;;107144:22:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;107144:22:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;125623:738::-;;;;;;:::i;:::-;;:::i;132245:913::-;;;:::i;:::-;;;;51303:25:1;;;51359:2;51344:18;;51337:34;;;;51276:18;132245:913:0;51258:119:1;36502:120:0;;;:::i;29113:87::-;;;:::i;127739:157::-;;;:::i;133278:487::-;;;:::i;135350:252::-;;;;;;:::i;:::-;;:::i;32608:29::-;;;;;24667:377;;;;;;:::i;:::-;;:::i;21931:175::-;;;;;;:::i;:::-;;:::i;124075:1228::-;;;;;;:::i;:::-;;:::i;112265:852::-;;;;;;:::i;:::-;;:::i;122256:1147::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;127998:119::-;;;:::i;:::-;;;;;;;:::i;136805:108::-;;;:::i;134682:497::-;;;;;;:::i;:::-;;:::i;115732:1090::-;;;;;;:::i;:::-;;:::i;22169:151::-;;;;;;:::i;:::-;-1:-1:-1;;;;;22285:18:0;;;22258:7;22285:18;;;:11;:18;;;;;;;;:27;;;;;;;;;;;;;22169:151;114487:490;;;;;;:::i;:::-;;:::i;110929:727::-;;;;;;:::i;:::-;;:::i;126686:739::-;126847:23;126897:17;126940:7;;;;;:33;;-1:-1:-1;126951:22:0;;;126940:33;126932:65;;;;-1:-1:-1;;;126932:65:0;;43458:2:1;126932:65:0;;;43440:21:1;43497:2;43477:18;;;43470:30;-1:-1:-1;;;43516:18:1;;;43509:49;43575:18;;126932:65:0;;;;;;;;;127010:22;127035:20;127046:8;;127035:20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;127035:10:0;;-1:-1:-1;;;127035:20:0:i;:::-;127010:45;-1:-1:-1;127068:22:0;127106:11;:30;127155:15;127010:45;127215:17;;127251:12;:10;:12::i;:::-;127106:172;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;127342:18;;127068:210;;-1:-1:-1;127307:54:0;;127335:25;;:4;:25;:::i;:::-;127307:14;;:27;:54::i;:::-;127289:72;-1:-1:-1;127376:19:0;;127372:45;;127397:20;127416:1;127397:20;;:::i;:::-;;;127372:45;126686:739;;;;;;;;;:::o;28911:83::-;28948:13;28981:5;28974:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;28911:83;;:::o;22467:169::-;22550:4;22567:39;18253:10;22590:7;22599:6;22567:8;:39::i;:::-;-1:-1:-1;22624:4:0;22467:169;;;;;:::o;113400:711::-;113531:18;113592:1;113575:14;:18;113567:37;;;;-1:-1:-1;;;113567:37:0;;;;;;;:::i;:::-;113617:18;113638:17;113648:6;113638:9;:17::i;:::-;113617:38;;113672:5;:12;;;113668:436;;;113790:9;;113714:11;;:23;;113756:15;;113818:14;113851:12;:10;:12::i;:::-;113714:164;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;113701:177;;113668:436;;;113937:53;;-1:-1:-1;;;113937:53:0;;-1:-1:-1;;;;;22622:32:1;;;113937:53:0;;;22604:51:1;22671:18;;;22664:34;;;113911:23:0;;113945:6;113937:29;;;;;;22577:18:1;;113937:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;113911:79;-1:-1:-1;114018:11:0;:23;114042:15;114059:1;113911:79;114079:12;:10;:12::i;:::-;114018:74;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;114005:87;;113668:436;;113400:711;;;;;:::o;134166:214::-;33042:15;:13;:15::i;:::-;134263:4:::1;134249:10;:18;;134241:45;;;::::0;-1:-1:-1;;;134241:45:0;;44898:2:1;134241:45:0::1;::::0;::::1;44880:21:1::0;44937:2;44917:18;;;44910:30;-1:-1:-1;;;44956:18:1;;;44949:44;45010:18;;134241:45:0::1;44870:164:1::0;134241:45:0::1;134299:14:::0;:27;;;134344:28:::1;::::0;37064:25:1;;;134344:28:0::1;::::0;37052:2:1;37037:18;134344:28:0::1;;;;;;;134166:214:::0;:::o;128934:215::-;129024:23;129049:29;129104:4;:19;;129125:4;:15;;129096:45;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;129096:45:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;129096:45:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;129096:45:0;;;;;;;;;;-1:-1:-1;;;129096:45:0;;;;;;;;;;;;;;;-1:-1:-1;;;129096:45:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;129096:45:0;;;;;-1:-1:-1;;;129096:45:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;128934:215;;:::o;23118:422::-;23224:4;23241:36;23251:6;23259:9;23270:6;23241:9;:36::i;:::-;-1:-1:-1;;;;;23317:19:0;;23290:24;23317:19;;;:11;:19;;;;;;;;18253:10;23317:33;;;;;;;;23369:26;;;;23361:79;;;;-1:-1:-1;;;23361:79:0;;45648:2:1;23361:79:0;;;45630:21:1;45687:2;45667:18;;;45660:30;45726:34;45706:18;;;45699:62;-1:-1:-1;;;45777:18:1;;;45770:38;45825:19;;23361:79:0;45620:230:1;23361:79:0;23451:57;23460:6;18253:10;23482:25;23501:6;23482:16;:25;:::i;:::-;23451:8;:57::i;:::-;23528:4;23521:11;;;23118:422;;;;;;:::o;108047:1483::-;17024:13;;;;;;;;:30;;-1:-1:-1;17042:12:0;;;;17041:13;17024:30;17016:89;;;;-1:-1:-1;;;17016:89:0;;44483:2:1;17016:89:0;;;44465:21:1;44522:2;44502:18;;;44495:30;44561:34;44541:18;;;44534:62;-1:-1:-1;;;44612:18:1;;;44605:44;44666:19;;17016:89:0;44455:236:1;17016:89:0;17118:19;17141:13;;;;;;17140:14;17165:101;;;;17200:13;:20;;-1:-1:-1;;;;17200:20:0;;;;;17235:19;17216:4;17235:19;;;17165:101;108336:52:::1;108367:8;;108336:52;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;;;;-1:-1:-1;;108336:52:0::1;::::0;;::::1;;::::0;::::1;::::0;;::::1;::::0;::::1;::::0;;;;;;;;;;;-1:-1:-1;108377:10:0;;-1:-1:-1;108377:10:0;;;;108336:52;::::1;108377:10:::0;;;;108336:52;::::1;;::::0;::::1;::::0;;;;-1:-1:-1;108336:30:0::1;::::0;-1:-1:-1;;;108336:52:0:i:1;:::-;108401:28;37400:11:::0;:18;;-1:-1:-1;;37400:18:0;;;;;36924:502;108401:28:::1;-1:-1:-1::0;;;;;108466:6:0::1;108450:22;:12;;::::0;::::1;:7:::0;:12:::1;:::i;:::-;-1:-1:-1::0;;;;;108450:22:0::1;;108442:51;;;::::0;-1:-1:-1;;;108442:51:0;;48663:2:1;108442:51:0::1;::::0;::::1;48645:21:1::0;48702:2;48682:18;;;48675:30;-1:-1:-1;;;48721:18:1;;;48714:46;48777:18;;108442:51:0::1;48635:166:1::0;108442:51:0::1;108543:76;::::0;;::::1;::::0;::::1;::::0;;;108504:19;;108543:76;108558:12:::1;;::::0;::::1;:7:::0;:12:::1;:::i;:::-;-1:-1:-1::0;;;;;108543:76:0::1;;;;;108572:7;:18;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;108543:76:0::1;::::0;;108592:5:::1;108543:76;::::0;::::1;::::0;;;;;;108504:126;;::::1;::::0;;::::1;::::0;;-1:-1:-1;108504:126:0;;;::::1;::::0;;;;;;::::1;::::0;;::::1;;::::0;;-1:-1:-1;;;;;108504:126:0;;::::1;-1:-1:-1::0;;;;;;108504:126:0;;::::1;;::::0;;;;::::1;::::0;;;::::1;::::0;;::::1;::::0;::::1;::::0;::::1;;-1:-1:-1::0;;;108504:126:0::1;-1:-1:-1::0;;;;108504:126:0;;;::::1;::::0;::::1;::::0;;;::::1;::::0;;;::::1;::::0;;;::::1;::::0;;;::::1;::::0;::::1;::::0;;;;;;;-1:-1:-1;;;;108504:126:0::1;-1:-1:-1::0;;;108504:126:0;::::1;::::0;::::1;;;;-1:-1:-1::0;;;108504:126:0::1;;;;;;;;;;;::::0;;-1:-1:-1;;108662:18:0::1;::::0;;;;::::1;::::0;;108673:3:::1;108662:18:::0;;-1:-1:-1;108662:18:0::1;::::0;;::::1;::::0;;;108641:15;:40;;::::1;::::0;::::1;::::0;;;;;;;;;::::1;::::0;;;;-1:-1:-1;;;;;;108641:40:0;;::::1;-1:-1:-1::0;;;;;108641:40:0;;::::1;;::::0;::::1;-1:-1:-1::0;;;108641:40:0;;;::::1;::::0;;;::::1;::::0;;;::::1;::::0;;108731:87;;::::1;::::0;::::1;::::0;;;108692:19;;-1:-1:-1;108731:87:0;;108746:12:::1;::::0;;::::1;::::0;::::1;:::i;:::-;-1:-1:-1::0;;;;;108731:87:0::1;;;;;108760:7;:18;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;108731:87:0::1;::::0;;::::1;;108780:16;::::0;;;::::1;::::0;::::1;;:::i;:::-;108731:87;;::::0;;::::1;;108798:19;108731:87:::0;;108692:137;;::::1;::::0;;::::1;::::0;;-1:-1:-1;108692:137:0;;;::::1;::::0;;;;;;::::1;::::0;;::::1;;::::0;;-1:-1:-1;;;;;108692:137:0;;::::1;-1:-1:-1::0;;;;;;108692:137:0;;::::1;;::::0;;;;::::1;::::0;;;::::1;::::0;;::::1;::::0;::::1;::::0;::::1;;-1:-1:-1::0;;;108692:137:0::1;-1:-1:-1::0;;;;108692:137:0;;;::::1;::::0;::::1;::::0;;;::::1;::::0;;;::::1;::::0;;;::::1;::::0;;;::::1;::::0;::::1;::::0;;;;;;;-1:-1:-1;;;;108692:137:0::1;-1:-1:-1::0;;;108692:137:0;::::1;::::0;::::1;;;;-1:-1:-1::0;;;108692:137:0::1;;;;;;;;;;;::::0;;-1:-1:-1;;108875:82:0::1;::::0;;;;::::1;::::0;;;108840:15;;-1:-1:-1;108875:82:0;108886:67:::1;108927:12;;::::0;::::1;:7:::0;:12:::1;:::i;:::-;-1:-1:-1::0;;;;;108915:34:0::1;;:36;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;108910:41;::::0;:2:::1;:41;:::i;:::-;108905:47;::::0;:2:::1;:47;:::i;:::-;108886:18;:67::i;:::-;-1:-1:-1::0;;;;;108875:82:0;;::::1;::::0;;108955:1:::1;108875:82;::::0;;::::1;::::0;;;108840:128;;::::1;::::0;::::1;::::0;;;;;;;;;;;::::1;::::0;;;;;::::1;::::0;;::::1;-1:-1:-1::0;;;108840:128:0::1;::::0;;::::1;-1:-1:-1::0;;;;;;108840:128:0;;::::1;::::0;;;::::1;;::::0;;;::::1;::::0;;;108979:244:::1;108999:20:::0;;::::1;108979:244;;;109105:12;;::::0;::::1;:7:::0;:12:::1;:::i;:::-;-1:-1:-1::0;;;;;109097:31:0::1;;109129:9;;109139:1;109129:12;;;;;-1:-1:-1::0;;;109129:12:0::1;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;109097:45;::::0;-1:-1:-1;;;;;;109097:45:0::1;::::0;;;;;;-1:-1:-1;;;;;20896:32:1;;;109097:45:0::1;::::0;::::1;20878:51:1::0;20851:18;;109097:45:0::1;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;109157:54:0::1;::::0;-1:-1:-1;109190:12:0::1;;::::0;::::1;:7:::0;:12:::1;:::i;:::-;-1:-1:-1::0;;;109164:9:0::1;;109174:1;109164:12;;;;;-1:-1:-1::0;;;109164:12:0::1;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;109157:32:0::1;::::0;:54;:32:::1;:54::i;:::-;109021:3:::0;::::1;::::0;::::1;:::i;:::-;;;;108979:244;;;;109235:13;109251:42;107059:3;109269:7;:9;;;:23;;;;:::i;:::-;109251:17;:42::i;:::-;109319:29;::::0;;::::1;::::0;::::1;::::0;;-1:-1:-1;;;;;109319:29:0;;;::::1;::::0;;;::::1;::::0;;::::1;::::0;;;-1:-1:-1;109319:29:0;;;;;;;;;;;;;;109304:12;:44;;-1:-1:-1;;109304:44:0::1;::::0;::::1;-1:-1:-1::0;;109304:44:0::1;-1:-1:-1::0;;;109304:44:0;;::::1;::::0;;;::::1;-1:-1:-1::0;;;;;109304:44:0;;;;;;109379:14;;::::1;::::0;109359:34;;:17;:34;;;;;::::1;::::0;-1:-1:-1;;;;;;109359:34:0;;::::1;::::0;;::::1;;::::0;::::1;-1:-1:-1::0;;;109359:34:0;;;::::1;;;::::0;;-1:-1:-1;109421:4:0::1;109304;109406:19:::0;;;-1:-1:-1;109436:25:0;109489:4:::1;109472:14:::0;:21;;;109504:11;:18;17292:68;;;;17343:5;17327:21;;-1:-1:-1;;17327:21:0;;;17292:68;108047:1483;;;;;;;;;;:::o;23949:215::-;18253:10;24037:4;24086:25;;;:11;:25;;;;;;;;-1:-1:-1;;;;;24086:34:0;;;;;;;;;;24037:4;;24054:80;;24077:7;;24086:47;;24123:10;;24086:47;:::i;128358:378::-;128462:30;;:::i;:::-;-1:-1:-1;;;;;;;;;;;;;;;;;128539:18:0;128560;128570:7;128560:9;:18::i;:::-;128539:39;;128597:5;:12;;;128589:38;;;;-1:-1:-1;;;128589:38:0;;38666:2:1;128589:38:0;;;38648:21:1;38705:2;38685:18;;;38678:30;-1:-1:-1;;;38724:18:1;;;38717:43;38777:18;;128589:38:0;38638:163:1;128589:38:0;128669:9;;128649:19;:30;;:19;;:30;;;;;;;-1:-1:-1;;;128649:30:0;;;;;;;;;;;;;;;;;;128638:41;;;;;;;;128649:30;;;;;;;128638:41;;-1:-1:-1;;;;;128638:41:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;128638:41:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;128638:41:0;;;;;;;;;;-1:-1:-1;;;128638:41:0;;;;;;;;;;;;;;;-1:-1:-1;;;128638:41:0;;;;;;;;;;;;;;;128702:4;:15;;128718:5;:9;;;128702:26;;;;;;;;-1:-1:-1;;;128702:26:0;;;;;;;;;;;;;;;;;;128690:38;;;;;;;;;128702:26;;128690:38;-1:-1:-1;;;;;128690:38:0;;;;;-1:-1:-1;;;128690:38:0;;;;;;;;;;;128358:378;;128690:38;;-1:-1:-1;;;128358:378:0:o;36717:122::-;33042:15;:13;:15::i;:::-;35830:7:::1;::::0;::::1;::::0;::::1;;;35822:40;;;::::0;-1:-1:-1;;;35822:40:0;;38317:2:1;35822:40:0::1;::::0;::::1;38299:21:1::0;38356:2;38336:18;;;38329:30;-1:-1:-1;;;38375:18:1;;;38368:50;38435:18;;35822:40:0::1;38289:170:1::0;35822:40:0::1;36780:7:::2;:15:::0;;-1:-1:-1;;36780:15:0::2;::::0;;36811:20:::2;::::0;36820:10:::2;20878:51:1::0;;36811:20:0::2;::::0;20866:2:1;20851:18;36811:20:0::2;;;;;;;;36717:122::o:0;120560:1157::-;37925:11;;120766:22;;37925:11;;;;;37917:55;;;;-1:-1:-1;;;37917:55:0;;;;;;;:::i;:::-;38050:11;:19;;-1:-1:-1;;38050:19:0;;;109664:16:::1;:14;:16::i;:::-;-1:-1:-1::0;;;;;120809:24:0;::::2;120801:54;;;;-1:-1:-1::0;;;120801:54:0::2;;;;;;;:::i;:::-;120893:1;120874:16;:20;120866:39;;;;-1:-1:-1::0;;;120866:39:0::2;;;;;;;:::i;:::-;120918:19;120940:18;120950:7;120940:9;:18::i;:::-;120918:40;;121036:26;121065:12;:10;:12::i;:::-;121036:41;;121088:35;121094:10;121106:16;121088:5;:35::i;:::-;121192:179;::::0;-1:-1:-1;;;121192:179:0;;121136:16:::2;::::0;121192:11:::2;::::0;:18:::2;::::0;:179:::2;::::0;121225:4:::2;::::0;121244:6;;121265;;121286:16;;121317:18;;121350:10;;121192:179:::2;;;:::i;:::-;;::::0;::::2;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;121401:11:::0;;121163:208;;-1:-1:-1;121163:208:0;-1:-1:-1;121427:10:0;;121423:91:::2;;121497:4;121476:17;121487:6:::0;121476:8;:17:::2;:::i;:::-;121475:26;;;;:::i;:::-;121454:16:::0;:48;;:16:::2;::::0;:48:::2;::::0;;;::::2;:::i;:::-;::::0;;;-1:-1:-1;;121423:91:0::2;121635:11;::::0;;::::2;::::0;121531:178:::2;::::0;;-1:-1:-1;;;;;23476:15:1;;;23458:34;;23508:18;;;23501:34;;;23571:15;;;;23551:18;;;23544:43;23618:2;23603:18;;23596:34;;;23661:3;23646:19;;23639:35;;;121554:10:0::2;::::0;121531:178:::2;::::0;23407:3:1;23392:19;121531:178:0::2;;;;;;;;-1:-1:-1::0;;38230:11:0;:18;;-1:-1:-1;;38230:18:0;;;;;-1:-1:-1;120560:1157:0;;;-1:-1:-1;;;;;120560:1157:0:o;136481:185::-;33042:15;:13;:15::i;:::-;136574:13:::1;:24;136599:12:::0;136613:8;136623:12;136637:7:::1;:5;:7::i;:::-;136574:84;::::0;-1:-1:-1;;;;;;136574:84:0::1;::::0;;;;;;::::1;::::0;::::1;51670:25:1::0;;;;51711:18;;;51704:34;;;;51754:18;;;51747:34;107059:3:0::1;51797:18:1::0;;;51790:34;;;;51840:19;;;51833:35;51642:19;;136574:84:0::1;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;136481:185:::0;;:::o;136068:218::-;33042:15;:13;:15::i;:::-;136202:76:::1;::::0;-1:-1:-1;;;136202:76:0;;:13:::1;::::0;:28:::1;::::0;:76:::1;::::0;136231:19;;136252:8;;;;136262:15;;136202:76:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;136068:218:::0;;;:::o;21591:127::-;-1:-1:-1;;;;;21692:18:0;;21665:7;21692:18;;;:9;:18;;;;;;21591:127;;;;:::o;117294:1749::-;117440:18;117489:7;-1:-1:-1;;;;;117479:17:0;:6;-1:-1:-1;;;;;117479:17:0;;;117471:42;;;;-1:-1:-1;;;117471:42:0;;;;;;;:::i;:::-;117549:1;117532:14;:18;117524:37;;;;-1:-1:-1;;;117524:37:0;;;;;;;:::i;:::-;117574:18;117595:17;117605:6;117595:9;:17::i;:::-;117574:38;;117623:19;117645:18;117655:7;117645:9;:18::i;:::-;117623:40;;117682:27;117695:5;117702:6;117682:12;:27::i;:::-;117674:52;;;;-1:-1:-1;;;117674:52:0;;;;;;;:::i;:::-;117795:5;:12;;;:29;;;;;117811:6;:13;;;117795:29;117791:357;;;117934:9;;117962:10;;117858:11;;:23;;117900:15;;117934:9;117991:14;118024:15;;;;:34;;118046:4;:12;118024:34;;;118042:1;118024:34;118077:12;:10;:12::i;:::-;117858:246;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;117841:263:0;-1:-1:-1;118119:17:0;;-1:-1:-1;;118119:17:0;117791:357;118199:5;:12;;;118195:841;;;118300:11;:23;118342:15;118376:1;118396;118416:14;118396:1;118469:12;:10;:12::i;:::-;118300:196;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;118524:52:0;;-1:-1:-1;;;118524:52:0;;-1:-1:-1;;;;;22622:32:1;;;118524:52:0;;;22604:51:1;22671:18;;;22664:34;;;118283:213:0;;-1:-1:-1;118532:6:0;118524:31;;;;;;22577:18:1;;118524:52:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;118511:65;;118195:841;;;118736:53;;-1:-1:-1;;;118736:53:0;;-1:-1:-1;;;;;22622:32:1;;;118736:53:0;;;22604:51:1;22671:18;;;22664:34;;;118744:6:0;118736:29;;;;22577:18:1;;118736:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;118723:66;;118821:11;:23;118863:4;:15;;118897:1;118917;118937:10;118966:4;:12;;;118997;:10;:12::i;:::-;118821:203;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;118804:220:0;-1:-1:-1;118195:841:0;117294:1749;;;;;;;:::o;125623:738::-;125759:20;125824:1;125805:16;:20;125797:39;;;;-1:-1:-1;;;125797:39:0;;;;;;;:::i;:::-;125849:19;125871:18;125881:7;125871:9;:18::i;:::-;125949;;125849:40;;-1:-1:-1;125900:17:0;;125920:48;;:16;;:28;:48::i;:::-;125900:68;;125996:11;:25;126036:4;:15;;126066:6;:13;;;:30;;126095:1;126066:30;;;126082:10;;126066:30;126111:28;126130:9;126111:16;:28;:::i;:::-;126154:12;:10;:12::i;:::-;125996:181;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;125981:196;;126239:6;:13;;;126234:120;;126316:11;;;;126284:58;;-1:-1:-1;;;126284:58:0;;-1:-1:-1;;;;;22622:32:1;;;126284:58:0;;;22604:51:1;22671:18;;;22664:34;;;126292:6:0;126284:31;;;;;;22577:18:1;;126284:58:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;126234:120;125623:738;;;;;;:::o;132245:913::-;110044:39;;-1:-1:-1;;;110044:39:0;;31893:66;110044:39;;;37064:25:1;132412:18:0;;;;110087:10;;-1:-1:-1;;;;;110044:5:0;:15;;;;37037:18:1;;110044:39:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;110044:53:0;;110036:80;;;;-1:-1:-1;;;110036:80:0;;40094:2:1;110036:80:0;;;40076:21:1;40133:2;40113:18;;;40106:30;-1:-1:-1;;;40152:18:1;;;40145:44;40206:18;;110036:80:0;40066:164:1;110036:80:0;109664:16:::1;:14;:16::i;:::-;37925:11:::2;::::0;;;::::2;;;37917:55;;;;-1:-1:-1::0;;;37917:55:0::2;;;;;;;:::i;:::-;38050:11;:19:::0;;-1:-1:-1;;38050:19:0::2;::::0;;132528:77:::3;::::0;-1:-1:-1;;;132528:77:0;;38064:5:::2;::::0;;;132528:13:::3;::::0;:39:::3;::::0;:77:::3;::::0;132568:19;;132589:15;;132528:77:::3;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::3;;;;;;;;;;;;::::0;::::3;;;;;;;;;;;;;;;;;::::0;;::::3;-1:-1:-1::0;;132528:77:0::3;::::0;::::3;;::::0;::::3;::::0;;;::::3;::::0;::::3;:::i;:::-;132467:138:::0;;-1:-1:-1;132467:138:0;-1:-1:-1;132723:11:0::3;:28;132752:15:::0;132467:138;;132782:12:::3;:10;:12::i;:::-;132723:72;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::3;;;;;;;;;;;;::::0;::::3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;132834:16:::0;;::::3;21508:12:::0;132710:85;;-1:-1:-1;132710:85:0;;132818:32:::3;;;;:::i;:::-;:45;;;;:::i;:::-;132893:11:::0;;132806:57;;-1:-1:-1;132919:10:0;;132915:93:::3;;132991:4;132968:19;132981:6:::0;132968:10;:19:::3;:::i;:::-;132967:28;;;;:::i;:::-;132946:16:::0;:50;;:16:::3;::::0;:50:::3;::::0;;;::::3;:::i;:::-;::::0;;;-1:-1:-1;;132915:93:0::3;133126:16;::::0;;133123:1:::3;133126:16:::0;;;::::3;::::0;::::3;::::0;;;;133104:4:::3;::::0;133084:66:::3;::::0;::::3;::::0;133111:10:::3;::::0;133123:1;;133126:16;133144:5;;133084:66:::3;:::i;:::-;;;;;;;;-1:-1:-1::0;;38230:11:0::2;:18:::0;;-1:-1:-1;;38230:18:0::2;::::0;::::2;::::0;;-1:-1:-1;132245:913:0;;:::o;36502:120::-;33042:15;:13;:15::i;:::-;35631:7:::1;::::0;::::1;::::0;::::1;;;35630:8;35622:37;;;::::0;-1:-1:-1;;;35622:37:0;;43113:2:1;35622:37:0::1;::::0;::::1;43095:21:1::0;43152:2;43132:18;;;43125:30;-1:-1:-1;;;43171:18:1;;;43164:46;43227:18;;35622:37:0::1;43085:166:1::0;35622:37:0::1;36566:7:::2;:14:::0;;-1:-1:-1;;36566:14:0::2;;;::::0;;36596:18:::2;::::0;36603:10:::2;20878:51:1::0;;36596:18:0::2;::::0;20866:2:1;20851:18;36596::0::2;20833:102:1::0;29113:87:0;29152:13;29185:7;29178:14;;;;;:::i;127739:157::-;127789:13;;127833:11;:24;127858:15;127875:12;:10;:12::i;:::-;127833:55;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;127826:62;;;;127739:157;;:::o;133278:487::-;110044:39;;-1:-1:-1;;;110044:39:0;;31893:66;110044:39;;;37064:25:1;110087:10:0;;-1:-1:-1;;;;;110044:5:0;:15;;;;37037:18:1;;110044:39:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;110044:53:0;;110036:80;;;;-1:-1:-1;;;110036:80:0;;40094:2:1;110036:80:0;;;40076:21:1;40133:2;40113:18;;;40106:30;-1:-1:-1;;;40152:18:1;;;40145:44;40206:18;;110036:80:0;40066:164:1;110036:80:0;133374:16;;133412:1:::1;133405:8:::0;::::1;133401:357;;;133430:18;133451:8;133458:1;133451:4:::0;:8:::1;:::i;:::-;133493:1;133474:16:::0;:20;133430:29;-1:-1:-1;133511:29:0::1;133517:10;133430:29:::0;133511:5:::1;:29::i;:::-;133598:4;133560:186;133622:10;133651::::0;133694:1:::1;133680:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;-1:-1:-1;133680:16:0::1;-1:-1:-1::0;133715:16:0::1;::::0;;133729:1:::1;133715:16:::0;;::::1;::::0;::::1;::::0;;;;133560:186:::1;::::0;;;;::::1;:::i;:::-;;;;;;;;133401:357;;110127:1;133278:487::o:0;135350:252::-;33042:15;:13;:15::i;:::-;135452:4:::1;135444;-1:-1:-1::0;;;;;135444:12:0::1;;;:28;;;;;135468:4;135460;-1:-1:-1::0;;;;;135460:12:0::1;;;135444:28;135436:52;;;::::0;-1:-1:-1;;;135436:52:0;;43806:2:1;135436:52:0::1;::::0;::::1;43788:21:1::0;43845:2;43825:18;;;43818:30;-1:-1:-1;;;43864:18:1;;;43857:41;43915:18;;135436:52:0::1;43778:161:1::0;135436:52:0::1;135521:24;::::0;;;;::::1;::::0;;-1:-1:-1;;;;;135521:24:0;;::::1;::::0;;;;;::::1;;::::0;;::::1;::::0;;;135501:17;:44;;-1:-1:-1;;;;;;135501:44:0::1;::::0;::::1;::::0;;::::1;-1:-1:-1::0;;;135501:44:0;::::1;;::::0;;;135563:31;;57748:34:1;;;57798:18;;;57791:43;135563:31:0::1;::::0;57668:18:1;135563:31:0::1;;;;;;;135350:252:::0;;:::o;24667:377::-;18253:10;24760:4;24804:25;;;:11;:25;;;;;;;;-1:-1:-1;;;;;24804:34:0;;;;;;;;;;24857:35;;;;24849:85;;;;-1:-1:-1;;;24849:85:0;;50536:2:1;24849:85:0;;;50518:21:1;50575:2;50555:18;;;50548:30;50614:34;50594:18;;;50587:62;-1:-1:-1;;;50665:18:1;;;50658:35;50710:19;;24849:85:0;50508:227:1;24849:85:0;24945:67;18253:10;24968:7;24977:34;24996:15;24977:16;:34;:::i;24945:67::-;-1:-1:-1;25032:4:0;;24667:377;-1:-1:-1;;;24667:377:0:o;21931:175::-;22017:4;22034:42;18253:10;22058:9;22069:6;22034:9;:42::i;124075:1228::-;37925:11;;124316:23;;37925:11;;;;;37917:55;;;;-1:-1:-1;;;37917:55:0;;;;;;;:::i;:::-;38050:11;:19;;-1:-1:-1;;38050:19:0;;;109664:16:::1;:14;:16::i;:::-;-1:-1:-1::0;;;;;124360:24:0;::::2;124352:54;;;;-1:-1:-1::0;;;124352:54:0::2;;;;;;;:::i;:::-;124431:17:::0;124474:7;;;;;:33:::2;;-1:-1:-1::0;124485:22:0;;::::2;124474:33;124466:65;;;::::0;-1:-1:-1;;;124466:65:0;;43458:2:1;124466:65:0::2;::::0;::::2;43440:21:1::0;43497:2;43477:18;;;43470:30;-1:-1:-1;;;43516:18:1;;;43509:49;43575:18;;124466:65:0::2;43430:169:1::0;124466:65:0::2;124570:1;124550:17;:21;124542:40;;;;-1:-1:-1::0;;;124542:40:0::2;;;;;;;:::i;:::-;124595:22;124620:20;124631:8;;124620:20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;::::0;;;;-1:-1:-1;124620:10:0::2;::::0;-1:-1:-1;;;124620:20:0:i:2;:::-;124595:45;;124653:16;124710:11;:30;124755:4;124774:12;:10;:12::i;:::-;124801:7;124823:17;;124855;124887:10;124710:198;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;::::0;::::2;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;124680:228:::0;;-1:-1:-1;124680:228:0;-1:-1:-1;124921:34:0::2;124927:10;124680:228:::0;124921:5:::2;:34::i;:::-;124983:11:::0;;125009:10;;125005:91:::2;;125079:4;125058:17;125069:6:::0;125058:8;:17:::2;:::i;:::-;125057:26;;;;:::i;:::-;125036:16:::0;:48;;:16:::2;::::0;:48:::2;::::0;;;::::2;:::i;:::-;::::0;;;-1:-1:-1;;125005:91:0::2;125141:10;-1:-1:-1::0;;;;;125113:182:0::2;;125166:10;125191:15;125221:8;;125244:17;;125276:8;125113:182;;;;;;;;;;;;:::i;:::-;;;;;;;;-1:-1:-1::0;;38230:11:0;:18;;-1:-1:-1;;38230:18:0;;;;;-1:-1:-1;124075:1228:0;;;-1:-1:-1;;;;;;;124075:1228:0:o;112265:852::-;37925:11;;112496:18;;37925:11;;;;;37917:55;;;;-1:-1:-1;;;37917:55:0;;;;;;;:::i;:::-;38050:11;:19;;-1:-1:-1;;38050:19:0;;;109664:16:::1;:14;:16::i;:::-;-1:-1:-1::0;;;;;112535:24:0;::::2;112527:54;;;;-1:-1:-1::0;;;112527:54:0::2;;;;;;;:::i;:::-;112606:16:::0;112648:7;;;;;:32:::2;;-1:-1:-1::0;112659:21:0;;::::2;112648:32;112640:65;;;::::0;-1:-1:-1;;;112640:65:0;;41247:2:1;112640:65:0::2;::::0;::::2;41229:21:1::0;41286:2;41266:18;;;41259:30;-1:-1:-1;;;41305:18:1;;;41298:50;41365:18;;112640:65:0::2;41219:170:1::0;112640:65:0::2;112718:22;112743:19;112754:7;;112743:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;::::0;;;;-1:-1:-1;112743:10:0::2;::::0;-1:-1:-1;;;112743:19:0:i:2;:::-;112718:44;;112786:11;:21;112822:4;112841:12;:10;:12::i;:::-;112868:7;112890:16;;112921:18;112786:164;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;112773:177;;112990:29;112996:10;113008;112990:5;:29::i;:::-;113047:10;-1:-1:-1::0;;;;;113035:74:0::2;;113059:10;113071;113083:7;;113092:16;;113035:74;;;;;;;;;;;:::i;:::-;;;;;;;;-1:-1:-1::0;;38230:11:0;:18;;-1:-1:-1;;38230:18:0;;;;;112265:852;;-1:-1:-1;;;;;;112265:852:0:o;122256:1147::-;37925:11;;122462:33;;37925:11;;;;;37917:55;;;;-1:-1:-1;;;37917:55:0;;;;;;;:::i;:::-;38050:11;:19;;-1:-1:-1;;38050:19:0;;;109664:16:::1;:14;:16::i;:::-;-1:-1:-1::0;;;;;122516:24:0;::::2;122508:54;;;;-1:-1:-1::0;;;122508:54:0::2;;;;;;;:::i;:::-;122598:1;122581:14;:18;122573:37;;;;-1:-1:-1::0;;;122573:37:0::2;;;;;;;:::i;:::-;122679:26;122708:12;:10;:12::i;:::-;122679:41;;122731:33;122737:10;122749:14;122731:5;:33::i;:::-;122777:24;122812:17;122881:11;:33;122929:4;122948:6;122969:14;122998:20;;123033:10;122881:173;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;::::0;;::::2;-1:-1:-1::0;;122881:173:0::2;::::0;::::2;;::::0;::::2;::::0;;;::::2;::::0;::::2;:::i;:::-;123084:11:::0;;122840:214;;-1:-1:-1;122840:214:0;;-1:-1:-1;122840:214:0;;-1:-1:-1;123110:10:0;;123106:92:::2;;123181:4;123159:18;123171:6:::0;123159:9;:18:::2;:::i;:::-;123158:27;;;;:::i;:::-;123137:16:::0;:49;;:16:::2;::::0;:49:::2;::::0;;;::::2;:::i;:::-;::::0;;;-1:-1:-1;;123106:92:0::2;123243:10;-1:-1:-1::0;;;;;123215:180:0::2;;123268:10;123293:14;123322:7;123344:16;123375:9;123215:180;;;;;;;;;;:::i;127998:119::-:0;128051:26;;:::i;:::-;128097:12;:10;:12::i;:::-;128090:19;;127998:119;:::o;136805:108::-;33042:15;:13;:15::i;:::-;136859:13:::1;:23;136883:12:::0;136897:7:::1;:5;:7::i;:::-;136859:46;::::0;-1:-1:-1;;;;;;136859:46:0::1;::::0;;;;;;::::1;::::0;::::1;51303:25:1::0;;;;51344:18;;;51337:34;51276:18;;136859:46:0::1;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;136805:108::o:0;134682:497::-;33042:15;:13;:15::i;:::-;107009:4:::1;134833:8;:19;;134825:45;;;::::0;-1:-1:-1;;;134825:45:0;;39411:2:1;134825:45:0::1;::::0;::::1;39393:21:1::0;39450:2;39430:18;;;39423:30;-1:-1:-1;;;39469:18:1;;;39462:43;39522:18;;134825:45:0::1;39383:163:1::0;134825:45:0::1;107009:4;134889:14;:25;;134881:57;;;::::0;-1:-1:-1;;;134881:57:0;;42004:2:1;134881:57:0::1;::::0;::::1;41986:21:1::0;42043:2;42023:18;;;42016:30;-1:-1:-1;;;42062:18:1;;;42055:49;42121:18;;134881:57:0::1;41976:169:1::0;134881:57:0::1;134968:4;134957:7;:15;;134949:44;;;::::0;-1:-1:-1;;;134949:44:0;;46403:2:1;134949:44:0::1;::::0;::::1;46385:21:1::0;46442:2;46422:18;;;46415:30;-1:-1:-1;;;46461:18:1;;;46454:46;46517:18;;134949:44:0::1;46375:166:1::0;134949:44:0::1;135006:4;:23:::0;;;135040:18;:35;;;135086:11;:21;;;135125:46:::1;::::0;;58482:25:1;;;58538:2;58523:18;;58516:34;;;58566:18;;;58559:34;;;135125:46:0::1;::::0;58470:2:1;58455:18;135125:46:0::1;;;;;;;134682:497:::0;;;:::o;115732:1090::-;37925:11;;115959:18;;37925:11;;;;;37917:55;;;;-1:-1:-1;;;37917:55:0;;;;;;;:::i;:::-;38050:11;:19;;-1:-1:-1;;38050:19:0;;;109664:16:::1;:14;:16::i;:::-;-1:-1:-1::0;;;;;115998:24:0;::::2;115990:54;;;;-1:-1:-1::0;;;115990:54:0::2;;;;;;;:::i;:::-;116073:7;-1:-1:-1::0;;;;;116063:17:0::2;:6;-1:-1:-1::0;;;;;116063:17:0::2;;;116055:42;;;;-1:-1:-1::0;;;116055:42:0::2;;;;;;;:::i;:::-;116133:1;116116:14;:18;116108:37;;;;-1:-1:-1::0;;;116108:37:0::2;;;;;;;:::i;:::-;116158:18;116179:17;116189:6;116179:9;:17::i;:::-;116158:38;;116207:19;116229:18;116239:7;116229:9;:18::i;:::-;116207:40;;116266:27;116279:5;116286:6;116266:12;:27::i;:::-;116258:52;;;;-1:-1:-1::0;;;116258:52:0::2;;;;;;;:::i;:::-;116323:16;116375:11;:16;116406:4;116425:12;:10;:12::i;:::-;116452:5;116472:6;116493:14;116522:18;116555:10;116375:201;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;::::0;::::2;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;116606:11:::0;;116350:226;;-1:-1:-1;116350:226:0;-1:-1:-1;116632:10:0;;116628:91:::2;;116702:4;116681:17;116692:6:::0;116681:8;:17:::2;:::i;:::-;116680:26;;;;:::i;:::-;116659:16:::0;:48;;:16:::2;::::0;:48:::2;::::0;;;::::2;:::i;:::-;::::0;;;-1:-1:-1;;116628:91:0::2;116756:10;::::0;;::::2;::::0;116768:11;;::::2;::::0;116736:78:::2;::::0;;-1:-1:-1;;;;;21564:15:1;;;21546:34;;21616:15;;;21596:18;;;21589:43;;;;21648:18;;;21641:34;;;21706:2;21691:18;;21684:34;;;21755:15;;21749:3;21734:19;;21727:44;116744:10:0::2;::::0;116736:78:::2;::::0;21495:3:1;21480:19;116736:78:0::2;;;;;;;-1:-1:-1::0;;38230:11:0;:18;;-1:-1:-1;;38230:18:0;;;;;-1:-1:-1;115732:1090:0;;;-1:-1:-1;;;;;;115732:1090:0:o;114487:490::-;114648:18;114698:16;114740:7;;;;;:32;;-1:-1:-1;114751:21:0;;;114740:32;114732:65;;;;-1:-1:-1;;;114732:65:0;;41247:2:1;114732:65:0;;;41229:21:1;41286:2;41266:18;;;41259:30;-1:-1:-1;;;41305:18:1;;;41298:50;41365:18;;114732:65:0;41219:170:1;114732:65:0;114808:22;114833:19;114844:7;;114833:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;114833:10:0;;-1:-1:-1;;;114833:19:0:i;:::-;114808:44;-1:-1:-1;114883:11:0;:28;114912:15;114808:44;114938:16;;114956:12;:10;:12::i;:::-;114883:86;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;114863:106;114487:490;-1:-1:-1;;;;;;;114487:490:0:o;110929:727::-;37925:11;;111130:18;;37925:11;;;;;37917:55;;;;-1:-1:-1;;;37917:55:0;;;;;;;:::i;:::-;38050:11;:19;;-1:-1:-1;;38050:19:0;;;109664:16:::1;:14;:16::i;:::-;-1:-1:-1::0;;;;;111169:24:0;::::2;111161:54;;;;-1:-1:-1::0;;;111161:54:0::2;;;;;;;:::i;:::-;111251:1;111234:14;:18;111226:37;;;;-1:-1:-1::0;;;111226:37:0::2;;;;;;;:::i;:::-;111276:18;111297:17;111307:6;111297:9;:17::i;:::-;111276:38;;111340:11;:16;111371:4;111390:12;:10;:12::i;:::-;111417:5;111437:14;111466:18;111340:155;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;111327:168;;111537:29;111543:10;111555;111537:5;:29::i;:::-;111582:66;::::0;;-1:-1:-1;;;;;22996:15:1;;;22978:34;;23043:2;23028:18;;23021:34;;;23091:15;;23071:18;;;23064:43;23138:2;23123:18;;23116:34;;;111582:66:0;;111589:10:::2;::::0;111582:66:::2;::::0;;;;;22927:3:1;111582:66:0;;::::2;-1:-1:-1::0;38230:11:0;:18;;-1:-1:-1;;38230:18:0;;;;;110929:727;;-1:-1:-1;;;;110929:727:0:o;130018:545::-;130136:14;;130087:22;;130136:14;-1:-1:-1;;;;;130173:16:0;;;;;-1:-1:-1;;;130173:16:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;130173:16:0;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;130163:26:0;;-1:-1:-1;130232:324:0;130256:3;130252:1;:7;130232:324;;;130290:21;130300:7;130308:1;130300:10;;;;;;-1:-1:-1;;;130300:10:0;;;;;;;;;;;;;;;130290:9;:21::i;:::-;130281:30;;130339:6;:10;;;130326:7;130334:1;130326:10;;;;;;-1:-1:-1;;;130326:10:0;;;;;;;;;;;;;;:23;;;;;;;;;;;130372:6;:13;;;130364:39;;;;-1:-1:-1;;;130364:39:0;;38666:2:1;130364:39:0;;;38648:21:1;38705:2;38685:18;;;38678:30;-1:-1:-1;;;38724:18:1;;;38717:43;38777:18;;130364:39:0;38638:163:1;130364:39:0;130425:9;130437:5;:1;130441;130437:5;:::i;:::-;130425:17;;130420:125;130448:3;130444:1;:7;130420:125;;;130499:7;130507:1;130499:10;;;;;;-1:-1:-1;;;130499:10:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;130485:24:0;:7;130493:1;130485:10;;;;;;-1:-1:-1;;;130485:10:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;130485:24:0;;;130477:52;;;;-1:-1:-1;;;130477:52:0;;47150:2:1;130477:52:0;;;47132:21:1;47189:2;47169:18;;;47162:30;-1:-1:-1;;;47208:18:1;;;47201:45;47263:18;;130477:52:0;47122:165:1;130477:52:0;130453:3;;;;:::i;:::-;;;;130420:125;;;-1:-1:-1;130261:3:0;;;;:::i;:::-;;;;130232:324;;;;130018:545;;;;;:::o;130662:166::-;130707:19;;:::i;:::-;130746:74;;;;;;;;130775:4;:16;;;130759:13;21508:12;;21420:108;;130759:13;:32;;;;:::i;:::-;130746:74;;;;130793:7;:5;:7::i;:::-;130746:74;;;;;;;;;;;130802:17;130746:74;-1:-1:-1;;;;;130746:74:0;;;;;-1:-1:-1;;;130746:74:0;;;;;;;;;;;;;;;;130739:81;-1:-1:-1;130662:166:0;:::o;51597:195::-;51664:7;51783:1;51765:14;47841:4;51765:1;:14;:::i;:::-;51764:20;;;;:::i;27839:346::-;-1:-1:-1;;;;;27941:19:0;;27933:68;;;;-1:-1:-1;;;27933:68:0;;47900:2:1;27933:68:0;;;47882:21:1;47939:2;47919:18;;;47912:30;47978:34;47958:18;;;47951:62;-1:-1:-1;;;48029:18:1;;;48022:34;48073:19;;27933:68:0;47872:226:1;27933:68:0;-1:-1:-1;;;;;28020:21:0;;28012:68;;;;-1:-1:-1;;;28012:68:0;;40437:2:1;28012:68:0;;;40419:21:1;40476:2;40456:18;;;40449:30;40515:34;40495:18;;;40488:62;-1:-1:-1;;;40566:18:1;;;40559:32;40608:19;;28012:68:0;40409:224:1;28012:68:0;-1:-1:-1;;;;;28093:18:0;;;;;;;:11;:18;;;;;;;;:27;;;;;;;;;;;;;:36;;;28145:32;;37064:25:1;;;28145:32:0;;37037:18:1;28145:32:0;;;;;;;;27839:346;;;:::o;129471:336::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;129632:6:0;-1:-1:-1;;;;;129622:16:0;:6;-1:-1:-1;;;;;129622:16:0;;129618:51;;;-1:-1:-1;129647:22:0;;;;;;;;-1:-1:-1;129647:22:0;;-1:-1:-1;;;;;129647:22:0;;;;;;129664:4;129647:22;;;;;;;129640:29;;129618:51;129744:55;;;;;;;;129750:1;129744:55;;;;;;129753:6;-1:-1:-1;;;;;129744:55:0;;;;;129792:6;-1:-1:-1;;;;;129761:37:0;:4;:19;;129781:1;129761:22;;;;;;-1:-1:-1;;;129761:22:0;;;;;;;;;;;;;;;;;;;;;;:27;-1:-1:-1;;;;;129761:27:0;:37;129744:55;;129737:62;129471:336;-1:-1:-1;;129471:336:0:o;33085:121::-;33157:11;:9;:11::i;:::-;-1:-1:-1;;;;;33143:25:0;:10;-1:-1:-1;;;;;33143:25:0;;33135:63;;;;-1:-1:-1;;;33135:63:0;;42759:2:1;33135:63:0;;;42741:21:1;42798:2;42778:18;;;42771:30;42837:27;42817:18;;;42810:55;42882:18;;33135:63:0;42731:175:1;33135:63:0;33085:121::o;25534:544::-;-1:-1:-1;;;;;25640:20:0;;25632:70;;;;-1:-1:-1;;;25632:70:0;;47494:2:1;25632:70:0;;;47476:21:1;47533:2;47513:18;;;47506:30;47572:34;47552:18;;;47545:62;-1:-1:-1;;;47623:18:1;;;47616:35;47668:19;;25632:70:0;47466:227:1;25632:70:0;-1:-1:-1;;;;;25721:23:0;;25713:71;;;;-1:-1:-1;;;25713:71:0;;37913:2:1;25713:71:0;;;37895:21:1;37952:2;37932:18;;;37925:30;37991:34;37971:18;;;37964:62;-1:-1:-1;;;38042:18:1;;;38035:33;38085:19;;25713:71:0;37885:225:1;25713:71:0;-1:-1:-1;;;;;25821:17:0;;25797:21;25821:17;;;:9;:17;;;;;;25857:23;;;;25849:74;;;;-1:-1:-1;;;25849:74:0;;40840:2:1;25849:74:0;;;40822:21:1;40879:2;40859:18;;;40852:30;40918:34;40898:18;;;40891:62;-1:-1:-1;;;40969:18:1;;;40962:36;41015:19;;25849:74:0;40812:228:1;25849:74:0;25954:22;25970:6;25954:13;:22;:::i;:::-;-1:-1:-1;;;;;25934:17:0;;;;;;;:9;:17;;;;;;:42;;;;25987:20;;;;;;;;:30;;26011:6;;25934:17;25987:30;;26011:6;;25987:30;:::i;:::-;;;;;;;;26052:9;-1:-1:-1;;;;;26035:35:0;26044:6;-1:-1:-1;;;;;26035:35:0;;26063:6;26035:35;;;;37064:25:1;;37052:2;37037:18;;37019:76;26035:35:0;;;;;;;;25534:544;;;;:::o;30097:163::-;30188:64;30227:8;30237:10;30249:2;30188:38;:64::i;:::-;30097:163;;:::o;38668:184::-;38725:7;-1:-1:-1;;;38753:5:0;:14;38745:67;;;;-1:-1:-1;;;38745:67:0;;41596:2:1;38745:67:0;;;41578:21:1;41635:2;41615:18;;;41608:30;41674:34;41654:18;;;41647:62;-1:-1:-1;;;41725:18:1;;;41718:37;41772:19;;38745:67:0;41568:229:1;38745:67:0;-1:-1:-1;38838:5:0;38668:184::o;45100:622::-;45470:10;;;45469:62;;-1:-1:-1;45486:39:0;;-1:-1:-1;;;45486:39:0;;45510:4;45486:39;;;21152:34:1;-1:-1:-1;;;;;21222:15:1;;;21202:18;;;21195:43;45486:15:0;;;;;21087:18:1;;45486:39:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:44;45469:62;45461:152;;;;-1:-1:-1;;;45461:152:0;;50113:2:1;45461:152:0;;;50095:21:1;50152:2;50132:18;;;50125:30;50191:34;50171:18;;;50164:62;-1:-1:-1;;;50242:18:1;;;50235:52;50304:19;;45461:152:0;50085:244:1;45461:152:0;45651:62;;;-1:-1:-1;;;;;22622:32:1;;45651:62:0;;;22604:51:1;22671:18;;;;22664:34;;;45651:62:0;;;;;;;;;;22577:18:1;;;;45651:62:0;;;;;;;;-1:-1:-1;;;;;45651:62:0;-1:-1:-1;;;45651:62:0;;;45624:90;;45644:5;;45624:19;:90::i;:::-;45100:622;;;:::o;39151:179::-;39207:6;-1:-1:-1;;;39234:5:0;:13;39226:65;;;;-1:-1:-1;;;39226:65:0;;45241:2:1;39226:65:0;;;45223:21:1;45280:2;45260:18;;;45253:30;45319:34;45299:18;;;45292:62;-1:-1:-1;;;45370:18:1;;;45363:36;45416:19;;39226:65:0;45213:228:1;109767:126:0;109827:7;;;;;;;109826:8;;:45;;;109852:19;:17;:19::i;:::-;-1:-1:-1;;;;;109838:33:0;:10;-1:-1:-1;;;;;109838:33:0;;109826:45;109818:67;;;;-1:-1:-1;;;109818:67:0;;44146:2:1;109818:67:0;;;44128:21:1;44185:1;44165:18;;;44158:29;-1:-1:-1;;;44203:18:1;;;44196:39;44252:18;;109818:67:0;44118:158:1;26969:432:0;-1:-1:-1;;;;;27053:21:0;;27045:67;;;;-1:-1:-1;;;27045:67:0;;46748:2:1;27045:67:0;;;46730:21:1;46787:2;46767:18;;;46760:30;46826:34;46806:18;;;46799:62;-1:-1:-1;;;46877:18:1;;;46870:31;46918:19;;27045:67:0;46720:223:1;27045:67:0;-1:-1:-1;;;;;27150:18:0;;27125:22;27150:18;;;:9;:18;;;;;;27187:24;;;;27179:71;;;;-1:-1:-1;;;27179:71:0;;39008:2:1;27179:71:0;;;38990:21:1;39047:2;39027:18;;;39020:30;39086:34;39066:18;;;39059:62;-1:-1:-1;;;39137:18:1;;;39130:32;39179:19;;27179:71:0;38980:224:1;27179:71:0;27282:23;27299:6;27282:14;:23;:::i;:::-;-1:-1:-1;;;;;27261:18:0;;;;;;:9;:18;;;;;:44;;;;27316:12;:22;;27332:6;;27261:18;27316:22;;27332:6;;27316:22;:::i;:::-;;;;-1:-1:-1;;27356:37:0;;37064:25:1;;;27382:1:0;;-1:-1:-1;;;;;27356:37:0;;;;;37052:2:1;37037:18;27356:37:0;37019:76:1;130900:831:0;130960:38;;;;;;;;130986:12;130960:38;-1:-1:-1;;;;;130960:38:0;;;;;-1:-1:-1;;;130960:38:0;;;;;;;;;;-1:-1:-1;;;130960:38:0;;;;;;;;;;;-1:-1:-1;;;130960:38:0;;;;;;;;;;130940:7;;130960:38;131173:15;:25;-1:-1:-1;131169:555:0;;;131231:17;;131282:22;;;;131215:13;;131357:27;-1:-1:-1;;;;;131357:27:0;;:15;:27;:::i;:::-;131386:19;131396:9;131386:7;:19;:::i;:::-;-1:-1:-1;;;;;131321:85:0;;;;;131434:6;-1:-1:-1;;;;;131427:13:0;:4;-1:-1:-1;;;;;131427:13:0;;131423:201;;;131508:5;131497:7;131480:13;131487:6;131480:4;:13;:::i;:::-;-1:-1:-1;;;;;131479:25:0;;;;;:::i;:::-;131478:35;;;;:::i;:::-;131468:46;;-1:-1:-1;;;;;131468:46:0;;;:::i;:::-;131461:53;;;;;;;;;;;131423:201;131602:5;131591:7;131574:13;131583:4;131574:6;:13;:::i;:::-;-1:-1:-1;;;;;131573:25:0;;;;;:::i;:::-;131572:35;;;;:::i;:::-;131562:46;;-1:-1:-1;;;;;131562:46:0;;;:::i;131169:555::-;-1:-1:-1;;;;;;131701:11:0;;-1:-1:-1;131701:11:0;;-1:-1:-1;131701:11:0;119179:574;119288:12;119354:3;:10;;;119353:11;:27;;;;;119369:4;:11;;;119368:12;119353:27;119349:45;;;-1:-1:-1;119389:5:0;119382:12;;119349:45;119442:3;:10;;;:25;;;;;119456:4;:11;;;119442:25;119438:42;;;-1:-1:-1;119476:4:0;119469:11;;119438:42;119525:3;:10;;;:26;;;;;119539:3;:7;;;:12;;119550:1;119539:12;119525:26;119521:43;;;-1:-1:-1;119560:4:0;119553:11;;119521:43;119609:4;:11;;;:28;;;;;119624:4;:8;;;:13;;119636:1;119624:13;119609:28;119605:45;;;-1:-1:-1;119646:4:0;119639:11;;119605:45;-1:-1:-1;119740:5:0;119179:574;;;;:::o;49467:135::-;49533:7;49560:34;49577:1;49580;47841:4;49560:16;:34::i;26360:276::-;-1:-1:-1;;;;;26444:21:0;;26436:65;;;;-1:-1:-1;;;26436:65:0;;50942:2:1;26436:65:0;;;50924:21:1;50981:2;50961:18;;;50954:30;51020:33;51000:18;;;50993:61;51071:18;;26436:65:0;50914:181:1;26436:65:0;26530:6;26514:12;;:22;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;;;26547:18:0;;;;;;:9;:18;;;;;:28;;26569:6;;26547:18;:28;;26569:6;;26547:28;:::i;:::-;;;;-1:-1:-1;;26591:37:0;;37064:25:1;;;-1:-1:-1;;;;;26591:37:0;;;26608:1;;26591:37;;37052:2:1;37037:18;26591:37:0;;;;;;;26360:276;;:::o;33692:95::-;33736:7;33763:5;-1:-1:-1;;;;;33763:14:0;;:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;28612:229::-;28754:15;;;;:5;;:15;;;;;:::i;:::-;-1:-1:-1;28780:19:0;;;;:7;;:19;;;;;:::i;:::-;-1:-1:-1;28810:9:0;:23;;-1:-1:-1;;28810:23:0;;;;;;;;;;;;-1:-1:-1;;28612:229:0:o;46875:761::-;47299:23;47325:69;47353:4;47325:69;;;;;;;;;;;;;;;;;47333:5;-1:-1:-1;;;;;47325:27:0;;;:69;;;;;:::i;:::-;47409:17;;47299:95;;-1:-1:-1;47409:21:0;47405:224;;47551:10;47540:30;;;;;;;;;;;;:::i;:::-;47532:85;;;;-1:-1:-1;;;47532:85:0;;49342:2:1;47532:85:0;;;49324:21:1;49381:2;49361:18;;;49354:30;49420:34;49400:18;;;49393:62;-1:-1:-1;;;49471:18:1;;;49464:40;49521:19;;47532:85:0;49314:232:1;34481:124:0;34560:37;;-1:-1:-1;;;34560:37:0;;31239:66;34560:37;;;37064:25:1;34533:7:0;;34560:5;-1:-1:-1;;;;;34560:15:0;;;;37037:18:1;;34560:37:0;;;;;;;;;;;;;;;;;;50075:286;50195:7;50348:5;50339;50343:1;50339;:5;:::i;:::-;50338:15;;;;:::i;:::-;50331:22;50075:286;-1:-1:-1;;;;50075:286:0:o;12250:195::-;12353:12;12385:52;12407:6;12415:4;12421:1;12424:12;12353;9699:20;;13546:60;;;;-1:-1:-1;;;13546:60:0;;48305:2:1;13546:60:0;;;48287:21:1;48344:2;48324:18;;;48317:30;48383:31;48363:18;;;48356:59;48432:18;;13546:60:0;48277:179:1;13546:60:0;13680:12;13694:23;13721:6;-1:-1:-1;;;;;13721:11:0;13741:5;13749:4;13721:33;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13679:75;;;;13772:52;13790:7;13799:10;13811:12;15957;15986:7;15982:595;;;-1:-1:-1;16017:10:0;16010:17;;15982:595;16131:17;;:21;16127:439;;16394:10;16388:17;16455:15;16442:10;16438:2;16434:19;16427:44;16342:148;16537:12;16530:20;;-1:-1:-1;;;16530:20:0;;;;;;;;:::i;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14:398:1;;;141:3;134:4;126:6;122:17;118:27;108:2;;166:8;156;149:26;108:2;-1:-1:-1;196:20:1;;-1:-1:-1;;;;;228:30:1;;225:2;;;278:8;268;261:26;225:2;322:4;314:6;310:17;298:29;;385:3;378:4;370;362:6;358:17;350:6;346:30;342:41;339:50;336:2;;;402:1;399;392:12;336:2;98:314;;;;;:::o;417:691::-;;535:3;528:4;520:6;516:17;512:27;502:2;;557:5;550;543:20;502:2;590:6;584:13;616:4;640:60;656:43;696:2;656:43;:::i;:::-;640:60;:::i;:::-;734:15;;;765:12;;;;797:15;;;843:11;;;831:24;;827:33;;824:42;-1:-1:-1;821:2:1;;;883:5;876;869:20;821:2;909:5;923:156;937:2;934:1;931:9;923:156;;;994:10;;982:23;;1025:12;;;;1057;;;;955:1;948:9;923:156;;;-1:-1:-1;1097:5:1;;492:616;-1:-1:-1;;;;;;;492:616:1:o;1113:376::-;;;1229:3;1222:4;1214:6;1210:17;1206:27;1196:2;;1254:8;1244;1237:26;1196:2;-1:-1:-1;1284:20:1;;-1:-1:-1;;;;;1316:30:1;;1313:2;;;1366:8;1356;1349:26;1313:2;1410:4;1402:6;1398:17;1386:29;;1462:3;1455:4;1446:6;1438;1434:19;1430:30;1427:39;1424:2;;;1479:1;1476;1469:12;1494:171;;1606:3;1597:6;1592:3;1588:16;1584:26;1581:2;;;1627:5;1620;1613:20;1581:2;-1:-1:-1;1653:6:1;1571:94;-1:-1:-1;1571:94:1:o;1670:160::-;1747:13;;1800:4;1789:16;;1779:27;;1769:2;;1820:1;1817;1810:12;1835:257;;1947:2;1935:9;1926:7;1922:23;1918:32;1915:2;;;1968:6;1960;1953:22;1915:2;2012:9;1999:23;2031:31;2056:5;2031:31;:::i;2097:261::-;;2220:2;2208:9;2199:7;2195:23;2191:32;2188:2;;;2241:6;2233;2226:22;2188:2;2278:9;2272:16;2297:31;2322:5;2297:31;:::i;2363:398::-;;;2492:2;2480:9;2471:7;2467:23;2463:32;2460:2;;;2513:6;2505;2498:22;2460:2;2557:9;2544:23;2576:31;2601:5;2576:31;:::i;:::-;2626:5;-1:-1:-1;2683:2:1;2668:18;;2655:32;2696:33;2655:32;2696:33;:::i;:::-;2748:7;2738:17;;;2450:311;;;;;:::o;2766:466::-;;;;2912:2;2900:9;2891:7;2887:23;2883:32;2880:2;;;2933:6;2925;2918:22;2880:2;2977:9;2964:23;2996:31;3021:5;2996:31;:::i;:::-;3046:5;-1:-1:-1;3103:2:1;3088:18;;3075:32;3116:33;3075:32;3116:33;:::i;:::-;2870:362;;3168:7;;-1:-1:-1;;;3222:2:1;3207:18;;;;3194:32;;2870:362::o;3237:677::-;;;;;;3417:3;3405:9;3396:7;3392:23;3388:33;3385:2;;;3439:6;3431;3424:22;3385:2;3483:9;3470:23;3502:31;3527:5;3502:31;:::i;:::-;3552:5;-1:-1:-1;3609:2:1;3594:18;;3581:32;3622:33;3581:32;3622:33;:::i;:::-;3674:7;-1:-1:-1;3728:2:1;3713:18;;3700:32;;-1:-1:-1;3779:2:1;3764:18;;3751:32;;-1:-1:-1;3835:3:1;3820:19;;3807:33;3849;3807;3849;:::i;:::-;3901:7;3891:17;;;3375:539;;;;;;;;:::o;3919:325::-;;;4048:2;4036:9;4027:7;4023:23;4019:32;4016:2;;;4069:6;4061;4054:22;4016:2;4113:9;4100:23;4132:31;4157:5;4132:31;:::i;:::-;4182:5;4234:2;4219:18;;;;4206:32;;-1:-1:-1;;;4006:238:1:o;4249:535::-;;;;;4412:3;4400:9;4391:7;4387:23;4383:33;4380:2;;;4434:6;4426;4419:22;4380:2;4478:9;4465:23;4497:31;4522:5;4497:31;:::i;:::-;4547:5;-1:-1:-1;4599:2:1;4584:18;;4571:32;;-1:-1:-1;4650:2:1;4635:18;;4622:32;;-1:-1:-1;4706:2:1;4691:18;;4678:32;4719:33;4678:32;4719:33;:::i;:::-;4370:414;;;;-1:-1:-1;4370:414:1;;-1:-1:-1;;4370:414:1:o;4789:592::-;;;;4953:2;4941:9;4932:7;4928:23;4924:32;4921:2;;;4974:6;4966;4959:22;4921:2;5019:9;5006:23;-1:-1:-1;;;;;5044:6:1;5041:30;5038:2;;;5089:6;5081;5074:22;5038:2;5133:70;5195:7;5186:6;5175:9;5171:22;5133:70;:::i;:::-;5222:8;;-1:-1:-1;5107:96:1;-1:-1:-1;;5307:2:1;5292:18;;5279:32;5320:31;5279:32;5320:31;:::i;:::-;5370:5;5360:15;;;4911:470;;;;;:::o;5386:803::-;;;;;5585:2;5573:9;5564:7;5560:23;5556:32;5553:2;;;5606:6;5598;5591:22;5553:2;5651:9;5638:23;-1:-1:-1;;;;;5721:2:1;5713:6;5710:14;5707:2;;;5742:6;5734;5727:22;5707:2;5786:70;5848:7;5839:6;5828:9;5824:22;5786:70;:::i;:::-;5875:8;;-1:-1:-1;5760:96:1;-1:-1:-1;5963:2:1;5948:18;;5935:32;;-1:-1:-1;5979:16:1;;;5976:2;;;6013:6;6005;5998:22;5976:2;;6057:72;6121:7;6110:8;6099:9;6095:24;6057:72;:::i;:::-;5543:646;;;;-1:-1:-1;6148:8:1;-1:-1:-1;;;;5543:646:1:o;6194:1007::-;;;;;;;6427:3;6415:9;6406:7;6402:23;6398:33;6395:2;;;6449:6;6441;6434:22;6395:2;6494:9;6481:23;-1:-1:-1;;;;;6564:2:1;6556:6;6553:14;6550:2;;;6585:6;6577;6570:22;6550:2;6629:70;6691:7;6682:6;6671:9;6667:22;6629:70;:::i;:::-;6718:8;;-1:-1:-1;6603:96:1;-1:-1:-1;6806:2:1;6791:18;;6778:32;;-1:-1:-1;6822:16:1;;;6819:2;;;6856:6;6848;6841:22;6819:2;;6900:72;6964:7;6953:8;6942:9;6938:24;6900:72;:::i;:::-;6991:8;;-1:-1:-1;6874:98:1;-1:-1:-1;;7073:2:1;7058:18;;7045:32;;-1:-1:-1;7127:2:1;7112:18;;7099:32;7140:31;7099:32;7140:31;:::i;:::-;7190:5;7180:15;;;6385:816;;;;;;;;:::o;7206:1221::-;;;7394:2;7382:9;7373:7;7369:23;7365:32;7362:2;;;7415:6;7407;7400:22;7362:2;7453:9;7447:16;-1:-1:-1;;;;;7523:2:1;7515:6;7512:14;7509:2;;;7544:6;7536;7529:22;7509:2;7587:6;7576:9;7572:22;7562:32;;7632:7;7625:4;7621:2;7617:13;7613:27;7603:2;;7659:6;7651;7644:22;7603:2;7693;7687:9;7715:4;7739:60;7755:43;7795:2;7755:43;:::i;7739:60::-;7833:15;;;7864:12;;;;7896:11;;;7934;;;7926:20;;7922:29;;7919:42;-1:-1:-1;7916:2:1;;;7979:6;7971;7964:22;7916:2;8006:6;7997:15;;8021:178;8035:2;8032:1;8029:9;8021:178;;;8092:32;8120:3;8092:32;:::i;:::-;8080:45;;8053:1;8046:9;;;;;8145:12;;;;8177;;8021:178;;;-1:-1:-1;8254:18:1;;;8248:25;8218:5;;-1:-1:-1;8248:25:1;;-1:-1:-1;;;8285:16:1;;;8282:2;;;8319:6;8311;8304:22;8282:2;;8347:74;8413:7;8402:8;8391:9;8387:24;8347:74;:::i;:::-;8337:84;;;7352:1075;;;;;:::o;8432:251::-;;8541:2;8529:9;8520:7;8516:23;8512:32;8509:2;;;8562:6;8554;8547:22;8509:2;8606:9;8593:23;8625:28;8647:5;8625:28;:::i;8688:255::-;;8808:2;8796:9;8787:7;8783:23;8779:32;8776:2;;;8829:6;8821;8814:22;8776:2;8866:9;8860:16;8885:28;8907:5;8885:28;:::i;8948:2031::-;;;;;;;;;;9303:9;9294:7;9290:23;9333:3;9329:2;9325:12;9322:2;;;9355:6;9347;9340:22;9322:2;9400:9;9387:23;-1:-1:-1;;;;;9470:2:1;9462:6;9459:14;9456:2;;;9491:6;9483;9476:22;9456:2;9535:59;9586:7;9577:6;9566:9;9562:22;9535:59;:::i;:::-;9613:8;;-1:-1:-1;9509:85:1;-1:-1:-1;9701:2:1;9686:18;;9673:32;;-1:-1:-1;9717:16:1;;;9714:2;;;9751:6;9743;9736:22;9714:2;9795:61;9848:7;9837:8;9826:9;9822:24;9795:61;:::i;:::-;9875:8;;-1:-1:-1;9769:87:1;-1:-1:-1;9769:87:1;;-1:-1:-1;9929:70:1;9991:7;9986:2;9971:18;;9929:70;:::i;:::-;9919:80;;10018:71;10081:7;10075:3;10064:9;10060:19;10018:71;:::i;:::-;10008:81;;10142:3;10131:9;10127:19;10114:33;10098:49;;10172:2;10162:8;10159:16;10156:2;;;10193:6;10185;10178:22;10156:2;;10237:72;10301:7;10290:8;10279:9;10275:24;10237:72;:::i;:::-;10328:8;;-1:-1:-1;10211:98:1;-1:-1:-1;;10398:4:1;-1:-1:-1;;10379:17:1;;10375:28;10372:2;;;10421:6;10413;10406:22;10372:2;10452:19;10468:2;10452:19;:::i;:::-;10522:3;10507:19;;10494:33;10480:48;;10563:2;-1:-1:-1;;10544:17:1;;10540:26;10537:2;;;10584:6;10576;10569:22;10537:2;10617:19;10633:2;10617:19;:::i;:::-;10602:34;;10688:3;10677:9;10673:19;10660:33;10702;10727:7;10702:33;:::i;:::-;10744:24;;10820:3;10805:19;;10792:33;10834;10792;10834;:::i;:::-;10901:7;10896:2;10887:7;10883:16;10876:33;;10941:7;10936:2;10929:5;10925:14;10918:31;10968:5;10958:15;;;;9270:1709;;;;;;;;;;;:::o;10984:1289::-;;;11171:9;11162:7;11158:23;11201:3;11197:2;11193:12;11190:2;;;11223:6;11215;11208:22;11190:2;11252:4;11248:2;11244:13;11241:2;;;11275:6;11267;11260:22;11241:2;11306:21;11322:4;11306:21;:::i;:::-;11357:9;11351:16;11376:33;11401:7;11376:33;:::i;:::-;11418:22;;11485:2;11470:18;;11464:25;11498:33;11464:25;11498:33;:::i;:::-;11558:2;11547:14;;11540:31;11616:2;11601:18;;11595:25;11629:30;11595:25;11629:30;:::i;:::-;11686:2;11675:14;;11668:31;11744:2;11729:18;;11723:25;11779:1;11767:14;;11757:2;;11800:6;11792;11785:22;11757:2;11836;11825:14;;11818:31;11829:5;-1:-1:-1;11908:2:1;-1:-1:-1;;11889:17:1;;11885:26;11882:2;;;11929:6;11921;11914:22;11882:2;;11962:19;11978:2;11962:19;:::i;:::-;12026:4;12015:9;12011:20;12005:27;12041:33;12066:7;12041:33;:::i;:::-;12083:24;;12152:3;12137:19;;12131:26;12166:33;12131:26;12166:33;:::i;:::-;12228:2;12215:16;;12208:33;11138:1135;;12219:7;;-1:-1:-1;11138:1135:1;;-1:-1:-1;;11138:1135:1:o;12278:398::-;;;12407:2;12395:9;12386:7;12382:23;12378:32;12375:2;;;12428:6;12420;12413:22;12375:2;12472:9;12459:23;12491:31;12516:5;12491:31;:::i;:::-;12541:5;-1:-1:-1;12598:2:1;12583:18;;12570:32;12611:33;12570:32;12611:33;:::i;12681:190::-;;12793:2;12781:9;12772:7;12768:23;12764:32;12761:2;;;12814:6;12806;12799:22;12761:2;-1:-1:-1;12842:23:1;;12751:120;-1:-1:-1;12751:120:1:o;12876:194::-;;12999:2;12987:9;12978:7;12974:23;12970:32;12967:2;;;13020:6;13012;13005:22;12967:2;-1:-1:-1;13048:16:1;;12957:113;-1:-1:-1;12957:113:1:o;13075:1335::-;;;;13282:2;13270:9;13261:7;13257:23;13253:32;13250:2;;;13303:6;13295;13288:22;13250:2;13337:9;13331:16;13321:26;;13366:2;13412;13401:9;13397:18;13391:25;-1:-1:-1;;;;;13476:2:1;13468:6;13465:14;13462:2;;;13497:6;13489;13482:22;13462:2;13540:6;13529:9;13525:22;13515:32;;13585:7;13578:4;13574:2;13570:13;13566:27;13556:2;;13612:6;13604;13597:22;13556:2;13646;13640:9;13669:60;13685:43;13725:2;13685:43;:::i;13669:60::-;13763:15;;;13794:12;;;;13826:11;;;13864;;;13856:20;;13852:29;;13849:42;-1:-1:-1;13846:2:1;;;13909:6;13901;13894:22;13846:2;13936:6;13927:15;;13951:231;13965:2;13962:1;13959:9;13951:231;;;14029:3;14023:10;14046:31;14071:5;14046:31;:::i;:::-;14090:18;;13983:1;13976:9;;;;;14128:12;;;;14160;;13951:231;;;-1:-1:-1;14252:2:1;14237:18;;14231:25;14201:5;;-1:-1:-1;14231:25:1;-1:-1:-1;;;14268:16:1;;;14265:2;;;14302:6;14294;14287:22;14265:2;;;14330:74;14396:7;14385:8;14374:9;14370:24;14330:74;:::i;:::-;14320:84;;;13240:1170;;;;;:::o;14415:660::-;;;;;14596:2;14584:9;14575:7;14571:23;14567:32;14564:2;;;14617:6;14609;14602:22;14564:2;14658:9;14645:23;14635:33;;14719:2;14708:9;14704:18;14691:32;-1:-1:-1;;;;;14738:6:1;14735:30;14732:2;;;14783:6;14775;14768:22;14732:2;14827:70;14889:7;14880:6;14869:9;14865:22;14827:70;:::i;:::-;14916:8;;-1:-1:-1;14801:96:1;-1:-1:-1;;15001:2:1;14986:18;;14973:32;15014:31;14973:32;15014:31;:::i;15080:258::-;;;15209:2;15197:9;15188:7;15184:23;15180:32;15177:2;;;15230:6;15222;15215:22;15177:2;-1:-1:-1;;15258:23:1;;;15328:2;15313:18;;;15300:32;;-1:-1:-1;15167:171:1:o;15343:255::-;;;15483:2;15471:9;15462:7;15458:23;15454:32;15451:2;;;15504:6;15496;15489:22;15451:2;-1:-1:-1;;15532:16:1;;15588:2;15573:18;;;15567:25;15532:16;;15567:25;;-1:-1:-1;15441:157:1:o;15603:326::-;;;;15749:2;15737:9;15728:7;15724:23;15720:32;15717:2;;;15770:6;15762;15755:22;15717:2;-1:-1:-1;;15798:23:1;;;15868:2;15853:18;;15840:32;;-1:-1:-1;15919:2:1;15904:18;;;15891:32;;15707:222;-1:-1:-1;15707:222:1:o;15934:214::-;;16055:2;16043:9;16034:7;16030:23;16026:32;16023:2;;;16076:6;16068;16061:22;16023:2;16104:38;16132:9;16104:38;:::i;16153:524::-;;16253:6;16248:3;16241:19;16279:4;16308:2;16303:3;16299:12;16292:19;;16334:5;16357:3;16369:283;16383:6;16380:1;16377:13;16369:283;;;16460:6;16447:20;16480:33;16505:7;16480:33;:::i;:::-;-1:-1:-1;;;;;16538:33:1;16526:46;;16592:12;;;;16627:15;;;;16568:1;16398:9;16369:283;;;-1:-1:-1;16668:3:1;;16231:446;-1:-1:-1;;;;;16231:446:1:o;16682:463::-;;16773:5;16767:12;16800:6;16795:3;16788:19;16826:4;16855:2;16850:3;16846:12;16839:19;;16892:2;16885:5;16881:14;16913:3;16925:195;16939:6;16936:1;16933:13;16925:195;;;17004:13;;-1:-1:-1;;;;;17000:39:1;16988:52;;17060:12;;;;17095:15;;;;17036:1;16954:9;16925:195;;17150:621;;17259:5;17253:12;17286:6;17281:3;17274:19;17312:4;17341:2;17336:3;17332:12;17325:19;;17365:5;17360:3;17353:18;17409:2;17404:3;17394:18;17430:3;17442:304;17456:6;17453:1;17450:13;17442:304;;;17522:13;;-1:-1:-1;;;;;17560:50:1;;17548:63;;17649:3;17645:19;17631:12;;;17624:41;17694:4;17685:14;;;;17734:1;17722:14;;;;17471:9;17442:304;;17776:363;17864:19;;;17776:363;-1:-1:-1;;;;;17895:31:1;;17892:2;;;17941:3;17936;17929:16;17892:2;17984:4;17976:6;17972:17;18034:8;18027:5;18020:4;18015:3;18011:14;17998:45;18066:18;;;;18086:4;18062:29;18100:15;;;-1:-1:-1;18062:29:1;;17854:285;-1:-1:-1;17854:285:1:o;18144:437::-;;18235:5;18229:12;18262:6;18257:3;18250:19;18288:4;18317:2;18312:3;18308:12;18301:19;;18354:2;18347:5;18343:14;18375:3;18387:169;18401:6;18398:1;18395:13;18387:169;;;18462:13;;18450:26;;18496:12;;;;18531:15;;;;18423:1;18416:9;18387:169;;18586:446;;18675:5;18669:12;18702:6;18697:3;18690:19;18728:4;18757:2;18752:3;18748:12;18741:19;;18794:2;18787:5;18783:14;18815:3;18827:180;18841:6;18838:1;18835:13;18827:180;;;18906:13;;18921:4;18902:24;18890:37;;18947:12;;;;18982:15;;;;18863:1;18856:9;18827:180;;19037:240;19121:1;19114:5;19111:12;19101:2;;19166:10;19161:3;19157:20;19154:1;19147:31;19201:4;19198:1;19191:15;19229:4;19226:1;19219:15;19101:2;19253:18;;19091:186::o;19282:255::-;19357:12;;19371:4;19353:23;19341:36;;19430:4;19419:16;;;19413:23;-1:-1:-1;;;;;19409:49:1;19393:14;;;19386:73;19522:4;19511:16;;;19505:23;19498:31;19491:39;19475:14;;19468:63;19331:206::o;19769:402::-;19864:1;19860;19855:3;19851:11;19847:19;19905:2;19897:5;19891:12;19887:21;19882:3;19875:34;19970:2;19962:4;19955:5;19951:16;19945:23;19941:32;19934:4;19929:3;19925:14;19918:56;;20037:4;20030:5;20026:16;20020:23;20013:31;20006:39;19999:4;19994:3;19990:14;19983:63;20092:4;20085:5;20081:16;20075:23;20107:58;20159:4;20154:3;20150:14;20136:12;20107:58;:::i;20176:272::-;20260:5;20254:12;20249:3;20242:25;20316:4;20309:5;20305:16;20299:23;20292:4;20287:3;20283:14;20276:47;20369:4;20362:5;20358:16;20352:23;20384:58;20436:4;20431:3;20427:14;20413:12;19675;;-1:-1:-1;;;;;19671:21:1;;;19659:34;;19746:4;19735:16;;;19729:23;19725:32;19709:14;;19702:56;19596:168;20453:274;;20620:6;20614:13;20636:53;20682:6;20677:3;20670:4;20662:6;20658:17;20636:53;:::i;:::-;20705:16;;;;;20590:137;-1:-1:-1;;20590:137:1:o;21782:643::-;;22132:1;22128;22123:3;22119:11;22115:19;22107:6;22103:32;22092:9;22085:51;22172:6;22167:2;22156:9;22152:18;22145:34;22215:3;22210:2;22199:9;22195:18;22188:31;22242:57;22294:3;22283:9;22279:19;22271:6;22242:57;:::i;:::-;22347:9;22339:6;22335:22;22330:2;22319:9;22315:18;22308:50;22375:44;22412:6;22404;22375:44;:::i;23685:689::-;;24047:1;24043;24038:3;24034:11;24030:19;24022:6;24018:32;24007:9;24000:51;24087:6;24082:2;24071:9;24067:18;24060:34;24130:3;24125:2;24114:9;24110:18;24103:31;24157:74;24226:3;24215:9;24211:19;24203:6;24195;24157:74;:::i;:::-;24279:9;24271:6;24267:22;24262:2;24251:9;24247:18;24240:50;24307:61;24361:6;24353;24345;24307:61;:::i;:::-;24299:69;23990:384;-1:-1:-1;;;;;;;;;23990:384:1:o;24379:761::-;;24769:1;24765;24760:3;24756:11;24752:19;24744:6;24740:32;24729:9;24722:51;24809:6;24804:2;24793:9;24789:18;24782:34;24852:3;24847:2;24836:9;24832:18;24825:31;24879:74;24948:3;24937:9;24933:19;24925:6;24917;24879:74;:::i;:::-;25001:9;24993:6;24989:22;24984:2;24973:9;24969:18;24962:50;25029:61;25083:6;25075;25067;25029:61;:::i;:::-;25021:69;;;25127:6;25121:3;25110:9;25106:19;25099:35;24712:428;;;;;;;;;;:::o;25785:707::-;;26155:1;26151;26146:3;26142:11;26138:19;26130:6;26126:32;26115:9;26108:51;26195:6;26190:2;26179:9;26175:18;26168:34;26238:3;26233:2;26222:9;26218:18;26211:31;26265:57;26317:3;26306:9;26302:19;26294:6;26265:57;:::i;:::-;26370:9;26362:6;26358:22;26353:2;26342:9;26338:18;26331:50;26398:44;26435:6;26427;26398:44;:::i;:::-;26390:52;;;26479:6;26473:3;26462:9;26458:19;26451:35;26098:394;;;;;;;;:::o;26497:917::-;;26978:3;26967:9;26960:22;27005:75;27075:3;27064:9;27060:19;27052:6;27005:75;:::i;:::-;27128:9;27120:6;27116:22;27111:2;27100:9;27096:18;27089:50;27162:42;27197:6;27189;27162:42;:::i;:::-;27148:56;;27252:9;27244:6;27240:22;27235:2;27224:9;27220:18;27213:50;27280:61;27334:6;27326;27318;27280:61;:::i;:::-;27272:69;;;27350:58;27404:2;27393:9;27389:18;27381:6;27350:58;:::i;:::-;26950:464;;;;;;;;:::o;27419:1232::-;;27890:3;27879:9;27872:22;27917:75;27987:3;27976:9;27972:19;27964:6;27917:75;:::i;:::-;28011:2;28061:9;28053:6;28049:22;28044:2;28033:9;28029:18;28022:50;28095:42;28130:6;28122;28095:42;:::i;:::-;28173:22;;;28168:2;28153:18;;28146:50;28245:13;;28267:22;;;28343:15;;;;-1:-1:-1;28305:15:1;;;;28376:4;28389:169;28403:6;28400:1;28397:13;28389:169;;;28464:13;;28452:26;;28533:15;;;;28498:12;;;;28425:1;28418:9;28389:169;;;28393:3;;28575;28567:11;;;;;28587:58;28641:2;28630:9;28626:18;28618:6;28587:58;:::i;:::-;27862:789;;;;;;;:::o;28656:828::-;;29091:3;29121:2;29110:9;29103:21;29141:74;29211:2;29200:9;29196:18;29188:6;29141:74;:::i;:::-;29133:82;;;29263:4;29255:6;29251:17;29246:2;29235:9;29231:18;29224:45;29317:4;29309:6;29305:17;29300:2;29289:9;29285:18;29278:45;29359:6;29354:2;29343:9;29339:18;29332:34;29403:6;29397:3;29386:9;29382:19;29375:35;29419:59;29473:3;29462:9;29458:19;29450:6;29419:59;:::i;29489:647::-;;29870:3;29859:9;29852:22;29891:75;29961:3;29950:9;29946:19;29938:6;29891:75;:::i;:::-;29883:83;;30014:4;30006:6;30002:17;29997:2;29986:9;29982:18;29975:45;30056:6;30051:2;30040:9;30036:18;30029:34;30072:58;30126:2;30115:9;30111:18;30103:6;30072:58;:::i;30982:488::-;;31301:3;31290:9;31283:22;31322:75;31392:3;31381:9;31377:19;31369:6;31322:75;:::i;:::-;31314:83;;31406:58;31460:2;31449:9;31445:18;31437:6;31406:58;:::i;32930:1341::-;33291:2;33343:21;;;33413:13;;33316:18;;;33435:22;;;32930:1341;;33291:2;33510:4;;33488:2;33473:18;;;33537:15;;;32930:1341;33583:197;33597:6;33594:1;33591:13;33583:197;;;33646:52;33694:3;33685:6;33679:13;33646:52;:::i;:::-;33727:4;33718:14;;;;;33755:15;;;;33619:1;33612:9;33583:197;;;-1:-1:-1;;;33816:19:1;;;33796:18;;;33789:47;33886:13;;33908:21;;;33984:15;;;;33947:12;;;34019:4;34032:211;34048:8;34043:3;34040:17;34032:211;;;34103:52;34149:5;34138:8;34132:15;19675:12;;-1:-1:-1;;;;;19671:21:1;;;19659:34;;19746:4;19735:16;;;19729:23;19725:32;19709:14;;19702:56;19596:168;34103:52;34216:17;;;;34177:14;;;;34076:1;34067:11;34032:211;;;-1:-1:-1;34260:5:1;;33271:1000;-1:-1:-1;;;;;;;;33271:1000:1:o;34276:934::-;34601:25;;;34589:2;34645;34663:18;;;34656:30;;;34574:18;;;34721:22;;;34276:934;;34801:6;;34774:3;34759:19;;34276:934;34838:277;34852:6;34849:1;34846:13;34838:277;;;34927:6;34914:20;34947:31;34972:5;34947:31;:::i;:::-;-1:-1:-1;;;;;35003:31:1;34991:44;;35090:15;;;;35055:12;;;;35031:1;34867:9;34838:277;;;-1:-1:-1;;;;;;35171:32:1;;;;35166:2;35151:18;;;;35144:60;;;;-1:-1:-1;35132:3:1;;34550:660;-1:-1:-1;;;;;34550:660:1:o;35215:1240::-;;35521:2;35561;35550:9;35546:18;35591:2;35580:9;35573:21;35614:6;35649;35643:13;35680:6;35672;35665:22;35706:2;35696:12;;35739:2;35728:9;35724:18;35717:25;;35764:6;35758:4;35751:20;35790:4;35833:2;35827:4;35817:19;35854:4;35867:519;35881:6;35878:1;35875:13;35867:519;;;35988:13;;-1:-1:-1;;;;;35984:22:1;;;35972:35;;35957:1;36043:14;;36037:21;36092:18;;;36078:12;;;36071:40;36134:4;35948:3;36190:19;;;36186:28;;36179:36;36172:44;36158:12;;;36151:66;36134:4;36230:72;36289:12;;;36267:3;36263:19;;;36259:28;;36230:72;:::i;:::-;-1:-1:-1;;36331:4:1;36322:14;;;;;36371:4;36359:17;;;;;35903:1;35896:9;35867:519;;;-1:-1:-1;;36422:18:1;;;;36415:34;;;;-1:-1:-1;36403:3:1;;35501:954;-1:-1:-1;;;;35501:954:1:o;36460:261::-;;36639:2;36628:9;36621:21;36659:56;36711:2;36700:9;36696:18;36688:6;36659:56;:::i;37323:383::-;;37472:2;37461:9;37454:21;37504:6;37498:13;37547:6;37542:2;37531:9;37527:18;37520:34;37563:66;37622:6;37617:2;37606:9;37602:18;37597:2;37589:6;37585:15;37563:66;:::i;:::-;37690:2;37669:15;-1:-1:-1;;37665:29:1;37650:45;;;;37697:2;37646:54;;37444:262;-1:-1:-1;;37444:262:1:o;39551:336::-;39753:2;39735:21;;;39792:2;39772:18;;;39765:30;-1:-1:-1;;;39826:2:1;39811:18;;39804:42;39878:2;39863:18;;39725:162::o;45855:341::-;46057:2;46039:21;;;46096:2;46076:18;;;46069:30;-1:-1:-1;;;46130:2:1;46115:18;;46108:47;46187:2;46172:18;;46029:167::o;48806:329::-;49008:2;48990:21;;;49047:1;49027:18;;;49020:29;-1:-1:-1;;;49080:2:1;49065:18;;49058:36;49126:2;49111:18;;48980:155::o;49551:355::-;49753:2;49735:21;;;49792:2;49772:18;;;49765:30;49831:33;49826:2;49811:18;;49804:61;49897:2;49882:18;;49725:181::o;51879:410::-;52153:3;52138:19;;52166:51;52142:9;52199:6;52166:51;:::i;:::-;19675:12;;-1:-1:-1;;;;;19671:21:1;;;52278:3;52263:19;;19659:34;19746:4;19735:16;;19729:23;19725:32;19709:14;;;19702:56;52226:57;19596:168;52294:432;;52486:3;52475:9;52471:19;52463:27;;52523:6;52517:13;52506:9;52499:32;52587:4;52579:6;52575:17;52569:24;52562:4;52551:9;52547:20;52540:54;52641:4;52633:6;52629:17;52623:24;52656:64;52714:4;52703:9;52699:20;52685:12;19675;;-1:-1:-1;;;;;19671:21:1;;;19659:34;;19746:4;19735:16;;;19729:23;19725:32;19709:14;;19702:56;19596:168;52731:838;;53160:3;53190:6;53179:9;53172:25;53206:58;53260:2;53249:9;53245:18;53237:6;53206:58;:::i;:::-;53301:2;53295:3;53284:9;53280:19;53273:31;53327:54;53377:2;53366:9;53362:18;53354:6;53327:54;:::i;:::-;53313:68;;53430:9;53422:6;53418:22;53412:3;53401:9;53397:19;53390:51;53458:61;53512:6;53504;53496;53458:61;:::i;:::-;53450:69;;;53556:6;53550:3;53539:9;53535:19;53528:35;53140:429;;;;;;;;;:::o;53574:936::-;;54031:3;54061:6;54050:9;54043:25;54077:58;54131:2;54120:9;54116:18;54108:6;54077:58;:::i;:::-;54172:2;54166:3;54155:9;54151:19;54144:31;54198:54;54248:2;54237:9;54233:18;54225:6;54198:54;:::i;:::-;54184:68;;54301:9;54293:6;54289:22;54283:3;54272:9;54268:19;54261:51;54329:61;54383:6;54375;54367;54329:61;:::i;:::-;54421:3;54406:19;;54399:35;;;;-1:-1:-1;;;;;;;54471:32:1;;;;54465:3;54450:19;;;54443:61;54321:69;54011:499;-1:-1:-1;;;;;54011:499:1:o;54515:871::-;55008:25;;;54995:3;54980:19;;55042:58;55096:2;55081:18;;55073:6;55042:58;:::i;:::-;55109:52;55156:3;55145:9;55141:19;55133:6;55109:52;:::i;:::-;55170;55217:3;55206:9;55202:19;55194:6;55170:52;:::i;:::-;55253:3;55238:19;;55231:35;;;;55297:3;55282:19;;55275:35;;;;-1:-1:-1;;;;;55347:32:1;55341:3;55326:19;;;55319:61;54962:424;;-1:-1:-1;;;;54962:424:1:o;55391:640::-;55784:25;;;55771:3;55756:19;;55818:58;55872:2;55857:18;;55849:6;55818:58;:::i;:::-;55885:52;55932:3;55921:9;55917:19;55909:6;55885:52;:::i;:::-;55968:3;55953:19;;55946:35;;;;56012:3;55997:19;55990:35;55738:293;;-1:-1:-1;;;55738:293:1:o;56036:738::-;56457:25;;;56444:3;56429:19;;56491:58;56545:2;56530:18;;56522:6;56491:58;:::i;:::-;56558:52;56605:3;56594:9;56590:19;56582:6;56558:52;:::i;:::-;56641:3;56626:19;;56619:35;;;;56685:3;56670:19;;56663:35;;;;-1:-1:-1;;;;;56735:32:1;56729:3;56714:19;;;56707:61;56411:363;;-1:-1:-1;;;56411:363:1:o;56779:737::-;;57162:3;57192:6;57181:9;57174:25;57208:58;57262:2;57251:9;57247:18;57239:6;57208:58;:::i;:::-;57303:6;57297:3;57286:9;57282:19;57275:35;57347:2;57341:3;57330:9;57326:19;57319:31;57367:73;57436:2;57425:9;57421:18;57413:6;57405;57367:73;:::i;:::-;57359:81;;;57506:1;57502;57497:3;57493:11;57489:19;57481:6;57477:32;57471:3;57460:9;57456:19;57449:61;57142:374;;;;;;;;;:::o;58604:995::-;;59012:3;59001:9;58997:19;58989:27;;59043:6;59032:9;59025:25;59086:6;59081:2;59070:9;59066:18;59059:34;59129:6;59124:2;59113:9;59109:18;59102:34;59172:6;59167:2;59156:9;59152:18;59145:34;59216:6;59210:3;59199:9;59195:19;59188:35;-1:-1:-1;;;;;59316:2:1;59307:6;59301:13;59297:22;59291:3;59280:9;59276:19;59269:51;59385:2;59379;59371:6;59367:15;59361:22;59357:31;59351:3;59340:9;59336:19;59329:60;59454:2;59448;59440:6;59436:15;59430:22;59426:31;59420:3;59409:9;59405:19;59398:60;59523:2;59517;59509:6;59505:15;59499:22;59495:31;59489:3;59478:9;59474:19;59467:60;;59536:57;59588:3;59577:9;59573:19;59565:6;19675:12;;-1:-1:-1;;;;;19671:21:1;;;19659:34;;19746:4;19735:16;;;19729:23;19725:32;19709:14;;19702:56;19596:168;59536:57;58979:620;;;;;;;;;;:::o;59793:275::-;59864:2;59858:9;59929:2;59910:13;;-1:-1:-1;;59906:27:1;59894:40;;-1:-1:-1;;;;;59949:34:1;;59985:22;;;59946:62;59943:2;;;60011:18;;:::i;:::-;60047:2;60040:22;59838:230;;-1:-1:-1;59838:230:1:o;60073:186::-;;-1:-1:-1;;;;;60158:6:1;60155:30;60152:2;;;60188:18;;:::i;:::-;-1:-1:-1;60248:4:1;60229:17;;;60225:28;;60142:117::o;60264:128::-;;60335:1;60331:6;60328:1;60325:13;60322:2;;;60341:18;;:::i;:::-;-1:-1:-1;60377:9:1;;60312:80::o;60397:217::-;;60463:1;60453:2;;-1:-1:-1;;;60488:31:1;;60542:4;60539:1;60532:15;60570:4;60495:1;60560:15;60453:2;-1:-1:-1;60599:9:1;;60443:171::o;60619:453::-;60715:6;60738:5;60752:314;60801:1;60838:2;60828:8;60825:16;60815:2;;60845:5;;;60815:2;60886:4;60881:3;60877:14;60871:4;60868:24;60865:2;;;60895:18;;:::i;:::-;60945:2;60935:8;60931:17;60928:2;;;60960:16;;;;60928:2;61039:17;;;;;60999:15;;60752:314;;;60696:376;;;;;;;:::o;61077:148::-;;61164:55;-1:-1:-1;;61205:4:1;61191:19;;61185:4;61230:922;61314:8;61304:2;;-1:-1:-1;61355:1:1;61369:5;;61304:2;61403:4;61393:2;;-1:-1:-1;61440:1:1;61454:5;;61393:2;61485:4;61503:1;61498:59;;;;61571:1;61566:183;;;;61478:271;;61498:59;61528:1;61519:10;;61542:5;;;61566:183;61603:3;61593:8;61590:17;61587:2;;;61610:18;;:::i;:::-;61666:1;61656:8;61652:16;61643:25;;61694:3;61687:5;61684:14;61681:2;;;61701:18;;:::i;:::-;61734:5;;;61478:271;;61833:2;61823:8;61820:16;61814:3;61808:4;61805:13;61801:36;61795:2;61785:8;61782:16;61777:2;61771:4;61768:12;61764:35;61761:77;61758:2;;;-1:-1:-1;61870:19:1;;;61905:14;;;61902:2;;;61922:18;;:::i;:::-;61955:5;;61758:2;62002:42;62040:3;62030:8;62024:4;62021:1;62002:42;:::i;:::-;62077:6;62072:3;62068:16;62059:7;62056:29;62053:2;;;62088:18;;:::i;:::-;62126:20;;61294:858;-1:-1:-1;;;;61294:858:1:o;62157:168::-;;62263:1;62259;62255:6;62251:14;62248:1;62245:21;62240:1;62233:9;62226:17;62222:45;62219:2;;;62270:18;;:::i;:::-;-1:-1:-1;62310:9:1;;62209:116::o;62330:125::-;;62398:1;62395;62392:8;62389:2;;;62403:18;;:::i;:::-;-1:-1:-1;62440:9:1;;62379:76::o;62460:229::-;;-1:-1:-1;;;;;62596:10:1;;;;62566;;62618:12;;;62615:2;;;62633:18;;:::i;:::-;62670:13;;62508:181;-1:-1:-1;;;62508:181:1:o;62694:195::-;;62769:4;62766:1;62762:12;62801:4;62798:1;62794:12;62826:3;62821;62818:12;62815:2;;;62833:18;;:::i;:::-;62870:13;;;62741:148;-1:-1:-1;;;62741:148:1:o;62894:258::-;62966:1;62976:113;62990:6;62987:1;62984:13;62976:113;;;63066:11;;;63060:18;63047:11;;;63040:39;63012:2;63005:10;62976:113;;;63107:6;63104:1;63101:13;63098:2;;;-1:-1:-1;;63142:1:1;63124:16;;63117:27;62947:205::o;63157:380::-;63242:1;63232:12;;63289:1;63279:12;;;63300:2;;63354:4;63346:6;63342:17;63332:27;;63300:2;63407;63399:6;63396:14;63376:18;63373:38;63370:2;;;63453:10;63448:3;63444:20;63441:1;63434:31;63488:4;63485:1;63478:15;63516:4;63513:1;63506:15;63542:135;;-1:-1:-1;;63602:17:1;;63599:2;;;63622:18;;:::i;:::-;-1:-1:-1;63669:1:1;63658:13;;63589:88::o;63682:127::-;63743:10;63738:3;63734:20;63731:1;63724:31;63774:4;63771:1;63764:15;63798:4;63795:1;63788:15;63814:127;63875:10;63870:3;63866:20;63863:1;63856:31;63906:4;63903:1;63896:15;63930:4;63927:1;63920:15;63946:131;-1:-1:-1;;;;;64021:31:1;;64011:42;;64001:2;;64067:1;64064;64057:12;64082:118;64168:5;64161:13;64154:21;64147:5;64144:32;64134:2;;64190:1;64187;64180:12;64205:146;-1:-1:-1;;;;;64284:5:1;64280:46;64273:5;64270:57;64260:2;;64341:1;64338;64331:12

Swarm Source

ipfs://850dd1f167ac97afe719deef338bad5974094486512a857d3b35961d8341c7f6

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

OVERVIEW

Logic contract for mStable Alchemix USD (alUSD) Feeder Pool.

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

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