ETH Price: $2,391.76 (-0.28%)

Contract

0x55C6Fe0c38AF2a59ed945bB84D6898EbCE63743c
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
0x60a06040169390852023-03-30 9:10:35525 days ago1680167435IN
 Create: MassetBtcV2
0 ETH0.1613233733

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
MassetBtcV2

Compiler Version
v0.8.0+commit.c7dfd78e

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, GNU AGPLv3 license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2023-03-30
*/

/**
 *Submitted for verification at Etherscan.io on 2021-02-12
 */

pragma solidity 0.8.0;
pragma abicoder v2;

interface MassetStructs {
    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;
    }

    // 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 InvariantConfig {
        uint256 a;
        WeightLimits limits;
    }

    struct WeightLimits {
        uint128 min;
        uint128 max;
    }

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

abstract contract IInvariantValidator is MassetStructs {
    // Mint
    function computeMint(
        BassetData[] calldata _bAssets,
        uint8 _i,
        uint256 _rawInput,
        InvariantConfig memory _config
    ) external view virtual returns (uint256);

    function computeMintMulti(
        BassetData[] calldata _bAssets,
        uint8[] calldata _indices,
        uint256[] calldata _rawInputs,
        InvariantConfig memory _config
    ) external view virtual returns (uint256);

    // Swap
    function computeSwap(
        BassetData[] calldata _bAssets,
        uint8 _i,
        uint8 _o,
        uint256 _rawInput,
        uint256 _feeRate,
        InvariantConfig memory _config
    ) external view virtual returns (uint256, uint256);

    // Redeem
    function computeRedeem(
        BassetData[] calldata _bAssets,
        uint8 _i,
        uint256 _mAssetQuantity,
        InvariantConfig memory _config
    ) external view virtual returns (uint256);

    function computeRedeemExact(
        BassetData[] calldata _bAssets,
        uint8[] calldata _indices,
        uint256[] calldata _rawOutputs,
        InvariantConfig memory _config
    ) external view virtual returns (uint256);
}

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

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

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

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

        _;

        if (isTopLevelCall) {
            initializing = false;
        }
    }

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

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

// SPDX-License-Identifier: AGPL-3.0-or-later
/*
 * @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 override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view 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 override returns (bool) {
        _transfer(_msgSender(), recipient, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view 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 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 override returns (bool) {
        _transfer(sender, recipient, amount);
        _approve(sender, _msgSender(), _allowances[sender][_msgSender()] - 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 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 returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender] - 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 {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");

        _balances[sender] -= 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 {
        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 {
        require(account != address(0), "ERC20: burn from the zero address");

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

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.
     *
     * This is 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 {
        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);
    }

    /**
     * @dev Destroys `amount` tokens from `account`.`amount` is then deducted
     * from the caller's allowance.
     *
     * See {_burn} and {_approve}.
     */
    function _burnFrom(address account, uint256 amount) internal {
        _burn(account, amount);
        _approve(account, _msgSender(), _allowances[account][_msgSender()] - 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;
}

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 Modifier to allow function calls only from the ProxyAdmin.
     */
    modifier onlyProxyAdmin() {
        require(msg.sender == _proxyAdmin(), "Only ProxyAdmin can execute");
        _;
    }

    /**
     * @dev Modifier to allow function calls only from the Manager.
     */
    modifier onlyManager() {
        require(msg.sender == _manager(), "Only manager 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 Staking Module address from the Nexus
     * @return Address of the Staking Module contract
     */
    function _staking() internal view returns (address) {
        return nexus.getModule(KEY_STAKING);
    }

    /**
     * @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);
    }

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

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

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

    /**
     * @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);
    }
}

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

abstract contract IMasset is MassetStructs {
    // 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);

    // 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 upgradeForgeValidator(address _newForgeValidator) 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;
}

abstract contract Deprecated_BasketManager is MassetStructs {}

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

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 9e38 / 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);

    /**
     * @dev Returns the pToken
     */
    function bAssetToPToken(address _bAsset) external returns (address pToken);
}

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

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

/**
 * @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.3._
     */
    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.3._
     */
    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);
            }
        }
    }
}

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 {
        uint256 newAllowance = token.allowance(address(this), spender) - 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 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 MassetManagerBtcV2 {
    using SafeERC20 for IERC20;
    using StableMath for uint256;

    event BassetsMigrated(address[] bAssets, address newIntegrator);
    event TransferFeeEnabled(address indexed bAsset, bool enabled);
    event BassetAdded(address indexed bAsset, address integrator);
    event BassetStatusChanged(address indexed bAsset, MassetStructs.BassetStatus status);
    event BasketStatusChanged();
    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;

    /**
     * @notice Adds a bAsset to the given personal, data and mapping, provided it is valid
     * @param _bAssetPersonal   Basset data storage array
     * @param _bAssetData       Basset data storage array
     * @param _bAssetIndexes    Mapping of bAsset address to their index
     * @param _maxBassets       Max size of the basket
     * @param _bAsset           Address of the ERC20 token to add to the Basket
     * @param _integration      Address of the Platform Integration
     * @param _mm               Base 1e8 var to determine measurement ratio
     * @param _hasTxFee         Are transfer fees charged on this bAsset (e.g. USDT)
     */
    function addBasset(
        MassetStructs.BassetPersonal[] storage _bAssetPersonal,
        MassetStructs.BassetData[] storage _bAssetData,
        mapping(address => uint8) storage _bAssetIndexes,
        uint8 _maxBassets,
        address _bAsset,
        address _integration,
        uint256 _mm,
        bool _hasTxFee
    ) external {
        require(_bAsset != address(0), "bAsset address must be valid");
        uint8 bAssetCount = uint8(_bAssetPersonal.length);
        require(bAssetCount < _maxBassets, "Max bAssets in Basket");

        uint8 idx = _bAssetIndexes[_bAsset];
        require(
            bAssetCount == 0 || _bAssetPersonal[idx].addr != _bAsset,
            "bAsset already exists in Basket"
        );

        // Should fail if bAsset is not added to integration
        // Programmatic enforcement of bAsset validity should service through decentralised feed
        if (_integration != address(0)) {
            IPlatformIntegration(_integration).checkBalance(_bAsset);
        }

        uint256 bAssetDecimals = IBasicToken(_bAsset).decimals();
        require(
            bAssetDecimals >= 4 && bAssetDecimals <= 18,
            "Token must have sufficient decimal places"
        );

        uint256 delta = uint256(18) - bAssetDecimals;
        uint256 ratio = _mm * (10 ** delta);

        _bAssetIndexes[_bAsset] = bAssetCount;

        _bAssetPersonal.push(
            MassetStructs.BassetPersonal({
                addr: _bAsset,
                integrator: _integration,
                hasTxFee: _hasTxFee,
                status: MassetStructs.BassetStatus.Normal
            })
        );
        _bAssetData.push(
            MassetStructs.BassetData({ ratio: SafeCast.toUint128(ratio), vaultBalance: 0 })
        );

        emit BassetAdded(_bAsset, _integration);
    }

    /**
     * @dev Collects the interest generated from the Basket, minting a relative
     *      amount of mAsset and sending it over to the SavingsManager.
     * @param _bAssetPersonal   Basset personal storage array
     * @param _bAssetData       Basset data storage array
     * @param _forgeValidator   Link to the current InvariantValidator
     * @return mintAmount       Lending market interest collected
     * @return rawGains         Raw increases in vault Balance
     */
    function collectPlatformInterest(
        MassetStructs.BassetPersonal[] memory _bAssetPersonal,
        MassetStructs.BassetData[] storage _bAssetData,
        IInvariantValidator _forgeValidator,
        MassetStructs.InvariantConfig memory _config
    ) external returns (uint256 mintAmount, uint256[] memory rawGains) {
        // Get basket details
        MassetStructs.BassetData[] memory bAssetData_ = _bAssetData;
        uint256 count = bAssetData_.length;
        uint8[] memory indices = 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++) {
            indices[i] = uint8(i);
            MassetStructs.BassetPersonal memory bPersonal = _bAssetPersonal[i];
            MassetStructs.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 == MassetStructs.BassetStatus.Normal
            ) {
                _bAssetData[i].vaultBalance = SafeCast.toUint128(balance);
                uint256 interestDelta = balance - oldVaultBalance;
                rawGains[i] = interestDelta;
            } else {
                rawGains[i] = 0;
            }
        }
        mintAmount = _forgeValidator.computeMintMulti(bAssetData_, indices, rawGains, _config);
    }

    /**
     * @dev Update transfer fee flag for a given bAsset, should it change its fee practice
     * @param _bAssetPersonal   Basset data storage array
     * @param _bAssetIndexes    Mapping of bAsset address to their index
     * @param _bAsset   bAsset address
     * @param _flag         Charge transfer fee when its set to 'true', otherwise 'false'
     */
    function setTransferFeesFlag(
        MassetStructs.BassetPersonal[] storage _bAssetPersonal,
        mapping(address => uint8) storage _bAssetIndexes,
        address _bAsset,
        bool _flag
    ) external {
        uint256 index = _getAssetIndex(_bAssetPersonal, _bAssetIndexes, _bAsset);
        _bAssetPersonal[index].hasTxFee = _flag;

        if (_flag) {
            // if token has tx fees, it can no longer operate with a cache
            address integration = _bAssetPersonal[index].integrator;
            if (integration != address(0)) {
                uint256 bal = IERC20(_bAsset).balanceOf(integration);
                if (bal > 0) {
                    IPlatformIntegration(integration).deposit(_bAsset, bal, true);
                }
            }
        }

        emit TransferFeeEnabled(_bAsset, _flag);
    }

    /**
     * @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 _bAssetIndexes    Mapping of bAsset address to their index
     * @param _bAssets          Array of basket assets to migrate
     * @param _newIntegration   Address of the new platform integration
     */
    function migrateBassets(
        MassetStructs.BassetPersonal[] storage _bAssetPersonal,
        mapping(address => uint8) storage _bAssetIndexes,
        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, _bAssetIndexes, 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
            if (_newIntegration != address(0)) {
                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"
                );
            } else {
                uint256 newCache = IERC20(bAsset).balanceOf(address(this));
                require(newCache == sum, "Must cache full amount");
            }
        }

        emit BassetsMigrated(_bAssets, _newIntegration);
    }

    /**
     * @dev Executes the Auto Redistribution event by isolating the bAsset from the Basket
     * @param _basket          Struct containing core basket info
     * @param _bAssetPersonal  Basset data storage array
     * @param _bAsset          Address of the ERC20 token to isolate
     * @param _belowPeg        Bool to describe whether the bAsset deviated below peg (t)
     *                         or above (f)
     */
    function handlePegLoss(
        MassetStructs.BasketState storage _basket,
        MassetStructs.BassetPersonal[] storage _bAssetPersonal,
        mapping(address => uint8) storage _bAssetIndexes,
        address _bAsset,
        bool _belowPeg
    ) external {
        require(!_basket.failed, "Basket must be alive");

        uint256 i = _getAssetIndex(_bAssetPersonal, _bAssetIndexes, _bAsset);

        MassetStructs.BassetStatus newStatus = _belowPeg
            ? MassetStructs.BassetStatus.BrokenBelowPeg
            : MassetStructs.BassetStatus.BrokenAbovePeg;
        _bAssetPersonal[i].status = newStatus;

        _basket.undergoingRecol = true;

        emit BassetStatusChanged(_bAsset, newStatus);
    }

    /**
     * @dev Negates the isolation of a given bAsset
     * @param _basket          Struct containing core basket info
     * @param _bAssetPersonal  Basset data storage array
     * @param _bAssetIndexes    Mapping of bAsset address to their index
     * @param _bAsset Address of the bAsset
     */
    function negateIsolation(
        MassetStructs.BasketState storage _basket,
        MassetStructs.BassetPersonal[] storage _bAssetPersonal,
        mapping(address => uint8) storage _bAssetIndexes,
        address _bAsset
    ) external {
        uint256 i = _getAssetIndex(_bAssetPersonal, _bAssetIndexes, _bAsset);

        _bAssetPersonal[i].status = MassetStructs.BassetStatus.Normal;

        bool undergoingRecol = false;
        for (uint256 j = 0; j < _bAssetPersonal.length; j++) {
            if (_bAssetPersonal[j].status != MassetStructs.BassetStatus.Normal) {
                undergoingRecol = true;
                break;
            }
        }
        _basket.undergoingRecol = undergoingRecol;

        emit BassetStatusChanged(_bAsset, MassetStructs.BassetStatus.Normal);
    }

    /**
     * @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(
        MassetStructs.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(MassetStructs.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);
    }

    /**
     * @dev Gets a bAsset index from storage
     * @param _asset      Address of the asset
     * @return idx        Index of the asset
     */
    function _getAssetIndex(
        MassetStructs.BassetPersonal[] storage _bAssetPersonal,
        mapping(address => uint8) storage _bAssetIndexes,
        address _asset
    ) internal view returns (uint8 idx) {
        idx = _bAssetIndexes[_asset];
        require(_bAssetPersonal[idx].addr == _asset, "Invalid asset input");
    }

    /***************************************
                    FORGING
    ****************************************/

    /**
     * @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(
        MassetStructs.BassetPersonal memory _bAsset,
        uint256 _bAssetRatio,
        uint256 _quantity,
        uint256 _maxCache
    ) external 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,
        MassetStructs.BassetPersonal memory _personal,
        MassetStructs.BassetData memory _data,
        address _recipient,
        uint256 _maxCache
    ) external {
        if (_quantity == 0) return;

        // 1.0 If there is no integrator, send from here
        if (_personal.integrator == address(0)) {
            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
                );
            }
        }
    }
}

// External
// Internal
// Libs
/**
 * @title   Masset
 * @author  mStable
 * @notice  An incentivised constant sum market maker with hard limits at max region. This supports
 *          low slippage swaps and applies penalties towards min and max regions. AMM produces a
 *          stablecoin (mAsset) and redirects lending market interest and swap fees to the savings
 *          contract, producing a second yield bearing asset.
 * @dev     VERSION: 3.0
 *          DATE:    2021-01-22
 */
contract MassetBtcV2 is
    IMasset,
    Initializable,
    InitializableToken,
    ImmutableModule,
    InitializableReentrancyGuard
{
    using StableMath for uint256;

    // Forging Events
    event Minted(
        address indexed minter,
        address recipient,
        uint256 mAssetQuantity,
        address input,
        uint256 inputQuantity
    );
    event MintedMulti(
        address indexed minter,
        address recipient,
        uint256 mAssetQuantity,
        address[] inputs,
        uint256[] inputQuantities
    );
    event Swapped(
        address indexed swapper,
        address input,
        address output,
        uint256 outputAmount,
        uint256 scaledFee,
        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);
    event WeightLimitsChanged(uint128 min, uint128 max);
    event ForgeValidatorChanged(address forgeValidator);

    // Release 1.0 VARS
    IInvariantValidator public forgeValidator;
    bool private forgeValidatorLocked;
    // Deprecated - maintain for storage layout in mUSD
    Deprecated_BasketManager private deprecated_basketManager;

    // Basic redemption fee information
    uint256 public swapFee;
    uint256 private MAX_FEE;

    // Release 1.1 VARS
    uint256 public redemptionFee;

    // Release 2.0 VARS
    uint256 public cacheSize;
    uint256 public surplus;

    // Release 3.0 VARS
    // Struct holding Basket details
    BassetPersonal[] public bAssetPersonal;
    BassetData[] public bAssetData;
    mapping(address => uint8) public override bAssetIndexes;
    uint8 public maxBassets;
    BasketState public basket;
    // Amplification Data
    uint256 private constant A_PRECISION = 100;
    AmpData public ampData;
    WeightLimits public weightLimits;

    /**
     * @dev Constructor to set immutable bytecode
     * @param _nexus   Nexus address
     */
    constructor(address _nexus) ImmutableModule(_nexus) {}

    // /**
    //  * @dev Initialization function for upgradable proxy contract.
    //  *      This function should be called via Proxy just after contract deployment.
    //  *      To avoid variable shadowing appended `Arg` after arguments name.
    //  * @param _nameArg          Name of the mAsset
    //  * @param _symbolArg        Symbol of the mAsset
    //  * @param _forgeValidator   Address of the AMM implementation
    //  * @param _bAssets          Array of Basset data
    //  */
    // function initialize(
    //     string calldata _nameArg,
    //     string calldata _symbolArg,
    //     address _forgeValidator,
    //     BassetPersonal[] calldata _bAssets,
    //     InvariantConfig memory _config
    // ) public initializer {
    //     InitializableToken._initialize(_nameArg, _symbolArg);

    //     _initializeReentrancyGuard();

    //     forgeValidator = IInvariantValidator(_forgeValidator);

    //     maxBassets = 10;

    //     uint256 len = _bAssets.length;
    //     require(len > 0, "No bAssets");
    //     for (uint256 i = 0; i < len; i++) {
    //         Manager.addBasset(
    //             bAssetPersonal,
    //             bAssetData,
    //             bAssetIndexes,
    //             maxBassets,
    //             _bAssets[i].addr,
    //             _bAssets[i].integrator,
    //             1e8,
    //             _bAssets[i].hasTxFee
    //         );
    //     }

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

    //     MAX_FEE = 2e16;
    //     swapFee = 6e14;
    //     redemptionFee = 3e14;
    //     cacheSize = 1e17;
    // }

    /**
     * @dev Verifies that the caller is the Savings Manager contract
     */
    modifier onlySavingsManager() {
        _isSavingsManager();
        _;
    }

    // Internal fn for modifier to reduce deployment size
    function _isSavingsManager() internal view {
        require(_savingsManager() == msg.sender, "Must be savings manager");
    }

    /**
     * @dev Requires the overall basket composition to be healthy
     */
    modifier whenHealthy() {
        _isHealthy();
        _;
    }

    // Internal fn for modifier to reduce deployment size
    function _isHealthy() internal view {
        BasketState memory basket_ = basket;
        require(!basket_.undergoingRecol && !basket_.failed, "Unhealthy");
    }

    /**
     * @dev Requires the basket not to be undergoing recollateralisation
     */
    modifier whenNoRecol() {
        _noRecol();
        _;
    }

    // Internal fn for modifier to reduce deployment size
    function _noRecol() internal view {
        BasketState memory basket_ = basket;
        require(!basket_.undergoingRecol, "In recol");
    }

    /***************************************
                MINTING (PUBLIC)
    ****************************************/

    /**
     * @dev Mint a single bAsset, at a 1:1 ratio with the bAsset. This contract
     *      must have approval to spend the senders bAsset
     * @param _input             Address of the bAsset to deposit for the minted mAsset.
     * @param _inputQuantity     Quantity in bAsset units
     * @param _minOutputQuantity Minimum mAsset quanity to be minted. This protects against slippage.
     * @param _recipient         Receipient of the newly minted mAsset tokens
     * @return mintOutput        Quantity of newly minted mAssets for the deposited bAsset.
     */
    function mint(
        address _input,
        uint256 _inputQuantity,
        uint256 _minOutputQuantity,
        address _recipient
    ) external override nonReentrant whenHealthy returns (uint256 mintOutput) {
        mintOutput = _mintTo(_input, _inputQuantity, _minOutputQuantity, _recipient);
    }

    /**
     * @dev Mint with multiple bAssets, at a 1:1 ratio to mAsset. This contract
     *      must have approval to spend the senders bAssets
     * @param _inputs            Non-duplicate address array of bASset addresses to deposit for the minted mAsset tokens.
     * @param _inputQuantities   Quantity of each bAsset to deposit for the minted mAsset.
     *                           Order of array should mirror the above bAsset addresses.
     * @param _minOutputQuantity Minimum mAsset quanity to be minted. This protects against slippage.
     * @param _recipient         Address to receive the newly minted mAsset tokens
     * @return mintOutput    Quantity of newly minted mAssets for the deposited bAssets.
     */
    function mintMulti(
        address[] calldata _inputs,
        uint256[] calldata _inputQuantities,
        uint256 _minOutputQuantity,
        address _recipient
    ) external override nonReentrant whenHealthy returns (uint256 mintOutput) {
        mintOutput = _mintMulti(_inputs, _inputQuantities, _minOutputQuantity, _recipient);
    }

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

        (uint8 idx, ) = _getAsset(_input);

        mintOutput = forgeValidator.computeMint(bAssetData, idx, _inputQuantity, _getConfig());
    }

    /**
     * @dev 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 mAsset.
     * @return mintOutput        Estimated mint output in mAsset 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, ) = _getBassets(_inputs);
        return forgeValidator.computeMintMulti(bAssetData, indexes, _inputQuantities, _getConfig());
    }

    /***************************************
              MINTING (INTERNAL)
    ****************************************/

    /** @dev Mint Single */
    function _mintTo(
        address _input,
        uint256 _inputQuantity,
        uint256 _minMassetQuantity,
        address _recipient
    ) internal returns (uint256 mAssetMinted) {
        require(_recipient != address(0), "Invalid recipient");
        require(_inputQuantity > 0, "Qty==0");
        BassetData[] memory allBassets = bAssetData;
        (uint8 bAssetIndex, BassetPersonal memory personal) = _getAsset(_input);
        Cache memory cache = _getCacheDetails();
        // Transfer collateral to the platform integration address and call deposit
        uint256 quantityDeposited = MassetManagerBtcV2.depositTokens(
            personal,
            allBassets[bAssetIndex].ratio,
            _inputQuantity,
            cache.maxCache
        );
        // Validation should be after token transfer, as bAssetQty is unknown before
        mAssetMinted = forgeValidator.computeMint(
            allBassets,
            bAssetIndex,
            quantityDeposited,
            _getConfig()
        );
        require(mAssetMinted >= _minMassetQuantity, "Mint quantity < min qty");
        // Log the Vault increase - can only be done when basket is healthy
        bAssetData[bAssetIndex].vaultBalance =
            allBassets[bAssetIndex].vaultBalance +
            SafeCast.toUint128(quantityDeposited);
        // Mint the Masset
        _mint(_recipient, mAssetMinted);
        emit Minted(msg.sender, _recipient, mAssetMinted, _input, quantityDeposited);
    }

    /** @dev Mint Multi */
    function _mintMulti(
        address[] memory _inputs,
        uint256[] memory _inputQuantities,
        uint256 _minMassetQuantity,
        address _recipient
    ) internal returns (uint256 mAssetMinted) {
        require(_recipient != address(0), "Invalid recipient");
        uint256 len = _inputQuantities.length;
        require(len > 0 && len == _inputs.length, "Input array mismatch");
        // Load bAssets from storage into memory
        (uint8[] memory indexes, BassetPersonal[] memory personals) = _getBassets(_inputs);
        BassetData[] memory allBassets = bAssetData;
        Cache memory cache = _getCacheDetails();
        uint256[] memory quantitiesDeposited = new uint256[](len);
        // Transfer the Bassets to the integrator, update storage and calc MassetQ
        for (uint256 i = 0; i < len; i++) {
            uint256 bAssetQuantity = _inputQuantities[i];
            if (bAssetQuantity > 0) {
                uint8 idx = indexes[i];
                BassetData memory data = allBassets[idx];
                BassetPersonal memory personal = personals[i];
                uint256 quantityDeposited = MassetManagerBtcV2.depositTokens(
                    personal,
                    data.ratio,
                    bAssetQuantity,
                    cache.maxCache
                );
                quantitiesDeposited[i] = quantityDeposited;
                bAssetData[idx].vaultBalance =
                    data.vaultBalance +
                    SafeCast.toUint128(quantityDeposited);
            }
        }
        // Validate the proposed mint, after token transfer
        mAssetMinted = forgeValidator.computeMintMulti(
            allBassets,
            indexes,
            quantitiesDeposited,
            _getConfig()
        );
        require(mAssetMinted >= _minMassetQuantity, "Mint quantity < min qty");
        require(mAssetMinted > 0, "Zero mAsset quantity");

        // Mint the Masset
        _mint(_recipient, mAssetMinted);
        emit MintedMulti(msg.sender, _recipient, mAssetMinted, _inputs, _inputQuantities);
    }

    /***************************************
                SWAP (PUBLIC)
    ****************************************/

    /**
     * @dev Swaps one bAsset for another bAsset using the bAsset addresses.
     * bAsset <> bAsset swaps will incur a small fee (swapFee()).
     * @param _input             Address of bAsset to deposit
     * @param _output            Address of bAsset to receive
     * @param _inputQuantity     Units of input bAsset to swap
     * @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 whenHealthy returns (uint256 swapOutput) {
        swapOutput = _swap(_input, _output, _inputQuantity, _minOutputQuantity, _recipient);
    }

    /**
     * @dev 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, "Invalid swap quantity");

        // 1. Load the bAssets from storage into memory
        BassetData[] memory allBassets = bAssetData;
        (uint8 inputIdx, ) = _getAsset(_input);
        (uint8 outputIdx, ) = _getAsset(_output);

        // 2. If a bAsset swap, calculate the validity, output and fee
        (swapOutput, ) = forgeValidator.computeSwap(
            allBassets,
            inputIdx,
            outputIdx,
            _inputQuantity,
            swapFee,
            _getConfig()
        );
    }

    /***************************************
              SWAP (INTERNAL)
    ****************************************/

    /** @dev Swap single */
    function _swap(
        address _input,
        address _output,
        uint256 _inputQuantity,
        uint256 _minOutputQuantity,
        address _recipient
    ) internal returns (uint256 swapOutput) {
        require(_recipient != address(0), "Invalid recipient");
        require(_input != _output, "Invalid pair");
        require(_inputQuantity > 0, "Invalid swap quantity");

        // 1. Load the bAssets from storage into memory
        BassetData[] memory allBassets = bAssetData;
        (uint8 inputIdx, BassetPersonal memory inputPersonal) = _getAsset(_input);
        (uint8 outputIdx, BassetPersonal memory outputPersonal) = _getAsset(_output);
        // 2. Load cache
        Cache memory cache = _getCacheDetails();
        // 3. Deposit the input tokens
        uint256 quantityDeposited = MassetManagerBtcV2.depositTokens(
            inputPersonal,
            allBassets[inputIdx].ratio,
            _inputQuantity,
            cache.maxCache
        );
        // 3.1. Update the input balance
        bAssetData[inputIdx].vaultBalance =
            allBassets[inputIdx].vaultBalance +
            SafeCast.toUint128(quantityDeposited);

        // 3. Validate the swap
        uint256 scaledFee;
        (swapOutput, scaledFee) = forgeValidator.computeSwap(
            allBassets,
            inputIdx,
            outputIdx,
            quantityDeposited,
            swapFee,
            _getConfig()
        );
        require(swapOutput >= _minOutputQuantity, "Output qty < minimum qty");
        require(swapOutput > 0, "Zero output quantity");
        //4. Settle the swap
        //4.1. Decrease output bal
        MassetManagerBtcV2.withdrawTokens(
            swapOutput,
            outputPersonal,
            allBassets[outputIdx],
            _recipient,
            cache.maxCache
        );
        bAssetData[outputIdx].vaultBalance =
            allBassets[outputIdx].vaultBalance -
            SafeCast.toUint128(swapOutput);
        // Save new surplus to storage
        surplus = cache.surplus + scaledFee;
        emit Swapped(
            msg.sender,
            inputPersonal.addr,
            outputPersonal.addr,
            swapOutput,
            scaledFee,
            _recipient
        );
    }

    /***************************************
                REDEMPTION (PUBLIC)
    ****************************************/

    /**
     * @notice Redeems a specified quantity of mAsset in return for a bAsset specified by bAsset address.
     * The bAsset is sent to the specified recipient.
     * The bAsset quantity is relative to current vault balance levels and desired mAsset quantity.
     * The quantity of mAsset is burnt as payment.
     * A minimum quantity of bAsset is specified to protect against price slippage between the mAsset and bAsset.
     * @param _output            Address of the bAsset to receive
     * @param _mAssetQuantity    Quantity of mAsset to redeem
     * @param _minOutputQuantity Minimum bAsset quantity to receive for the burnt mAssets. This protects against slippage.
     * @param _recipient         Address to transfer the withdrawn bAssets to.
     * @return outputQuantity    Quanity of bAsset units received for the burnt mAssets
     */
    function redeem(
        address _output,
        uint256 _mAssetQuantity,
        uint256 _minOutputQuantity,
        address _recipient
    ) external override nonReentrant whenNoRecol returns (uint256 outputQuantity) {
        outputQuantity = _redeem(_output, _mAssetQuantity, _minOutputQuantity, _recipient);
    }

    /**
     * @dev Credits a recipient with a proportionate amount of bAssets, relative to current vault
     * balance levels and desired mAsset quantity. Burns the mAsset as payment.
     * @param _mAssetQuantity       Quantity of mAsset to redeem
     * @param _minOutputQuantities  Min units of output to receive
     * @param _recipient            Address to credit the withdrawn bAssets
     */
    function redeemMasset(
        uint256 _mAssetQuantity,
        uint256[] calldata _minOutputQuantities,
        address _recipient
    ) external override nonReentrant whenNoRecol returns (uint256[] memory outputQuantities) {
        outputQuantities = _redeemMasset(_mAssetQuantity, _minOutputQuantities, _recipient);
    }

    /**
     * @dev Credits a recipient with a certain quantity of selected bAssets, in exchange for burning the
     *      relative Masset quantity from the sender. Sender also incurs a small fee on the outgoing asset.
     * @param _outputs           Addresses of the bAssets to receive
     * @param _outputQuantities  Units of the bAssets to redeem
     * @param _maxMassetQuantity Maximum mAsset quantity to burn for the received bAssets. This protects against slippage.
     * @param _recipient         Address to receive the withdrawn bAssets
     * @return mAssetQuantity    Quantity of mAsset units burned plus the swap fee to pay for the redeemed bAssets
     */
    function redeemExactBassets(
        address[] calldata _outputs,
        uint256[] calldata _outputQuantities,
        uint256 _maxMassetQuantity,
        address _recipient
    ) external override nonReentrant whenNoRecol returns (uint256 mAssetQuantity) {
        mAssetQuantity = _redeemExactBassets(
            _outputs,
            _outputQuantities,
            _maxMassetQuantity,
            _recipient
        );
    }

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

        (uint8 idx, ) = _getAsset(_output);

        uint256 scaledFee = _mAssetQuantity.mulTruncate(swapFee);
        bAssetOutput = forgeValidator.computeRedeem(
            bAssetData,
            idx,
            _mAssetQuantity - scaledFee,
            _getConfig()
        );
    }

    /**
     * @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 mAssetQuantity    Estimated quantity of mAsset units needed to burn to receive output
     */
    function getRedeemExactBassetsOutput(
        address[] calldata _outputs,
        uint256[] calldata _outputQuantities
    ) external view override returns (uint256 mAssetQuantity) {
        uint256 len = _outputQuantities.length;
        require(len > 0 && len == _outputs.length, "Invalid array input");

        (uint8[] memory indexes, ) = _getBassets(_outputs);

        // calculate the value of mAssets need to cover the value of bAssets being redeemed
        uint256 mAssetRedeemed = forgeValidator.computeRedeemExact(
            bAssetData,
            indexes,
            _outputQuantities,
            _getConfig()
        );
        mAssetQuantity = mAssetRedeemed.divPrecisely(1e18 - swapFee) + 1;
    }

    /***************************************
                REDEMPTION (INTERNAL)
    ****************************************/

    /**
     * @dev Redeem mAsset for a single bAsset
     */
    function _redeem(
        address _output,
        uint256 _inputQuantity,
        uint256 _minOutputQuantity,
        address _recipient
    ) internal returns (uint256 bAssetQuantity) {
        require(_recipient != address(0), "Invalid recipient");
        require(_inputQuantity > 0, "Qty==0");

        // Load the bAsset data from storage into memory
        BassetData[] memory allBassets = bAssetData;
        (uint8 bAssetIndex, BassetPersonal memory personal) = _getAsset(_output);
        // Calculate redemption quantities
        uint256 scaledFee = _inputQuantity.mulTruncate(swapFee);
        bAssetQuantity = forgeValidator.computeRedeem(
            allBassets,
            bAssetIndex,
            _inputQuantity - scaledFee,
            _getConfig()
        );
        require(bAssetQuantity >= _minOutputQuantity, "bAsset qty < min qty");
        require(bAssetQuantity > 0, "Output == 0");
        // Apply fees, burn mAsset and return bAsset to recipient
        // 1.0. Burn the full amount of Masset
        _burn(msg.sender, _inputQuantity);
        surplus += scaledFee;
        Cache memory cache = _getCacheDetails();
        // 2.0. Transfer the Bassets to the recipient
        MassetManagerBtcV2.withdrawTokens(
            bAssetQuantity,
            personal,
            allBassets[bAssetIndex],
            _recipient,
            cache.maxCache
        );
        // 3.0. Set vault balance
        bAssetData[bAssetIndex].vaultBalance =
            allBassets[bAssetIndex].vaultBalance -
            SafeCast.toUint128(bAssetQuantity);

        emit Redeemed(
            msg.sender,
            _recipient,
            _inputQuantity,
            personal.addr,
            bAssetQuantity,
            scaledFee
        );
    }

    /**
     * @dev Redeem mAsset for proportional amount of bAssets
     */
    function _redeemMasset(
        uint256 _inputQuantity,
        uint256[] calldata _minOutputQuantities,
        address _recipient
    ) internal returns (uint256[] memory outputQuantities) {
        require(_recipient != address(0), "Invalid recipient");
        require(_inputQuantity > 0, "Qty==0");

        // Calculate mAsset redemption quantities
        uint256 scaledFee = _inputQuantity.mulTruncate(redemptionFee);
        uint256 mAssetRedemptionAmount = _inputQuantity - scaledFee;

        // Burn mAsset quantity
        _burn(msg.sender, _inputQuantity);
        surplus += scaledFee;

        // Calc cache and total mAsset circulating
        Cache memory cache = _getCacheDetails();
        // Total mAsset = (totalSupply + _inputQuantity - scaledFee) + surplus
        uint256 totalMasset = cache.vaultBalanceSum + mAssetRedemptionAmount;

        // Load the bAsset data from storage into memory
        BassetData[] memory allBassets = bAssetData;

        uint256 len = allBassets.length;
        address[] memory outputs = new address[](len);
        outputQuantities = new uint256[](len);
        for (uint256 i = 0; i < len; i++) {
            // Get amount out, proportionate to redemption quantity
            // Use `cache.sum` here as the total mAsset supply is actually totalSupply + surplus
            uint256 amountOut = (allBassets[i].vaultBalance * mAssetRedemptionAmount) / totalMasset;
            require(amountOut > 1, "Output == 0");
            amountOut -= 1;
            require(amountOut >= _minOutputQuantities[i], "bAsset qty < min qty");
            // Set output in array
            (outputQuantities[i], outputs[i]) = (amountOut, bAssetPersonal[i].addr);
            // Transfer the bAsset to the recipient
            MassetManagerBtcV2.withdrawTokens(
                amountOut,
                bAssetPersonal[i],
                allBassets[i],
                _recipient,
                cache.maxCache
            );
            // reduce vaultBalance
            bAssetData[i].vaultBalance = allBassets[i].vaultBalance - SafeCast.toUint128(amountOut);
        }

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

    /** @dev Redeem mAsset for one or more bAssets */
    function _redeemExactBassets(
        address[] memory _outputs,
        uint256[] memory _outputQuantities,
        uint256 _maxMassetQuantity,
        address _recipient
    ) internal returns (uint256 mAssetQuantity) {
        require(_recipient != address(0), "Invalid recipient");
        uint256 len = _outputQuantities.length;
        require(len > 0 && len == _outputs.length, "Invalid array input");
        require(_maxMassetQuantity > 0, "Qty==0");

        (uint8[] memory indexes, BassetPersonal[] memory personal) = _getBassets(_outputs);
        // Load bAsset data from storage to memory
        BassetData[] memory allBassets = bAssetData;
        // Validate redemption
        uint256 mAssetRequired = forgeValidator.computeRedeemExact(
            allBassets,
            indexes,
            _outputQuantities,
            _getConfig()
        );
        mAssetQuantity = mAssetRequired.divPrecisely(1e18 - swapFee);
        uint256 fee = mAssetQuantity - mAssetRequired;
        require(mAssetQuantity > 0, "Must redeem some mAssets");
        mAssetQuantity += 1;
        require(mAssetQuantity <= _maxMassetQuantity, "Redeem mAsset qty > max quantity");
        // Apply fees, burn mAsset and return bAsset to recipient
        // 1.0. Burn the full amount of Masset
        _burn(msg.sender, mAssetQuantity);
        surplus += fee;
        Cache memory cache = _getCacheDetails();
        // 2.0. Transfer the Bassets to the recipient and count fees
        for (uint256 i = 0; i < len; i++) {
            uint8 idx = indexes[i];
            MassetManagerBtcV2.withdrawTokens(
                _outputQuantities[i],
                personal[i],
                allBassets[idx],
                _recipient,
                cache.maxCache
            );
            bAssetData[idx].vaultBalance =
                allBassets[idx].vaultBalance -
                SafeCast.toUint128(_outputQuantities[i]);
        }
        emit RedeemedMulti(
            msg.sender,
            _recipient,
            mAssetQuantity,
            _outputs,
            _outputQuantities,
            fee
        );
    }

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

    /**
     * @dev Get basket details for `Masset_MassetStructs.Basket`
     * @return b   Basket struct
     */
    function getBasket() external view override returns (bool, bool) {
        return (basket.undergoingRecol, basket.failed);
    }

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

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

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

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

    /**
     * vaultBalanceSum = totalSupply + 'surplus'
     * maxCache = vaultBalanceSum * (cacheSize / 1e18)
     * surplus is simply surplus, to reduce SLOADs
     */
    struct Cache {
        uint256 vaultBalanceSum;
        uint256 maxCache;
        uint256 surplus;
    }

    /**
     * @dev Gets the supply and cache details for the mAsset, taking into account the surplus
     * @return Cache containing (tracked) sum of vault balances, ideal cache size and surplus
     */
    function _getCacheDetails() internal view returns (Cache memory) {
        // read surplus from storage into memory
        uint256 _surplus = surplus;
        uint256 sum = totalSupply() + _surplus;
        return Cache(sum, sum.mulTruncate(cacheSize), _surplus);
    }

    /**
     * @dev Gets a bAsset from storage
     * @param _asset        Address of the asset
     * @return idx        Index of the asset
     * @return personal   Personal details for the asset
     */
    function _getAsset(
        address _asset
    ) internal view returns (uint8 idx, BassetPersonal memory personal) {
        idx = bAssetIndexes[_asset];
        personal = bAssetPersonal[idx];
        require(personal.addr == _asset, "Invalid asset");
    }

    /**
     * @dev Gets a an array of bAssets from storage and protects against duplicates
     * @param _bAssets    Addresses of the assets
     * @return indexes    Indexes of the assets
     * @return personal   Personal details for the assets
     */
    function _getBassets(
        address[] memory _bAssets
    ) internal view returns (uint8[] memory indexes, BassetPersonal[] memory personal) {
        uint256 len = _bAssets.length;

        indexes = new uint8[](len);
        personal = new BassetPersonal[](len);

        for (uint256 i = 0; i < len; i++) {
            (indexes[i], personal[i]) = _getAsset(_bAssets[i]);

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

    /**
     * @dev Gets all config needed for general InvariantValidator calls
     */
    function _getConfig() internal view returns (InvariantConfig memory) {
        return InvariantConfig(_getA(), weightLimits);
    }

    /**
     * @dev Gets current amplification var A
     */
    function _getA() internal view returns (uint256) {
        AmpData memory ampData_ = 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 Converts recently accrued swap and redeem fees into mAsset
     * @return mintAmount   mAsset units generated from swap and redeem fees
     * @return newSupply    mAsset total supply after mint
     */
    function collectInterest()
        external
        override
        onlySavingsManager
        returns (uint256 mintAmount, uint256 newSupply)
    {
        // Set the surplus variable to 1 to optimise for SSTORE costs.
        // If setting to 0 here, it would save 5k per savings deposit, but cost 20k for the
        // first surplus call (a SWAP or REDEEM).
        uint256 surplusFees = surplus;
        if (surplusFees > 1) {
            mintAmount = surplusFees - 1;
            surplus = 1;

            // mint new mAsset to savings manager
            _mint(msg.sender, mintAmount);
            emit MintedMulti(
                address(this),
                msg.sender,
                mintAmount,
                new address[](0),
                new uint256[](0)
            );
        }
        newSupply = totalSupply();
    }

    /**
     * @dev Collects the interest generated from the Basket, minting a relative
     *      amount of mAsset and sends it over to the SavingsManager.
     * @return mintAmount   mAsset units generated from interest collected from lending markets
     * @return newSupply    mAsset total supply after mint
     */
    function collectPlatformInterest()
        external
        override
        onlySavingsManager
        whenHealthy
        nonReentrant
        returns (uint256 mintAmount, uint256 newSupply)
    {
        uint256[] memory gains;
        (mintAmount, gains) = MassetManagerBtcV2.collectPlatformInterest(
            bAssetPersonal,
            bAssetData,
            forgeValidator,
            _getConfig()
        );

        require(mintAmount > 0, "Must collect something");

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

        newSupply = totalSupply();
    }

    /***************************************
                    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 mAsset supply to hold for each bAsset
     */
    function setCacheSize(uint256 _cacheSize) external override onlyGovernor {
        require(_cacheSize <= 2e17, "Must be <= 20%");

        cacheSize = _cacheSize;

        emit CacheSizeChanged(_cacheSize);
    }

    /**
     * @dev Upgrades the version of ForgeValidator protocol. Governor can do this
     *      only while ForgeValidator is unlocked.
     * @param _newForgeValidator Address of the new ForgeValidator
     */
    function upgradeForgeValidator(address _newForgeValidator) external override onlyGovernor {
        require(!forgeValidatorLocked, "ForgeVal locked");
        require(_newForgeValidator != address(0), "Null address");

        forgeValidator = IInvariantValidator(_newForgeValidator);

        emit ForgeValidatorChanged(_newForgeValidator);
    }

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

        swapFee = _swapFee;
        redemptionFee = _redemptionFee;

        emit FeesChanged(_swapFee, _redemptionFee);
    }

    /**
     * @dev Set the maximum weight for a given bAsset
     * @param _min Weight where 100% = 1e18
     * @param _max Weight where 100% = 1e18
     */
    function setWeightLimits(uint128 _min, uint128 _max) external onlyGovernor {
        require(_min <= 1e18 / (bAssetData.length * 2), "Min weight oob");
        require(_max >= 1e18 / (bAssetData.length - 1), "Max weight oob");

        weightLimits = WeightLimits(_min, _max);

        emit WeightLimitsChanged(_min, _max);
    }

    /**
     * @dev Update transfer fee flag for a given bAsset, should it change its fee practice
     * @param _bAsset   bAsset address
     * @param _flag         Charge transfer fee when its set to 'true', otherwise 'false'
     */
    function setTransferFeesFlag(address _bAsset, bool _flag) external override onlyGovernor {
        MassetManagerBtcV2.setTransferFeesFlag(bAssetPersonal, bAssetIndexes, _bAsset, _flag);
    }

    /**
     * @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 override onlyGovernor {
        MassetManagerBtcV2.migrateBassets(bAssetPersonal, bAssetIndexes, _bAssets, _newIntegration);
    }

    /**
     * @dev Executes the Auto Redistribution event by isolating the bAsset from the Basket
     * @param _bAsset          Address of the ERC20 token to isolate
     * @param _belowPeg        Bool to describe whether the bAsset deviated below peg (t)
     *                         or above (f)
     */
    function handlePegLoss(address _bAsset, bool _belowPeg) external onlyGovernor {
        MassetManagerBtcV2.handlePegLoss(basket, bAssetPersonal, bAssetIndexes, _bAsset, _belowPeg);
    }

    /**
     * @dev Negates the isolation of a given bAsset
     * @param _bAsset Address of the bAsset
     */
    function negateIsolation(address _bAsset) external onlyGovernor {
        MassetManagerBtcV2.negateIsolation(basket, bAssetPersonal, bAssetIndexes, _bAsset);
    }

    /**
     * @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 {
        MassetManagerBtcV2.startRampA(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 {
        MassetManagerBtcV2.stopRampA(ampData, _getA());
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_nexus","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":"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"}],"name":"FeesChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"forgeValidator","type":"address"}],"name":"ForgeValidatorChanged","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":"mAssetQuantity","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":"mAssetQuantity","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":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":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":"scaledFee","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":"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":[],"name":"ampData","outputs":[{"internalType":"uint64","name":"initialA","type":"uint64"},{"internalType":"uint64","name":"targetA","type":"uint64"},{"internalType":"uint64","name":"rampStartTime","type":"uint64"},{"internalType":"uint64","name":"rampEndTime","type":"uint64"}],"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":"uint256","name":"","type":"uint256"}],"name":"bAssetData","outputs":[{"internalType":"uint128","name":"ratio","type":"uint128"},{"internalType":"uint128","name":"vaultBalance","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"bAssetIndexes","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"bAssetPersonal","outputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"address","name":"integrator","type":"address"},{"internalType":"bool","name":"hasTxFee","type":"bool"},{"internalType":"enum MassetStructs.BassetStatus","name":"status","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"basket","outputs":[{"internalType":"bool","name":"undergoingRecol","type":"bool"},{"internalType":"bool","name":"failed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cacheSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collectInterest","outputs":[{"internalType":"uint256","name":"mintAmount","type":"uint256"},{"internalType":"uint256","name":"newSupply","type":"uint256"}],"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":"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":[],"name":"forgeValidator","outputs":[{"internalType":"contract IInvariantValidator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBasket","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","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 MassetStructs.BassetStatus","name":"status","type":"uint8"}],"internalType":"struct MassetStructs.BassetPersonal","name":"personal","type":"tuple"},{"components":[{"internalType":"uint128","name":"ratio","type":"uint128"},{"internalType":"uint128","name":"vaultBalance","type":"uint128"}],"internalType":"struct MassetStructs.BassetData","name":"data","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 MassetStructs.BassetStatus","name":"status","type":"uint8"}],"internalType":"struct MassetStructs.BassetPersonal[]","name":"personal","type":"tuple[]"},{"components":[{"internalType":"uint128","name":"ratio","type":"uint128"},{"internalType":"uint128","name":"vaultBalance","type":"uint128"}],"internalType":"struct MassetStructs.BassetData[]","name":"data","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getConfig","outputs":[{"components":[{"internalType":"uint256","name":"a","type":"uint256"},{"components":[{"internalType":"uint128","name":"min","type":"uint128"},{"internalType":"uint128","name":"max","type":"uint128"}],"internalType":"struct MassetStructs.WeightLimits","name":"limits","type":"tuple"}],"internalType":"struct MassetStructs.InvariantConfig","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":[{"internalType":"address[]","name":"_outputs","type":"address[]"},{"internalType":"uint256[]","name":"_outputQuantities","type":"uint256[]"}],"name":"getRedeemExactBassetsOutput","outputs":[{"internalType":"uint256","name":"mAssetQuantity","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_output","type":"address"},{"internalType":"uint256","name":"_mAssetQuantity","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":"_bAsset","type":"address"},{"internalType":"bool","name":"_belowPeg","type":"bool"}],"name":"handlePegLoss","outputs":[],"stateMutability":"nonpayable","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":[],"name":"maxBassets","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"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":[{"internalType":"address","name":"_bAsset","type":"address"}],"name":"negateIsolation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nexus","outputs":[{"internalType":"contract INexus","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_output","type":"address"},{"internalType":"uint256","name":"_mAssetQuantity","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":"_maxMassetQuantity","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"redeemExactBassets","outputs":[{"internalType":"uint256","name":"mAssetQuantity","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_mAssetQuantity","type":"uint256"},{"internalType":"uint256[]","name":"_minOutputQuantities","type":"uint256[]"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"redeemMasset","outputs":[{"internalType":"uint256[]","name":"outputQuantities","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"redemptionFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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"}],"name":"setFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_bAsset","type":"address"},{"internalType":"bool","name":"_flag","type":"bool"}],"name":"setTransferFeesFlag","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":[],"name":"surplus","outputs":[{"internalType":"uint256","name":"","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"},{"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":"swapFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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":[{"internalType":"address","name":"_newForgeValidator","type":"address"}],"name":"upgradeForgeValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"weightLimits","outputs":[{"internalType":"uint128","name":"min","type":"uint128"},{"internalType":"uint128","name":"max","type":"uint128"}],"stateMutability":"view","type":"function"}]

60a06040523480156200001157600080fd5b506040516200587c3803806200587c83398101604081905262000034916200007e565b806001600160a01b038116620000675760405162461bcd60e51b81526004016200005e90620000ae565b60405180910390fd5b60601b6001600160601b03191660805250620000e5565b60006020828403121562000090578081fd5b81516001600160a01b0381168114620000a7578182fd5b9392505050565b60208082526015908201527f4e657875732061646472657373206973207a65726f0000000000000000000000604082015260600190565b60805160601c61576a620001126000396000818161182c01528181613f120152613fbb015261576a6000f3fe608060405234801561001057600080fd5b50600436106102f15760003560e01c80636d5d6eb11161019d578063aa5d27e9116100e9578063cd6ef2b0116100a2578063dd62ed3e1161007c578063dd62ed3e1461066e578063e5555b8f14610681578063edc832b314610694578063f74bfe8e1461069c576102f1565b8063cd6ef2b01461063d578063d5bcb9b514610653578063d7d5226614610666576102f1565b8063aa5d27e9146105c7578063ab06346c146105da578063af290bd4146105fa578063bdfbe29c1461060d578063c3f909d414610620578063c4db7fa014610635576102f1565b8063905e891411610156578063a1c2515111610130578063a1c2515114610579578063a3f5c1d21461058c578063a457c2d7146105a1578063a9059cbb146105b4576102f1565b8063905e89141461054b57806395d89b411461055e578063969642b914610566576102f1565b80636d5d6eb1146104e45780636fb3e89c146104f757806370a082311461050a57806372ea90761461051d57806378aa987e146105305780637e8901ea14610543576102f1565b806326bbe60a1161025c57806343bcfab61161021557806354cf2aeb116101ef57806354cf2aeb146104b4578063598362f0146104bc578063674a64e0146104d45780636c36581c146104dc576102f1565b806343bcfab61461048657806344e3fa3c14610499578063458f5815146104ac576102f1565b806326bbe60a146104015780632a2fab22146104145780632f91a7241461042a578063313ce5671461044a57806339509351146104525780633e37bcbc14610465576102f1565b806313888565116102ae578063138885651461039f57806318160ddd146103a75780631820783d146103af5780631d3ce398146103c2578063213c501a146103d857806323b872dd146103ee576102f1565b80630357359c146102f657806304de5a731461032257806306fdde0314610342578063095ea7b3146103575780630b78f9c014610377578063119849cf1461038c575b600080fd5b61030961030436600461456b565b6106af565b60405161031994939291906148f6565b60405180910390f35b610335610330366004614449565b6106ff565b6040516103199190614d05565b61034a610847565b6040516103199190614d0e565b61036a610365366004614381565b6108da565b6040516103199190614ce8565b61038a6103853660046146b1565b6108f8565b005b61033561039a366004614381565b61098c565b610335610a56565b610335610a5c565b61038a6103bd36600461456b565b610a62565b6103ca610ad2565b604051610319929190614b73565b6103e0610c2f565b604051610319929190615515565b61036a6103fc3660046142b2565b610c49565b61038a61040f366004614242565b610cbf565b61041c610d69565b604051610319929190615437565b61043d610438366004614242565b610e20565b60405161031991906155ae565b61043d610e35565b61036a610460366004614381565b610e3e565b610478610473366004614242565b610e8d565b6040516103199291906154ba565b6103356104943660046143ac565b611018565b61038a6104a73660046146b1565b611079565b6103356110fd565b610335611103565b6104c4611109565b6040516103199493929190615583565b610335611137565b61043d61113d565b6103e06104f236600461456b565b611146565b61038a6105053660046143f5565b61117b565b610335610518366004614242565b6111f9565b61033561052b3660046142b2565b611218565b61033561053e366004614381565b6113aa565b61041c611497565b61038a610559366004614350565b611640565b61034a61168a565b61038a610574366004614242565b611699565b61038a610587366004614539565b611714565b61059461182a565b60405161031991906148e2565b61036a6105af366004614381565b61184e565b61036a6105c2366004614381565b61189d565b6103356105d53660046144b1565b6118b1565b6105ed6105e836600461459b565b611979565b6040516103199190614cd5565b6103356106083660046144b1565b6119c2565b61038a61061b366004614350565b611a70565b610628611ab7565b6040516103199190615507565b61038a611acc565b610645611b47565b604051610319929190614cf3565b6103356106613660046142f2565b611b5a565b610594611bbd565b61033561067c36600461427a565b611bd2565b61033561068f366004614449565b611bfd565b610645611d0b565b6103356106aa3660046143ac565b611d1d565b603f81815481106106bf57600080fd5b6000918252602090912060029091020180546001909101546001600160a01b0391821692509081169060ff600160a01b8204811691600160a81b90041684565b600081801580159061071057508085145b6107355760405162461bcd60e51b815260040161072c90615077565b60405180910390fd5b6000610773878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250611d6692505050565b506038549091506000906201000090046001600160a01b031663d176d694604084898961079e611f7c565b6040518663ffffffff1660e01b81526004016107be959493929190614af2565b60206040518083038186803b1580156107d657600080fd5b505afa1580156107ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061080e9190614583565b9050610830603a54670de0b6b3a76400006108299190615666565b8290611fce565b61083b9060016155e7565b98975050505050505050565b6060603680546108569061569d565b80601f01602080910402602001604051908101604052809291908181526020018280546108829061569d565b80156108cf5780601f106108a4576101008083540402835291602001916108cf565b820191906000526020600020905b8154815290600101906020018083116108b257829003601f168201915b505050505090505b90565b60006108ee6108e7611fed565b8484611ff1565b5060015b92915050565b6109006120a5565b603b548211156109225760405162461bcd60e51b815260040161072c90614df4565b603b548111156109445760405162461bcd60e51b815260040161072c90615013565b603a829055603c8190556040517f64f84976d9c917a44796104a59950fdbd9b3c16a5dd348b546d738301f6bd068906109809084908490615437565b60405180910390a15050565b60008082116109ad5760405162461bcd60e51b815260040161072c9061530f565b60006109b8846120df565b506038549091506201000090046001600160a01b0316637910213b604083866109df611f7c565b6040518563ffffffff1660e01b81526004016109fe9493929190614b60565b60206040518083038186803b158015610a1657600080fd5b505afa158015610a2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a4e9190614583565b949350505050565b603e5481565b60355490565b610a6a6120a5565b6702c68af0bb140000811115610a925760405162461bcd60e51b815260040161072c9061511f565b603d8190556040517f2f5a6b1defeafd30e7568ea5c176aa0702b0af5b00ba41fa20e58b2c72e8afe790610ac7908390614d05565b60405180910390a150565b606080603f604081805480602002602001604051908101604052809291908181526020016000905b82821015610bb1576000848152602090819020604080516080810182526002860290920180546001600160a01b03908116845260018201549081169484019490945260ff600160a01b8504811615159284019290925291926060840191600160a81b909104166007811115610b7f57634e487b7160e01b600052602160045260246000fd5b6007811115610b9e57634e487b7160e01b600052602160045260246000fd5b8152505081526020019060010190610afa565b50505050915080805480602002602001604051908101604052809291908181526020016000905b82821015610c2157600084815260209081902060408051808201909152908401546001600160801b038082168352600160801b9091041681830152825260019092019101610bd8565b505050509050915091509091565b6045546001600160801b0380821691600160801b90041682565b6000610c56848484612209565b610cb484610c62611fed565b6001600160a01b03871660009081526034602052604081208691610c84611fed565b6001600160a01b03166001600160a01b0316815260200190815260200160002054610caf9190615666565b611ff1565b5060015b9392505050565b610cc76120a5565b603854600160b01b900460ff1615610cf15760405162461bcd60e51b815260040161072c90614d61565b6001600160a01b038116610d175760405162461bcd60e51b815260040161072c90614f7f565b6038805462010000600160b01b031916620100006001600160a01b038416021790556040517f2e137a82d7f7fe8a4c453313f3d08557c162ad9d78219a2e937e318b41e12f7a90610ac79083906148e2565b600080610d746122f4565b603e546001811115610e1157610d8b600182615666565b6001603e559250610d9c3384612323565b307f7d3ff197e9071095bd36b627028ef523ecf46fcbf17cbde745a4b65aec88b6bc33856000604051908082528060200260200182016040528015610deb578160200160208202803683370190505b5060408051600081526020810191829052610e08949392916149b1565b60405180910390a25b610e19610a5c565b9150509091565b60416020526000908152604090205460ff1681565b60385460ff1690565b60006108ee610e4b611fed565b848460346000610e59611fed565b6001600160a01b03908116825260208083019390935260409182016000908120918b1681529252902054610caf91906155e7565b610e95614169565b610e9d614191565b6001600160a01b038316600090815260416020526040902054603f805460ff9092169182908110610ede57634e487b7160e01b600052603260045260246000fd5b600091825260209182902060408051608081018252600290930290910180546001600160a01b03908116845260018201549081169484019490945260ff600160a01b8504811615159284019290925291926060840191600160a81b909104166007811115610f5c57634e487b7160e01b600052602160045260246000fd5b6007811115610f7b57634e487b7160e01b600052602160045260246000fd5b815250509250836001600160a01b031683600001516001600160a01b031614610fb65760405162461bcd60e51b815260040161072c90614dcd565b60408160ff1681548110610fda57634e487b7160e01b600052603260045260246000fd5b6000918252602091829020604080518082019091529101546001600160801b038082168352600160801b909104169181019190915292949293505050565b603854600090610100900460ff166110425760405162461bcd60e51b815260040161072c9061532f565b6038805461ff00191690556110556123d7565b6110618585858561241b565b6038805461ff00191661010017905595945050505050565b6110816120a5565b73c3ff9c67fd926e84bf0555f38da7ceb0a1c6524963e2a5f044604484846110a7612783565b60646040518663ffffffff1660e01b81526004016110c9959493929190615445565b60006040518083038186803b1580156110e157600080fd5b505af41580156110f5573d6000803e3d6000fd5b505050505050565b603c5481565b603a5481565b6044546001600160401b0380821691600160401b8104821691600160801b8204811691600160c01b90041684565b603d5481565b60425460ff1681565b6040818154811061115657600080fd5b6000918252602090912001546001600160801b038082169250600160801b9091041682565b6111836120a5565b60405163a5bee44b60e01b815273c3ff9c67fd926e84bf0555f38da7ceb0a1c652499063a5bee44b906111c490603f90604190889088908890600401614c60565b60006040518083038186803b1580156111dc57600080fd5b505af41580156111f0573d6000803e3d6000fd5b50505050505050565b6001600160a01b0381166000908152603360205260409020545b919050565b6000826001600160a01b0316846001600160a01b0316141561124c5760405162461bcd60e51b815260040161072c90614e1b565b6000821161126c5760405162461bcd60e51b815260040161072c90615197565b60006040805480602002602001604051908101604052809291908181526020016000905b828210156112d957600084815260209081902060408051808201909152908401546001600160801b038082168352600160801b9091041681830152825260019092019101611290565b50505050905060006112ea866120df565b50905060006112f8866120df565b509050603860029054906101000a90046001600160a01b03166001600160a01b0316630e3c01d384848489603a5461132e611f7c565b6040518763ffffffff1660e01b815260040161134f96959493929190614ab0565b604080518083038186803b15801561136657600080fd5b505afa15801561137a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061139e91906146d2565b50979650505050505050565b60008082116113cb5760405162461bcd60e51b815260040161072c9061530f565b60006113d6846120df565b50905060006113f0603a54856128c090919063ffffffff16565b6038549091506201000090046001600160a01b03166350494dc06040846114178589615666565b61141f611f7c565b6040518563ffffffff1660e01b815260040161143e9493929190614b60565b60206040518083038186803b15801561145657600080fd5b505afa15801561146a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061148e9190614583565b95945050505050565b6000806114a26122f4565b6114aa6128d5565b603854610100900460ff166114d15760405162461bcd60e51b815260040161072c9061532f565b6038805461ff0019169081905560609073c3ff9c67fd926e84bf0555f38da7ceb0a1c6524990638b8029b490603f906040906201000090046001600160a01b031661151a611f7c565b6040518563ffffffff1660e01b81526004016115399493929190614bca565b60006040518083038186803b15801561155157600080fd5b505af4158015611565573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261158d91908101906145ec565b9093509050826115af5760405162461bcd60e51b815260040161072c906150ef565b6115b93384612323565b307f7d3ff197e9071095bd36b627028ef523ecf46fcbf17cbde745a4b65aec88b6bc33856000604051908082528060200260200182016040528015611608578160200160208202803683370190505b508560405161161a94939291906149b1565b60405180910390a261162a610a5c565b6038805461ff0019166101001790559293915050565b6116486120a5565b60405163ee60ee2b60e01b815273c3ff9c67fd926e84bf0555f38da7ceb0a1c652499063ee60ee2b906110c990604390603f906041908890889060040161548c565b6060603780546108569061569d565b6116a16120a5565b604051634c1e9da160e11b815273c3ff9c67fd926e84bf0555f38da7ceb0a1c652499063983d3b42906116e190604390603f906041908790600401615468565b60006040518083038186803b1580156116f957600080fd5b505af415801561170d573d6000803e3d6000fd5b5050505050565b61171c6120a5565b60405461172a90600261561f565b61173c90670de0b6b3a76400006155ff565b826001600160801b031611156117645760405162461bcd60e51b815260040161072c906152a3565b60405461177390600190615666565b61178590670de0b6b3a76400006155ff565b816001600160801b031610156117ad5760405162461bcd60e51b815260040161072c906150a4565b6040805180820182526001600160801b038481168083528482166020909301839052604580546fffffffffffffffffffffffffffffffff1916909117909116600160801b909202919091179055517f1633022fee8dcf5a3cdeb5f1b49d5b734a3cfef7fc093e30cfdd28ddde8cd136906109809084908490615515565b7f000000000000000000000000000000000000000000000000000000000000000081565b60006108ee61185b611fed565b848460346000611869611fed565b6001600160a01b03908116825260208083019390935260409182016000908120918b1681529252902054610caf9190615666565b60006108ee6118aa611fed565b8484612209565b603854600090610100900460ff166118db5760405162461bcd60e51b815260040161072c9061532f565b6038805461ff00191690556118ee6123d7565b61195f87878080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808b0282810182019093528a82529093508a9250899182918501908490808284376000920191909152508892508791506129269050565b6038805461ff001916610100179055979650505050505050565b603854606090610100900460ff166119a35760405162461bcd60e51b815260040161072c9061532f565b6038805461ff00191690556119b66123d7565b61106185858585612d96565b603854600090610100900460ff166119ec5760405162461bcd60e51b815260040161072c9061532f565b6038805461ff00191690556119ff6128d5565b61195f87878080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808b0282810182019093528a82529093508a9250899182918501908490808284376000920191909152508892508791506132819050565b611a786120a5565b604051638d18aef960e01b815273c3ff9c67fd926e84bf0555f38da7ceb0a1c6524990638d18aef9906110c990603f9060419087908790600401614c3a565b611abf6141a8565b611ac7611f7c565b905090565b611ad46120a5565b73c3ff9c67fd926e84bf0555f38da7ceb0a1c652496318068e406044611af8612783565b6040518363ffffffff1660e01b8152600401611b15929190615437565b60006040518083038186803b158015611b2d57600080fd5b505af4158015611b41573d6000803e3d6000fd5b50505050565b60435460ff808216916101009004169091565b603854600090610100900460ff16611b845760405162461bcd60e51b815260040161072c9061532f565b6038805461ff0019169055611b976128d5565b611ba486868686866136ed565b6038805461ff0019166101001790559695505050505050565b6038546201000090046001600160a01b031681565b6001600160a01b03918216600090815260346020908152604080832093909416825291909152205490565b6000818015801590611c0e57508085145b611c2a5760405162461bcd60e51b815260040161072c90614f0a565b6000611c68878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250611d6692505050565b506038549091506201000090046001600160a01b031663b7ecbf726040838888611c90611f7c565b6040518663ffffffff1660e01b8152600401611cb0959493929190614af2565b60206040518083038186803b158015611cc857600080fd5b505afa158015611cdc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d009190614583565b979650505050505050565b60435460ff8082169161010090041682565b603854600090610100900460ff16611d475760405162461bcd60e51b815260040161072c9061532f565b6038805461ff0019169055611d5a6128d5565b61106185858585613beb565b80516060908190806001600160401b03811115611d9357634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611dbc578160200160208202803683370190505b509250806001600160401b03811115611de557634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611e1e57816020015b611e0b614169565b815260200190600190039081611e035790505b50915060005b81811015611f7557611e5c858281518110611e4f57634e487b7160e01b600052603260045260246000fd5b60200260200101516120df565b858381518110611e7c57634e487b7160e01b600052603260045260246000fd5b60200260200101858481518110611ea357634e487b7160e01b600052603260045260246000fd5b602090810291909101019190915260ff90911690526000611ec58260016155e7565b90505b82811015611f6257858181518110611ef057634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b0316868381518110611f2157634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b03161415611f505760405162461bcd60e51b815260040161072c90615235565b80611f5a816156d8565b915050611ec8565b5080611f6d816156d8565b915050611e24565b5050915091565b611f846141a8565b6040518060400160405280611f97612783565b8152604080518082019091526045546001600160801b038082168352600160801b9091041660208281019190915290910152905090565b600081611fe3670de0b6b3a76400008561561f565b610cb891906155ff565b3390565b6001600160a01b0383166120175760405162461bcd60e51b815260040161072c906152cb565b6001600160a01b03821661203d5760405162461bcd60e51b815260040161072c90614e41565b6001600160a01b0380841660008181526034602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590612098908590614d05565b60405180910390a3505050565b6120ad613f0e565b6001600160a01b0316336001600160a01b0316146120dd5760405162461bcd60e51b815260040161072c90615040565b565b60006120e9614169565b6001600160a01b038316600090815260416020526040902054603f805460ff9092169350908390811061212c57634e487b7160e01b600052603260045260246000fd5b600091825260209182902060408051608081018252600290930290910180546001600160a01b03908116845260018201549081169484019490945260ff600160a01b8504811615159284019290925291926060840191600160a81b9091041660078111156121aa57634e487b7160e01b600052602160045260246000fd5b60078111156121c957634e487b7160e01b600052602160045260246000fd5b815250509050826001600160a01b031681600001516001600160a01b0316146122045760405162461bcd60e51b815260040161072c90614dcd565b915091565b6001600160a01b03831661222f5760405162461bcd60e51b815260040161072c9061525e565b6001600160a01b0382166122555760405162461bcd60e51b815260040161072c90614d8a565b6001600160a01b0383166000908152603360205260408120805483929061227d908490615666565b90915550506001600160a01b038216600090815260336020526040812080548392906122aa9084906155e7565b92505081905550816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516120989190614d05565b336122fd613fa1565b6001600160a01b0316146120dd5760405162461bcd60e51b815260040161072c90614fdc565b6001600160a01b0382166123495760405162461bcd60e51b815260040161072c90615400565b806035600082825461235b91906155e7565b90915550506001600160a01b038216600090815260336020526040812080548392906123889084906155e7565b90915550506040516001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906123cb908590614d05565b60405180910390a35050565b6040805180820190915260435460ff808216158015845261010090920416151560208301526124185760405162461bcd60e51b815260040161072c90614eba565b50565b60006001600160a01b0382166124435760405162461bcd60e51b815260040161072c9061516c565b600084116124635760405162461bcd60e51b815260040161072c9061530f565b60006040805480602002602001604051908101604052809291908181526020016000905b828210156124d057600084815260209081902060408051808201909152908401546001600160801b038082168352600160801b9091041681830152825260019092019101612487565b5050505090506000806124e2886120df565b9150915060006124fd603a54896128c090919063ffffffff16565b6038549091506201000090046001600160a01b03166350494dc08585612523858d615666565b61252b611f7c565b6040518563ffffffff1660e01b815260040161254a9493929190614a7f565b60206040518083038186803b15801561256257600080fd5b505afa158015612576573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061259a9190614583565b9450868510156125bc5760405162461bcd60e51b815260040161072c90614edc565b600085116125dc5760405162461bcd60e51b815260040161072c90615147565b6125e63389614028565b80603e60008282546125f891906155e7565b90915550600090506126086140d2565b905073c3ff9c67fd926e84bf0555f38da7ceb0a1c65249634e331a548785888860ff168151811061264957634e487b7160e01b600052603260045260246000fd5b60200260200101518b86602001516040518663ffffffff1660e01b815260040161267795949392919061552f565b60006040518083038186803b15801561268f57600080fd5b505af41580156126a3573d6000803e3d6000fd5b505050506126b086614129565b858560ff16815181106126d357634e487b7160e01b600052603260045260246000fd5b6020026020010151602001516126e9919061563e565b60408560ff168154811061270d57634e487b7160e01b600052603260045260246000fd5b600091825260209091200180546001600160801b03928316600160801b029216919091179055825160405133917f105ffcfe6c5fa767ff5a53039fdd9ba80ce97196d4daa0beb1bfbfa0ed838ad89161276e918b918e91908c90899061497d565b60405180910390a25050505050949350505050565b604080516080810182526044546001600160401b038082168352600160401b8204811660208401819052600160801b8304821694840194909452600160c01b909104166060820181905260009290428111156128ad57825160408401516000806127f66001600160401b03841642615666565b612800848761567d565b6001600160401b031691509150836001600160401b0316866001600160401b03161115612871578082612833868961567d565b6001600160401b0316612846919061561f565b61285091906155ff565b612863906001600160401b0386166155e7565b9750505050505050506108d7565b808261287d888761567d565b6001600160401b0316612890919061561f565b61289a91906155ff565b612863906001600160401b038616615666565b506001600160401b031691506108d79050565b6000610cb88383670de0b6b3a7640000614152565b6040805180820190915260435460ff808216158015808552610100909304909116151560208401529061290a57508060200151155b6124185760405162461bcd60e51b815260040161072c906150cc565b60006001600160a01b03821661294e5760405162461bcd60e51b815260040161072c9061516c565b8351801580159061295f5750855181145b61297b5760405162461bcd60e51b815260040161072c90615077565b6000841161299b5760405162461bcd60e51b815260040161072c9061530f565b6000806129a788611d66565b6040805481516020808302820181018452828252949650929450600093849084015b82821015612a1257600084815260209081902060408051808201909152908401546001600160801b038082168352600160801b90910416818301528252600190920191016129c9565b50506038549293506000926201000090046001600160a01b0316915063d176d694905083868c612a40611f7c565b6040518563ffffffff1660e01b8152600401612a5f9493929190614a36565b60206040518083038186803b158015612a7757600080fd5b505afa158015612a8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aaf9190614583565b9050612aca603a54670de0b6b3a76400006108299190615666565b95506000612ad88288615666565b905060008711612afa5760405162461bcd60e51b815260040161072c90615394565b612b056001886155e7565b965088871115612b275760405162461bcd60e51b815260040161072c906153cb565b612b313388614028565b80603e6000828254612b4391906155e7565b9091555060009050612b536140d2565b905060005b87811015612d3d576000878281518110612b8257634e487b7160e01b600052603260045260246000fd5b6020026020010151905073c3ff9c67fd926e84bf0555f38da7ceb0a1c65249634e331a548e8481518110612bc657634e487b7160e01b600052603260045260246000fd5b6020026020010151898581518110612bee57634e487b7160e01b600052603260045260246000fd5b6020026020010151898560ff1681518110612c1957634e487b7160e01b600052603260045260246000fd5b60200260200101518f88602001516040518663ffffffff1660e01b8152600401612c4795949392919061552f565b60006040518083038186803b158015612c5f57600080fd5b505af4158015612c73573d6000803e3d6000fd5b50505050612ca78d8381518110612c9a57634e487b7160e01b600052603260045260246000fd5b6020026020010151614129565b868260ff1681518110612cca57634e487b7160e01b600052603260045260246000fd5b602002602001015160200151612ce0919061563e565b60408260ff1681548110612d0457634e487b7160e01b600052603260045260246000fd5b600091825260209091200180546001600160801b03928316600160801b0292169190911790555080612d35816156d8565b915050612b58565b50336001600160a01b03167fdf5bf345d5d6eedd0e8667d799d60af65d7127e3b0417e04bef4d954d2a4750e8a8a8f8f87604051612d7f9594939291906149ea565b60405180910390a250505050505050949350505050565b60606001600160a01b038216612dbe5760405162461bcd60e51b815260040161072c9061516c565b60008511612dde5760405162461bcd60e51b815260040161072c9061530f565b6000612df5603c54876128c090919063ffffffff16565b90506000612e038288615666565b9050612e0f3388614028565b81603e6000828254612e2191906155e7565b9091555060009050612e316140d2565b90506000828260000151612e4591906155e7565b905060006040805480602002602001604051908101604052809291908181526020016000905b82821015612eb457600084815260209081902060408051808201909152908401546001600160801b038082168352600160801b9091041681830152825260019092019101612e6b565b5050505090506000815190506000816001600160401b03811115612ee857634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015612f11578160200160208202803683370190505b509050816001600160401b03811115612f3a57634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015612f63578160200160208202803683370190505b50975060005b8281101561323f5760008588868481518110612f9557634e487b7160e01b600052603260045260246000fd5b6020026020010151602001516001600160801b0316612fb4919061561f565b612fbe91906155ff565b905060018111612fe05760405162461bcd60e51b815260040161072c90615147565b612feb600182615666565b90508c8c8381811061300d57634e487b7160e01b600052603260045260246000fd5b905060200201358110156130335760405162461bcd60e51b815260040161072c90614edc565b80603f838154811061305557634e487b7160e01b600052603260045260246000fd5b60009182526020909120600290910201548b516001600160a01b03909116908c908590811061309457634e487b7160e01b600052603260045260246000fd5b602002602001018585815181106130bb57634e487b7160e01b600052603260045260246000fd5b60200260200101826001600160a01b03166001600160a01b031681525082815250505073c3ff9c67fd926e84bf0555f38da7ceb0a1c65249634e331a5482603f858154811061311a57634e487b7160e01b600052603260045260246000fd5b906000526020600020906002020188868151811061314857634e487b7160e01b600052603260045260246000fd5b60200260200101518f8c602001516040518663ffffffff1660e01b815260040161317695949392919061556e565b60006040518083038186803b15801561318e57600080fd5b505af41580156131a2573d6000803e3d6000fd5b505050506131af81614129565b8583815181106131cf57634e487b7160e01b600052603260045260246000fd5b6020026020010151602001516131e5919061563e565b6040838154811061320657634e487b7160e01b600052603260045260246000fd5b600091825260209091200180546001600160801b03928316600160801b0292169190911790555080613237816156d8565b915050612f69565b50336001600160a01b03167fdf5bf345d5d6eedd0e8667d799d60af65d7127e3b0417e04bef4d954d2a4750e8a8e848c8c604051612d7f9594939291906149ea565b60006001600160a01b0382166132a95760405162461bcd60e51b815260040161072c9061516c565b835180158015906132ba5750855181145b6132d65760405162461bcd60e51b815260040161072c90614f0a565b6000806132e288611d66565b6040805481516020808302820181018452828252949650929450600093849084015b8282101561334d57600084815260209081902060408051808201909152908401546001600160801b038082168352600160801b9091041681830152825260019092019101613304565b505050509050600061335d6140d2565b90506000856001600160401b0381111561338757634e487b7160e01b600052604160045260246000fd5b6040519080825280602002602001820160405280156133b0578160200160208202803683370190505b50905060005b868110156135ba5760008b82815181106133e057634e487b7160e01b600052603260045260246000fd5b6020026020010151905060008111156135a757600087838151811061341557634e487b7160e01b600052603260045260246000fd5b602002602001015190506000868260ff168151811061344457634e487b7160e01b600052603260045260246000fd5b60200260200101519050600088858151811061347057634e487b7160e01b600052603260045260246000fd5b60200260200101519050600073c3ff9c67fd926e84bf0555f38da7ceb0a1c65249634e3d3913838560000151888c602001516040518563ffffffff1660e01b81526004016134c194939291906154d5565b60206040518083038186803b1580156134d957600080fd5b505af41580156134ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135119190614583565b90508087878151811061353457634e487b7160e01b600052603260045260246000fd5b60200260200101818152505061354981614129565b836020015161355891906155bc565b60408560ff168154811061357c57634e487b7160e01b600052603260045260246000fd5b600091825260209091200180546001600160801b03928316600160801b029216919091179055505050505b50806135b2816156d8565b9150506133b6565b506038546201000090046001600160a01b031663b7ecbf728487846135dd611f7c565b6040518563ffffffff1660e01b81526004016135fc9493929190614a36565b60206040518083038186803b15801561361457600080fd5b505afa158015613628573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061364c9190614583565b96508887101561366e5760405162461bcd60e51b815260040161072c90614e83565b6000871161368e5760405162461bcd60e51b815260040161072c906151c6565b6136988888612323565b336001600160a01b03167f7d3ff197e9071095bd36b627028ef523ecf46fcbf17cbde745a4b65aec88b6bc89898e8e6040516136d794939291906149b1565b60405180910390a2505050505050949350505050565b60006001600160a01b0382166137155760405162461bcd60e51b815260040161072c9061516c565b846001600160a01b0316866001600160a01b031614156137475760405162461bcd60e51b815260040161072c90614e1b565b600084116137675760405162461bcd60e51b815260040161072c90615197565b60006040805480602002602001604051908101604052809291908181526020016000905b828210156137d457600084815260209081902060408051808201909152908401546001600160801b038082168352600160801b909104168183015282526001909201910161378b565b5050505090506000806137e6896120df565b915091506000806137f68a6120df565b9150915060006138046140d2565b9050600073c3ff9c67fd926e84bf0555f38da7ceb0a1c65249634e3d391386898960ff168151811061384657634e487b7160e01b600052603260045260246000fd5b6020026020010151600001518e86602001516040518563ffffffff1660e01b815260040161387794939291906154d5565b60206040518083038186803b15801561388f57600080fd5b505af41580156138a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138c79190614583565b90506138d281614129565b878760ff16815181106138f557634e487b7160e01b600052603260045260246000fd5b60200260200101516020015161390b91906155bc565b60408760ff168154811061392f57634e487b7160e01b600052603260045260246000fd5b9060005260206000200160000160106101000a8154816001600160801b0302191690836001600160801b031602179055506000603860029054906101000a90046001600160a01b03166001600160a01b0316630e3c01d389898886603a54613995611f7c565b6040518763ffffffff1660e01b81526004016139b696959493929190614ab0565b604080518083038186803b1580156139cd57600080fd5b505afa1580156139e1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a0591906146d2565b90995090508a891015613a2a5760405162461bcd60e51b815260040161072c90614fa5565b60008911613a4a5760405162461bcd60e51b815260040161072c90615366565b73c3ff9c67fd926e84bf0555f38da7ceb0a1c65249634e331a548a868b8960ff1681518110613a8957634e487b7160e01b600052603260045260246000fd5b60200260200101518e88602001516040518663ffffffff1660e01b8152600401613ab795949392919061552f565b60006040518083038186803b158015613acf57600080fd5b505af4158015613ae3573d6000803e3d6000fd5b50505050613af089614129565b888660ff1681518110613b1357634e487b7160e01b600052603260045260246000fd5b602002602001015160200151613b29919061563e565b60408660ff1681548110613b4d57634e487b7160e01b600052603260045260246000fd5b600091825260209091200180546001600160801b03928316600160801b0292169190911790556040830151613b839082906155e7565b603e81905550336001600160a01b03167f1eeaa4acf3c225a4033105c2647625dbb298dec93b14e16253c4231e26c02b1d876000015186600001518c858f604051613bd2959493929190614923565b60405180910390a2505050505050505095945050505050565b60006001600160a01b038216613c135760405162461bcd60e51b815260040161072c9061516c565b60008411613c335760405162461bcd60e51b815260040161072c9061530f565b60006040805480602002602001604051908101604052809291908181526020016000905b82821015613ca057600084815260209081902060408051808201909152908401546001600160801b038082168352600160801b9091041681830152825260019092019101613c57565b505050509050600080613cb2886120df565b915091506000613cc06140d2565b9050600073c3ff9c67fd926e84bf0555f38da7ceb0a1c65249634e3d391384878760ff1681518110613d0257634e487b7160e01b600052603260045260246000fd5b6020026020010151600001518c86602001516040518563ffffffff1660e01b8152600401613d3394939291906154d5565b60206040518083038186803b158015613d4b57600080fd5b505af4158015613d5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d839190614583565b6038549091506201000090046001600160a01b0316637910213b868684613da8611f7c565b6040518563ffffffff1660e01b8152600401613dc79493929190614a7f565b60206040518083038186803b158015613ddf57600080fd5b505afa158015613df3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e179190614583565b955087861015613e395760405162461bcd60e51b815260040161072c90614e83565b613e4281614129565b858560ff1681518110613e6557634e487b7160e01b600052603260045260246000fd5b602002602001015160200151613e7b91906155bc565b60408560ff1681548110613e9f57634e487b7160e01b600052603260045260246000fd5b600091825260209091200180546001600160801b03928316600160801b029216919091179055613ecf8787612323565b336001600160a01b03167f30873c596f54a2e2e09894670d7e1a48b2433c00204f81fbedf557353c36e7c788888d8560405161276e9493929190614953565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b158015613f6957600080fd5b505afa158015613f7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ac7919061425e565b6040516385acd64160e01b81526000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906385acd64190614010907f12fe936c77a1e196473c4314f3bed8eeac1d757b319abb85bdda70df35511bf190600401614d05565b60206040518083038186803b158015613f6957600080fd5b6001600160a01b03821661404e5760405162461bcd60e51b815260040161072c906151f4565b6001600160a01b03821660009081526033602052604081208054839290614076908490615666565b92505081905550806035600082825461408f9190615666565b90915550506040516000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906123cb908590614d05565b6140da6141c2565b603e546000816140e8610a5c565b6140f291906155e7565b9050604051806060016040528082815260200161411a603d54846128c090919063ffffffff16565b81526020019290925250905090565b6000600160801b821061414e5760405162461bcd60e51b815260040161072c90614f38565b5090565b60008161415f848661561f565b610a4e91906155ff565b604080516080810182526000808252602082018190529181018290529060608201905b905290565b604080518082019091526000808252602082015290565b60405180604001604052806000815260200161418c614191565b60405180606001604052806000815260200160008152602001600081525090565b60008083601f8401126141f4578081fd5b5081356001600160401b0381111561420a578182fd5b602083019150836020808302850101111561422457600080fd5b9250929050565b80356001600160801b038116811461121357600080fd5b600060208284031215614253578081fd5b8135610cb88161571f565b60006020828403121561426f578081fd5b8151610cb88161571f565b6000806040838503121561428c578081fd5b82356142978161571f565b915060208301356142a78161571f565b809150509250929050565b6000806000606084860312156142c6578081fd5b83356142d18161571f565b925060208401356142e18161571f565b929592945050506040919091013590565b600080600080600060a08688031215614309578081fd5b85356143148161571f565b945060208601356143248161571f565b9350604086013592506060860135915060808601356143428161571f565b809150509295509295909350565b60008060408385031215614362578182fd5b823561436d8161571f565b9150602083013580151581146142a7578182fd5b60008060408385031215614393578182fd5b823561439e8161571f565b946020939093013593505050565b600080600080608085870312156143c1578384fd5b84356143cc8161571f565b9350602085013592506040850135915060608501356143ea8161571f565b939692955090935050565b600080600060408486031215614409578283fd5b83356001600160401b0381111561441e578384fd5b61442a868287016141e3565b909450925050602084013561443e8161571f565b809150509250925092565b6000806000806040858703121561445e578384fd5b84356001600160401b0380821115614474578586fd5b614480888389016141e3565b90965094506020870135915080821115614498578384fd5b506144a5878288016141e3565b95989497509550505050565b600080600080600080608087890312156144c9578081fd5b86356001600160401b03808211156144df578283fd5b6144eb8a838b016141e3565b90985096506020890135915080821115614503578283fd5b5061451089828a016141e3565b90955093505060408701359150606087013561452b8161571f565b809150509295509295509295565b6000806040838503121561454b578182fd5b6145548361422b565b91506145626020840161422b565b90509250929050565b60006020828403121561457c578081fd5b5035919050565b600060208284031215614594578081fd5b5051919050565b600080600080606085870312156145b0578182fd5b8435935060208501356001600160401b038111156145cc578283fd5b6145d8878288016141e3565b90945092505060408501356143ea8161571f565b600080604083850312156145fe578182fd5b825191506020808401516001600160401b038082111561461c578384fd5b818601915086601f83011261462f578384fd5b81518181111561464157614641615709565b8381026040518582820101818110858211171561466057614660615709565b604052828152858101935084860182860187018b101561467e578788fd5b8795505b838610156146a0578051855260019590950194938601938601614682565b508096505050505050509250929050565b600080604083850312156146c3578182fd5b50508035926020909101359150565b600080604083850312156146e4578182fd5b505080516020909101519092909150565b6000815180845260208085019450808401835b8381101561472d5781516001600160a01b031687529582019590820190600101614708565b509495945050505050565b6000815180845260208085019450808401835b8381101561472d5761475e878351614839565b604096909601959082019060010161474b565b6000815480845260208085019450838352808320835b8381101561472d5781546001600160801b038116885260801c8388015260409096019560019182019101614787565b6000815180845260208085019450808401835b8381101561472d578151875295820195908201906001016147c9565b6000815180845260208085019450808401835b8381101561472d57815160ff16875295820195908201906001016147f8565b6008811061483557634e487b7160e01b600052602160045260246000fd5b9052565b80516001600160801b03908116835260209182015116910152565b60018060a01b0380825116835280602083015116602084015250604081015115156040830152606081015161488c6060840182614817565b505050565b60018060a01b038082541683526001820154818116602085015260ff8160a01c1615156040850152611b416060850160ff8360a81c16614817565b80518252602081015161488c6020840182614839565b6001600160a01b0391909116815260200190565b6001600160a01b0385811682528416602082015282151560408201526080810161148e6060830184614817565b6001600160a01b039586168152938516602085015260408401929092526060830152909116608082015260a00190565b6001600160a01b039485168152602081019390935292166040820152606081019190915260800190565b6001600160a01b03958616815260208101949094529190931660408301526060820192909252608081019190915260a00190565b600060018060a01b0386168252846020830152608060408301526149d860808301856146f5565b8281036060840152611d0081856147b6565b600060018060a01b038716825285602083015260a06040830152614a1160a08301866146f5565b8281036060840152614a2381866147b6565b9150508260808301529695505050505050565b600060c08252614a4960c0830187614738565b8281036020840152614a5b81876147e5565b90508281036040840152614a6f81866147b6565b91505061148e60608301846148cc565b600060c08252614a9260c0830187614738565b905060ff8516602083015283604083015261148e60608301846148cc565b6000610100808352614ac48184018a614738565b91505060ff8716602083015260ff86166040830152846060830152836080830152611d0060a08301846148cc565b600060c08252614b0560c0830188614771565b8281036020840152614b1781886147e5565b838103604085015285815290506001600160fb1b03851115614b37578182fd5b602085028087602084013701602001908152614b5660608301846148cc565b9695505050505050565b600060c08252614a9260c0830187614771565b604080825283519082018190526000906020906060840190828701845b82811015614bb657614ba3848351614854565b6080939093019290840190600101614b90565b50505083810382850152614b568186614738565b60c08082528554908201819052600086815260208120909160e0840190835b81811015614c1157614bfb8385614891565b6002939093019260809290920191600101614be9565b5050602084018790526001600160a01b0386166040850152915061148e905060608301846148cc565b93845260208401929092526001600160a01b031660408301521515606082015260800190565b85815260208082018690526080604083018190528201849052600090859060a08401835b87811015614cb2578335614c978161571f565b6001600160a01b031682529282019290820190600101614c84565b506001600160a01b03959095166060949094019390935250919695505050505050565b600060208252610cb860208301846147b6565b901515815260200190565b91151582521515602082015260400190565b90815260200190565b6000602080835283518082850152825b81811015614d3a57858101830151858201604001528201614d1e565b81811115614d4b5783604083870101525b50601f01601f1916929092016040019392505050565b6020808252600f908201526e119bdc99d955985b081b1bd8dad959608a1b604082015260600190565b60208082526023908201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260408201526265737360e81b606082015260800190565b6020808252600d908201526c125b9d985b1a5908185cdcd95d609a1b604082015260600190565b6020808252600d908201526c29bbb0b8103930ba329037b7b160991b604082015260600190565b6020808252600c908201526b24b73b30b634b2103830b4b960a11b604082015260600190565b60208082526022908201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604082015261737360f01b606082015260800190565b60208082526017908201527f4d696e74207175616e74697479203c206d696e20717479000000000000000000604082015260600190565b602080825260089082015267125b881c9958dbdb60c21b604082015260600190565b60208082526014908201527362417373657420717479203c206d696e2071747960601b604082015260600190565b602080825260149082015273092dce0eae840c2e4e4c2f240dad2e6dac2e8c6d60631b604082015260600190565b60208082526027908201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316040820152663238206269747360c81b606082015260800190565b6020808252600c908201526b4e756c6c206164647265737360a01b604082015260600190565b60208082526018908201527f4f757470757420717479203c206d696e696d756d207174790000000000000000604082015260600190565b60208082526017908201527f4d75737420626520736176696e6773206d616e61676572000000000000000000604082015260600190565b6020808252601390820152722932b232b6b83a34b7b7103930ba329037b7b160691b604082015260600190565b60208082526019908201527f4f6e6c7920676f7665726e6f722063616e206578656375746500000000000000604082015260600190565b602080825260139082015272125b9d985b1a5908185c9c985e481a5b9c1d5d606a1b604082015260600190565b6020808252600e908201526d26b0bc103bb2b4b3b43a1037b7b160911b604082015260600190565b602080825260099082015268556e6865616c74687960b81b604082015260600190565b6020808252601690820152754d75737420636f6c6c65637420736f6d657468696e6760501b604082015260600190565b6020808252600e908201526d4d757374206265203c3d2032302560901b604082015260600190565b6020808252600b908201526a04f7574707574203d3d20360ac1b604082015260600190565b602080825260119082015270125b9d985b1a59081c9958da5c1a595b9d607a1b604082015260600190565b602080825260159082015274496e76616c69642073776170207175616e7469747960581b604082015260600190565b6020808252601490820152735a65726f206d4173736574207175616e7469747960601b604082015260600190565b60208082526021908201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736040820152607360f81b606082015260800190565b6020808252600f908201526e111d5c1b1a58d85d1948185cdcd95d608a1b604082015260600190565b60208082526025908201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604082015264647265737360d81b606082015260800190565b6020808252600e908201526d26b4b7103bb2b4b3b43a1037b7b160911b604082015260600190565b60208082526024908201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646040820152637265737360e01b606082015260800190565b60208082526006908201526505174793d3d360d41b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6020808252601490820152735a65726f206f7574707574207175616e7469747960601b604082015260600190565b60208082526018908201527f4d7573742072656465656d20736f6d65206d4173736574730000000000000000604082015260600190565b6020808252818101527f52656465656d206d417373657420717479203e206d6178207175616e74697479604082015260600190565b6020808252601f908201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604082015260600190565b918252602082015260400190565b948552602085019390935260408401919091526060830152608082015260a00190565b938452602084019290925260408301526001600160a01b0316606082015260800190565b948552602085019390935260408401919091526001600160a01b031660608301521515608082015260a00190565b60c081016154c88285614854565b610cb86080830184614839565b60e081016154e38287614854565b6001600160801b03851660808301528360a08301528260c083015295945050505050565b606081016108f282846148cc565b6001600160801b0392831681529116602082015260400190565b85815261012081016155446020830187614854565b61555160a0830186614839565b6001600160a01b039390931660e082015261010001529392505050565b85815261012081016155446020830187614891565b6001600160401b03948516815292841660208401529083166040830152909116606082015260800190565b60ff91909116815260200190565b60006001600160801b038083168185168083038211156155de576155de6156f3565b01949350505050565b600082198211156155fa576155fa6156f3565b500190565b60008261561a57634e487b7160e01b81526012600452602481fd5b500490565b6000816000190483118215151615615639576156396156f3565b500290565b60006001600160801b038381169083168181101561565e5761565e6156f3565b039392505050565b600082821015615678576156786156f3565b500390565b60006001600160401b038381169083168181101561565e5761565e6156f3565b6002810460018216806156b157607f821691505b602082108114156156d257634e487b7160e01b600052602260045260246000fd5b50919050565b60006000198214156156ec576156ec6156f3565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461241857600080fdfea2646970667358221220af3c4c0b4e5eb78b3bd030aeca63dd38ef79a65a2ef13e1484d268c12f499f7764736f6c63430008000033000000000000000000000000afce80b19a8ce13dec0739a1aab7a028d6845eb3

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102f15760003560e01c80636d5d6eb11161019d578063aa5d27e9116100e9578063cd6ef2b0116100a2578063dd62ed3e1161007c578063dd62ed3e1461066e578063e5555b8f14610681578063edc832b314610694578063f74bfe8e1461069c576102f1565b8063cd6ef2b01461063d578063d5bcb9b514610653578063d7d5226614610666576102f1565b8063aa5d27e9146105c7578063ab06346c146105da578063af290bd4146105fa578063bdfbe29c1461060d578063c3f909d414610620578063c4db7fa014610635576102f1565b8063905e891411610156578063a1c2515111610130578063a1c2515114610579578063a3f5c1d21461058c578063a457c2d7146105a1578063a9059cbb146105b4576102f1565b8063905e89141461054b57806395d89b411461055e578063969642b914610566576102f1565b80636d5d6eb1146104e45780636fb3e89c146104f757806370a082311461050a57806372ea90761461051d57806378aa987e146105305780637e8901ea14610543576102f1565b806326bbe60a1161025c57806343bcfab61161021557806354cf2aeb116101ef57806354cf2aeb146104b4578063598362f0146104bc578063674a64e0146104d45780636c36581c146104dc576102f1565b806343bcfab61461048657806344e3fa3c14610499578063458f5815146104ac576102f1565b806326bbe60a146104015780632a2fab22146104145780632f91a7241461042a578063313ce5671461044a57806339509351146104525780633e37bcbc14610465576102f1565b806313888565116102ae578063138885651461039f57806318160ddd146103a75780631820783d146103af5780631d3ce398146103c2578063213c501a146103d857806323b872dd146103ee576102f1565b80630357359c146102f657806304de5a731461032257806306fdde0314610342578063095ea7b3146103575780630b78f9c014610377578063119849cf1461038c575b600080fd5b61030961030436600461456b565b6106af565b60405161031994939291906148f6565b60405180910390f35b610335610330366004614449565b6106ff565b6040516103199190614d05565b61034a610847565b6040516103199190614d0e565b61036a610365366004614381565b6108da565b6040516103199190614ce8565b61038a6103853660046146b1565b6108f8565b005b61033561039a366004614381565b61098c565b610335610a56565b610335610a5c565b61038a6103bd36600461456b565b610a62565b6103ca610ad2565b604051610319929190614b73565b6103e0610c2f565b604051610319929190615515565b61036a6103fc3660046142b2565b610c49565b61038a61040f366004614242565b610cbf565b61041c610d69565b604051610319929190615437565b61043d610438366004614242565b610e20565b60405161031991906155ae565b61043d610e35565b61036a610460366004614381565b610e3e565b610478610473366004614242565b610e8d565b6040516103199291906154ba565b6103356104943660046143ac565b611018565b61038a6104a73660046146b1565b611079565b6103356110fd565b610335611103565b6104c4611109565b6040516103199493929190615583565b610335611137565b61043d61113d565b6103e06104f236600461456b565b611146565b61038a6105053660046143f5565b61117b565b610335610518366004614242565b6111f9565b61033561052b3660046142b2565b611218565b61033561053e366004614381565b6113aa565b61041c611497565b61038a610559366004614350565b611640565b61034a61168a565b61038a610574366004614242565b611699565b61038a610587366004614539565b611714565b61059461182a565b60405161031991906148e2565b61036a6105af366004614381565b61184e565b61036a6105c2366004614381565b61189d565b6103356105d53660046144b1565b6118b1565b6105ed6105e836600461459b565b611979565b6040516103199190614cd5565b6103356106083660046144b1565b6119c2565b61038a61061b366004614350565b611a70565b610628611ab7565b6040516103199190615507565b61038a611acc565b610645611b47565b604051610319929190614cf3565b6103356106613660046142f2565b611b5a565b610594611bbd565b61033561067c36600461427a565b611bd2565b61033561068f366004614449565b611bfd565b610645611d0b565b6103356106aa3660046143ac565b611d1d565b603f81815481106106bf57600080fd5b6000918252602090912060029091020180546001909101546001600160a01b0391821692509081169060ff600160a01b8204811691600160a81b90041684565b600081801580159061071057508085145b6107355760405162461bcd60e51b815260040161072c90615077565b60405180910390fd5b6000610773878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250611d6692505050565b506038549091506000906201000090046001600160a01b031663d176d694604084898961079e611f7c565b6040518663ffffffff1660e01b81526004016107be959493929190614af2565b60206040518083038186803b1580156107d657600080fd5b505afa1580156107ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061080e9190614583565b9050610830603a54670de0b6b3a76400006108299190615666565b8290611fce565b61083b9060016155e7565b98975050505050505050565b6060603680546108569061569d565b80601f01602080910402602001604051908101604052809291908181526020018280546108829061569d565b80156108cf5780601f106108a4576101008083540402835291602001916108cf565b820191906000526020600020905b8154815290600101906020018083116108b257829003601f168201915b505050505090505b90565b60006108ee6108e7611fed565b8484611ff1565b5060015b92915050565b6109006120a5565b603b548211156109225760405162461bcd60e51b815260040161072c90614df4565b603b548111156109445760405162461bcd60e51b815260040161072c90615013565b603a829055603c8190556040517f64f84976d9c917a44796104a59950fdbd9b3c16a5dd348b546d738301f6bd068906109809084908490615437565b60405180910390a15050565b60008082116109ad5760405162461bcd60e51b815260040161072c9061530f565b60006109b8846120df565b506038549091506201000090046001600160a01b0316637910213b604083866109df611f7c565b6040518563ffffffff1660e01b81526004016109fe9493929190614b60565b60206040518083038186803b158015610a1657600080fd5b505afa158015610a2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a4e9190614583565b949350505050565b603e5481565b60355490565b610a6a6120a5565b6702c68af0bb140000811115610a925760405162461bcd60e51b815260040161072c9061511f565b603d8190556040517f2f5a6b1defeafd30e7568ea5c176aa0702b0af5b00ba41fa20e58b2c72e8afe790610ac7908390614d05565b60405180910390a150565b606080603f604081805480602002602001604051908101604052809291908181526020016000905b82821015610bb1576000848152602090819020604080516080810182526002860290920180546001600160a01b03908116845260018201549081169484019490945260ff600160a01b8504811615159284019290925291926060840191600160a81b909104166007811115610b7f57634e487b7160e01b600052602160045260246000fd5b6007811115610b9e57634e487b7160e01b600052602160045260246000fd5b8152505081526020019060010190610afa565b50505050915080805480602002602001604051908101604052809291908181526020016000905b82821015610c2157600084815260209081902060408051808201909152908401546001600160801b038082168352600160801b9091041681830152825260019092019101610bd8565b505050509050915091509091565b6045546001600160801b0380821691600160801b90041682565b6000610c56848484612209565b610cb484610c62611fed565b6001600160a01b03871660009081526034602052604081208691610c84611fed565b6001600160a01b03166001600160a01b0316815260200190815260200160002054610caf9190615666565b611ff1565b5060015b9392505050565b610cc76120a5565b603854600160b01b900460ff1615610cf15760405162461bcd60e51b815260040161072c90614d61565b6001600160a01b038116610d175760405162461bcd60e51b815260040161072c90614f7f565b6038805462010000600160b01b031916620100006001600160a01b038416021790556040517f2e137a82d7f7fe8a4c453313f3d08557c162ad9d78219a2e937e318b41e12f7a90610ac79083906148e2565b600080610d746122f4565b603e546001811115610e1157610d8b600182615666565b6001603e559250610d9c3384612323565b307f7d3ff197e9071095bd36b627028ef523ecf46fcbf17cbde745a4b65aec88b6bc33856000604051908082528060200260200182016040528015610deb578160200160208202803683370190505b5060408051600081526020810191829052610e08949392916149b1565b60405180910390a25b610e19610a5c565b9150509091565b60416020526000908152604090205460ff1681565b60385460ff1690565b60006108ee610e4b611fed565b848460346000610e59611fed565b6001600160a01b03908116825260208083019390935260409182016000908120918b1681529252902054610caf91906155e7565b610e95614169565b610e9d614191565b6001600160a01b038316600090815260416020526040902054603f805460ff9092169182908110610ede57634e487b7160e01b600052603260045260246000fd5b600091825260209182902060408051608081018252600290930290910180546001600160a01b03908116845260018201549081169484019490945260ff600160a01b8504811615159284019290925291926060840191600160a81b909104166007811115610f5c57634e487b7160e01b600052602160045260246000fd5b6007811115610f7b57634e487b7160e01b600052602160045260246000fd5b815250509250836001600160a01b031683600001516001600160a01b031614610fb65760405162461bcd60e51b815260040161072c90614dcd565b60408160ff1681548110610fda57634e487b7160e01b600052603260045260246000fd5b6000918252602091829020604080518082019091529101546001600160801b038082168352600160801b909104169181019190915292949293505050565b603854600090610100900460ff166110425760405162461bcd60e51b815260040161072c9061532f565b6038805461ff00191690556110556123d7565b6110618585858561241b565b6038805461ff00191661010017905595945050505050565b6110816120a5565b73c3ff9c67fd926e84bf0555f38da7ceb0a1c6524963e2a5f044604484846110a7612783565b60646040518663ffffffff1660e01b81526004016110c9959493929190615445565b60006040518083038186803b1580156110e157600080fd5b505af41580156110f5573d6000803e3d6000fd5b505050505050565b603c5481565b603a5481565b6044546001600160401b0380821691600160401b8104821691600160801b8204811691600160c01b90041684565b603d5481565b60425460ff1681565b6040818154811061115657600080fd5b6000918252602090912001546001600160801b038082169250600160801b9091041682565b6111836120a5565b60405163a5bee44b60e01b815273c3ff9c67fd926e84bf0555f38da7ceb0a1c652499063a5bee44b906111c490603f90604190889088908890600401614c60565b60006040518083038186803b1580156111dc57600080fd5b505af41580156111f0573d6000803e3d6000fd5b50505050505050565b6001600160a01b0381166000908152603360205260409020545b919050565b6000826001600160a01b0316846001600160a01b0316141561124c5760405162461bcd60e51b815260040161072c90614e1b565b6000821161126c5760405162461bcd60e51b815260040161072c90615197565b60006040805480602002602001604051908101604052809291908181526020016000905b828210156112d957600084815260209081902060408051808201909152908401546001600160801b038082168352600160801b9091041681830152825260019092019101611290565b50505050905060006112ea866120df565b50905060006112f8866120df565b509050603860029054906101000a90046001600160a01b03166001600160a01b0316630e3c01d384848489603a5461132e611f7c565b6040518763ffffffff1660e01b815260040161134f96959493929190614ab0565b604080518083038186803b15801561136657600080fd5b505afa15801561137a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061139e91906146d2565b50979650505050505050565b60008082116113cb5760405162461bcd60e51b815260040161072c9061530f565b60006113d6846120df565b50905060006113f0603a54856128c090919063ffffffff16565b6038549091506201000090046001600160a01b03166350494dc06040846114178589615666565b61141f611f7c565b6040518563ffffffff1660e01b815260040161143e9493929190614b60565b60206040518083038186803b15801561145657600080fd5b505afa15801561146a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061148e9190614583565b95945050505050565b6000806114a26122f4565b6114aa6128d5565b603854610100900460ff166114d15760405162461bcd60e51b815260040161072c9061532f565b6038805461ff0019169081905560609073c3ff9c67fd926e84bf0555f38da7ceb0a1c6524990638b8029b490603f906040906201000090046001600160a01b031661151a611f7c565b6040518563ffffffff1660e01b81526004016115399493929190614bca565b60006040518083038186803b15801561155157600080fd5b505af4158015611565573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261158d91908101906145ec565b9093509050826115af5760405162461bcd60e51b815260040161072c906150ef565b6115b93384612323565b307f7d3ff197e9071095bd36b627028ef523ecf46fcbf17cbde745a4b65aec88b6bc33856000604051908082528060200260200182016040528015611608578160200160208202803683370190505b508560405161161a94939291906149b1565b60405180910390a261162a610a5c565b6038805461ff0019166101001790559293915050565b6116486120a5565b60405163ee60ee2b60e01b815273c3ff9c67fd926e84bf0555f38da7ceb0a1c652499063ee60ee2b906110c990604390603f906041908890889060040161548c565b6060603780546108569061569d565b6116a16120a5565b604051634c1e9da160e11b815273c3ff9c67fd926e84bf0555f38da7ceb0a1c652499063983d3b42906116e190604390603f906041908790600401615468565b60006040518083038186803b1580156116f957600080fd5b505af415801561170d573d6000803e3d6000fd5b5050505050565b61171c6120a5565b60405461172a90600261561f565b61173c90670de0b6b3a76400006155ff565b826001600160801b031611156117645760405162461bcd60e51b815260040161072c906152a3565b60405461177390600190615666565b61178590670de0b6b3a76400006155ff565b816001600160801b031610156117ad5760405162461bcd60e51b815260040161072c906150a4565b6040805180820182526001600160801b038481168083528482166020909301839052604580546fffffffffffffffffffffffffffffffff1916909117909116600160801b909202919091179055517f1633022fee8dcf5a3cdeb5f1b49d5b734a3cfef7fc093e30cfdd28ddde8cd136906109809084908490615515565b7f000000000000000000000000afce80b19a8ce13dec0739a1aab7a028d6845eb381565b60006108ee61185b611fed565b848460346000611869611fed565b6001600160a01b03908116825260208083019390935260409182016000908120918b1681529252902054610caf9190615666565b60006108ee6118aa611fed565b8484612209565b603854600090610100900460ff166118db5760405162461bcd60e51b815260040161072c9061532f565b6038805461ff00191690556118ee6123d7565b61195f87878080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808b0282810182019093528a82529093508a9250899182918501908490808284376000920191909152508892508791506129269050565b6038805461ff001916610100179055979650505050505050565b603854606090610100900460ff166119a35760405162461bcd60e51b815260040161072c9061532f565b6038805461ff00191690556119b66123d7565b61106185858585612d96565b603854600090610100900460ff166119ec5760405162461bcd60e51b815260040161072c9061532f565b6038805461ff00191690556119ff6128d5565b61195f87878080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808b0282810182019093528a82529093508a9250899182918501908490808284376000920191909152508892508791506132819050565b611a786120a5565b604051638d18aef960e01b815273c3ff9c67fd926e84bf0555f38da7ceb0a1c6524990638d18aef9906110c990603f9060419087908790600401614c3a565b611abf6141a8565b611ac7611f7c565b905090565b611ad46120a5565b73c3ff9c67fd926e84bf0555f38da7ceb0a1c652496318068e406044611af8612783565b6040518363ffffffff1660e01b8152600401611b15929190615437565b60006040518083038186803b158015611b2d57600080fd5b505af4158015611b41573d6000803e3d6000fd5b50505050565b60435460ff808216916101009004169091565b603854600090610100900460ff16611b845760405162461bcd60e51b815260040161072c9061532f565b6038805461ff0019169055611b976128d5565b611ba486868686866136ed565b6038805461ff0019166101001790559695505050505050565b6038546201000090046001600160a01b031681565b6001600160a01b03918216600090815260346020908152604080832093909416825291909152205490565b6000818015801590611c0e57508085145b611c2a5760405162461bcd60e51b815260040161072c90614f0a565b6000611c68878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250611d6692505050565b506038549091506201000090046001600160a01b031663b7ecbf726040838888611c90611f7c565b6040518663ffffffff1660e01b8152600401611cb0959493929190614af2565b60206040518083038186803b158015611cc857600080fd5b505afa158015611cdc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d009190614583565b979650505050505050565b60435460ff8082169161010090041682565b603854600090610100900460ff16611d475760405162461bcd60e51b815260040161072c9061532f565b6038805461ff0019169055611d5a6128d5565b61106185858585613beb565b80516060908190806001600160401b03811115611d9357634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611dbc578160200160208202803683370190505b509250806001600160401b03811115611de557634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611e1e57816020015b611e0b614169565b815260200190600190039081611e035790505b50915060005b81811015611f7557611e5c858281518110611e4f57634e487b7160e01b600052603260045260246000fd5b60200260200101516120df565b858381518110611e7c57634e487b7160e01b600052603260045260246000fd5b60200260200101858481518110611ea357634e487b7160e01b600052603260045260246000fd5b602090810291909101019190915260ff90911690526000611ec58260016155e7565b90505b82811015611f6257858181518110611ef057634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b0316868381518110611f2157634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b03161415611f505760405162461bcd60e51b815260040161072c90615235565b80611f5a816156d8565b915050611ec8565b5080611f6d816156d8565b915050611e24565b5050915091565b611f846141a8565b6040518060400160405280611f97612783565b8152604080518082019091526045546001600160801b038082168352600160801b9091041660208281019190915290910152905090565b600081611fe3670de0b6b3a76400008561561f565b610cb891906155ff565b3390565b6001600160a01b0383166120175760405162461bcd60e51b815260040161072c906152cb565b6001600160a01b03821661203d5760405162461bcd60e51b815260040161072c90614e41565b6001600160a01b0380841660008181526034602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590612098908590614d05565b60405180910390a3505050565b6120ad613f0e565b6001600160a01b0316336001600160a01b0316146120dd5760405162461bcd60e51b815260040161072c90615040565b565b60006120e9614169565b6001600160a01b038316600090815260416020526040902054603f805460ff9092169350908390811061212c57634e487b7160e01b600052603260045260246000fd5b600091825260209182902060408051608081018252600290930290910180546001600160a01b03908116845260018201549081169484019490945260ff600160a01b8504811615159284019290925291926060840191600160a81b9091041660078111156121aa57634e487b7160e01b600052602160045260246000fd5b60078111156121c957634e487b7160e01b600052602160045260246000fd5b815250509050826001600160a01b031681600001516001600160a01b0316146122045760405162461bcd60e51b815260040161072c90614dcd565b915091565b6001600160a01b03831661222f5760405162461bcd60e51b815260040161072c9061525e565b6001600160a01b0382166122555760405162461bcd60e51b815260040161072c90614d8a565b6001600160a01b0383166000908152603360205260408120805483929061227d908490615666565b90915550506001600160a01b038216600090815260336020526040812080548392906122aa9084906155e7565b92505081905550816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516120989190614d05565b336122fd613fa1565b6001600160a01b0316146120dd5760405162461bcd60e51b815260040161072c90614fdc565b6001600160a01b0382166123495760405162461bcd60e51b815260040161072c90615400565b806035600082825461235b91906155e7565b90915550506001600160a01b038216600090815260336020526040812080548392906123889084906155e7565b90915550506040516001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906123cb908590614d05565b60405180910390a35050565b6040805180820190915260435460ff808216158015845261010090920416151560208301526124185760405162461bcd60e51b815260040161072c90614eba565b50565b60006001600160a01b0382166124435760405162461bcd60e51b815260040161072c9061516c565b600084116124635760405162461bcd60e51b815260040161072c9061530f565b60006040805480602002602001604051908101604052809291908181526020016000905b828210156124d057600084815260209081902060408051808201909152908401546001600160801b038082168352600160801b9091041681830152825260019092019101612487565b5050505090506000806124e2886120df565b9150915060006124fd603a54896128c090919063ffffffff16565b6038549091506201000090046001600160a01b03166350494dc08585612523858d615666565b61252b611f7c565b6040518563ffffffff1660e01b815260040161254a9493929190614a7f565b60206040518083038186803b15801561256257600080fd5b505afa158015612576573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061259a9190614583565b9450868510156125bc5760405162461bcd60e51b815260040161072c90614edc565b600085116125dc5760405162461bcd60e51b815260040161072c90615147565b6125e63389614028565b80603e60008282546125f891906155e7565b90915550600090506126086140d2565b905073c3ff9c67fd926e84bf0555f38da7ceb0a1c65249634e331a548785888860ff168151811061264957634e487b7160e01b600052603260045260246000fd5b60200260200101518b86602001516040518663ffffffff1660e01b815260040161267795949392919061552f565b60006040518083038186803b15801561268f57600080fd5b505af41580156126a3573d6000803e3d6000fd5b505050506126b086614129565b858560ff16815181106126d357634e487b7160e01b600052603260045260246000fd5b6020026020010151602001516126e9919061563e565b60408560ff168154811061270d57634e487b7160e01b600052603260045260246000fd5b600091825260209091200180546001600160801b03928316600160801b029216919091179055825160405133917f105ffcfe6c5fa767ff5a53039fdd9ba80ce97196d4daa0beb1bfbfa0ed838ad89161276e918b918e91908c90899061497d565b60405180910390a25050505050949350505050565b604080516080810182526044546001600160401b038082168352600160401b8204811660208401819052600160801b8304821694840194909452600160c01b909104166060820181905260009290428111156128ad57825160408401516000806127f66001600160401b03841642615666565b612800848761567d565b6001600160401b031691509150836001600160401b0316866001600160401b03161115612871578082612833868961567d565b6001600160401b0316612846919061561f565b61285091906155ff565b612863906001600160401b0386166155e7565b9750505050505050506108d7565b808261287d888761567d565b6001600160401b0316612890919061561f565b61289a91906155ff565b612863906001600160401b038616615666565b506001600160401b031691506108d79050565b6000610cb88383670de0b6b3a7640000614152565b6040805180820190915260435460ff808216158015808552610100909304909116151560208401529061290a57508060200151155b6124185760405162461bcd60e51b815260040161072c906150cc565b60006001600160a01b03821661294e5760405162461bcd60e51b815260040161072c9061516c565b8351801580159061295f5750855181145b61297b5760405162461bcd60e51b815260040161072c90615077565b6000841161299b5760405162461bcd60e51b815260040161072c9061530f565b6000806129a788611d66565b6040805481516020808302820181018452828252949650929450600093849084015b82821015612a1257600084815260209081902060408051808201909152908401546001600160801b038082168352600160801b90910416818301528252600190920191016129c9565b50506038549293506000926201000090046001600160a01b0316915063d176d694905083868c612a40611f7c565b6040518563ffffffff1660e01b8152600401612a5f9493929190614a36565b60206040518083038186803b158015612a7757600080fd5b505afa158015612a8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aaf9190614583565b9050612aca603a54670de0b6b3a76400006108299190615666565b95506000612ad88288615666565b905060008711612afa5760405162461bcd60e51b815260040161072c90615394565b612b056001886155e7565b965088871115612b275760405162461bcd60e51b815260040161072c906153cb565b612b313388614028565b80603e6000828254612b4391906155e7565b9091555060009050612b536140d2565b905060005b87811015612d3d576000878281518110612b8257634e487b7160e01b600052603260045260246000fd5b6020026020010151905073c3ff9c67fd926e84bf0555f38da7ceb0a1c65249634e331a548e8481518110612bc657634e487b7160e01b600052603260045260246000fd5b6020026020010151898581518110612bee57634e487b7160e01b600052603260045260246000fd5b6020026020010151898560ff1681518110612c1957634e487b7160e01b600052603260045260246000fd5b60200260200101518f88602001516040518663ffffffff1660e01b8152600401612c4795949392919061552f565b60006040518083038186803b158015612c5f57600080fd5b505af4158015612c73573d6000803e3d6000fd5b50505050612ca78d8381518110612c9a57634e487b7160e01b600052603260045260246000fd5b6020026020010151614129565b868260ff1681518110612cca57634e487b7160e01b600052603260045260246000fd5b602002602001015160200151612ce0919061563e565b60408260ff1681548110612d0457634e487b7160e01b600052603260045260246000fd5b600091825260209091200180546001600160801b03928316600160801b0292169190911790555080612d35816156d8565b915050612b58565b50336001600160a01b03167fdf5bf345d5d6eedd0e8667d799d60af65d7127e3b0417e04bef4d954d2a4750e8a8a8f8f87604051612d7f9594939291906149ea565b60405180910390a250505050505050949350505050565b60606001600160a01b038216612dbe5760405162461bcd60e51b815260040161072c9061516c565b60008511612dde5760405162461bcd60e51b815260040161072c9061530f565b6000612df5603c54876128c090919063ffffffff16565b90506000612e038288615666565b9050612e0f3388614028565b81603e6000828254612e2191906155e7565b9091555060009050612e316140d2565b90506000828260000151612e4591906155e7565b905060006040805480602002602001604051908101604052809291908181526020016000905b82821015612eb457600084815260209081902060408051808201909152908401546001600160801b038082168352600160801b9091041681830152825260019092019101612e6b565b5050505090506000815190506000816001600160401b03811115612ee857634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015612f11578160200160208202803683370190505b509050816001600160401b03811115612f3a57634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015612f63578160200160208202803683370190505b50975060005b8281101561323f5760008588868481518110612f9557634e487b7160e01b600052603260045260246000fd5b6020026020010151602001516001600160801b0316612fb4919061561f565b612fbe91906155ff565b905060018111612fe05760405162461bcd60e51b815260040161072c90615147565b612feb600182615666565b90508c8c8381811061300d57634e487b7160e01b600052603260045260246000fd5b905060200201358110156130335760405162461bcd60e51b815260040161072c90614edc565b80603f838154811061305557634e487b7160e01b600052603260045260246000fd5b60009182526020909120600290910201548b516001600160a01b03909116908c908590811061309457634e487b7160e01b600052603260045260246000fd5b602002602001018585815181106130bb57634e487b7160e01b600052603260045260246000fd5b60200260200101826001600160a01b03166001600160a01b031681525082815250505073c3ff9c67fd926e84bf0555f38da7ceb0a1c65249634e331a5482603f858154811061311a57634e487b7160e01b600052603260045260246000fd5b906000526020600020906002020188868151811061314857634e487b7160e01b600052603260045260246000fd5b60200260200101518f8c602001516040518663ffffffff1660e01b815260040161317695949392919061556e565b60006040518083038186803b15801561318e57600080fd5b505af41580156131a2573d6000803e3d6000fd5b505050506131af81614129565b8583815181106131cf57634e487b7160e01b600052603260045260246000fd5b6020026020010151602001516131e5919061563e565b6040838154811061320657634e487b7160e01b600052603260045260246000fd5b600091825260209091200180546001600160801b03928316600160801b0292169190911790555080613237816156d8565b915050612f69565b50336001600160a01b03167fdf5bf345d5d6eedd0e8667d799d60af65d7127e3b0417e04bef4d954d2a4750e8a8e848c8c604051612d7f9594939291906149ea565b60006001600160a01b0382166132a95760405162461bcd60e51b815260040161072c9061516c565b835180158015906132ba5750855181145b6132d65760405162461bcd60e51b815260040161072c90614f0a565b6000806132e288611d66565b6040805481516020808302820181018452828252949650929450600093849084015b8282101561334d57600084815260209081902060408051808201909152908401546001600160801b038082168352600160801b9091041681830152825260019092019101613304565b505050509050600061335d6140d2565b90506000856001600160401b0381111561338757634e487b7160e01b600052604160045260246000fd5b6040519080825280602002602001820160405280156133b0578160200160208202803683370190505b50905060005b868110156135ba5760008b82815181106133e057634e487b7160e01b600052603260045260246000fd5b6020026020010151905060008111156135a757600087838151811061341557634e487b7160e01b600052603260045260246000fd5b602002602001015190506000868260ff168151811061344457634e487b7160e01b600052603260045260246000fd5b60200260200101519050600088858151811061347057634e487b7160e01b600052603260045260246000fd5b60200260200101519050600073c3ff9c67fd926e84bf0555f38da7ceb0a1c65249634e3d3913838560000151888c602001516040518563ffffffff1660e01b81526004016134c194939291906154d5565b60206040518083038186803b1580156134d957600080fd5b505af41580156134ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135119190614583565b90508087878151811061353457634e487b7160e01b600052603260045260246000fd5b60200260200101818152505061354981614129565b836020015161355891906155bc565b60408560ff168154811061357c57634e487b7160e01b600052603260045260246000fd5b600091825260209091200180546001600160801b03928316600160801b029216919091179055505050505b50806135b2816156d8565b9150506133b6565b506038546201000090046001600160a01b031663b7ecbf728487846135dd611f7c565b6040518563ffffffff1660e01b81526004016135fc9493929190614a36565b60206040518083038186803b15801561361457600080fd5b505afa158015613628573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061364c9190614583565b96508887101561366e5760405162461bcd60e51b815260040161072c90614e83565b6000871161368e5760405162461bcd60e51b815260040161072c906151c6565b6136988888612323565b336001600160a01b03167f7d3ff197e9071095bd36b627028ef523ecf46fcbf17cbde745a4b65aec88b6bc89898e8e6040516136d794939291906149b1565b60405180910390a2505050505050949350505050565b60006001600160a01b0382166137155760405162461bcd60e51b815260040161072c9061516c565b846001600160a01b0316866001600160a01b031614156137475760405162461bcd60e51b815260040161072c90614e1b565b600084116137675760405162461bcd60e51b815260040161072c90615197565b60006040805480602002602001604051908101604052809291908181526020016000905b828210156137d457600084815260209081902060408051808201909152908401546001600160801b038082168352600160801b909104168183015282526001909201910161378b565b5050505090506000806137e6896120df565b915091506000806137f68a6120df565b9150915060006138046140d2565b9050600073c3ff9c67fd926e84bf0555f38da7ceb0a1c65249634e3d391386898960ff168151811061384657634e487b7160e01b600052603260045260246000fd5b6020026020010151600001518e86602001516040518563ffffffff1660e01b815260040161387794939291906154d5565b60206040518083038186803b15801561388f57600080fd5b505af41580156138a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138c79190614583565b90506138d281614129565b878760ff16815181106138f557634e487b7160e01b600052603260045260246000fd5b60200260200101516020015161390b91906155bc565b60408760ff168154811061392f57634e487b7160e01b600052603260045260246000fd5b9060005260206000200160000160106101000a8154816001600160801b0302191690836001600160801b031602179055506000603860029054906101000a90046001600160a01b03166001600160a01b0316630e3c01d389898886603a54613995611f7c565b6040518763ffffffff1660e01b81526004016139b696959493929190614ab0565b604080518083038186803b1580156139cd57600080fd5b505afa1580156139e1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a0591906146d2565b90995090508a891015613a2a5760405162461bcd60e51b815260040161072c90614fa5565b60008911613a4a5760405162461bcd60e51b815260040161072c90615366565b73c3ff9c67fd926e84bf0555f38da7ceb0a1c65249634e331a548a868b8960ff1681518110613a8957634e487b7160e01b600052603260045260246000fd5b60200260200101518e88602001516040518663ffffffff1660e01b8152600401613ab795949392919061552f565b60006040518083038186803b158015613acf57600080fd5b505af4158015613ae3573d6000803e3d6000fd5b50505050613af089614129565b888660ff1681518110613b1357634e487b7160e01b600052603260045260246000fd5b602002602001015160200151613b29919061563e565b60408660ff1681548110613b4d57634e487b7160e01b600052603260045260246000fd5b600091825260209091200180546001600160801b03928316600160801b0292169190911790556040830151613b839082906155e7565b603e81905550336001600160a01b03167f1eeaa4acf3c225a4033105c2647625dbb298dec93b14e16253c4231e26c02b1d876000015186600001518c858f604051613bd2959493929190614923565b60405180910390a2505050505050505095945050505050565b60006001600160a01b038216613c135760405162461bcd60e51b815260040161072c9061516c565b60008411613c335760405162461bcd60e51b815260040161072c9061530f565b60006040805480602002602001604051908101604052809291908181526020016000905b82821015613ca057600084815260209081902060408051808201909152908401546001600160801b038082168352600160801b9091041681830152825260019092019101613c57565b505050509050600080613cb2886120df565b915091506000613cc06140d2565b9050600073c3ff9c67fd926e84bf0555f38da7ceb0a1c65249634e3d391384878760ff1681518110613d0257634e487b7160e01b600052603260045260246000fd5b6020026020010151600001518c86602001516040518563ffffffff1660e01b8152600401613d3394939291906154d5565b60206040518083038186803b158015613d4b57600080fd5b505af4158015613d5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d839190614583565b6038549091506201000090046001600160a01b0316637910213b868684613da8611f7c565b6040518563ffffffff1660e01b8152600401613dc79493929190614a7f565b60206040518083038186803b158015613ddf57600080fd5b505afa158015613df3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e179190614583565b955087861015613e395760405162461bcd60e51b815260040161072c90614e83565b613e4281614129565b858560ff1681518110613e6557634e487b7160e01b600052603260045260246000fd5b602002602001015160200151613e7b91906155bc565b60408560ff1681548110613e9f57634e487b7160e01b600052603260045260246000fd5b600091825260209091200180546001600160801b03928316600160801b029216919091179055613ecf8787612323565b336001600160a01b03167f30873c596f54a2e2e09894670d7e1a48b2433c00204f81fbedf557353c36e7c788888d8560405161276e9493929190614953565b60007f000000000000000000000000afce80b19a8ce13dec0739a1aab7a028d6845eb36001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b158015613f6957600080fd5b505afa158015613f7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ac7919061425e565b6040516385acd64160e01b81526000906001600160a01b037f000000000000000000000000afce80b19a8ce13dec0739a1aab7a028d6845eb316906385acd64190614010907f12fe936c77a1e196473c4314f3bed8eeac1d757b319abb85bdda70df35511bf190600401614d05565b60206040518083038186803b158015613f6957600080fd5b6001600160a01b03821661404e5760405162461bcd60e51b815260040161072c906151f4565b6001600160a01b03821660009081526033602052604081208054839290614076908490615666565b92505081905550806035600082825461408f9190615666565b90915550506040516000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906123cb908590614d05565b6140da6141c2565b603e546000816140e8610a5c565b6140f291906155e7565b9050604051806060016040528082815260200161411a603d54846128c090919063ffffffff16565b81526020019290925250905090565b6000600160801b821061414e5760405162461bcd60e51b815260040161072c90614f38565b5090565b60008161415f848661561f565b610a4e91906155ff565b604080516080810182526000808252602082018190529181018290529060608201905b905290565b604080518082019091526000808252602082015290565b60405180604001604052806000815260200161418c614191565b60405180606001604052806000815260200160008152602001600081525090565b60008083601f8401126141f4578081fd5b5081356001600160401b0381111561420a578182fd5b602083019150836020808302850101111561422457600080fd5b9250929050565b80356001600160801b038116811461121357600080fd5b600060208284031215614253578081fd5b8135610cb88161571f565b60006020828403121561426f578081fd5b8151610cb88161571f565b6000806040838503121561428c578081fd5b82356142978161571f565b915060208301356142a78161571f565b809150509250929050565b6000806000606084860312156142c6578081fd5b83356142d18161571f565b925060208401356142e18161571f565b929592945050506040919091013590565b600080600080600060a08688031215614309578081fd5b85356143148161571f565b945060208601356143248161571f565b9350604086013592506060860135915060808601356143428161571f565b809150509295509295909350565b60008060408385031215614362578182fd5b823561436d8161571f565b9150602083013580151581146142a7578182fd5b60008060408385031215614393578182fd5b823561439e8161571f565b946020939093013593505050565b600080600080608085870312156143c1578384fd5b84356143cc8161571f565b9350602085013592506040850135915060608501356143ea8161571f565b939692955090935050565b600080600060408486031215614409578283fd5b83356001600160401b0381111561441e578384fd5b61442a868287016141e3565b909450925050602084013561443e8161571f565b809150509250925092565b6000806000806040858703121561445e578384fd5b84356001600160401b0380821115614474578586fd5b614480888389016141e3565b90965094506020870135915080821115614498578384fd5b506144a5878288016141e3565b95989497509550505050565b600080600080600080608087890312156144c9578081fd5b86356001600160401b03808211156144df578283fd5b6144eb8a838b016141e3565b90985096506020890135915080821115614503578283fd5b5061451089828a016141e3565b90955093505060408701359150606087013561452b8161571f565b809150509295509295509295565b6000806040838503121561454b578182fd5b6145548361422b565b91506145626020840161422b565b90509250929050565b60006020828403121561457c578081fd5b5035919050565b600060208284031215614594578081fd5b5051919050565b600080600080606085870312156145b0578182fd5b8435935060208501356001600160401b038111156145cc578283fd5b6145d8878288016141e3565b90945092505060408501356143ea8161571f565b600080604083850312156145fe578182fd5b825191506020808401516001600160401b038082111561461c578384fd5b818601915086601f83011261462f578384fd5b81518181111561464157614641615709565b8381026040518582820101818110858211171561466057614660615709565b604052828152858101935084860182860187018b101561467e578788fd5b8795505b838610156146a0578051855260019590950194938601938601614682565b508096505050505050509250929050565b600080604083850312156146c3578182fd5b50508035926020909101359150565b600080604083850312156146e4578182fd5b505080516020909101519092909150565b6000815180845260208085019450808401835b8381101561472d5781516001600160a01b031687529582019590820190600101614708565b509495945050505050565b6000815180845260208085019450808401835b8381101561472d5761475e878351614839565b604096909601959082019060010161474b565b6000815480845260208085019450838352808320835b8381101561472d5781546001600160801b038116885260801c8388015260409096019560019182019101614787565b6000815180845260208085019450808401835b8381101561472d578151875295820195908201906001016147c9565b6000815180845260208085019450808401835b8381101561472d57815160ff16875295820195908201906001016147f8565b6008811061483557634e487b7160e01b600052602160045260246000fd5b9052565b80516001600160801b03908116835260209182015116910152565b60018060a01b0380825116835280602083015116602084015250604081015115156040830152606081015161488c6060840182614817565b505050565b60018060a01b038082541683526001820154818116602085015260ff8160a01c1615156040850152611b416060850160ff8360a81c16614817565b80518252602081015161488c6020840182614839565b6001600160a01b0391909116815260200190565b6001600160a01b0385811682528416602082015282151560408201526080810161148e6060830184614817565b6001600160a01b039586168152938516602085015260408401929092526060830152909116608082015260a00190565b6001600160a01b039485168152602081019390935292166040820152606081019190915260800190565b6001600160a01b03958616815260208101949094529190931660408301526060820192909252608081019190915260a00190565b600060018060a01b0386168252846020830152608060408301526149d860808301856146f5565b8281036060840152611d0081856147b6565b600060018060a01b038716825285602083015260a06040830152614a1160a08301866146f5565b8281036060840152614a2381866147b6565b9150508260808301529695505050505050565b600060c08252614a4960c0830187614738565b8281036020840152614a5b81876147e5565b90508281036040840152614a6f81866147b6565b91505061148e60608301846148cc565b600060c08252614a9260c0830187614738565b905060ff8516602083015283604083015261148e60608301846148cc565b6000610100808352614ac48184018a614738565b91505060ff8716602083015260ff86166040830152846060830152836080830152611d0060a08301846148cc565b600060c08252614b0560c0830188614771565b8281036020840152614b1781886147e5565b838103604085015285815290506001600160fb1b03851115614b37578182fd5b602085028087602084013701602001908152614b5660608301846148cc565b9695505050505050565b600060c08252614a9260c0830187614771565b604080825283519082018190526000906020906060840190828701845b82811015614bb657614ba3848351614854565b6080939093019290840190600101614b90565b50505083810382850152614b568186614738565b60c08082528554908201819052600086815260208120909160e0840190835b81811015614c1157614bfb8385614891565b6002939093019260809290920191600101614be9565b5050602084018790526001600160a01b0386166040850152915061148e905060608301846148cc565b93845260208401929092526001600160a01b031660408301521515606082015260800190565b85815260208082018690526080604083018190528201849052600090859060a08401835b87811015614cb2578335614c978161571f565b6001600160a01b031682529282019290820190600101614c84565b506001600160a01b03959095166060949094019390935250919695505050505050565b600060208252610cb860208301846147b6565b901515815260200190565b91151582521515602082015260400190565b90815260200190565b6000602080835283518082850152825b81811015614d3a57858101830151858201604001528201614d1e565b81811115614d4b5783604083870101525b50601f01601f1916929092016040019392505050565b6020808252600f908201526e119bdc99d955985b081b1bd8dad959608a1b604082015260600190565b60208082526023908201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260408201526265737360e81b606082015260800190565b6020808252600d908201526c125b9d985b1a5908185cdcd95d609a1b604082015260600190565b6020808252600d908201526c29bbb0b8103930ba329037b7b160991b604082015260600190565b6020808252600c908201526b24b73b30b634b2103830b4b960a11b604082015260600190565b60208082526022908201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604082015261737360f01b606082015260800190565b60208082526017908201527f4d696e74207175616e74697479203c206d696e20717479000000000000000000604082015260600190565b602080825260089082015267125b881c9958dbdb60c21b604082015260600190565b60208082526014908201527362417373657420717479203c206d696e2071747960601b604082015260600190565b602080825260149082015273092dce0eae840c2e4e4c2f240dad2e6dac2e8c6d60631b604082015260600190565b60208082526027908201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316040820152663238206269747360c81b606082015260800190565b6020808252600c908201526b4e756c6c206164647265737360a01b604082015260600190565b60208082526018908201527f4f757470757420717479203c206d696e696d756d207174790000000000000000604082015260600190565b60208082526017908201527f4d75737420626520736176696e6773206d616e61676572000000000000000000604082015260600190565b6020808252601390820152722932b232b6b83a34b7b7103930ba329037b7b160691b604082015260600190565b60208082526019908201527f4f6e6c7920676f7665726e6f722063616e206578656375746500000000000000604082015260600190565b602080825260139082015272125b9d985b1a5908185c9c985e481a5b9c1d5d606a1b604082015260600190565b6020808252600e908201526d26b0bc103bb2b4b3b43a1037b7b160911b604082015260600190565b602080825260099082015268556e6865616c74687960b81b604082015260600190565b6020808252601690820152754d75737420636f6c6c65637420736f6d657468696e6760501b604082015260600190565b6020808252600e908201526d4d757374206265203c3d2032302560901b604082015260600190565b6020808252600b908201526a04f7574707574203d3d20360ac1b604082015260600190565b602080825260119082015270125b9d985b1a59081c9958da5c1a595b9d607a1b604082015260600190565b602080825260159082015274496e76616c69642073776170207175616e7469747960581b604082015260600190565b6020808252601490820152735a65726f206d4173736574207175616e7469747960601b604082015260600190565b60208082526021908201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736040820152607360f81b606082015260800190565b6020808252600f908201526e111d5c1b1a58d85d1948185cdcd95d608a1b604082015260600190565b60208082526025908201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604082015264647265737360d81b606082015260800190565b6020808252600e908201526d26b4b7103bb2b4b3b43a1037b7b160911b604082015260600190565b60208082526024908201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646040820152637265737360e01b606082015260800190565b60208082526006908201526505174793d3d360d41b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6020808252601490820152735a65726f206f7574707574207175616e7469747960601b604082015260600190565b60208082526018908201527f4d7573742072656465656d20736f6d65206d4173736574730000000000000000604082015260600190565b6020808252818101527f52656465656d206d417373657420717479203e206d6178207175616e74697479604082015260600190565b6020808252601f908201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604082015260600190565b918252602082015260400190565b948552602085019390935260408401919091526060830152608082015260a00190565b938452602084019290925260408301526001600160a01b0316606082015260800190565b948552602085019390935260408401919091526001600160a01b031660608301521515608082015260a00190565b60c081016154c88285614854565b610cb86080830184614839565b60e081016154e38287614854565b6001600160801b03851660808301528360a08301528260c083015295945050505050565b606081016108f282846148cc565b6001600160801b0392831681529116602082015260400190565b85815261012081016155446020830187614854565b61555160a0830186614839565b6001600160a01b039390931660e082015261010001529392505050565b85815261012081016155446020830187614891565b6001600160401b03948516815292841660208401529083166040830152909116606082015260800190565b60ff91909116815260200190565b60006001600160801b038083168185168083038211156155de576155de6156f3565b01949350505050565b600082198211156155fa576155fa6156f3565b500190565b60008261561a57634e487b7160e01b81526012600452602481fd5b500490565b6000816000190483118215151615615639576156396156f3565b500290565b60006001600160801b038381169083168181101561565e5761565e6156f3565b039392505050565b600082821015615678576156786156f3565b500390565b60006001600160401b038381169083168181101561565e5761565e6156f3565b6002810460018216806156b157607f821691505b602082108114156156d257634e487b7160e01b600052602260045260246000fd5b50919050565b60006000198214156156ec576156ec6156f3565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461241857600080fdfea2646970667358221220af3c4c0b4e5eb78b3bd030aeca63dd38ef79a65a2ef13e1484d268c12f499f7764736f6c63430008000033

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

000000000000000000000000afce80b19a8ce13dec0739a1aab7a028d6845eb3

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

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


Libraries Used


Deployed Bytecode Sourcemap

75640:41451:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;77641:38;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;97697:737;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;15688:83::-;;;:::i;:::-;;;;;;;:::i;9517:161::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;113652:349::-;;;;;;:::i;:::-;;:::i;:::-;;83496:341;;;;;;:::i;:::-;;:::i;77547:22::-;;;:::i;8502:100::-;;;:::i;112681:218::-;;;;;;:::i;:::-;;:::i;105721:209::-;;;:::i;:::-;;;;;;;;:::i;77952:32::-;;;:::i;:::-;;;;;;;;:::i;10150:300::-;;;;;;:::i;:::-;;:::i;113128:354::-;;;;;;:::i;:::-;;:::i;110404:868::-;;;:::i;:::-;;;;;;;;:::i;77723:55::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;16540:83::-;;;:::i;10859:207::-;;;;;;:::i;:::-;;:::i;106163:328::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;94353:326::-;;;;;;:::i;:::-;;:::i;116656:185::-;;;;;;:::i;:::-;;:::i;77454:28::-;;;:::i;77368:22::-;;;:::i;77923:::-;;;:::i;:::-;;;;;;;;;;:::i;77516:24::-;;;:::i;77785:23::-;;;:::i;77686:30::-;;;;;;:::i;:::-;;:::i;115416:244::-;;;;;;:::i;:::-;;:::i;8665:119::-;;;;;;:::i;:::-;;:::i;90071:792::-;;;;;;:::i;:::-;;:::i;96877:496::-;;;;;;:::i;:::-;;:::i;111607:674::-;;;:::i;115984:188::-;;;;;;:::i;:::-;;:::i;15890:87::-;;;:::i;116296:165::-;;;;;;:::i;:::-;;:::i;114172:336::-;;;;;;:::i;:::-;;:::i;19212:29::-;;;:::i;:::-;;;;;;;:::i;11569:217::-;;;;;;:::i;:::-;;:::i;8997:167::-;;;;;;:::i;:::-;;:::i;96118:441::-;;;;;;:::i;:::-;;:::i;95096:331::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;82848:348::-;;;;;;:::i;:::-;;:::i;114757:193::-;;;;;;:::i;:::-;;:::i;106590:113::-;;;:::i;:::-;;;;;;;:::i;116980:108::-;;;:::i;105400:130::-;;;:::i;:::-;;;;;;;;:::i;89257:345::-;;;;;;:::i;:::-;;:::i;77116:41::-;;;:::i;9227:143::-;;;;;;:::i;:::-;;:::i;84207:464::-;;;;;;:::i;:::-;;:::i;77815:25::-;;;:::i;81785:312::-;;;;;;:::i;:::-;;:::i;77641:38::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;77641:38:0;;;;-1:-1:-1;77641:38:0;;;;;-1:-1:-1;;;77641:38:0;;;;;-1:-1:-1;;;77641:38:0;;;;:::o;97697:737::-;97858:22;97907:17;97950:7;;;;;:33;;-1:-1:-1;97961:22:0;;;97950:33;97942:65;;;;-1:-1:-1;;;97942:65:0;;;;;;;:::i;:::-;;;;;;;;;98021:22;98049:21;98061:8;;98049:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;98049:11:0;;-1:-1:-1;;;98049:21:0:i;:::-;-1:-1:-1;98201:14:0;;98020:50;;-1:-1:-1;98176:22:0;;98201:14;;;-1:-1:-1;;;;;98201:14:0;:33;98249:10;98020:50;98296:17;;98328:12;:10;:12::i;:::-;98201:150;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;98176:175;;98379:43;98414:7;;98407:4;:14;;;;:::i;:::-;98379;;:27;:43::i;:::-;:47;;98425:1;98379:47;:::i;:::-;98362:64;97697:737;-1:-1:-1;;;;;;;;97697:737:0:o;15688:83::-;15725:13;15758:5;15751:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;15688:83;;:::o;9517:161::-;9592:4;9609:39;9618:12;:10;:12::i;:::-;9632:7;9641:6;9609:8;:39::i;:::-;-1:-1:-1;9666:4:0;9517:161;;;;;:::o;113652:349::-;19646:15;:13;:15::i;:::-;113773:7:::1;;113761:8;:19;;113753:45;;;;-1:-1:-1::0;;;113753:45:0::1;;;;;;;:::i;:::-;113835:7;;113817:14;:25;;113809:57;;;;-1:-1:-1::0;;;113809:57:0::1;;;;;;;:::i;:::-;113879:7;:18:::0;;;113908:13:::1;:30:::0;;;113956:37:::1;::::0;::::1;::::0;::::1;::::0;113889:8;;113924:14;;113956:37:::1;:::i;:::-;;;;;;;;113652:349:::0;;:::o;83496:341::-;83616:18;83672:1;83655:14;:18;83647:37;;;;-1:-1:-1;;;83647:37:0;;;;;;;:::i;:::-;83698:9;83713:17;83723:6;83713:9;:17::i;:::-;-1:-1:-1;83756:14:0;;83697:33;;-1:-1:-1;83756:14:0;;;-1:-1:-1;;;;;83756:14:0;:26;83783:10;83697:33;83800:14;83816:12;:10;:12::i;:::-;83756:73;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;83743:86;83496:341;-1:-1:-1;;;;83496:341:0:o;77547:22::-;;;;:::o;8502:100::-;8582:12;;8502:100;:::o;112681:218::-;19646:15;:13;:15::i;:::-;112787:4:::1;112773:10;:18;;112765:45;;;;-1:-1:-1::0;;;112765:45:0::1;;;;;;;:::i;:::-;112823:9;:22:::0;;;112863:28:::1;::::0;::::1;::::0;::::1;::::0;112835:10;;112863:28:::1;:::i;:::-;;;;;;;;112681:218:::0;:::o;105721:209::-;105811:32;105845:24;105895:14;105911:10;105887:35;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;105887:35:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;105887:35:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;105887:35:0;;;;;;;;;;-1:-1:-1;;;105887:35:0;;;;;;;;;;;;;;;-1:-1:-1;;;105887:35:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;105887:35:0;;;;;-1:-1:-1;;;105887:35:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;105721:209;;:::o;77952:32::-;;;-1:-1:-1;;;;;77952:32:0;;;;-1:-1:-1;;;77952:32:0;;;;:::o;10150:300::-;10282:4;10299:36;10309:6;10317:9;10328:6;10299:9;:36::i;:::-;10346:74;10355:6;10363:12;:10;:12::i;:::-;-1:-1:-1;;;;;10377:19:0;;;;;;:11;:19;;;;;10413:6;;10397:12;:10;:12::i;:::-;-1:-1:-1;;;;;10377:33:0;-1:-1:-1;;;;;10377:33:0;;;;;;;;;;;;;:42;;;;:::i;:::-;10346:8;:74::i;:::-;-1:-1:-1;10438:4:0;10150:300;;;;;;:::o;113128:354::-;19646:15;:13;:15::i;:::-;113238:20:::1;::::0;-1:-1:-1;;;113238:20:0;::::1;;;113237:21;113229:49;;;;-1:-1:-1::0;;;113229:49:0::1;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;113297:32:0;::::1;113289:57;;;;-1:-1:-1::0;;;113289:57:0::1;;;;;;;:::i;:::-;113359:14;:56:::0;;-1:-1:-1;;;;;;113359:56:0::1;::::0;-1:-1:-1;;;;;113359:56:0;::::1;;;::::0;;113433:41:::1;::::0;::::1;::::0;::::1;::::0;113359:56;;113433:41:::1;:::i;110404:868::-:0;110513:18;110533:17;80063:19;:17;:19::i;:::-;110806:7:::1;::::0;110842:1:::1;110828:15:::0;::::1;110824:405;;;110873:15;110887:1;110873:11:::0;:15:::1;:::i;:::-;110913:1;110903:7;:11:::0;110860:28;-1:-1:-1;110982:29:0::1;110988:10;110860:28:::0;110982:5:::1;:29::i;:::-;111069:4;111031:186;111093:10;111122::::0;111165:1:::1;111151:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;-1:-1:-1;111151:16:0::1;-1:-1:-1::0;111186:16:0::1;::::0;;111200:1:::1;111186:16:::0;;::::1;::::0;::::1;::::0;;;;111031:186:::1;::::0;;;;::::1;:::i;:::-;;;;;;;;110824:405;111251:13;:11;:13::i;:::-;111239:25;;80093:1;110404:868:::0;;:::o;77723:55::-;;;;;;;;;;;;;;;:::o;16540:83::-;16606:9;;;;16540:83;:::o;10859:207::-;10939:4;10956:80;10965:12;:10;:12::i;:::-;10979:7;11025:10;10988:11;:25;11000:12;:10;:12::i;:::-;-1:-1:-1;;;;;10988:25:0;;;;;;;;;;;;;;;;;-1:-1:-1;10988:25:0;;;:34;;;;;;;;;;:47;;;;:::i;106163:328::-;106247:30;;:::i;:::-;106279:22;;:::i;:::-;-1:-1:-1;;;;;106326:22:0;;106314:9;106326:22;;;:13;:22;;;;;;106370:14;:19;;106326:22;;;;;;;106370:19;;;;-1:-1:-1;;;106370:19:0;;;;;;;;;;;;;;;;;;106359:30;;;;;;;;106370:19;;;;;;;106359:30;;-1:-1:-1;;;;;106359:30:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;106359:30:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;106359:30:0;;;;;;;;;;-1:-1:-1;;;106359:30:0;;;;;;;;;;;;;;;-1:-1:-1;;;106359:30:0;;;;;;;;;;;;;;;106425:7;-1:-1:-1;;;;;106408:24:0;:8;:13;;;-1:-1:-1;;;;;106408:24:0;;106400:50;;;;-1:-1:-1;;;106400:50:0;;;;;;;:::i;:::-;106468:10;106479:3;106468:15;;;;;;;;-1:-1:-1;;;106468:15:0;;;;;;;;;;;;;;;;;;106461:22;;;;;;;;;106468:15;;106461:22;-1:-1:-1;;;;;106461:22:0;;;;;-1:-1:-1;;;106461:22:0;;;;;;;;;;;106163:328;;106461:22;;-1:-1:-1;;;106163:328:0:o;94353:326::-;23983:11;;94554:22;;23983:11;;;;;23975:55;;;;-1:-1:-1;;;23975:55:0;;;;;;;:::i;:::-;24108:11;:19;;-1:-1:-1;;24108:19:0;;;80824:10:::1;:8;:10::i;:::-;94606:65:::2;94614:7;94623:15;94640:18;94660:10;94606:7;:65::i;:::-;24288:11:::0;:18;;-1:-1:-1;;24288:18:0;;;;;94589:82;94353:326;-1:-1:-1;;;;;94353:326:0:o;116656:185::-;19646:15;:13;:15::i;:::-;116749:18:::1;:29;116779:7;116788:8;116798:12;116812:7;:5;:7::i;:::-;77913:3;116749:84;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;116656:185:::0;;:::o;77454:28::-;;;;:::o;77368:22::-;;;;:::o;77923:::-;;;-1:-1:-1;;;;;77923:22:0;;;;-1:-1:-1;;;77923:22:0;;;;;-1:-1:-1;;;77923:22:0;;;;;-1:-1:-1;;;77923:22:0;;;;:::o;77516:24::-;;;;:::o;77785:23::-;;;;;;:::o;77686:30::-;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;77686:30:0;;;;-1:-1:-1;;;;77686:30:0;;;;;:::o;115416:244::-;19646:15;:13;:15::i;:::-;115561:91:::1;::::0;-1:-1:-1;;;115561:91:0;;:18:::1;::::0;:33:::1;::::0;:91:::1;::::0;115595:14:::1;::::0;115611:13:::1;::::0;115626:8;;;;115636:15;;115561:91:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;115416:244:::0;;;:::o;8665:119::-;-1:-1:-1;;;;;8758:18:0;;8731:7;8758:18;;;:9;:18;;;;;;8665:119;;;;:::o;90071:792::-;90217:18;90266:7;-1:-1:-1;;;;;90256:17:0;:6;-1:-1:-1;;;;;90256:17:0;;;90248:42;;;;-1:-1:-1;;;90248:42:0;;;;;;;:::i;:::-;90326:1;90309:14;:18;90301:52;;;;-1:-1:-1;;;90301:52:0;;;;;;;:::i;:::-;90423:30;90456:10;90423:43;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;90423:43:0;;;;;-1:-1:-1;;;90423:43:0;;;;;;;;;;;;;;;;;;;;;;;;;90478:14;90498:17;90508:6;90498:9;:17::i;:::-;90477:38;;;90527:15;90548:18;90558:7;90548:9;:18::i;:::-;90526:40;;;90668:14;;;;;;;;;-1:-1:-1;;;;;90668:14:0;-1:-1:-1;;;;;90668:26:0;;90709:10;90734:8;90757:9;90781:14;90810:7;;90832:12;:10;:12::i;:::-;90668:187;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;90651:204:0;90071:792;-1:-1:-1;;;;;;;90071:792:0:o;96877:496::-;97001:20;97060:1;97042:15;:19;97034:38;;;;-1:-1:-1;;;97034:38:0;;;;;;;:::i;:::-;97086:9;97101:18;97111:7;97101:9;:18::i;:::-;97085:34;;;97132:17;97152:36;97180:7;;97152:15;:27;;:36;;;;:::i;:::-;97214:14;;97132:56;;-1:-1:-1;97214:14:0;;;-1:-1:-1;;;;;97214:14:0;:28;97257:10;97282:3;97300:27;97132:56;97300:15;:27;:::i;:::-;97342:12;:10;:12::i;:::-;97214:151;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;97199:166;96877:496;-1:-1:-1;;;;;96877:496:0:o;111607:674::-;111767:18;111787:17;80063:19;:17;:19::i;:::-;80425:12:::1;:10;:12::i;:::-;23983:11:::2;::::0;::::2;::::0;::::2;;;23975:55;;;;-1:-1:-1::0;;;23975:55:0::2;;;;;;;:::i;:::-;24108:11;:19:::0;;-1:-1:-1;;24108:19:0::2;::::0;;;;111822:22:::3;::::0;111877:18:::3;::::0;:42:::3;::::0;111934:14:::3;::::0;111963:10:::3;::::0;111988:14;;::::3;-1:-1:-1::0;;;;;111988:14:0::3;112017:12;:10;:12::i;:::-;111877:163;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::3;;;;;;;;;;;;::::0;::::3;;;;;;;;;;;;;;;;;::::0;;::::3;-1:-1:-1::0;;111877:163:0::3;::::0;::::3;;::::0;::::3;::::0;;;::::3;::::0;::::3;:::i;:::-;111855:185:::0;;-1:-1:-1;111855:185:0;-1:-1:-1;112061:14:0;112053:49:::3;;;;-1:-1:-1::0;;;112053:49:0::3;;;;;;;:::i;:::-;112115:29;112121:10;112133;112115:5;:29::i;:::-;112180:4;112160:75;112187:10;112199::::0;112225:1:::3;112211:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;-1:-1:-1;112211:16:0::3;;112229:5;112160:75;;;;;;;;;:::i;:::-;;;;;;;;112260:13;:11;:13::i;:::-;24288:11:::2;:18:::0;;-1:-1:-1;;24288:18:0::2;;;::::0;;111607:674;;;-1:-1:-1;;111607:674:0:o;115984:188::-;19646:15;:13;:15::i;:::-;116073:91:::1;::::0;-1:-1:-1;;;116073:91:0;;:18:::1;::::0;:32:::1;::::0;:91:::1;::::0;116106:6:::1;::::0;116114:14:::1;::::0;116130:13:::1;::::0;116145:7;;116154:9;;116073:91:::1;;;:::i;15890:87::-:0;15929:13;15962:7;15955:14;;;;;:::i;116296:165::-;19646:15;:13;:15::i;:::-;116371:82:::1;::::0;-1:-1:-1;;;116371:82:0;;:18:::1;::::0;:34:::1;::::0;:82:::1;::::0;116406:6:::1;::::0;116414:14:::1;::::0;116430:13:::1;::::0;116445:7;;116371:82:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;116296:165:::0;:::o;114172:336::-;19646:15;:13;:15::i;:::-;114282:10:::1;:17:::0;:21:::1;::::0;114302:1:::1;114282:21;:::i;:::-;114274:30;::::0;:4:::1;:30;:::i;:::-;114266:4;-1:-1:-1::0;;;;;114266:38:0::1;;;114258:65;;;;-1:-1:-1::0;;;114258:65:0::1;;;;;;;:::i;:::-;114358:10;:17:::0;:21:::1;::::0;114378:1:::1;::::0;114358:21:::1;:::i;:::-;114350:30;::::0;:4:::1;:30;:::i;:::-;114342:4;-1:-1:-1::0;;;;;114342:38:0::1;;;114334:65;;;;-1:-1:-1::0;;;114334:65:0::1;;;;;;;:::i;:::-;114427:24;::::0;;;;::::1;::::0;;-1:-1:-1;;;;;114427:24:0;;::::1;::::0;;;;;::::1;;::::0;;::::1;::::0;;;114412:12:::1;:39:::0;;-1:-1:-1;;114412:39:0::1;::::0;;::::1;::::0;;::::1;-1:-1:-1::0;;;114412:39:0;;::::1;::::0;;;::::1;::::0;;114469:31;::::1;::::0;::::1;::::0;114427:24;;;;114469:31:::1;:::i;19212:29::-:0;;;:::o;11569:217::-;11654:4;11671:85;11680:12;:10;:12::i;:::-;11694:7;11740:15;11703:11;:25;11715:12;:10;:12::i;:::-;-1:-1:-1;;;;;11703:25:0;;;;;;;;;;;;;;;;;-1:-1:-1;11703:25:0;;;:34;;;;;;;;;;:52;;;;:::i;8997:167::-;9075:4;9092:42;9102:12;:10;:12::i;:::-;9116:9;9127:6;9092:9;:42::i;96118:441::-;23983:11;;96356:22;;23983:11;;;;;23975:55;;;;-1:-1:-1;;;23975:55:0;;;;;;;:::i;:::-;24108:11;:19;;-1:-1:-1;;24108:19:0;;;80824:10:::1;:8;:10::i;:::-;96408:143:::2;96442:8;;96408:143;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;::::0;;;;-1:-1:-1;;96408:143:0::2;::::0;;::::2;::::0;;::::2;::::0;;;;;;;;;;;;;-1:-1:-1;96465:17:0;;-1:-1:-1;96465:17:0;;;;96408:143;::::2;::::0;96465:17;;96408:143;96465:17;96408:143;::::2;;::::0;::::2;::::0;;;;-1:-1:-1;96497:18:0;;-1:-1:-1;96530:10:0;;-1:-1:-1;96408:19:0::2;::::0;-1:-1:-1;96408:143:0:i:2;:::-;24288:11:::0;:18;;-1:-1:-1;;24288:18:0;;;;;96391:160;96118:441;-1:-1:-1;;;;;;;96118:441:0:o;95096:331::-;23983:11;;95290:33;;23983:11;;;;;23975:55;;;;-1:-1:-1;;;23975:55:0;;;;;;;:::i;:::-;24108:11;:19;;-1:-1:-1;;24108:19:0;;;80824:10:::1;:8;:10::i;:::-;95355:64:::2;95369:15;95386:20;;95408:10;95355:13;:64::i;82848:348::-:0;23983:11;;83075:18;;23983:11;;;;;23975:55;;;;-1:-1:-1;;;23975:55:0;;;;;;;:::i;:::-;24108:11;:19;;-1:-1:-1;;24108:19:0;;;80425:12:::1;:10;:12::i;:::-;83119:69:::2;83130:7;;83119:69;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;::::0;;;;-1:-1:-1;;83119:69:0::2;::::0;;::::2;::::0;;::::2;::::0;;;;;;;;;;;;;-1:-1:-1;83139:16:0;;-1:-1:-1;83139:16:0;;;;83119:69;::::2;::::0;83139:16;;83119:69;83139:16;83119:69;::::2;;::::0;::::2;::::0;;;;-1:-1:-1;83157:18:0;;-1:-1:-1;83177:10:0;;-1:-1:-1;83119:10:0::2;::::0;-1:-1:-1;83119:69:0:i:2;114757:193::-:0;19646:15;:13;:15::i;:::-;114857:85:::1;::::0;-1:-1:-1;;;114857:85:0;;:18:::1;::::0;:38:::1;::::0;:85:::1;::::0;114896:14:::1;::::0;114912:13:::1;::::0;114927:7;;114936:5;;114857:85:::1;;;:::i;106590:113::-:0;106634:29;;:::i;:::-;106683:12;:10;:12::i;:::-;106676:19;;106590:113;:::o;116980:108::-;19646:15;:13;:15::i;:::-;117034:18:::1;:28;117063:7;117072;:5;:7::i;:::-;117034:46;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;116980:108::o:0;105400:130::-;105484:6;:22;;;;;;;105508:13;;;105400:130;;:::o;89257:345::-;23983:11;;89480:18;;23983:11;;;;;23975:55;;;;-1:-1:-1;;;23975:55:0;;;;;;;:::i;:::-;24108:11;:19;;-1:-1:-1;;24108:19:0;;;80425:12:::1;:10;:12::i;:::-;89524:70:::2;89530:6;89538:7;89547:14;89563:18;89583:10;89524:5;:70::i;:::-;24288:11:::0;:18;;-1:-1:-1;;24288:18:0;;;;;89511:83;89257:345;-1:-1:-1;;;;;;89257:345:0:o;77116:41::-;;;;;;-1:-1:-1;;;;;77116:41:0;;:::o;9227:143::-;-1:-1:-1;;;;;9335:18:0;;;9308:7;9335:18;;;:11;:18;;;;;;;;:27;;;;;;;;;;;;;9227:143::o;84207:464::-;84357:18;84402:16;84444:7;;;;;:32;;-1:-1:-1;84455:21:0;;;84444:32;84436:65;;;;-1:-1:-1;;;84436:65:0;;;;;;;:::i;:::-;84513:22;84541:20;84553:7;;84541:20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;84541:11:0;;-1:-1:-1;;;84541:20:0:i;:::-;-1:-1:-1;84579:14:0;;84512:49;;-1:-1:-1;84579:14:0;;;-1:-1:-1;;;;;84579:14:0;:31;84611:10;84512:49;84632:16;;84650:12;:10;:12::i;:::-;84579:84;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;84572:91;84207:464;-1:-1:-1;;;;;;;84207:464:0:o;77815:25::-;;;;;;;;;;;;;:::o;81785:312::-;23983:11;;81982:18;;23983:11;;;;;23975:55;;;;-1:-1:-1;;;23975:55:0;;;;;;;:::i;:::-;24108:11;:19;;-1:-1:-1;;24108:19:0;;;80425:12:::1;:10;:12::i;:::-;82026:63:::2;82034:6;82042:14;82058:18;82078:10;82026:7;:63::i;108371:545::-:0;108541:15;;108458:22;;;;108541:15;-1:-1:-1;;;;;108579:16:0;;;;;-1:-1:-1;;;108579:16:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;108579:16:0;;108569:26;;108638:3;-1:-1:-1;;;;;108617:25:0;;;;;-1:-1:-1;;;108617:25:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;108606:36;;108660:9;108655:254;108679:3;108675:1;:7;108655:254;;;108732:22;108742:8;108751:1;108742:11;;;;;;-1:-1:-1;;;108742:11:0;;;;;;;;;;;;;;;108732:9;:22::i;:::-;108705:7;108713:1;108705:10;;;;;;-1:-1:-1;;;108705:10:0;;;;;;;;;;;;;;108717:8;108726:1;108717:11;;;;;;-1:-1:-1;;;108717:11:0;;;;;;;;;;;;;;;;;;108704:50;;;;;;;;;;108776:9;108788:5;:1;108792;108788:5;:::i;:::-;108776:17;;108771:127;108799:3;108795:1;:7;108771:127;;;108851:8;108860:1;108851:11;;;;;;-1:-1:-1;;;108851:11:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;108836:26:0;:8;108845:1;108836:11;;;;;;-1:-1:-1;;;108836:11:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;108836:26:0;;;108828:54;;;;-1:-1:-1;;;108828:54:0;;;;;;;:::i;:::-;108804:3;;;;:::i;:::-;;;;108771:127;;;-1:-1:-1;108684:3:0;;;;:::i;:::-;;;;108655:254;;;;108371:545;;;;:::o;109015:133::-;109060:22;;:::i;:::-;109102:38;;;;;;;;109118:7;:5;:7::i;:::-;109102:38;;;;;;;;;;;109127:12;109102:38;-1:-1:-1;;;;;109102:38:0;;;;;-1:-1:-1;;;109102:38:0;;;;;;;;;;;;;;;;109095:45;-1:-1:-1;109015:133:0;:::o;37700:195::-;37767:7;37886:1;37868:14;33978:4;37868:1;:14;:::i;:::-;37867:20;;;;:::i;5216:107::-;5304:10;5216:107;:::o;14249:338::-;-1:-1:-1;;;;;14343:19:0;;14335:68;;;;-1:-1:-1;;;14335:68:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;14422:21:0;;14414:68;;;;-1:-1:-1;;;14414:68:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;14495:18:0;;;;;;;:11;:18;;;;;;;;:27;;;;;;;;;;;;;;:36;;;14547:32;;;;;14525:6;;14547:32;:::i;:::-;;;;;;;;14249:338;;;:::o;19689:121::-;19761:11;:9;:11::i;:::-;-1:-1:-1;;;;;19747:25:0;:10;-1:-1:-1;;;;;19747:25:0;;19739:63;;;;-1:-1:-1;;;19739:63:0;;;;;;;:::i;:::-;19689:121::o;107837:264::-;107911:9;107922:30;;:::i;:::-;-1:-1:-1;;;;;107971:21:0;;;;;;:13;:21;;;;;;108014:14;:19;;107971:21;;;;;-1:-1:-1;108014:14:0;107971:21;;108014:19;;;;-1:-1:-1;;;108014:19:0;;;;;;;;;;;;;;;;;;108003:30;;;;;;;;108014:19;;;;;;;108003:30;;-1:-1:-1;;;;;108003:30:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;108003:30:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;108003:30:0;;;;;;;;;;-1:-1:-1;;;108003:30:0;;;;;;;;;;;;;;;-1:-1:-1;;;108003:30:0;;;;;;;;;;;;;;;108069:6;-1:-1:-1;;;;;108052:23:0;:8;:13;;;-1:-1:-1;;;;;108052:23:0;;108044:49;;;;-1:-1:-1;;;108044:49:0;;;;;;;:::i;:::-;107837:264;;;:::o;12276:382::-;-1:-1:-1;;;;;12374:20:0;;12366:70;;;;-1:-1:-1;;;12366:70:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;12455:23:0;;12447:71;;;;-1:-1:-1;;;12447:71:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;12531:17:0;;;;;;:9;:17;;;;;:27;;12552:6;;12531:17;:27;;12552:6;;12531:27;:::i;:::-;;;;-1:-1:-1;;;;;;;12569:20:0;;;;;;:9;:20;;;;;:30;;12593:6;;12569:20;:30;;12593:6;;12569:30;:::i;:::-;;;;;;;;12632:9;-1:-1:-1;;;;;12615:35:0;12624:6;-1:-1:-1;;;;;12615:35:0;;12643:6;12615:35;;;;;;:::i;80169:129::-;80252:10;80231:17;:15;:17::i;:::-;-1:-1:-1;;;;;80231:31:0;;80223:67;;;;-1:-1:-1;;;80223:67:0;;;;;;;:::i;12939:268::-;-1:-1:-1;;;;;13015:21:0;;13007:65;;;;-1:-1:-1;;;13007:65:0;;;;;;;:::i;:::-;13101:6;13085:12;;:22;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;;;13118:18:0;;;;;;:9;:18;;;;;:28;;13140:6;;13118:18;:28;;13140:6;;13118:28;:::i;:::-;;;;-1:-1:-1;;13162:37:0;;-1:-1:-1;;;;;13162:37:0;;;13179:1;;13162:37;;;;13192:6;;13162:37;:::i;:::-;;;;;;;;12939:268;;:::o;80921:144::-;80966:35;;;;;;;;;80995:6;80966:35;;;;;;;;;;;;;;;;;;;;;81012:45;;;;-1:-1:-1;;;81012:45:0;;;;;;;:::i;:::-;80921:144;:::o;98641:1813::-;98808:22;-1:-1:-1;;;;;98851:24:0;;98843:54;;;;-1:-1:-1;;;98843:54:0;;;;;;;:::i;:::-;98933:1;98916:14;:18;98908:37;;;;-1:-1:-1;;;98908:37:0;;;;;;;:::i;:::-;99016:30;99049:10;99016:43;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;99016:43:0;;;;;-1:-1:-1;;;99016:43:0;;;;;;;;;;;;;;;;;;;;;;;;;99071:17;99090:30;99124:18;99134:7;99124:9;:18::i;:::-;99070:72;;;;99197:17;99217:35;99244:7;;99217:14;:26;;:35;;;;:::i;:::-;99280:14;;99197:55;;-1:-1:-1;99280:14:0;;;-1:-1:-1;;;;;99280:14:0;:28;99323:10;99348:11;99374:26;99197:55;99374:14;:26;:::i;:::-;99415:12;:10;:12::i;:::-;99280:158;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;99263:175;;99475:18;99457:14;:36;;99449:69;;;;-1:-1:-1;;;99449:69:0;;;;;;;:::i;:::-;99554:1;99537:14;:18;99529:42;;;;-1:-1:-1;;;99529:42:0;;;;;;;:::i;:::-;99697:33;99703:10;99715:14;99697:5;:33::i;:::-;99752:9;99741:7;;:20;;;;;;;:::i;:::-;;;;-1:-1:-1;99772:18:0;;-1:-1:-1;99793:18:0;:16;:18::i;:::-;99772:39;;99877:18;:33;99925:14;99954:8;99977:10;99988:11;99977:23;;;;;;;;-1:-1:-1;;;99977:23:0;;;;;;;;;;;;;;;100015:10;100040:5;:14;;;99877:188;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;100215:34;100234:14;100215:18;:34::i;:::-;100163:10;100174:11;100163:23;;;;;;;;-1:-1:-1;;;100163:23:0;;;;;;;;;;;;;;;:36;;;:86;;;;:::i;:::-;100111:10;100122:11;100111:23;;;;;;;;-1:-1:-1;;;100111:23:0;;;;;;;;;;;;;;;;;;:138;;-1:-1:-1;;;;;100111:138:0;;;-1:-1:-1;;;100111:138:0;;;;;;;;;100369:13;;100267:179;;100290:10;;100267:179;;;;100315:10;;100340:14;;100369:13;100397:14;;100426:9;;100267:179;:::i;:::-;;;;;;;;98641:1813;;;;;;;;;;;:::o;109220:826::-;109280:33;;;;;;;;109306:7;109280:33;-1:-1:-1;;;;;109280:33:0;;;;;-1:-1:-1;;;109280:33:0;;;;;;;;;;-1:-1:-1;;;109280:33:0;;;;;;;;;;;-1:-1:-1;;;109280:33:0;;;;;;;;;;109260:7;;109280:33;109488:15;:25;-1:-1:-1;109484:555:0;;;109546:17;;109597:22;;;;109530:13;;109672:27;-1:-1:-1;;;;;109672:27:0;;:15;:27;:::i;:::-;109701:19;109711:9;109701:7;:19;:::i;:::-;-1:-1:-1;;;;;109636:85:0;;;;;109749:6;-1:-1:-1;;;;;109742:13:0;:4;-1:-1:-1;;;;;109742:13:0;;109738:201;;;109823:5;109812:7;109795:13;109802:6;109795:4;:13;:::i;:::-;-1:-1:-1;;;;;109794:25:0;;;;;:::i;:::-;109793:35;;;;:::i;:::-;109783:46;;-1:-1:-1;;;;;109783:46:0;;;:::i;:::-;109776:53;;;;;;;;;;;109738:201;109917:5;109906:7;109889:13;109898:4;109889:6;:13;:::i;:::-;-1:-1:-1;;;;;109888:25:0;;;;;:::i;:::-;109887:35;;;;:::i;:::-;109877:46;;-1:-1:-1;;;;;109877:46:0;;;:::i;109484:555::-;-1:-1:-1;;;;;;110016:11:0;;-1:-1:-1;110016:11:0;;-1:-1:-1;110016:11:0;35604:135;35670:7;35697:34;35714:1;35717;33978:4;35697:16;:34::i;80524:166::-;80571:35;;;;;;;;;80600:6;80571:35;;;;;;;;;;;;;;;;;;;;;;;;;80625:43;;;80654:7;:14;;;80653:15;80625:43;80617:65;;;;-1:-1:-1;;;80617:65:0;;;;;;;:::i;102973:2177::-;103174:22;-1:-1:-1;;;;;103217:24:0;;103209:54;;;;-1:-1:-1;;;103209:54:0;;;;;;;:::i;:::-;103288:24;;103331:7;;;;;:33;;;103349:8;:15;103342:3;:22;103331:33;103323:65;;;;-1:-1:-1;;;103323:65:0;;;;;;;:::i;:::-;103428:1;103407:18;:22;103399:41;;;;-1:-1:-1;;;103399:41:0;;;;;;;:::i;:::-;103454:22;103478:32;103514:21;103526:8;103514:11;:21::i;:::-;103631:10;103598:43;;;;;;;;;;;;;;;;;103453:82;;-1:-1:-1;103453:82:0;;-1:-1:-1;103598:30:0;;;;:43;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;103598:43:0;;;;;-1:-1:-1;;;103598:43:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;;103709:14:0;;103598:43;;-1:-1:-1;103684:22:0;;103709:14;;;-1:-1:-1;;;;;103709:14:0;;-1:-1:-1;103709:33:0;;-1:-1:-1;103598:43:0;103782:7;103804:17;103836:12;:10;:12::i;:::-;103709:150;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;103684:175;;103887:43;103922:7;;103915:4;:14;;;;:::i;103887:43::-;103870:60;-1:-1:-1;103941:11:0;103955:31;103972:14;103870:60;103955:31;:::i;:::-;103941:45;;104022:1;104005:14;:18;103997:55;;;;-1:-1:-1;;;103997:55:0;;;;;;;:::i;:::-;104063:19;104081:1;104063:19;;:::i;:::-;;;104119:18;104101:14;:36;;104093:81;;;;-1:-1:-1;;;104093:81:0;;;;;;;:::i;:::-;104300:33;104306:10;104318:14;104300:5;:33::i;:::-;104355:3;104344:7;;:14;;;;;;;:::i;:::-;;;;-1:-1:-1;104369:18:0;;-1:-1:-1;104390:18:0;:16;:18::i;:::-;104369:39;;104494:9;104489:462;104513:3;104509:1;:7;104489:462;;;104538:9;104550:7;104558:1;104550:10;;;;;;-1:-1:-1;;;104550:10:0;;;;;;;;;;;;;;;104538:22;;104575:18;:33;104627:17;104645:1;104627:20;;;;;;-1:-1:-1;;;104627:20:0;;;;;;;;;;;;;;;104666:8;104675:1;104666:11;;;;;;-1:-1:-1;;;104666:11:0;;;;;;;;;;;;;;;104696:10;104707:3;104696:15;;;;;;;;-1:-1:-1;;;104696:15:0;;;;;;;;;;;;;;;104730:10;104759:5;:14;;;104575:213;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;104899:40;104918:17;104936:1;104918:20;;;;;;-1:-1:-1;;;104918:20:0;;;;;;;;;;;;;;;104899:18;:40::i;:::-;104851:10;104862:3;104851:15;;;;;;;;-1:-1:-1;;;104851:15:0;;;;;;;;;;;;;;;:28;;;:88;;;;:::i;:::-;104803:10;104814:3;104803:15;;;;;;;;-1:-1:-1;;;104803:15:0;;;;;;;;;;;;;;;;;;:136;;-1:-1:-1;;;;;104803:136:0;;;-1:-1:-1;;;104803:136:0;;;;;;;;;-1:-1:-1;104518:3:0;;;;:::i;:::-;;;;104489:462;;;;104994:10;-1:-1:-1;;;;;104966:176:0;;105019:10;105044:14;105073:8;105096:17;105128:3;104966:176;;;;;;;;;;:::i;:::-;;;;;;;;102973:2177;;;;;;;;;;;;;:::o;100542:2368::-;100702:33;-1:-1:-1;;;;;100756:24:0;;100748:54;;;;-1:-1:-1;;;100748:54:0;;;;;;;:::i;:::-;100838:1;100821:14;:18;100813:37;;;;-1:-1:-1;;;100813:37:0;;;;;;;:::i;:::-;100914:17;100934:41;100961:13;;100934:14;:26;;:41;;;;:::i;:::-;100914:61;-1:-1:-1;100986:30:0;101019:26;100914:61;101019:14;:26;:::i;:::-;100986:59;;101091:33;101097:10;101109:14;101091:5;:33::i;:::-;101146:9;101135:7;;:20;;;;;;;:::i;:::-;;;;-1:-1:-1;101220:18:0;;-1:-1:-1;101241:18:0;:16;:18::i;:::-;101220:39;;101350:19;101396:22;101372:5;:21;;;:46;;;;:::i;:::-;101350:68;;101489:30;101522:10;101489:43;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;101489:43:0;;;;;-1:-1:-1;;;101489:43:0;;;;;;;;;;;;;;;;;;;;;;;;;101545:11;101559:10;:17;101545:31;;101587:24;101628:3;-1:-1:-1;;;;;101614:18:0;;;;;-1:-1:-1;;;101614:18:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;101614:18:0;;101587:45;;101676:3;-1:-1:-1;;;;;101662:18:0;;;;;-1:-1:-1;;;101662:18:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;101662:18:0;;101643:37;;101696:9;101691:1014;101715:3;101711:1;:7;101691:1014;;;101907:17;101983:11;101957:22;101928:10;101939:1;101928:13;;;;;;-1:-1:-1;;;101928:13:0;;;;;;;;;;;;;;;:26;;;-1:-1:-1;;;;;101928:51:0;;;;;:::i;:::-;101927:67;;;;:::i;:::-;101907:87;;102029:1;102017:9;:13;102009:37;;;;-1:-1:-1;;;102009:37:0;;;;;;;:::i;:::-;102061:14;102074:1;102061:14;;:::i;:::-;;;102111:20;;102132:1;102111:23;;;;;-1:-1:-1;;;102111:23:0;;;;;;;;;;;;;;;102098:9;:36;;102090:69;;;;-1:-1:-1;;;102090:69:0;;;;;;;:::i;:::-;102247:9;102258:14;102273:1;102258:17;;;;;;-1:-1:-1;;;102258:17:0;;;;;;;;;;;;;;;;;;;;;;:22;102211:19;;-1:-1:-1;;;;;102258:22:0;;;;102211:16;;102228:1;;102211:19;;;;-1:-1:-1;;;102211:19:0;;;;;;;;;;;;;;102232:7;102240:1;102232:10;;;;;;-1:-1:-1;;;102232:10:0;;;;;;;;;;;;;;102210:71;-1:-1:-1;;;;;102210:71:0;-1:-1:-1;;;;;102210:71:0;;;;;;;;;;102349:18;:33;102401:9;102429:14;102444:1;102429:17;;;;;;-1:-1:-1;;;102429:17:0;;;;;;;;;;;;;;;;;;;102465:10;102476:1;102465:13;;;;;;-1:-1:-1;;;102465:13:0;;;;;;;;;;;;;;;102497:10;102526:5;:14;;;102349:206;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;102664:29;102683:9;102664:18;:29::i;:::-;102635:10;102646:1;102635:13;;;;;;-1:-1:-1;;;102635:13:0;;;;;;;;;;;;;;;:26;;;:58;;;;:::i;:::-;102606:10;102617:1;102606:13;;;;;;-1:-1:-1;;;102606:13:0;;;;;;;;;;;;;;;;;;:87;;-1:-1:-1;;;;;102606:87:0;;;-1:-1:-1;;;102606:87:0;;;;;;;;;-1:-1:-1;101720:3:0;;;;:::i;:::-;;;;101691:1014;;;;102750:10;-1:-1:-1;;;;;102722:180:0;;102775:10;102800:14;102829:7;102851:16;102882:9;102722:180;;;;;;;;;;:::i;86386:2129::-;86576:20;-1:-1:-1;;;;;86617:24:0;;86609:54;;;;-1:-1:-1;;;86609:54:0;;;;;;;:::i;:::-;86688:23;;86730:7;;;;;:32;;;86748:7;:14;86741:3;:21;86730:32;86722:65;;;;-1:-1:-1;;;86722:65:0;;;;;;;:::i;:::-;86849:22;86873:33;86910:20;86922:7;86910:11;:20::i;:::-;86974:10;86941:43;;;;;;;;;;;;;;;;;86848:82;;-1:-1:-1;86848:82:0;;-1:-1:-1;86941:30:0;;;;:43;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;86941:43:0;;;;;-1:-1:-1;;;86941:43:0;;;;;;;;;;;;;;;;;;;;;;;;;86995:18;87016;:16;:18::i;:::-;86995:39;;87045:36;87098:3;-1:-1:-1;;;;;87084:18:0;;;;;-1:-1:-1;;;87084:18:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;87084:18:0;;87045:57;;87202:9;87197:769;87221:3;87217:1;:7;87197:769;;;87246:22;87271:16;87288:1;87271:19;;;;;;-1:-1:-1;;;87271:19:0;;;;;;;;;;;;;;;87246:44;;87326:1;87309:14;:18;87305:650;;;87348:9;87360:7;87368:1;87360:10;;;;;;-1:-1:-1;;;87360:10:0;;;;;;;;;;;;;;;87348:22;;87389;87414:10;87425:3;87414:15;;;;;;;;-1:-1:-1;;;87414:15:0;;;;;;;;;;;;;;;87389:40;;87448:30;87481:9;87491:1;87481:12;;;;;;-1:-1:-1;;;87481:12:0;;;;;;;;;;;;;;;87448:45;;87512:25;87540:18;:32;87595:8;87626:4;:10;;;87659:14;87696:5;:14;;;87540:189;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;87512:217;;87773:17;87748:19;87768:1;87748:22;;;;;;-1:-1:-1;;;87748:22:0;;;;;;;;;;;;;;:42;;;;;87902:37;87921:17;87902:18;:37::i;:::-;87861:4;:17;;;:78;;;;:::i;:::-;87809:10;87820:3;87809:15;;;;;;;;-1:-1:-1;;;87809:15:0;;;;;;;;;;;;;;;;;;:130;;-1:-1:-1;;;;;87809:130:0;;;-1:-1:-1;;;87809:130:0;;;;;;;;;-1:-1:-1;;;;87305:650:0;-1:-1:-1;87226:3:0;;;;:::i;:::-;;;;87197:769;;;-1:-1:-1;88052:14:0;;;;;-1:-1:-1;;;;;88052:14:0;:31;88098:10;88123:7;88145:19;88179:12;:10;:12::i;:::-;88052:150;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;88037:165;;88237:18;88221:12;:34;;88213:70;;;;-1:-1:-1;;;88213:70:0;;;;;;;:::i;:::-;88317:1;88302:12;:16;88294:49;;;;-1:-1:-1;;;88294:49:0;;;;;;;:::i;:::-;88384:31;88390:10;88402:12;88384:5;:31::i;:::-;88443:10;-1:-1:-1;;;;;88431:76:0;;88455:10;88467:12;88481:7;88490:16;88431:76;;;;;;;;;:::i;:::-;;;;;;;;86386:2129;;;;;;;;;;;;:::o;91026:2316::-;91216:18;-1:-1:-1;;;;;91255:24:0;;91247:54;;;;-1:-1:-1;;;91247:54:0;;;;;;;:::i;:::-;91330:7;-1:-1:-1;;;;;91320:17:0;:6;-1:-1:-1;;;;;91320:17:0;;;91312:42;;;;-1:-1:-1;;;91312:42:0;;;;;;;:::i;:::-;91390:1;91373:14;:18;91365:52;;;;-1:-1:-1;;;91365:52:0;;;;;;;:::i;:::-;91487:30;91520:10;91487:43;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;91487:43:0;;;;;-1:-1:-1;;;91487:43:0;;;;;;;;;;;;;;;;;;;;;;;;;91542:14;91558:35;91597:17;91607:6;91597:9;:17::i;:::-;91541:73;;;;91626:15;91643:36;91683:18;91693:7;91683:9;:18::i;:::-;91625:76;;;;91738:18;91759;:16;:18::i;:::-;91738:39;;91828:25;91856:18;:32;91903:13;91931:10;91942:8;91931:20;;;;;;;;-1:-1:-1;;;91931:20:0;;;;;;;;;;;;;;;:26;;;91972:14;92001:5;:14;;;91856:170;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;91828:198;;92177:37;92196:17;92177:18;:37::i;:::-;92128:10;92139:8;92128:20;;;;;;;;-1:-1:-1;;;92128:20:0;;;;;;;;;;;;;;;:33;;;:86;;;;:::i;:::-;92079:10;92090:8;92079:20;;;;;;;;-1:-1:-1;;;92079:20:0;;;;;;;;;;;;;;;;:33;;;:135;;;;;-1:-1:-1;;;;;92079:135:0;;;;;-1:-1:-1;;;;;92079:135:0;;;;;;92260:17;92314:14;;;;;;;;;-1:-1:-1;;;;;92314:14:0;-1:-1:-1;;;;;92314:26:0;;92355:10;92380:8;92403:9;92427:17;92459:7;;92481:12;:10;:12::i;:::-;92314:190;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;92288:216;;-1:-1:-1;92288:216:0;-1:-1:-1;92523:32:0;;;;92515:69;;;;-1:-1:-1;;;92515:69:0;;;;;;;:::i;:::-;92616:1;92603:10;:14;92595:47;;;;-1:-1:-1;;;92595:47:0;;;;;;;:::i;:::-;92719:18;:33;92767:10;92792:14;92821:10;92832:9;92821:21;;;;;;;;-1:-1:-1;;;92821:21:0;;;;;;;;;;;;;;;92857:10;92882:5;:14;;;92719:188;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;93018:30;93037:10;93018:18;:30::i;:::-;92968:10;92979:9;92968:21;;;;;;;;-1:-1:-1;;;92968:21:0;;;;;;;;;;;;;;;:34;;;:80;;;;:::i;:::-;92918:10;92929:9;92918:21;;;;;;;;-1:-1:-1;;;92918:21:0;;;;;;;;;;;;;;;;;;:130;;-1:-1:-1;;;;;92918:130:0;;;-1:-1:-1;;;92918:130:0;;;;;;;;;93109:13;;;;:25;;93125:9;;93109:25;:::i;:::-;93099:7;:35;;;;93172:10;-1:-1:-1;;;;;93150:184:0;;93197:13;:18;;;93230:14;:19;;;93264:10;93289:9;93313:10;93150:184;;;;;;;;;;:::i;:::-;;;;;;;;91026:2316;;;;;;;;;;;;;;;:::o;84837:1513::-;85003:20;-1:-1:-1;;;;;85044:24:0;;85036:54;;;;-1:-1:-1;;;85036:54:0;;;;;;;:::i;:::-;85126:1;85109:14;:18;85101:37;;;;-1:-1:-1;;;85101:37:0;;;;;;;:::i;:::-;85149:30;85182:10;85149:43;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;85149:43:0;;;;;-1:-1:-1;;;85149:43:0;;;;;;;;;;;;;;;;;;;;;;;;;85204:17;85223:30;85257:17;85267:6;85257:9;:17::i;:::-;85203:71;;;;85285:18;85306;:16;:18::i;:::-;85285:39;;85420:25;85448:18;:32;85495:8;85518:10;85529:11;85518:23;;;;;;;;-1:-1:-1;;;85518:23:0;;;;;;;;;;;;;;;:29;;;85562:14;85591:5;:14;;;85448:168;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;85728:14;;85420:196;;-1:-1:-1;85728:14:0;;;-1:-1:-1;;;;;85728:14:0;:26;85769:10;85794:11;85420:196;85852:12;:10;:12::i;:::-;85728:147;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;85713:162;;85910:18;85894:12;:34;;85886:70;;;;-1:-1:-1;;;85886:70:0;;;;;;;:::i;:::-;86148:37;86167:17;86148:18;:37::i;:::-;86096:10;86107:11;86096:23;;;;;;;;-1:-1:-1;;;86096:23:0;;;;;;;;;;;;;;;:36;;;:89;;;;:::i;:::-;86044:10;86055:11;86044:23;;;;;;;;-1:-1:-1;;;86044:23:0;;;;;;;;;;;;;;;;;;:141;;-1:-1:-1;;;;;86044:141:0;;;-1:-1:-1;;;86044:141:0;;;;;;;;;86224:31;86230:10;86242:12;86224:5;:31::i;:::-;86278:10;-1:-1:-1;;;;;86271:71:0;;86290:10;86302:12;86316:6;86324:17;86271:71;;;;;;;;;:::i;20728:95::-;20772:7;20799:5;-1:-1:-1;;;;;20799:14:0;;:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;22484:121::-;22561:36;;-1:-1:-1;;;22561:36:0;;22534:7;;-1:-1:-1;;;;;22561:5:0;:15;;;;:36;;18339:66;;22561:36;;;:::i;:::-;;;;;;;;;;;;;;;;;;;13539:270;-1:-1:-1;;;;;13615:21:0;;13607:67;;;;-1:-1:-1;;;13607:67:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;13687:18:0;;;;;;:9;:18;;;;;:28;;13709:6;;13687:18;:28;;13709:6;;13687:28;:::i;:::-;;;;;;;;13742:6;13726:12;;:22;;;;;;;:::i;:::-;;;;-1:-1:-1;;13764:37:0;;13790:1;;-1:-1:-1;;;;;13764:37:0;;;;;;;13794:6;;13764:37;:::i;107342:275::-;107393:12;;:::i;:::-;107487:7;;107468:16;107487:7;107519:13;:11;:13::i;:::-;:24;;;;:::i;:::-;107505:38;;107561:48;;;;;;;;107567:3;107561:48;;;;107572:26;107588:9;;107572:3;:15;;:26;;;;:::i;:::-;107561:48;;;;;;;;-1:-1:-1;107554:55:0;-1:-1:-1;107342:275:0;:::o;28120:185::-;28177:7;-1:-1:-1;;;28205:5:0;:16;28197:68;;;;-1:-1:-1;;;28197:68:0;;;;;;;:::i;:::-;-1:-1:-1;28291:5:0;28120:185::o;36212:252::-;36298:7;36451:5;36442;36446:1;36442;:5;:::i;:::-;36441:15;;;;:::i;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;:::o;14:400:1:-;;;147:3;140:4;132:6;128:17;124:27;114:2;;170:6;162;155:22;114:2;-1:-1:-1;198:20:1;;-1:-1:-1;;;;;230:30:1;;227:2;;;280:8;270;263:26;227:2;324:4;316:6;312:17;300:29;;387:3;380:4;372;364:6;360:17;352:6;348:30;344:41;341:50;338:2;;;404:1;401;394:12;338:2;104:310;;;;;:::o;419:190::-;489:20;;-1:-1:-1;;;;;538:46:1;;528:57;;518:2;;599:1;596;589:12;614:259;;726:2;714:9;705:7;701:23;697:32;694:2;;;747:6;739;732:22;694:2;791:9;778:23;810:33;837:5;810:33;:::i;878:263::-;;1001:2;989:9;980:7;976:23;972:32;969:2;;;1022:6;1014;1007:22;969:2;1059:9;1053:16;1078:33;1105:5;1078:33;:::i;1146:402::-;;;1275:2;1263:9;1254:7;1250:23;1246:32;1243:2;;;1296:6;1288;1281:22;1243:2;1340:9;1327:23;1359:33;1386:5;1359:33;:::i;:::-;1411:5;-1:-1:-1;1468:2:1;1453:18;;1440:32;1481:35;1440:32;1481:35;:::i;:::-;1535:7;1525:17;;;1233:315;;;;;:::o;1553:470::-;;;;1699:2;1687:9;1678:7;1674:23;1670:32;1667:2;;;1720:6;1712;1705:22;1667:2;1764:9;1751:23;1783:33;1810:5;1783:33;:::i;:::-;1835:5;-1:-1:-1;1892:2:1;1877:18;;1864:32;1905:35;1864:32;1905:35;:::i;:::-;1657:366;;1959:7;;-1:-1:-1;;;2013:2:1;1998:18;;;;1985:32;;1657:366::o;2028:683::-;;;;;;2208:3;2196:9;2187:7;2183:23;2179:33;2176:2;;;2230:6;2222;2215:22;2176:2;2274:9;2261:23;2293:33;2320:5;2293:33;:::i;:::-;2345:5;-1:-1:-1;2402:2:1;2387:18;;2374:32;2415:35;2374:32;2415:35;:::i;:::-;2469:7;-1:-1:-1;2523:2:1;2508:18;;2495:32;;-1:-1:-1;2574:2:1;2559:18;;2546:32;;-1:-1:-1;2630:3:1;2615:19;;2602:33;2644:35;2602:33;2644:35;:::i;:::-;2698:7;2688:17;;;2166:545;;;;;;;;:::o;2716:438::-;;;2842:2;2830:9;2821:7;2817:23;2813:32;2810:2;;;2863:6;2855;2848:22;2810:2;2907:9;2894:23;2926:33;2953:5;2926:33;:::i;:::-;2978:5;-1:-1:-1;3035:2:1;3020:18;;3007:32;3077:15;;3070:23;3058:36;;3048:2;;3113:6;3105;3098:22;3159:327;;;3288:2;3276:9;3267:7;3263:23;3259:32;3256:2;;;3309:6;3301;3294:22;3256:2;3353:9;3340:23;3372:33;3399:5;3372:33;:::i;:::-;3424:5;3476:2;3461:18;;;;3448:32;;-1:-1:-1;;;3246:240:1:o;3491:539::-;;;;;3654:3;3642:9;3633:7;3629:23;3625:33;3622:2;;;3676:6;3668;3661:22;3622:2;3720:9;3707:23;3739:33;3766:5;3739:33;:::i;:::-;3791:5;-1:-1:-1;3843:2:1;3828:18;;3815:32;;-1:-1:-1;3894:2:1;3879:18;;3866:32;;-1:-1:-1;3950:2:1;3935:18;;3922:32;3963:35;3922:32;3963:35;:::i;:::-;3612:418;;;;-1:-1:-1;3612:418:1;;-1:-1:-1;;3612:418:1:o;4035:600::-;;;;4199:2;4187:9;4178:7;4174:23;4170:32;4167:2;;;4220:6;4212;4205:22;4167:2;4265:9;4252:23;-1:-1:-1;;;;;4290:6:1;4287:30;4284:2;;;4335:6;4327;4320:22;4284:2;4379:76;4447:7;4438:6;4427:9;4423:22;4379:76;:::i;:::-;4474:8;;-1:-1:-1;4353:102:1;-1:-1:-1;;4559:2:1;4544:18;;4531:32;4572:33;4531:32;4572:33;:::i;:::-;4624:5;4614:15;;;4157:478;;;;;:::o;4640:815::-;;;;;4839:2;4827:9;4818:7;4814:23;4810:32;4807:2;;;4860:6;4852;4845:22;4807:2;4905:9;4892:23;-1:-1:-1;;;;;4975:2:1;4967:6;4964:14;4961:2;;;4996:6;4988;4981:22;4961:2;5040:76;5108:7;5099:6;5088:9;5084:22;5040:76;:::i;:::-;5135:8;;-1:-1:-1;5014:102:1;-1:-1:-1;5223:2:1;5208:18;;5195:32;;-1:-1:-1;5239:16:1;;;5236:2;;;5273:6;5265;5258:22;5236:2;;5317:78;5387:7;5376:8;5365:9;5361:24;5317:78;:::i;:::-;4797:658;;;;-1:-1:-1;5414:8:1;-1:-1:-1;;;;4797:658:1:o;5460:1021::-;;;;;;;5693:3;5681:9;5672:7;5668:23;5664:33;5661:2;;;5715:6;5707;5700:22;5661:2;5760:9;5747:23;-1:-1:-1;;;;;5830:2:1;5822:6;5819:14;5816:2;;;5851:6;5843;5836:22;5816:2;5895:76;5963:7;5954:6;5943:9;5939:22;5895:76;:::i;:::-;5990:8;;-1:-1:-1;5869:102:1;-1:-1:-1;6078:2:1;6063:18;;6050:32;;-1:-1:-1;6094:16:1;;;6091:2;;;6128:6;6120;6113:22;6091:2;;6172:78;6242:7;6231:8;6220:9;6216:24;6172:78;:::i;:::-;6269:8;;-1:-1:-1;6146:104:1;-1:-1:-1;;6351:2:1;6336:18;;6323:32;;-1:-1:-1;6405:2:1;6390:18;;6377:32;6418:33;6377:32;6418:33;:::i;:::-;6470:5;6460:15;;;5651:830;;;;;;;;:::o;6486:274::-;;;6615:2;6603:9;6594:7;6590:23;6586:32;6583:2;;;6636:6;6628;6621:22;6583:2;6664:31;6685:9;6664:31;:::i;:::-;6654:41;;6714:40;6750:2;6739:9;6735:18;6714:40;:::i;:::-;6704:50;;6573:187;;;;;:::o;6765:190::-;;6877:2;6865:9;6856:7;6852:23;6848:32;6845:2;;;6898:6;6890;6883:22;6845:2;-1:-1:-1;6926:23:1;;6835:120;-1:-1:-1;6835:120:1:o;6960:194::-;;7083:2;7071:9;7062:7;7058:23;7054:32;7051:2;;;7104:6;7096;7089:22;7051:2;-1:-1:-1;7132:16:1;;7041:113;-1:-1:-1;7041:113:1:o;7159:668::-;;;;;7340:2;7328:9;7319:7;7315:23;7311:32;7308:2;;;7361:6;7353;7346:22;7308:2;7402:9;7389:23;7379:33;;7463:2;7452:9;7448:18;7435:32;-1:-1:-1;;;;;7482:6:1;7479:30;7476:2;;;7527:6;7519;7512:22;7476:2;7571:76;7639:7;7630:6;7619:9;7615:22;7571:76;:::i;:::-;7666:8;;-1:-1:-1;7545:102:1;-1:-1:-1;;7751:2:1;7736:18;;7723:32;7764:33;7723:32;7764:33;:::i;7832:1209::-;;;7997:2;7985:9;7976:7;7972:23;7968:32;7965:2;;;8018:6;8010;8003:22;7965:2;8052:9;8046:16;8036:26;;8081:2;8127;8116:9;8112:18;8106:25;-1:-1:-1;;;;;8191:2:1;8183:6;8180:14;8177:2;;;8212:6;8204;8197:22;8177:2;8255:6;8244:9;8240:22;8230:32;;8300:7;8293:4;8289:2;8285:13;8281:27;8271:2;;8327:6;8319;8312:22;8271:2;8361;8355:9;8383:2;8379;8376:10;8373:2;;;8389:18;;:::i;:::-;8436:2;8432;8428:11;8468:2;8462:9;8519:2;8514;8506:6;8502:15;8498:24;8572:6;8560:10;8557:22;8552:2;8540:10;8537:18;8534:46;8531:2;;;8583:18;;:::i;:::-;8619:2;8612:22;8669:18;;;8703:15;;;;-1:-1:-1;8738:11:1;;;8768;;;8764:20;;8761:33;-1:-1:-1;8758:2:1;;;8812:6;8804;8797:22;8758:2;8839:6;8830:15;;8854:156;8868:2;8865:1;8862:9;8854:156;;;8925:10;;8913:23;;8886:1;8879:9;;;;;8956:12;;;;8988;;8854:156;;;8858:3;9029:6;9019:16;;;;;;;;7955:1086;;;;;:::o;9046:258::-;;;9175:2;9163:9;9154:7;9150:23;9146:32;9143:2;;;9196:6;9188;9181:22;9143:2;-1:-1:-1;;9224:23:1;;;9294:2;9279:18;;;9266:32;;-1:-1:-1;9133:171:1:o;9309:255::-;;;9449:2;9437:9;9428:7;9424:23;9420:32;9417:2;;;9470:6;9462;9455:22;9417:2;-1:-1:-1;;9498:16:1;;9554:2;9539:18;;;9533:25;9498:16;;9533:25;;-1:-1:-1;9407:157:1:o;9569:469::-;;9666:5;9660:12;9693:6;9688:3;9681:19;9719:4;9748:2;9743:3;9739:12;9732:19;;9785:2;9778:5;9774:14;9806:3;9818:195;9832:6;9829:1;9826:13;9818:195;;;9897:13;;-1:-1:-1;;;;;9893:39:1;9881:52;;9953:12;;;;9988:15;;;;9929:1;9847:9;9818:195;;;-1:-1:-1;10029:3:1;;9636:402;-1:-1:-1;;;;;9636:402:1:o;10043:481::-;;10151:5;10145:12;10178:6;10173:3;10166:19;10204:4;10233:2;10228:3;10224:12;10217:19;;10270:2;10263:5;10259:14;10291:3;10303:196;10317:6;10314:1;10311:13;10303:196;;;10366:51;10413:3;10404:6;10398:13;10366:51;:::i;:::-;10446:4;10437:14;;;;;10474:15;;;;10339:1;10332:9;10303:196;;10529:636;;10653:5;10647:12;10680:6;10675:3;10668:19;10706:4;10735:2;10730:3;10726:12;10719:19;;10759:5;10754:3;10747:18;10803:2;10798:3;10788:18;10824:3;10836:304;10850:6;10847:1;10844:13;10836:304;;;10916:13;;-1:-1:-1;;;;;10954:50:1;;10942:63;;11043:3;11039:19;11025:12;;;11018:41;11088:4;11079:14;;;;11128:1;11116:14;;;;10865:9;10836:304;;11170:443;;11267:5;11261:12;11294:6;11289:3;11282:19;11320:4;11349:2;11344:3;11340:12;11333:19;;11386:2;11379:5;11375:14;11407:3;11419:169;11433:6;11430:1;11427:13;11419:169;;;11494:13;;11482:26;;11528:12;;;;11563:15;;;;11455:1;11448:9;11419:169;;11618:452;;11713:5;11707:12;11740:6;11735:3;11728:19;11766:4;11795:2;11790:3;11786:12;11779:19;;11832:2;11825:5;11821:14;11853:3;11865:180;11879:6;11876:1;11873:13;11865:180;;;11944:13;;11959:4;11940:24;11928:37;;11985:12;;;;12020:15;;;;11901:1;11894:9;11865:180;;12075:243;12162:1;12155:5;12152:12;12142:2;;12207:10;12202:3;12198:20;12195:1;12188:31;12242:4;12239:1;12232:15;12270:4;12267:1;12260:15;12142:2;12294:18;;12132:186::o;12323:225::-;12459:12;;-1:-1:-1;;;;;12455:21:1;;;12443:34;;12530:4;12519:16;;;12513:23;12509:32;12493:14;;12486:56;12380:168::o;12553:408::-;12651:1;12647;12642:3;12638:11;12634:19;12692:2;12684:5;12678:12;12674:21;12669:3;12662:34;12757:2;12749:4;12742:5;12738:16;12732:23;12728:32;12721:4;12716:3;12712:14;12705:56;;12824:4;12817:5;12813:16;12807:23;12800:31;12793:39;12786:4;12781:3;12777:14;12770:63;12879:4;12872:5;12868:16;12862:23;12894:61;12949:4;12944:3;12940:14;12926:12;12894:61;:::i;:::-;;12614:347;;:::o;12966:424::-;13072:1;13068;13063:3;13059:11;13055:19;13113:2;13105:5;13099:12;13095:21;13090:3;13083:34;13160:4;13153:5;13149:16;13143:23;13213:2;13202:9;13198:18;13191:4;13186:3;13182:14;13175:42;13288:4;13276:9;13271:3;13267:19;13263:30;13256:38;13249:46;13242:4;13237:3;13233:14;13226:70;13305:79;13378:4;13373:3;13369:14;13362:4;13350:9;13345:3;13341:19;13337:30;13305:79;:::i;13395:225::-;13485:5;13479:12;13474:3;13467:25;13538:4;13531:5;13527:16;13521:23;13553:61;13608:4;13603:3;13599:14;13585:12;13553:61;:::i;13625:203::-;-1:-1:-1;;;;;13789:32:1;;;;13771:51;;13759:2;13744:18;;13726:102::o;13833:495::-;-1:-1:-1;;;;;14127:15:1;;;14109:34;;14179:15;;14174:2;14159:18;;14152:43;14238:14;;14231:22;14226:2;14211:18;;14204:50;14058:3;14043:19;;14263:59;14318:2;14303:18;;14295:6;14263:59;:::i;14333:528::-;-1:-1:-1;;;;;14648:15:1;;;14630:34;;14700:15;;;14695:2;14680:18;;14673:43;14747:2;14732:18;;14725:34;;;;14790:2;14775:18;;14768:34;14839:15;;;14833:3;14818:19;;14811:44;14579:3;14564:19;;14546:315::o;14866:447::-;-1:-1:-1;;;;;15153:15:1;;;15135:34;;15200:2;15185:18;;15178:34;;;;15248:15;;15243:2;15228:18;;15221:43;15295:2;15280:18;;15273:34;;;;15084:3;15069:19;;15051:262::o;15318:519::-;-1:-1:-1;;;;;15633:15:1;;;15615:34;;15680:2;15665:18;;15658:34;;;;15728:15;;;;15723:2;15708:18;;15701:43;15775:2;15760:18;;15753:34;;;;15818:3;15803:19;;15796:35;;;;15564:3;15549:19;;15531:306::o;15842:647::-;;16184:1;16180;16175:3;16171:11;16167:19;16159:6;16155:32;16144:9;16137:51;16224:6;16219:2;16208:9;16204:18;16197:34;16267:3;16262:2;16251:9;16247:18;16240:31;16294:63;16352:3;16341:9;16337:19;16329:6;16294:63;:::i;:::-;16405:9;16397:6;16393:22;16388:2;16377:9;16373:18;16366:50;16433;16476:6;16468;16433:50;:::i;16494:719::-;;16864:1;16860;16855:3;16851:11;16847:19;16839:6;16835:32;16824:9;16817:51;16904:6;16899:2;16888:9;16884:18;16877:34;16947:3;16942:2;16931:9;16927:18;16920:31;16974:63;17032:3;17021:9;17017:19;17009:6;16974:63;:::i;:::-;17085:9;17077:6;17073:22;17068:2;17057:9;17053:18;17046:50;17113;17156:6;17148;17113:50;:::i;:::-;17105:58;;;17200:6;17194:3;17183:9;17179:19;17172:35;16807:406;;;;;;;;:::o;17218:909::-;;17691:3;17680:9;17673:22;17718:74;17787:3;17776:9;17772:19;17764:6;17718:74;:::i;:::-;17840:9;17832:6;17828:22;17823:2;17812:9;17808:18;17801:50;17874:48;17915:6;17907;17874:48;:::i;:::-;17860:62;;17970:9;17962:6;17958:22;17953:2;17942:9;17938:18;17931:50;17998;18041:6;18033;17998:50;:::i;:::-;17990:58;;;18057:64;18117:2;18106:9;18102:18;18094:6;18057:64;:::i;18132:644::-;;18505:3;18494:9;18487:22;18526:74;18595:3;18584:9;18580:19;18572:6;18526:74;:::i;:::-;18518:82;;18648:4;18640:6;18636:17;18631:2;18620:9;18616:18;18609:45;18690:6;18685:2;18674:9;18670:18;18663:34;18706:64;18766:2;18755:9;18751:18;18743:6;18706:64;:::i;18781:815::-;;19198:3;19228:2;19217:9;19210:21;19248:73;19317:2;19306:9;19302:18;19294:6;19248:73;:::i;:::-;19240:81;;;19369:4;19361:6;19357:17;19352:2;19341:9;19337:18;19330:45;19423:4;19415:6;19411:17;19406:2;19395:9;19391:18;19384:45;19465:6;19460:2;19449:9;19445:18;19438:34;19509:6;19503:3;19492:9;19488:19;19481:35;19525:65;19585:3;19574:9;19570:19;19562:6;19525:65;:::i;19601:1142::-;;20078:3;20067:9;20060:22;20105:90;20190:3;20179:9;20175:19;20167:6;20105:90;:::i;:::-;20243:9;20235:6;20231:22;20226:2;20215:9;20211:18;20204:50;20277:48;20318:6;20310;20277:48;:::i;:::-;20361:22;;;20356:2;20341:18;;20334:50;20393:22;;;20263:62;-1:-1:-1;;;;;;20427:31:1;;20424:2;;;20474:4;20468;20461:18;20424:2;20516;20508:6;20504:15;20566:6;20558;20553:2;20545:6;20541:15;20528:45;20596:19;20617:2;20592:28;20629:16;;;20673:64;20733:2;20718:18;;20710:6;20673:64;:::i;:::-;20050:693;;;;;;;;:::o;20748:654::-;;21115:3;21104:9;21097:22;21136:90;21221:3;21210:9;21206:19;21198:6;21136:90;:::i;21407:969::-;21787:2;21799:21;;;21869:13;;21772:18;;;21891:22;;;21407:969;;21966:4;;21944:2;21929:18;;;21993:15;;;21407:969;22039:200;22053:6;22050:1;22047:13;22039:200;;;22102:55;22153:3;22144:6;22138:13;22102:55;:::i;:::-;22186:4;22177:14;;;;;22214:15;;;;22075:1;22068:9;22039:200;;;22043:3;;;22284:9;22279:3;22275:19;22270:2;22259:9;22255:18;22248:47;22312:58;22366:3;22358:6;22312:58;:::i;22381:1153::-;22851:3;22864:22;;;22935:13;;22836:19;;;22957:22;;;22381:1153;23023:20;;;23082:4;23066:21;;22381:1153;;23010:3;22995:19;;;22381:1153;23118:203;23132:6;23129:1;23126:13;23118:203;;;23181:56;23233:3;23225:6;23181:56;:::i;:::-;23306:4;23294:17;;;;;23266:4;23257:14;;;;;23154:1;23147:9;23118:203;;;-1:-1:-1;;23372:4:1;23357:20;;23350:36;;;-1:-1:-1;;;;;23422:32:1;;23417:2;23402:18;;23395:60;23338:3;-1:-1:-1;23464:64:1;;-1:-1:-1;23524:2:1;23509:18;;23501:6;23464:64;:::i;23539:507::-;23844:25;;;23900:2;23885:18;;23878:34;;;;-1:-1:-1;;;;;23948:32:1;23943:2;23928:18;;23921:60;24024:14;24017:22;24012:2;23997:18;;23990:50;23831:3;23816:19;;23798:248::o;24051:1032::-;24428:25;;;24472:2;24490:18;;;24483:34;;;24415:3;24548:2;24533:18;;24526:31;;;24400:19;;24592:22;;;24051:1032;;24672:6;;24645:3;24630:19;;24051:1032;24709:279;24723:6;24720:1;24717:13;24709:279;;;24798:6;24785:20;24818:33;24845:5;24818:33;:::i;:::-;-1:-1:-1;;;;;24876:31:1;24864:44;;24963:15;;;;24928:12;;;;24904:1;24738:9;24709:279;;;-1:-1:-1;;;;;;25044:32:1;;;;25039:2;25024:18;;;;25017:60;;;;-1:-1:-1;25005:3:1;;24376:707;-1:-1:-1;;;;;;24376:707:1:o;25088:267::-;;25267:2;25256:9;25249:21;25287:62;25345:2;25334:9;25330:18;25322:6;25287:62;:::i;25360:187::-;25525:14;;25518:22;25500:41;;25488:2;25473:18;;25455:92::o;25552:268::-;25739:14;;25732:22;25714:41;;25798:14;25791:22;25786:2;25771:18;;25764:50;25702:2;25687:18;;25669:151::o;25825:177::-;25971:25;;;25959:2;25944:18;;25926:76::o;26464:603::-;;26605:2;26634;26623:9;26616:21;26666:6;26660:13;26709:6;26704:2;26693:9;26689:18;26682:34;26734:4;26747:140;26761:6;26758:1;26755:13;26747:140;;;26856:14;;;26852:23;;26846:30;26822:17;;;26841:2;26818:26;26811:66;26776:10;;26747:140;;;26905:6;26902:1;26899:13;26896:2;;;26975:4;26970:2;26961:6;26950:9;26946:22;26942:31;26935:45;26896:2;-1:-1:-1;27051:2:1;27030:15;-1:-1:-1;;27026:29:1;27011:45;;;;27058:2;27007:54;;26585:482;-1:-1:-1;;;26585:482:1:o;27072:339::-;27274:2;27256:21;;;27313:2;27293:18;;;27286:30;-1:-1:-1;;;27347:2:1;27332:18;;27325:45;27402:2;27387:18;;27246:165::o;27416:399::-;27618:2;27600:21;;;27657:2;27637:18;;;27630:30;27696:34;27691:2;27676:18;;27669:62;-1:-1:-1;;;27762:2:1;27747:18;;27740:33;27805:3;27790:19;;27590:225::o;27820:337::-;28022:2;28004:21;;;28061:2;28041:18;;;28034:30;-1:-1:-1;;;28095:2:1;28080:18;;28073:43;28148:2;28133:18;;27994:163::o;28162:337::-;28364:2;28346:21;;;28403:2;28383:18;;;28376:30;-1:-1:-1;;;28437:2:1;28422:18;;28415:43;28490:2;28475:18;;28336:163::o;28504:336::-;28706:2;28688:21;;;28745:2;28725:18;;;28718:30;-1:-1:-1;;;28779:2:1;28764:18;;28757:42;28831:2;28816:18;;28678:162::o;28845:398::-;29047:2;29029:21;;;29086:2;29066:18;;;29059:30;29125:34;29120:2;29105:18;;29098:62;-1:-1:-1;;;29191:2:1;29176:18;;29169:32;29233:3;29218:19;;29019:224::o;29248:347::-;29450:2;29432:21;;;29489:2;29469:18;;;29462:30;29528:25;29523:2;29508:18;;29501:53;29586:2;29571:18;;29422:173::o;29600:331::-;29802:2;29784:21;;;29841:1;29821:18;;;29814:29;-1:-1:-1;;;29874:2:1;29859:18;;29852:38;29922:2;29907:18;;29774:157::o;29936:344::-;30138:2;30120:21;;;30177:2;30157:18;;;30150:30;-1:-1:-1;;;30211:2:1;30196:18;;30189:50;30271:2;30256:18;;30110:170::o;30285:344::-;30487:2;30469:21;;;30526:2;30506:18;;;30499:30;-1:-1:-1;;;30560:2:1;30545:18;;30538:50;30620:2;30605:18;;30459:170::o;30634:403::-;30836:2;30818:21;;;30875:2;30855:18;;;30848:30;30914:34;30909:2;30894:18;;30887:62;-1:-1:-1;;;30980:2:1;30965:18;;30958:37;31027:3;31012:19;;30808:229::o;31042:336::-;31244:2;31226:21;;;31283:2;31263:18;;;31256:30;-1:-1:-1;;;31317:2:1;31302:18;;31295:42;31369:2;31354:18;;31216:162::o;31383:348::-;31585:2;31567:21;;;31624:2;31604:18;;;31597:30;31663:26;31658:2;31643:18;;31636:54;31722:2;31707:18;;31557:174::o;31736:347::-;31938:2;31920:21;;;31977:2;31957:18;;;31950:30;32016:25;32011:2;31996:18;;31989:53;32074:2;32059:18;;31910:173::o;32088:343::-;32290:2;32272:21;;;32329:2;32309:18;;;32302:30;-1:-1:-1;;;32363:2:1;32348:18;;32341:49;32422:2;32407:18;;32262:169::o;32436:349::-;32638:2;32620:21;;;32677:2;32657:18;;;32650:30;32716:27;32711:2;32696:18;;32689:55;32776:2;32761:18;;32610:175::o;32790:343::-;32992:2;32974:21;;;33031:2;33011:18;;;33004:30;-1:-1:-1;;;33065:2:1;33050:18;;33043:49;33124:2;33109:18;;32964:169::o;33138:338::-;33340:2;33322:21;;;33379:2;33359:18;;;33352:30;-1:-1:-1;;;33413:2:1;33398:18;;33391:44;33467:2;33452:18;;33312:164::o;33481:332::-;33683:2;33665:21;;;33722:1;33702:18;;;33695:29;-1:-1:-1;;;33755:2:1;33740:18;;33733:39;33804:2;33789:18;;33655:158::o;33818:346::-;34020:2;34002:21;;;34059:2;34039:18;;;34032:30;-1:-1:-1;;;34093:2:1;34078:18;;34071:52;34155:2;34140:18;;33992:172::o;34169:338::-;34371:2;34353:21;;;34410:2;34390:18;;;34383:30;-1:-1:-1;;;34444:2:1;34429:18;;34422:44;34498:2;34483:18;;34343:164::o;34512:335::-;34714:2;34696:21;;;34753:2;34733:18;;;34726:30;-1:-1:-1;;;34787:2:1;34772:18;;34765:41;34838:2;34823:18;;34686:161::o;34852:341::-;35054:2;35036:21;;;35093:2;35073:18;;;35066:30;-1:-1:-1;;;35127:2:1;35112:18;;35105:47;35184:2;35169:18;;35026:167::o;35198:345::-;35400:2;35382:21;;;35439:2;35419:18;;;35412:30;-1:-1:-1;;;35473:2:1;35458:18;;35451:51;35534:2;35519:18;;35372:171::o;35548:344::-;35750:2;35732:21;;;35789:2;35769:18;;;35762:30;-1:-1:-1;;;35823:2:1;35808:18;;35801:50;35883:2;35868:18;;35722:170::o;35897:397::-;36099:2;36081:21;;;36138:2;36118:18;;;36111:30;36177:34;36172:2;36157:18;;36150:62;-1:-1:-1;;;36243:2:1;36228:18;;36221:31;36284:3;36269:19;;36071:223::o;36299:339::-;36501:2;36483:21;;;36540:2;36520:18;;;36513:30;-1:-1:-1;;;36574:2:1;36559:18;;36552:45;36629:2;36614:18;;36473:165::o;36643:401::-;36845:2;36827:21;;;36884:2;36864:18;;;36857:30;36923:34;36918:2;36903:18;;36896:62;-1:-1:-1;;;36989:2:1;36974:18;;36967:35;37034:3;37019:19;;36817:227::o;37049:338::-;37251:2;37233:21;;;37290:2;37270:18;;;37263:30;-1:-1:-1;;;37324:2:1;37309:18;;37302:44;37378:2;37363:18;;37223:164::o;37392:400::-;37594:2;37576:21;;;37633:2;37613:18;;;37606:30;37672:34;37667:2;37652:18;;37645:62;-1:-1:-1;;;37738:2:1;37723:18;;37716:34;37782:3;37767:19;;37566:226::o;37797:329::-;37999:2;37981:21;;;38038:1;38018:18;;;38011:29;-1:-1:-1;;;38071:2:1;38056:18;;38049:36;38117:2;38102:18;;37971:155::o;38131:355::-;38333:2;38315:21;;;38372:2;38352:18;;;38345:30;38411:33;38406:2;38391:18;;38384:61;38477:2;38462:18;;38305:181::o;38491:344::-;38693:2;38675:21;;;38732:2;38712:18;;;38705:30;-1:-1:-1;;;38766:2:1;38751:18;;38744:50;38826:2;38811:18;;38665:170::o;38840:348::-;39042:2;39024:21;;;39081:2;39061:18;;;39054:30;39120:26;39115:2;39100:18;;39093:54;39179:2;39164:18;;39014:174::o;39193:356::-;39395:2;39377:21;;;39414:18;;;39407:30;39473:34;39468:2;39453:18;;39446:62;39540:2;39525:18;;39367:182::o;39554:355::-;39756:2;39738:21;;;39795:2;39775:18;;;39768:30;39834:33;39829:2;39814:18;;39807:61;39900:2;39885:18;;39728:181::o;39914:276::-;40116:25;;;40172:2;40157:18;;40150:34;40104:2;40089:18;;40071:119::o;40195:491::-;40482:25;;;40538:2;40523:18;;40516:34;;;;40581:2;40566:18;;40559:34;;;;40624:2;40609:18;;40602:34;40667:3;40652:19;;40645:35;40469:3;40454:19;;40436:250::o;40691:521::-;41026:25;;;41082:2;41067:18;;41060:34;;;;41125:2;41110:18;;41103:34;-1:-1:-1;;;;;41173:32:1;41168:2;41153:18;;41146:60;41013:3;40998:19;;40980:232::o;41217:603::-;41574:25;;;41630:2;41615:18;;41608:34;;;;41673:2;41658:18;;41651:34;;;;-1:-1:-1;;;;;41721:32:1;41716:2;41701:18;;41694:60;41798:14;41791:22;41785:3;41770:19;;41763:51;41561:3;41546:19;;41528:292::o;41825:416::-;42099:3;42084:19;;42112:54;42088:9;42148:6;42112:54;:::i;:::-;42175:60;42230:3;42219:9;42215:19;42207:6;42175:60;:::i;42246:532::-;42532:3;42517:19;;42545:54;42521:9;42581:6;42545:54;:::i;:::-;-1:-1:-1;;;;;42640:6:1;42636:47;42630:3;42619:9;42615:19;42608:76;42721:6;42715:3;42704:9;42700:19;42693:35;42765:6;42759:3;42748:9;42744:19;42737:35;42499:279;;;;;;;:::o;42783:269::-;42979:2;42964:18;;42991:55;42968:9;43028:6;42991:55;:::i;43057:319::-;-1:-1:-1;;;;;43302:15:1;;;43284:34;;43354:15;;43349:2;43334:18;;43327:43;43219:2;43204:18;;43186:190::o;43563:665::-;43942:25;;;43929:3;43914:19;;43976:63;44035:2;44020:18;;44012:6;43976:63;:::i;:::-;44048:60;44103:3;44092:9;44088:19;44080:6;44048:60;:::i;:::-;-1:-1:-1;;;;;44145:32:1;;;;44139:3;44124:19;;44117:61;44209:3;44194:19;44187:35;43896:332;;-1:-1:-1;;;43896:332:1:o;44233:670::-;44609:25;;;44596:3;44581:19;;44643:71;44710:2;44695:18;;44687:6;44643:71;:::i;45161:456::-;-1:-1:-1;;;;;45439:15:1;;;45421:34;;45491:15;;;45486:2;45471:18;;45464:43;45543:15;;;45538:2;45523:18;;45516:43;45595:15;;;45590:2;45575:18;;45568:43;45371:3;45356:19;;45338:279::o;45622:184::-;45794:4;45782:17;;;;45764:36;;45752:2;45737:18;;45719:87::o;45811:253::-;;-1:-1:-1;;;;;45940:2:1;45937:1;45933:10;45970:2;45967:1;45963:10;46001:3;45997:2;45993:12;45988:3;45985:21;45982:2;;;46009:18;;:::i;:::-;46045:13;;45859:205;-1:-1:-1;;;;45859:205:1:o;46069:128::-;;46140:1;46136:6;46133:1;46130:13;46127:2;;;46146:18;;:::i;:::-;-1:-1:-1;46182:9:1;;46117:80::o;46202:217::-;;46268:1;46258:2;;-1:-1:-1;;;46293:31:1;;46347:4;46344:1;46337:15;46375:4;46300:1;46365:15;46258:2;-1:-1:-1;46404:9:1;;46248:171::o;46424:168::-;;46530:1;46526;46522:6;46518:14;46515:1;46512:21;46507:1;46500:9;46493:17;46489:45;46486:2;;;46537:18;;:::i;:::-;-1:-1:-1;46577:9:1;;46476:116::o;46597:246::-;;-1:-1:-1;;;;;46750:10:1;;;;46720;;46772:12;;;46769:2;;;46787:18;;:::i;:::-;46824:13;;46646:197;-1:-1:-1;;;46646:197:1:o;46848:125::-;;46916:1;46913;46910:8;46907:2;;;46921:18;;:::i;:::-;-1:-1:-1;46958:9:1;;46897:76::o;46978:229::-;;-1:-1:-1;;;;;47114:10:1;;;;47084;;47136:12;;;47133:2;;;47151:18;;:::i;47212:380::-;47297:1;47287:12;;47344:1;47334:12;;;47355:2;;47409:4;47401:6;47397:17;47387:27;;47355:2;47462;47454:6;47451:14;47431:18;47428:38;47425:2;;;47508:10;47503:3;47499:20;47496:1;47489:31;47543:4;47540:1;47533:15;47571:4;47568:1;47561:15;47425:2;;47267:325;;;:::o;47597:135::-;;-1:-1:-1;;47657:17:1;;47654:2;;;47677:18;;:::i;:::-;-1:-1:-1;47724:1:1;47713:13;;47644:88::o;47737:127::-;47798:10;47793:3;47789:20;47786:1;47779:31;47829:4;47826:1;47819:15;47853:4;47850:1;47843:15;47869:127;47930:10;47925:3;47921:20;47918:1;47911:31;47961:4;47958:1;47951:15;47985:4;47982:1;47975:15;48001:133;-1:-1:-1;;;;;48078:31:1;;48068:42;;48058:2;;48124:1;48121;48114:12

Swarm Source

ipfs://af3c4c0b4e5eb78b3bd030aeca63dd38ef79a65a2ef13e1484d268c12f499f77

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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