MATIC Price: $0.99 (-2.45%)
Gas: 125 GWei
 

Overview

MATIC Balance

Polygon PoS Chain LogoPolygon PoS Chain LogoPolygon PoS Chain Logo0 MATIC

MATIC Value

$0.00

Sponsored

Transaction Hash
Method
Block
From
To
Value
0x6142f261136306362021-04-23 12:48:071070 days ago1619182087IN
 Create: MassetLogic
0 MATIC0.003752541

Parent Txn Hash Block From To Value
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
MassetLogic

Compiler Version
v0.8.2+commit.661d1103

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, GNU AGPLv3 license

Contract Source Code (Solidity)

/**
 *Submitted for verification at polygonscan.com on 2021-06-25
*/

pragma solidity 0.8.2;


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

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 FeederConfig {
    uint256 supply;
    uint256 a;
    WeightLimits limits;
}

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

struct BasicConfig {
    uint256 a;
    WeightLimits limits;
}

struct WeightLimits {
    uint128 min;
    uint128 max;
}

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

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

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

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

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

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

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

/**
 * @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.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

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

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

    function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

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

library SafeERC20 {
    using Address for address;

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

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

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

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

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

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

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

library 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 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 StableMath {
    /**
     * @dev Scaling unit for use in specific calculations,
     * where 1 * 10**18, or 1e18 represents a unit '1'
     */
    uint256 private constant FULL_SCALE = 1e18;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// SPDX-License-Identifier: AGPL-3.0-or-later
// External
// Internal
// Libs
/**
 * @title   MassetLogic
 * @author  mStable
 * @notice  Builds on and enforces the StableSwap invariant conceived by Michael Egorov. (https://www.curve.fi/stableswap-paper.pdf)
 *          Derived by mStable and adapted for the needs of an mAsset, as described in MIP-7 (http://mips.mstable.org/MIPS/mip-7)
 *          Calculates and validates the result of Masset operations with respect to the invariant.
 *          This supports low slippage swaps and applies penalties towards min and max regions.
 * @dev     VERSION: 1.0
 *          DATE:    2021-04-23
 */
library MassetLogic {
    using StableMath for uint256;
    using SafeERC20 for IERC20;

    uint256 internal constant A_PRECISION = 100;

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

    /**
     * @notice Transfers token in, updates internal balances and computes the mAsset output
     * @param _data                 Masset storage state
     * @param _config               Core config for use in the invariant validator
     * @param _input                Data on the bAsset to deposit for the minted mAsset.
     * @param _inputQuantity        Quantity in input token units.
     * @param _minOutputQuantity    Minimum mAsset quantity to be minted. This protects against slippage.
     * @return mintOutput           Quantity of mAsset minted from the deposited bAsset.
     */
    function mint(
        MassetData storage _data,
        InvariantConfig calldata _config,
        Asset calldata _input,
        uint256 _inputQuantity,
        uint256 _minOutputQuantity
    ) external returns (uint256 mintOutput) {
        BassetData[] memory cachedBassetData = _data.bAssetData;
        // Transfer collateral to the platform integration address and call deposit
        uint256 quantityDeposited =
            _depositTokens(
                _data.bAssetPersonal[_input.idx],
                cachedBassetData[_input.idx].ratio,
                _inputQuantity,
                _getCacheDetails(_data, _config.supply)
            );
        // Validation should be after token transfer, as bAssetQty is unknown before
        mintOutput = computeMint(cachedBassetData, _input.idx, quantityDeposited, _config);
        require(mintOutput >= _minOutputQuantity, "Mint quantity < min qty");
        // Log the Vault increase - can only be done when basket is healthy
        _data.bAssetData[_input.idx].vaultBalance =
            cachedBassetData[_input.idx].vaultBalance +
            SafeCast.toUint128(quantityDeposited);
    }

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

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

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

    /**
     * @notice Swaps two assets - either internally between fAsset<>mAsset, or between fAsset<>mpAsset by
     * first routing through the mAsset pool.
     * @param _data              Masset storage state
     * @param _config            Core config for use in the invariant validator
     * @param _input             Data on bAsset to deposit
     * @param _output            Data on bAsset to withdraw
     * @param _inputQuantity     Units of input bAsset to swap in
     * @param _minOutputQuantity Minimum quantity of the swap output asset. This protects against slippage
     * @param _recipient         Address to transfer output asset to
     * @return swapOutput        Quantity of output asset returned from swap
     * @return scaledFee          Fee paid, in mAsset terms
     */
    function swap(
        MassetData storage _data,
        InvariantConfig calldata _config,
        Asset calldata _input,
        Asset calldata _output,
        uint256 _inputQuantity,
        uint256 _minOutputQuantity,
        address _recipient
    ) external returns (uint256 swapOutput, uint256 scaledFee) {
        BassetData[] memory cachedBassetData = _data.bAssetData;
        // 3. Deposit the input tokens
        uint256 quantityDeposited =
            _depositTokens(
                _data.bAssetPersonal[_input.idx],
                cachedBassetData[_input.idx].ratio,
                _inputQuantity,
                _getCacheDetails(_data, _config.supply)
            );
        // 3.1. Update the input balance
        _data.bAssetData[_input.idx].vaultBalance =
            cachedBassetData[_input.idx].vaultBalance +
            SafeCast.toUint128(quantityDeposited);

        // 3. Validate the swap
        (swapOutput, scaledFee) = computeSwap(
            cachedBassetData,
            _input.idx,
            _output.idx,
            quantityDeposited,
            _data.swapFee,
            _config
        );
        require(swapOutput >= _minOutputQuantity, "Output qty < minimum qty");
        require(swapOutput > 0, "Zero output quantity");
        //4. Settle the swap
        //4.1. Decrease output bal
        uint256 maxCache = _getCacheDetails(_data, _config.supply);
        _withdrawTokens(
            swapOutput,
            _data.bAssetPersonal[_output.idx],
            cachedBassetData[_output.idx],
            _recipient,
            maxCache
        );
        _data.bAssetData[_output.idx].vaultBalance =
            cachedBassetData[_output.idx].vaultBalance -
            SafeCast.toUint128(swapOutput);
        // Save new surplus to storage
        _data.surplus += scaledFee;
    }

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

    /**
     * @notice Burns a specified quantity of the senders mAsset in return for a bAsset. The output amount is derived
     * from the invariant. Supports redemption into either the fAsset, mAsset or assets in the mAsset basket.
     * @param _data              Masset storage state
     * @param _config            Core config for use in the invariant validator
     * @param _output            Data on bAsset to withdraw
     * @param _inputQuantity   Quantity of mAsset to burn
     * @param _minOutputQuantity Minimum bAsset quantity to receive for the burnt mAsset. This protects against slippage.
     * @param _recipient         Address to transfer the withdrawn bAssets to.
     * @return bAssetQuantity    Quanity of bAsset units received for the burnt mAsset
     * @return scaledFee          Fee paid, in mAsset terms
     */
    function redeem(
        MassetData storage _data,
        InvariantConfig calldata _config,
        Asset calldata _output,
        uint256 _inputQuantity,
        uint256 _minOutputQuantity,
        address _recipient
    ) external returns (uint256 bAssetQuantity, uint256 scaledFee) {
        // Load the bAsset data from storage into memory
        BassetData[] memory cachedBassetData = _data.bAssetData;
        // Calculate redemption quantities
        (bAssetQuantity, scaledFee) = computeRedeem(
            cachedBassetData,
            _output.idx,
            _inputQuantity,
            _config,
            _data.swapFee
        );
        require(bAssetQuantity >= _minOutputQuantity, "bAsset qty < min qty");
        require(bAssetQuantity > 0, "Output == 0");
        // Apply fees, burn mAsset and return bAsset to recipient
        _data.surplus += scaledFee;
        // 2.0. Transfer the Bassets to the recipient
        uint256 maxCache = _getCacheDetails(_data, _config.supply - _inputQuantity + scaledFee);
        _withdrawTokens(
            bAssetQuantity,
            _data.bAssetPersonal[_output.idx],
            cachedBassetData[_output.idx],
            _recipient,
            maxCache
        );
        // 3.0. Set vault balance
        _data.bAssetData[_output.idx].vaultBalance =
            cachedBassetData[_output.idx].vaultBalance -
            SafeCast.toUint128(bAssetQuantity);
    }

    /**
     * @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. Only fAsset & mAsset are supported in this path.
     * @param _data                 Masset storage state
     * @param _config               Core config for use in the invariant validator
     * @param _inputQuantity        Quantity of mAsset to redeem
     * @param _minOutputQuantities  Min units of output to receive
     * @param _recipient            Address to credit the withdrawn bAssets
     * @return scaledFee            Fee collected in mAsset terms
     * @return outputs              Array of output asset addresses
     * @return outputQuantities     Array of output asset quantities
     */
    function redeemProportionately(
        MassetData storage _data,
        InvariantConfig calldata _config,
        uint256 _inputQuantity,
        uint256[] calldata _minOutputQuantities,
        address _recipient
    )
        external
        returns (
            uint256 scaledFee,
            address[] memory outputs,
            uint256[] memory outputQuantities
        )
    {
        // Load the bAsset data from storage into memory
        BassetData[] memory cachedBassetData = _data.bAssetData;

        // Calculate mAsset redemption quantities
        uint256 deductedInput;
        (deductedInput, scaledFee) = _getDeducted(
            cachedBassetData,
            _config,
            _inputQuantity,
            _data.redemptionFee
        );

        _data.surplus += scaledFee;

        // Calc cache and total mAsset circulating
        uint256 maxCache = _getCacheDetails(_data, _config.supply - _inputQuantity + scaledFee);

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

    /** @dev Internal func to get the deducted input to avoid stack depth error */
    function _getDeducted(
        BassetData[] memory _bData,
        InvariantConfig memory _config,
        uint256 _input,
        uint256 _redemptionFee
    ) internal pure returns (uint256 deductedInput, uint256 scaledFee) {
        deductedInput = _input;
        // If supply > k, deduct recolFee
        (uint256 price, ) = computePrice(_bData, _config);
        if (price < 1e18) {
            deductedInput -= ((_input * _config.recolFee) / 1e18);
        }
        scaledFee = deductedInput.mulTruncate(_redemptionFee);
        deductedInput -= scaledFee;
    }

    /**
     * @dev Credits a recipient with a certain quantity of selected bAssets, in exchange for burning the
     *      relative mAsset quantity from the sender. Only fAsset & mAsset (0,1) are supported in this path.
     * @param _data                 Masset storage state
     * @param _config               Core config for use in the invariant validator
     * @param _indices              Indices of the bAssets to receive
     * @param _outputQuantities     Units of the bAssets to receive
     * @param _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 to burn as payment
     * @return fee             Fee collected, in mAsset terms
     */
    function redeemExactBassets(
        MassetData storage _data,
        InvariantConfig memory _config,
        uint8[] calldata _indices,
        uint256[] calldata _outputQuantities,
        uint256 _maxMassetQuantity,
        address _recipient
    ) external returns (uint256 mAssetQuantity, uint256 fee) {
        // Load bAsset data from storage to memory
        BassetData[] memory cachedBassetData = _data.bAssetData;

        (mAssetQuantity, fee) = computeRedeemExact(
            cachedBassetData,
            _indices,
            _outputQuantities,
            _config,
            _data.swapFee
        );
        require(mAssetQuantity <= _maxMassetQuantity, "Redeem mAsset qty > max quantity");
        // Apply fees, burn mAsset and return bAsset to recipient
        _data.surplus += fee;
        // Transfer the Bassets to the recipient and count fees
        uint256 maxCache = _getCacheDetails(_data, _config.supply - mAssetQuantity + fee);
        for (uint256 i = 0; i < _indices.length; i++) {
            uint8 idx = _indices[i];
            _withdrawTokens(
                _outputQuantities[i],
                _data.bAssetPersonal[idx],
                cachedBassetData[idx],
                _recipient,
                maxCache
            );
            _data.bAssetData[idx].vaultBalance =
                cachedBassetData[idx].vaultBalance -
                SafeCast.toUint128(_outputQuantities[i]);
        }
    }

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

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

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

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

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

        uint256 relativeMaxCache = _maxCache.divRatioPrecisely(_bAssetRatio);

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

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

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

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

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

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

    /**
     * @notice Compute the amount of mAsset received for minting
     * with `quantity` amount of bAsset index `i`.
     * @param _bAssets      Array of all bAsset Data
     * @param _i            Index of bAsset with which to mint
     * @param _rawInput     Raw amount of bAsset to use in mint
     * @param _config       Generalised invariantConfig stored externally
     * @return mintAmount   Quantity of mAssets minted
     */
    function computeMint(
        BassetData[] memory _bAssets,
        uint8 _i,
        uint256 _rawInput,
        InvariantConfig memory _config
    ) public view returns (uint256 mintAmount) {
        // 1. Get raw reserves
        (uint256[] memory x, uint256 sum) = _getReserves(_bAssets);
        // 2. Get value of reserves according to invariant
        uint256 k0 = _invariant(x, sum, _config.a);
        uint256 scaledInput = (_rawInput * _bAssets[_i].ratio) / 1e8;

        // 3. Add deposit to x and sum
        x[_i] += scaledInput;
        sum += scaledInput;
        // 4. Finalise mint
        require(_inBounds(x, sum, _config.limits), "Exceeds weight limits");
        mintAmount = _computeMintOutput(x, sum, k0, _config);
    }

    /**
     * @notice Compute the amount of mAsset received for minting
     * with the given array of inputs.
     * @param _bAssets      Array of all bAsset Data
     * @param _indices      Indexes of bAssets with which to mint
     * @param _rawInputs    Raw amounts of bAssets to use in mint
     * @param _config       Generalised invariantConfig stored externally
     * @return mintAmount   Quantity of mAssets minted
     */
    function computeMintMulti(
        BassetData[] memory _bAssets,
        uint8[] memory _indices,
        uint256[] memory _rawInputs,
        InvariantConfig memory _config
    ) public view returns (uint256 mintAmount) {
        // 1. Get raw reserves
        (uint256[] memory x, uint256 sum) = _getReserves(_bAssets);
        // 2. Get value of reserves according to invariant
        uint256 k0 = _invariant(x, sum, _config.a);

        // 3. Add deposits to x and sum
        uint256 len = _indices.length;
        uint8 idx;
        uint256 scaledInput;
        for (uint256 i = 0; i < len; i++) {
            idx = _indices[i];
            scaledInput = (_rawInputs[i] * _bAssets[idx].ratio) / 1e8;
            x[idx] += scaledInput;
            sum += scaledInput;
        }
        // 4. Finalise mint
        require(_inBounds(x, sum, _config.limits), "Exceeds weight limits");
        mintAmount = _computeMintOutput(x, sum, k0, _config);
    }

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

    /** @dev Gets swap fee and scales to avoid stack depth errors in computeSwap */
    function _getSwapFee(
        uint256 _k0,
        uint256 _k1,
        uint256 _feeRate,
        InvariantConfig memory _config
    ) internal pure returns (uint256 k2, uint256 scaledSwapFee) {
        uint256 minted = _k1 - _k0;
        // Under col? Deduct fee
        if (_config.supply > _k0) {
            minted -= ((minted * _config.recolFee) / 1e18);
        }
        // base swap fee
        scaledSwapFee = (minted * _feeRate) / 1e18;
        k2 = _k1 - minted + scaledSwapFee;
        // swap fee in lpToken terms
        scaledSwapFee = (scaledSwapFee * _config.supply) / _k0;
    }

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

    function _getFee(
        uint256 _grossMassetQuantity,
        InvariantConfig memory _config,
        uint256 _feeRate,
        uint256 _k0
    ) internal pure returns (uint256 redemption, uint256 scaledFee) {
        redemption = _grossMassetQuantity;
        if (_config.supply > _k0) {
            redemption -= ((redemption * _config.recolFee) / 1e18);
        }
        scaledFee = redemption.mulTruncate(_feeRate);
        redemption -= scaledFee;
    }

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

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

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

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

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

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

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

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

        if (_sum == 0) return 0;

        uint256 nA = _a * len;
        uint256 kPrev;
        k = _sum;

        for (uint256 i = 0; i < 256; i++) {
            uint256 kP = k;
            for (uint256 j = 0; j < len; j++) {
                kP = (kP * k) / (_x[j] * len);
            }
            kPrev = k;
            k =
                (((nA * _sum) / A_PRECISION + (kP * len)) * k) /
                (((nA - A_PRECISION) * k) / A_PRECISION + ((len + 1) * kP));
            if (_hasConverged(k, kPrev)) {
                return k;
            }
        }

        revert("Invariant did not converge");
    }

    /**
     * @dev Checks if a given solution has converged within a factor of 1
     * @param _k              Current solution k
     * @param _kPrev          Previous iteration solution
     * @return hasConverged   Bool, true if diff abs(k, kPrev) <= 1
     */
    function _hasConverged(uint256 _k, uint256 _kPrev) internal pure returns (bool) {
        if (_kPrev > _k) {
            return (_kPrev - _k) <= 1;
        } else {
            return (_k - _kPrev) <= 1;
        }
    }

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

        (uint256 sum_, uint256 nA, uint256 kP) = (0, _a * len, _targetK);

        for (uint256 i = 0; i < len; i++) {
            if (i != _idx) {
                sum_ += _x[i];
                kP = (kP * _targetK) / (_x[i] * len);
            }
        }

        uint256 c = (((kP * _targetK) * A_PRECISION) / nA) / len;
        uint256 g = (_targetK * (nA - A_PRECISION)) / nA;
        uint256 b = 0;

        if (g > sum_) {
            b = g - sum_;
            y = (Root.sqrt((b**2) + (4 * c)) + b) / 2 + 1;
        } else {
            b = sum_ - g;
            y = (Root.sqrt((b**2) + (4 * c)) - b) / 2 + 1;
        }

        if (y < 1e8) revert("Invalid solution");
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"components":[{"internalType":"uint128","name":"ratio","type":"uint128"},{"internalType":"uint128","name":"vaultBalance","type":"uint128"}],"internalType":"struct BassetData[]","name":"_bAssets","type":"tuple[]"},{"internalType":"uint8","name":"_i","type":"uint8"},{"internalType":"uint256","name":"_rawInput","type":"uint256"},{"components":[{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"a","type":"uint256"},{"components":[{"internalType":"uint128","name":"min","type":"uint128"},{"internalType":"uint128","name":"max","type":"uint128"}],"internalType":"struct WeightLimits","name":"limits","type":"tuple"},{"internalType":"uint256","name":"recolFee","type":"uint256"}],"internalType":"struct InvariantConfig","name":"_config","type":"tuple"}],"name":"computeMint","outputs":[{"internalType":"uint256","name":"mintAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint128","name":"ratio","type":"uint128"},{"internalType":"uint128","name":"vaultBalance","type":"uint128"}],"internalType":"struct BassetData[]","name":"_bAssets","type":"tuple[]"},{"internalType":"uint8[]","name":"_indices","type":"uint8[]"},{"internalType":"uint256[]","name":"_rawInputs","type":"uint256[]"},{"components":[{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"a","type":"uint256"},{"components":[{"internalType":"uint128","name":"min","type":"uint128"},{"internalType":"uint128","name":"max","type":"uint128"}],"internalType":"struct WeightLimits","name":"limits","type":"tuple"},{"internalType":"uint256","name":"recolFee","type":"uint256"}],"internalType":"struct InvariantConfig","name":"_config","type":"tuple"}],"name":"computeMintMulti","outputs":[{"internalType":"uint256","name":"mintAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint128","name":"ratio","type":"uint128"},{"internalType":"uint128","name":"vaultBalance","type":"uint128"}],"internalType":"struct BassetData[]","name":"_bAssets","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"a","type":"uint256"},{"components":[{"internalType":"uint128","name":"min","type":"uint128"},{"internalType":"uint128","name":"max","type":"uint128"}],"internalType":"struct WeightLimits","name":"limits","type":"tuple"},{"internalType":"uint256","name":"recolFee","type":"uint256"}],"internalType":"struct InvariantConfig","name":"_config","type":"tuple"}],"name":"computePrice","outputs":[{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"k","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"uint128","name":"ratio","type":"uint128"},{"internalType":"uint128","name":"vaultBalance","type":"uint128"}],"internalType":"struct BassetData[]","name":"_bAssets","type":"tuple[]"},{"internalType":"uint8","name":"_o","type":"uint8"},{"internalType":"uint256","name":"_grossMassetQuantity","type":"uint256"},{"components":[{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"a","type":"uint256"},{"components":[{"internalType":"uint128","name":"min","type":"uint128"},{"internalType":"uint128","name":"max","type":"uint128"}],"internalType":"struct WeightLimits","name":"limits","type":"tuple"},{"internalType":"uint256","name":"recolFee","type":"uint256"}],"internalType":"struct InvariantConfig","name":"_config","type":"tuple"},{"internalType":"uint256","name":"_feeRate","type":"uint256"}],"name":"computeRedeem","outputs":[{"internalType":"uint256","name":"rawOutputUnits","type":"uint256"},{"internalType":"uint256","name":"scaledFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint128","name":"ratio","type":"uint128"},{"internalType":"uint128","name":"vaultBalance","type":"uint128"}],"internalType":"struct BassetData[]","name":"_bAssets","type":"tuple[]"},{"internalType":"uint8[]","name":"_indices","type":"uint8[]"},{"internalType":"uint256[]","name":"_rawOutputs","type":"uint256[]"},{"components":[{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"a","type":"uint256"},{"components":[{"internalType":"uint128","name":"min","type":"uint128"},{"internalType":"uint128","name":"max","type":"uint128"}],"internalType":"struct WeightLimits","name":"limits","type":"tuple"},{"internalType":"uint256","name":"recolFee","type":"uint256"}],"internalType":"struct InvariantConfig","name":"_config","type":"tuple"},{"internalType":"uint256","name":"_feeRate","type":"uint256"}],"name":"computeRedeemExact","outputs":[{"internalType":"uint256","name":"grossMasset","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint128","name":"ratio","type":"uint128"},{"internalType":"uint128","name":"vaultBalance","type":"uint128"}],"internalType":"struct BassetData[]","name":"_bAssets","type":"tuple[]"},{"internalType":"uint8","name":"_i","type":"uint8"},{"internalType":"uint8","name":"_o","type":"uint8"},{"internalType":"uint256","name":"_rawInput","type":"uint256"},{"internalType":"uint256","name":"_feeRate","type":"uint256"},{"components":[{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"a","type":"uint256"},{"components":[{"internalType":"uint128","name":"min","type":"uint128"},{"internalType":"uint128","name":"max","type":"uint128"}],"internalType":"struct WeightLimits","name":"limits","type":"tuple"},{"internalType":"uint256","name":"recolFee","type":"uint256"}],"internalType":"struct InvariantConfig","name":"_config","type":"tuple"}],"name":"computeSwap","outputs":[{"internalType":"uint256","name":"bAssetOutputQuantity","type":"uint256"},{"internalType":"uint256","name":"scaledSwapFee","type":"uint256"}],"stateMutability":"view","type":"function"}]

6142f261003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100be5760003560e01c8063b3ffbf311161007b578063b3ffbf3114610191578063b995a2b5146101a4578063bf9f08b2146101b7578063ccf4ddcc146101ca578063d38e18e9146101ea578063ee679672146101fd576100be565b806307aa92c8146100c35780630ce8bc9b146100fd5780632c51918f1461011e57806361ec51541461013e5780637c1449941461015e5780638c420a9714610171575b600080fd5b8180156100cf57600080fd5b506100e36100de366004613de8565b61022c565b604080519283526020830191909152015b60405180910390f35b61011061010b366004613a54565b610601565b6040519081526020016100f4565b81801561012a57600080fd5b506100e3610139366004613c5b565b610707565b81801561014a57600080fd5b506100e3610159366004613d25565b610c20565b6100e361016c366004613ab0565b610f45565b81801561017d57600080fd5b5061011061018c366004613cd3565b6110e0565b6100e361019f366004613969565b6113a4565b6100e36101b2366004613b0e565b61163a565b6101106101c53660046138d3565b6118bf565b8180156101d657600080fd5b506101106101e5366004613bc9565b611a39565b6100e36101f8366004613a08565b611e80565b81801561020957600080fd5b5061021d610218366004613d7d565b611ece565b6040516100f493929190613f3b565b60008060008a600501805480602002602001604051908101604052809291908181526020016000905b8282101561029e57600084815260209081902060408051808201909152908401546001600160801b038082168352600160801b9091041681830152825260019092019101610255565b505050509050610326818a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c918291850190849080828437600081840152601f19601f820116905080830192505050505050508d8f600001546113a4565b9093509150848311156103805760405162461bcd60e51b815260206004820181905260248201527f52656465656d206d417373657420717479203e206d6178207175616e7469747960448201526064015b60405180910390fd5b818b60030160008282546103949190614046565b9250508190555060006103c18c84868e600001516103b2919061421c565b6103bc9190614046565b612382565b905060005b898110156105f15760008b8b838181106103f057634e487b7160e01b600052603260045260246000fd5b90506020020160208101906104059190613ea3565b905061052a8a8a8481811061042a57634e487b7160e01b600052603260045260246000fd5b905060200201358f6004018360ff168154811061045757634e487b7160e01b600052603260045260246000fd5b600091825260209182902060408051608081018252600290930290910180546001600160a01b03908116845260018201549081169484019490945260ff600160a01b8504811615159284019290925291926060840191600160a81b9091041660078111156104d557634e487b7160e01b600052602160045260246000fd5b60078111156104f457634e487b7160e01b600052602160045260246000fd5b81525050868460ff168151811061051b57634e487b7160e01b600052603260045260246000fd5b60200260200101518a876123ae565b6105598a8a8481811061054d57634e487b7160e01b600052603260045260246000fd5b9050602002013561266c565b848260ff168151811061057c57634e487b7160e01b600052603260045260246000fd5b60200260200101516020015161059291906141f4565b8e6005018260ff16815481106105b857634e487b7160e01b600052603260045260246000fd5b600091825260209091200180546001600160801b03928316600160801b02921691909117905550806105e98161425f565b9150506103c6565b5050509850989650505050505050565b600080600061060f876126d9565b915091506000610624838387602001516127ed565b905060006305f5e100898960ff168151811061065057634e487b7160e01b600052603260045260246000fd5b6020026020010151600001516001600160801b03168861067091906141d5565b61067a9190614084565b905080848960ff16815181106106a057634e487b7160e01b600052603260045260246000fd5b602002602001018181516106b49190614046565b9052506106c18184614046565b92506106d284848860400151612983565b6106ee5760405162461bcd60e51b815260040161037790613f0c565b6106fa84848489612a2d565b9998505050505050505050565b600080600089600501805480602002602001604051908101604052809291908181526020016000905b8282101561077957600084815260209081902060408051808201909152908401546001600160801b038082168352600160801b9091041681830152825260019092019101610730565b50929350600092506108b191505060048c0161079860208c018c613ea3565b60ff16815481106107b957634e487b7160e01b600052603260045260246000fd5b600091825260209182902060408051608081018252600290930290910180546001600160a01b03908116845260018201549081169484019490945260ff600160a01b8504811615159284019290925291926060840191600160a81b90910416600781111561083757634e487b7160e01b600052602160045260246000fd5b600781111561085657634e487b7160e01b600052602160045260246000fd5b9052508361086760208d018d613ea3565b60ff168151811061088857634e487b7160e01b600052603260045260246000fd5b6020026020010151600001516001600160801b0316896108ac8f8f60000135612382565b612abf565b90506108bc8161266c565b826108ca60208c018c613ea3565b60ff16815181106108eb57634e487b7160e01b600052603260045260246000fd5b602002602001015160200151610901919061401b565b60058c0161091260208c018c613ea3565b60ff168154811061093357634e487b7160e01b600052603260045260246000fd5b60009182526020918290200180546001600160801b03938416600160801b0293169290921790915561099190839061096d908c018c613ea3565b61097a60208c018c613ea3565b848f600001548f8036038101906101b29190613bae565b9094509250858410156109e65760405162461bcd60e51b815260206004820152601860248201527f4f757470757420717479203c206d696e696d756d2071747900000000000000006044820152606401610377565b60008411610a2d5760405162461bcd60e51b81526020600482015260146024820152735a65726f206f7574707574207175616e7469747960601b6044820152606401610377565b6000610a3a8c8c35612382565b9050610b508560048e01610a5160208d018d613ea3565b60ff1681548110610a7257634e487b7160e01b600052603260045260246000fd5b600091825260209182902060408051608081018252600290930290910180546001600160a01b03908116845260018201549081169484019490945260ff600160a01b8504811615159284019290925291926060840191600160a81b909104166007811115610af057634e487b7160e01b600052602160045260246000fd5b6007811115610b0f57634e487b7160e01b600052602160045260246000fd5b90525085610b2060208e018e613ea3565b60ff1681518110610b4157634e487b7160e01b600052603260045260246000fd5b602002602001015189856123ae565b610b598561266c565b83610b6760208c018c613ea3565b60ff1681518110610b8857634e487b7160e01b600052603260045260246000fd5b602002602001015160200151610b9e91906141f4565b60058d01610baf60208c018c613ea3565b60ff1681548110610bd057634e487b7160e01b600052603260045260246000fd5b6000918252602082200180546001600160801b03938416600160801b0293169290921790915560038d018054869290610c0a908490614046565b9250508190555050505097509795505050505050565b600080600088600501805480602002602001604051908101604052809291908181526020016000905b82821015610c9257600084815260209081902060408051808201909152908401546001600160801b038082168352600160801b9091041681830152825260019092019101610c49565b50929350610cc49250839150610cad905060208a018a613ea3565b88610cbd368d90038d018d613bae565b8d54610f45565b909350915084831015610d105760405162461bcd60e51b815260206004820152601460248201527362417373657420717479203c206d696e2071747960601b6044820152606401610377565b60008311610d4e5760405162461bcd60e51b815260206004820152600b60248201526a04f7574707574203d3d20360ac1b6044820152606401610377565b81896003016000828254610d629190614046565b9091555060009050610d7a8a846103b28a8d3561421c565b9050610e908460048c01610d9160208c018c613ea3565b60ff1681548110610db257634e487b7160e01b600052603260045260246000fd5b600091825260209182902060408051608081018252600290930290910180546001600160a01b03908116845260018201549081169484019490945260ff600160a01b8504811615159284019290925291926060840191600160a81b909104166007811115610e3057634e487b7160e01b600052602160045260246000fd5b6007811115610e4f57634e487b7160e01b600052602160045260246000fd5b90525084610e6060208d018d613ea3565b60ff1681518110610e8157634e487b7160e01b600052603260045260246000fd5b602002602001015188856123ae565b610e998461266c565b82610ea760208b018b613ea3565b60ff1681518110610ec857634e487b7160e01b600052603260045260246000fd5b602002602001015160200151610ede91906141f4565b60058b01610eef60208b018b613ea3565b60ff1681548110610f1057634e487b7160e01b600052603260045260246000fd5b600091825260209091200180546001600160801b03928316600160801b02921691909117905550919890975095505050505050565b600080600080610f54896126d9565b915091506000610f69838389602001516127ed565b90506000610f7989898985612cdb565b8951909650909150600090610f8e838261421c565b610f9890856141d5565b610fa29190614084565b610fad906001614046565b90506000610fc1868b602001518e85612d3a565b90506000600182888f60ff1681518110610feb57634e487b7160e01b600052603260045260246000fd5b6020026020010151610ffd919061421c565b611007919061421c565b90508d8d60ff168151811061102c57634e487b7160e01b600052603260045260246000fd5b6020026020010151600001516001600160801b0316816305f5e10061105191906141d5565b61105b9190614084565b985080878e60ff168151811061108157634e487b7160e01b600052603260045260246000fd5b60200260200101818151611095919061421c565b9052506110a2818761421c565b95506110b387878d60400151612983565b6110cf5760405162461bcd60e51b815260040161037790613f0c565b505050505050509550959350505050565b60008086600501805480602002602001604051908101604052809291908181526020016000905b8282101561115057600084815260209081902060408051808201909152908401546001600160801b038082168352600160801b9091041681830152825260019092019101611107565b50929350600092506112839150506004890161116f6020890189613ea3565b60ff168154811061119057634e487b7160e01b600052603260045260246000fd5b600091825260209182902060408051608081018252600290930290910180546001600160a01b03908116845260018201549081169484019490945260ff600160a01b8504811615159284019290925291926060840191600160a81b90910416600781111561120e57634e487b7160e01b600052602160045260246000fd5b600781111561122d57634e487b7160e01b600052602160045260246000fd5b9052508361123e60208a018a613ea3565b60ff168151811061125f57634e487b7160e01b600052603260045260246000fd5b6020026020010151600001516001600160801b0316876108ac8c8c60000135612382565b90506112a6826112966020890189613ea3565b8361010b368c90038c018c613bae565b9250838310156112f25760405162461bcd60e51b81526020600482015260176024820152764d696e74207175616e74697479203c206d696e2071747960481b6044820152606401610377565b6112fb8161266c565b826113096020890189613ea3565b60ff168151811061132a57634e487b7160e01b600052603260045260246000fd5b602002602001015160200151611340919061401b565b600589016113516020890189613ea3565b60ff168154811061137257634e487b7160e01b600052603260045260246000fd5b600091825260209091200180546001600160801b03928316600160801b02921691909117905550909695505050505050565b6000806000806113b3896126d9565b9150915060006113c8838389602001516127ed565b89519091506000805b828110156114fb576305f5e1008d8d83815181106113ff57634e487b7160e01b600052603260045260246000fd5b602002602001015160ff168151811061142857634e487b7160e01b600052603260045260246000fd5b6020026020010151600001516001600160801b03168c838151811061145d57634e487b7160e01b600052603260045260246000fd5b602002602001015161146f91906141d5565b6114799190614084565b915081868d838151811061149d57634e487b7160e01b600052603260045260246000fd5b602002602001015160ff16815181106114c657634e487b7160e01b600052603260045260246000fd5b602002602001018181516114da919061421c565b9052506114e7828661421c565b9450806114f38161425f565b9150506113d1565b5061150b85858b60400151612983565b6115275760405162461bcd60e51b815260040161037790613f0c565b600061153886868c602001516127ed565b9050600084611547838261421c565b8c5161155391906141d5565b61155d9190614084565b9050620f424081116115b15760405162461bcd60e51b815260206004820152601760248201527f4d7573742072656465656d203e2031653620756e6974730000000000000000006044820152606401610377565b6115cd6115c68b670de0b6b3a764000061421c565b8290612f8e565b98506115d9818a61421c565b97506115e660018a614046565b9850848b6000015111156110cf5760608b015161160b90670de0b6b3a764000061421c565b61161d8a670de0b6b3a76400006141d5565b6116279190614084565b9850505050505050509550959350505050565b6000806000806116498a6126d9565b91509150600061165e838388602001516127ed565b905060006305f5e1008c8c60ff168151811061168a57634e487b7160e01b600052603260045260246000fd5b6020026020010151600001516001600160801b03168a6116aa91906141d5565b6116b49190614084565b905080848c60ff16815181106116da57634e487b7160e01b600052603260045260246000fd5b602002602001018181516116ee9190614046565b9052506116fb8184614046565b925060006117198361171287878c602001516127ed565b8b8b612fa9565b80975081925050506000611733868a602001518e85612d3a565b9050858c60ff168151811061175857634e487b7160e01b600052603260045260246000fd5b602002602001015181106117a15760405162461bcd60e51b815260206004820152601060248201526f16995c9bc81cddd85c081bdd5d1c1d5d60821b6044820152606401610377565b6000600182888f60ff16815181106117c957634e487b7160e01b600052603260045260246000fd5b60200260200101516117db919061421c565b6117e5919061421c565b90508e8d60ff168151811061180a57634e487b7160e01b600052603260045260246000fd5b6020026020010151600001516001600160801b0316816305f5e10061182f91906141d5565b6118399190614084565b985080878e60ff168151811061185f57634e487b7160e01b600052603260045260246000fd5b60200260200101818151611873919061421c565b905250611880818761421c565b955061189187878c60400151612983565b6118ad5760405162461bcd60e51b815260040161037790613f0c565b50505050505050965096945050505050565b60008060006118cd876126d9565b9150915060006118e2838387602001516127ed565b8751909150600080805b838110156119f2578a818151811061191457634e487b7160e01b600052603260045260246000fd5b602002602001015192506305f5e1008c8460ff168151811061194657634e487b7160e01b600052603260045260246000fd5b6020026020010151600001516001600160801b03168b838151811061197b57634e487b7160e01b600052603260045260246000fd5b602002602001015161198d91906141d5565b6119979190614084565b915081878460ff16815181106119bd57634e487b7160e01b600052603260045260246000fd5b602002602001018181516119d19190614046565b9052506119de8287614046565b9550806119ea8161425f565b9150506118ec565b50611a0286868a60400151612983565b611a1e5760405162461bcd60e51b815260040161037790613f0c565b611a2a8686868b612a2d565b9b9a5050505050505050505050565b60008481816001600160401b03811115611a6357634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611a8c578160200160208202803683370190505b50905060008a600501805480602002602001604051908101604052809291908181526020016000905b82821015611afe57600084815260209081902060408051808201909152908401546001600160801b038082168352600160801b9091041681830152825260019092019101611ab5565b5050505090506000611b148c8c60000135612382565b905060005b84811015611d85576000898983818110611b4357634e487b7160e01b600052603260045260246000fd5b905060200201351115611d735760008b8b83818110611b7257634e487b7160e01b600052603260045260246000fd5b9050602002016020810190611b879190613ea3565b90506000848260ff1681518110611bae57634e487b7160e01b600052603260045260246000fd5b60200260200101519050611cb98f6004018360ff1681548110611be157634e487b7160e01b600052603260045260246000fd5b600091825260209182902060408051608081018252600290930290910180546001600160a01b03908116845260018201549081169484019490945260ff600160a01b8504811615159284019290925291926060840191600160a81b909104166007811115611c5f57634e487b7160e01b600052602160045260246000fd5b6007811115611c7e57634e487b7160e01b600052602160045260246000fd5b90525082516001600160801b03168d8d87818110611cac57634e487b7160e01b600052603260045260246000fd5b9050602002013587612abf565b868481518110611cd957634e487b7160e01b600052603260045260246000fd5b602002602001018181525050611d15868481518110611d0857634e487b7160e01b600052603260045260246000fd5b602002602001015161266c565b8160200151611d24919061401b565b8f6005018360ff1681548110611d4a57634e487b7160e01b600052603260045260246000fd5b600091825260209091200180546001600160801b03928316600160801b02921691909117905550505b80611d7d8161425f565b915050611b19565b50611dde828b8b80806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f82011690508083019250505050505050858e8036038101906101c59190613bae565b945085851015611e2a5760405162461bcd60e51b81526020600482015260176024820152764d696e74207175616e74697479203c206d696e2071747960481b6044820152606401610377565b60008511611e715760405162461bcd60e51b81526020600482015260146024820152735a65726f206d4173736574207175616e7469747960601b6044820152606401610377565b50505050979650505050505050565b600080600080611e8f866126d9565b91509150611ea2828287602001516127ed565b8551909350611eb984670de0b6b3a76400006141d5565b611ec39190614084565b935050509250929050565b6000606080600089600501805480602002602001604051908101604052809291908181526020016000905b82821015611f4257600084815260209081902060408051808201909152908401546001600160801b038082168352600160801b9091041681830152825260019092019101611ef9565b5050505090506000611f6a828b803603810190611f5f9190613bae565b8b8e60010154613050565b8096508192505050848b6003016000828254611f869190614046565b9091555060009050611f9e8c876103b28d8f3561421c565b8351909150806001600160401b03811115611fc957634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611ff2578160200160208202803683370190505b509550806001600160401b0381111561201b57634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015612044578160200160208202803683370190505b50945060005b818110156123715760008d600001358587848151811061207a57634e487b7160e01b600052603260045260246000fd5b6020026020010151602001516001600160801b031661209991906141d5565b6120a39190614084565b9050600181116120e35760405162461bcd60e51b815260206004820152600b60248201526a04f7574707574203d3d20360ac1b6044820152606401610377565b6120ee60018261421c565b90508b8b8381811061211057634e487b7160e01b600052603260045260246000fd5b9050602002013581101561215d5760405162461bcd60e51b815260206004820152601460248201527362417373657420717479203c206d696e2071747960601b6044820152606401610377565b6121668161266c565b86838151811061218657634e487b7160e01b600052603260045260246000fd5b60200260200101516020015161219c91906141f4565b8f60050183815481106121bf57634e487b7160e01b600052603260045260246000fd5b9060005260206000200160000160106101000a8154816001600160801b0302191690836001600160801b0316021790555060008f600401838154811061221557634e487b7160e01b600052603260045260246000fd5b600091825260209182902060408051608081018252600290930290910180546001600160a01b03908116845260018201549081169484019490945260ff600160a01b8504811615159284019290925291926060840191600160a81b90910416600781111561229357634e487b7160e01b600052602160045260246000fd5b60078111156122b257634e487b7160e01b600052602160045260246000fd5b8152505090508181600001518985815181106122de57634e487b7160e01b600052603260045260246000fd5b602002602001018b868151811061230557634e487b7160e01b600052603260045260246000fd5b60200260200101826001600160a01b03166001600160a01b031681525082815250505061235c828289868151811061234d57634e487b7160e01b600052603260045260246000fd5b60200260200101518e896123ae565b505080806123699061425f565b91505061204a565b505050505096509650969350505050565b6000670de0b6b3a764000083600201548361239d91906141d5565b6123a79190614084565b9392505050565b846123b857612665565b60208401516001600160a01b03166123e55783516123e0906001600160a01b031683876130c3565b612665565b836040015115612473576020840151845160405163c89fc72f60e01b81526001600160a01b038581166004830152918216602482015260448101889052606481018890526001608482015291169063c89fc72f9060a401600060405180830381600087803b15801561245657600080fd5b505af115801561246a573d6000803e3d6000fd5b50505050612665565b835160208501516040516370a0823160e01b81526001600160a01b03918216600482015260009291909116906370a082319060240160206040518083038186803b1580156124c057600080fd5b505afa1580156124d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124f89190613e8b565b9050858110612577576020850151855160405163a4e2859560e01b81526001600160a01b03868116600483015291821660248201526044810189905291169063a4e2859590606401600060405180830381600087803b15801561255a57600080fd5b505af115801561256e573d6000803e3d6000fd5b50505050612663565b83516000906002906125939085906001600160801b031661312b565b61259d9190614084565b905060006125df836125af8a85614046565b6125b9919061421c565b6125c28561266c565b88602001516125d191906141f4565b6001600160801b031661313c565b6020880151885160405163c89fc72f60e01b81526001600160a01b0389811660048301529182166024820152604481018c90526064810184905260006084820152929350169063c89fc72f9060a401600060405180830381600087803b15801561264857600080fd5b505af115801561265c573d6000803e3d6000fd5b5050505050505b505b5050505050565b6000600160801b82106126d15760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b6064820152608401610377565b50805b919050565b8051606090600090806001600160401b0381111561270757634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015612730578160200160208202803683370190505b5092506000805b828110156127e557600086828151811061276157634e487b7160e01b600052603260045260246000fd5b602002602001015190506305f5e1008160000151826020015161278491906141af565b61278e919061405e565b6001600160801b03169250828683815181106127ba57634e487b7160e01b600052603260045260246000fd5b60209081029190910101526127cf8386614046565b94505080806127dd9061425f565b915050612737565b505050915091565b8251600090836128015760009150506123a7565b600061280d82856141d5565b9050600085935060005b61010081101561293a578460005b8581101561288857858a828151811061284e57634e487b7160e01b600052603260045260246000fd5b602002602001015161286091906141d5565b61286a88846141d5565b6128749190614084565b9150806128808161425f565b915050612825565b5085925080612898866001614046565b6128a291906141d5565b6064876128af828861421c565b6128b991906141d5565b6128c39190614084565b6128cd9190614046565b866128d887846141d5565b60646128e48c896141d5565b6128ee9190614084565b6128f89190614046565b61290291906141d5565b61290c9190614084565b95506129188684613151565b156129275750505050506123a7565b50806129328161425f565b915050612817565b5060405162461bcd60e51b815260206004820152601a60248201527f496e76617269616e7420646964206e6f7420636f6e76657267650000000000006044820152606401610377565b82516001906000805b82811015612a2357858782815181106129b557634e487b7160e01b600052603260045260246000fd5b6020026020010151670de0b6b3a76400006129d091906141d5565b6129da9190614084565b915084602001516001600160801b0316821180612a00575084516001600160801b031682105b15612a1157600093505050506123a7565b80612a1b8161425f565b91505061298c565b5050509392505050565b600080612a3f868685602001516127ed565b8351909150612a5957612a52848261421c565b9150612a7d565b83612a64818361421c565b8451612a7091906141d5565b612a7a9190614084565b91505b8251841015612ab657670de0b6b3a7640000836060015183612a9f91906141d5565b612aa99190614084565b612ab3908361421c565b91505b50949350505050565b60208401516000906001600160a01b0316612af0576000612ae6333088600001518761317c565b509150612cd39050565b6000612b0633876020015188600001518761317c565b6040880151919350915015612bbf57602086015186516040516307dba22560e31b81526001600160a01b03918216600482015260248101859052600160448201526000929190911690633edd112890606401602060405180830381600087803b158015612b7257600080fd5b505af1158015612b86573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612baa9190613e8b565b9050612bb6818461313c565b92505050612cd3565b838214612c0e5760405162461bcd60e51b815260206004820152601b60248201527f4173736574206e6f742066756c6c79207472616e7366657272656400000000006044820152606401610377565b6000612c1a848761312b565b905080821115612cd0576000612c31600283614084565b612c3b908461421c565b602089015189516040516307dba22560e31b81526001600160a01b03918216600482015260248101849052600060448201529293501690633edd112890606401602060405180830381600087803b158015612c9557600080fd5b505af1158015612ca9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ccd9190613e8b565b50505b50505b949350505050565b82518490600090831015612d1957670de0b6b3a7640000856060015183612d0291906141d5565b612d0c9190614084565b612d16908361421c565b91505b612d238285613299565b9050612d2f818361421c565b915094509492505050565b8351600090808460ff1610612d815760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610377565b6000808080612d90858a6141d5565b8792509250925060005b84811015612e3d578760ff168114612e2b57898181518110612dcc57634e487b7160e01b600052603260045260246000fd5b602002602001015184612ddf9190614046565b9350848a8281518110612e0257634e487b7160e01b600052603260045260246000fd5b6020026020010151612e1491906141d5565b612e1e88846141d5565b612e289190614084565b91505b80612e358161425f565b915050612d9a565b50600084836064612e4e8a866141d5565b612e5891906141d5565b612e629190614084565b612e6c9190614084565b9050600083612e7c60648261421c565b612e86908a6141d5565b612e909190614084565b9050600085821115612ef957612ea6868361421c565b9050600281612ed3612eb98660046141d5565b612ec46002866140de565b612ece9190614046565b6132ae565b612edd9190614046565b612ee79190614084565b612ef2906001614046565b9750612f38565b612f03828761421c565b9050600281612f16612eb98660046141d5565b612f20919061421c565b612f2a9190614084565b612f35906001614046565b97505b6305f5e100881015612f7f5760405162461bcd60e51b815260206004820152601060248201526f24b73b30b634b21039b7b63aba34b7b760811b6044820152606401610377565b50505050505050949350505050565b60008161239d670de0b6b3a7640000856141d5565b92915050565b60008080612fb7878761421c565b90508684600001511115612ff557670de0b6b3a7640000846060015182612fde91906141d5565b612fe89190614084565b612ff2908261421c565b90505b670de0b6b3a764000061300886836141d5565b6130129190614084565b91508161301f828861421c565b6130299190614046565b8451909350879061303a90846141d5565b6130449190614084565b91505094509492505050565b8160008061305e8787611e80565b509050670de0b6b3a76400008110156130a157670de0b6b3a764000086606001518661308a91906141d5565b6130949190614084565b61309e908461421c565b92505b6130ab8385613299565b91506130b7828461421c565b92505094509492505050565b6040516001600160a01b03831660248201526044810182905261312690849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261342d565b505050565b60008161239d6305f5e100856141d5565b600081831161314b57826123a7565b50919050565b600082821115613170576001613167848461421c565b11159050612fa3565b6001613167838561421c565b6040516370a0823160e01b81526001600160a01b03848116600483015260009182918291908616906370a082319060240160206040518083038186803b1580156131c557600080fd5b505afa1580156131d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131fd9190613e8b565b90506132146001600160a01b0386168888876134ff565b6040516370a0823160e01b81526001600160a01b0387811660048301528616906370a082319060240160206040518083038186803b15801561325557600080fd5b505afa158015613269573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061328d9190613e8b565b91506130b7818361421c565b60006123a78383670de0b6b3a764000061353d565b6000816132bd575060006126d4565b816001600160801b82106132d65760809190911c9060401b5b6801000000000000000082106132f15760409190911c9060201b5b64010000000082106133085760209190911c9060101b5b62010000821061331d5760109190911c9060081b5b61010082106133315760089190911c9060041b5b601082106133445760049190911c9060021b5b600882106133505760011b5b600161335c8286614084565b6133669083614046565b901c905060016133768286614084565b6133809083614046565b901c905060016133908286614084565b61339a9083614046565b901c905060016133aa8286614084565b6133b49083614046565b901c905060016133c48286614084565b6133ce9083614046565b901c905060016133de8286614084565b6133e89083614046565b901c905060016133f88286614084565b6134029083614046565b901c905060006134128286614084565b90508082106134215780613423565b815b93505050506126d4565b6000613482826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166135549092919063ffffffff16565b80519091501561312657808060200190518101906134a09190613b8e565b6131265760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610377565b6040516001600160a01b03808516602483015283166044820152606481018290526135379085906323b872dd60e01b906084016130ef565b50505050565b60008161354a84866141d5565b612cd39190614084565b6060612cd3848460008585843b6135ad5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610377565b600080866001600160a01b031685876040516135c99190613ebd565b60006040518083038185875af1925050503d8060008114613606576040519150601f19603f3d011682016040523d82523d6000602084013e61360b565b606091505b509150915061361b828286613626565b979650505050505050565b606083156136355750816123a7565b8251156136455782518084602001fd5b8160405162461bcd60e51b81526004016103779190613ed9565b80356001600160a01b03811681146126d457600080fd5b600082601f830112613686578081fd5b8135602061369b61369683613ff8565b613fc8565b828152818101908583016040808602880185018910156136b9578687fd5b865b868110156136df576136cd8a8461380e565b855293850193918101916001016136bb565b509198975050505050505050565b60008083601f8401126136fe578182fd5b5081356001600160401b03811115613714578182fd5b602083019150836020808302850101111561372e57600080fd5b9250929050565b600082601f830112613745578081fd5b8135602061375561369683613ff8565b8281528181019085830183850287018401881015613771578586fd5b855b8581101561378f57813584529284019290840190600101613773565b5090979650505050505050565b600082601f8301126137ac578081fd5b813560206137bc61369683613ff8565b82815281810190858301838502870184018810156137d8578586fd5b855b8581101561378f576137eb826138c2565b845292840192908401906001016137da565b60006060828403121561314b578081fd5b60006040828403121561381f578081fd5b6138296040613fc8565b9050613834826138ab565b8152613842602083016138ab565b602082015292915050565b600060a0828403121561314b578081fd5b600060a0828403121561386f578081fd5b6138796080613fc8565b90508135815260208201356020820152613896836040840161380e565b60408201526080820135606082015292915050565b80356001600160801b03811681146126d457600080fd5b803560ff811681146126d457600080fd5b60008060008061010085870312156138e9578384fd5b84356001600160401b03808211156138ff578586fd5b61390b88838901613676565b95506020870135915080821115613920578485fd5b61392c8883890161379c565b94506040870135915080821115613941578384fd5b5061394e87828801613735565b92505061395e866060870161385e565b905092959194509250565b60008060008060006101208688031215613981578081fd5b85356001600160401b0380821115613997578283fd5b6139a389838a01613676565b965060208801359150808211156139b8578283fd5b6139c489838a0161379c565b955060408801359150808211156139d9578283fd5b506139e688828901613735565b9350506139f6876060880161385e565b94979396509194610100013592915050565b60008060c08385031215613a1a578182fd5b82356001600160401b03811115613a2f578283fd5b613a3b85828601613676565b925050613a4b846020850161385e565b90509250929050565b6000806000806101008587031215613a6a578182fd5b84356001600160401b03811115613a7f578283fd5b613a8b87828801613676565b945050613a9a602086016138c2565b92506040850135915061395e866060870161385e565b60008060008060006101208688031215613ac8578283fd5b85356001600160401b03811115613add578384fd5b613ae988828901613676565b955050613af8602087016138c2565b9350604086013592506139f6876060880161385e565b6000806000806000806101408789031215613b27578384fd5b86356001600160401b03811115613b3c578485fd5b613b4889828a01613676565b965050613b57602088016138c2565b9450613b65604088016138c2565b93506060870135925060808701359150613b828860a0890161385e565b90509295509295509295565b600060208284031215613b9f578081fd5b815180151581146123a7578182fd5b600060a08284031215613bbf578081fd5b6123a7838361385e565b6000806000806000806000610120888a031215613be4578485fd5b87359650613bf58960208a0161384d565b955060c08801356001600160401b0380821115613c10578687fd5b613c1c8b838c016136ed565b909750955060e08a0135915080821115613c34578283fd5b50613c418a828b016136ed565b989b979a5095989497959661010090950135949350505050565b60008060008060008060006101e0888a031215613c76578081fd5b87359650613c878960208a0161384d565b9550613c968960c08a016137fd565b9450613ca6896101208a016137fd565b935061018088013592506101a08801359150613cc56101c0890161365f565b905092959891949750929550565b60008060008060006101608688031215613ceb578283fd5b85359450613cfc876020880161384d565b9350613d0b8760c088016137fd565b949793965093946101208101359450610140013592915050565b6000806000806000806101808789031215613d3e578384fd5b86359550613d4f886020890161384d565b9450613d5e8860c089016137fd565b935061012087013592506101408701359150613b82610160880161365f565b6000806000806000806101208789031215613d96578384fd5b86359550613da7886020890161384d565b945060c0870135935060e08701356001600160401b03811115613dc8578283fd5b613dd489828a016136ed565b9094509250613b829050610100880161365f565b600080600080600080600080610140898b031215613e04578182fd5b88359750613e158a60208b0161385e565b965060c08901356001600160401b0380821115613e30578384fd5b613e3c8c838d016136ed565b909850965060e08b0135915080821115613e54578384fd5b50613e618b828c016136ed565b9095509350506101008901359150613e7c6101208a0161365f565b90509295985092959890939650565b600060208284031215613e9c578081fd5b5051919050565b600060208284031215613eb4578081fd5b6123a7826138c2565b60008251613ecf818460208701614233565b9190910192915050565b6000602082528251806020840152613ef8816040850160208701614233565b601f01601f19169190910160400192915050565b6020808252601590820152744578636565647320776569676874206c696d69747360581b604082015260600190565b60006060820185835260206060818501528186518084526080860191508288019350845b81811015613f845784516001600160a01b031683529383019391830191600101613f5f565b505084810360408601528551808252908201925081860190845b81811015613fba57825185529383019391830191600101613f9e565b509298975050505050505050565b604051601f8201601f191681016001600160401b0381118282101715613ff057613ff06142a6565b604052919050565b60006001600160401b03821115614011576140116142a6565b5060209081020190565b60006001600160801b0380831681851680830382111561403d5761403d61427a565b01949350505050565b600082198211156140595761405961427a565b500190565b60006001600160801b038084168061407857614078614290565b92169190910492915050565b60008261409357614093614290565b500490565b80825b60018086116140aa57506140d5565b8187048211156140bc576140bc61427a565b808616156140c957918102915b9490941c93800261409b565b94509492505050565b60006123a760001960ff8516846000826140fa575060016123a7565b81614107575060006123a7565b816001811461411d576002811461412757614154565b60019150506123a7565b60ff8411156141385761413861427a565b6001841b91508482111561414e5761414e61427a565b506123a7565b5060208310610133831016604e8410600b8410161715614187575081810a838111156141825761418261427a565b6123a7565b6141948484846001614098565b8086048211156141a6576141a661427a565b02949350505050565b60006001600160801b03808316818516818304811182151516156141a6576141a661427a565b60008160001904831182151516156141ef576141ef61427a565b500290565b60006001600160801b03838116908316818110156142145761421461427a565b039392505050565b60008282101561422e5761422e61427a565b500390565b60005b8381101561424e578181015183820152602001614236565b838111156135375750506000910152565b60006000198214156142735761427361427a565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052604160045260246000fdfea2646970667358221220f78cb1fc5e5f9d3d51d2ceab0af6d29268e939f879fbfcba8b52c10ff7bbad2364736f6c63430008020033

Deployed Bytecode

0x73b9cca2b53e8d7bc4cbddccb66d20b411b87d213f30146080604052600436106100be5760003560e01c8063b3ffbf311161007b578063b3ffbf3114610191578063b995a2b5146101a4578063bf9f08b2146101b7578063ccf4ddcc146101ca578063d38e18e9146101ea578063ee679672146101fd576100be565b806307aa92c8146100c35780630ce8bc9b146100fd5780632c51918f1461011e57806361ec51541461013e5780637c1449941461015e5780638c420a9714610171575b600080fd5b8180156100cf57600080fd5b506100e36100de366004613de8565b61022c565b604080519283526020830191909152015b60405180910390f35b61011061010b366004613a54565b610601565b6040519081526020016100f4565b81801561012a57600080fd5b506100e3610139366004613c5b565b610707565b81801561014a57600080fd5b506100e3610159366004613d25565b610c20565b6100e361016c366004613ab0565b610f45565b81801561017d57600080fd5b5061011061018c366004613cd3565b6110e0565b6100e361019f366004613969565b6113a4565b6100e36101b2366004613b0e565b61163a565b6101106101c53660046138d3565b6118bf565b8180156101d657600080fd5b506101106101e5366004613bc9565b611a39565b6100e36101f8366004613a08565b611e80565b81801561020957600080fd5b5061021d610218366004613d7d565b611ece565b6040516100f493929190613f3b565b60008060008a600501805480602002602001604051908101604052809291908181526020016000905b8282101561029e57600084815260209081902060408051808201909152908401546001600160801b038082168352600160801b9091041681830152825260019092019101610255565b505050509050610326818a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c918291850190849080828437600081840152601f19601f820116905080830192505050505050508d8f600001546113a4565b9093509150848311156103805760405162461bcd60e51b815260206004820181905260248201527f52656465656d206d417373657420717479203e206d6178207175616e7469747960448201526064015b60405180910390fd5b818b60030160008282546103949190614046565b9250508190555060006103c18c84868e600001516103b2919061421c565b6103bc9190614046565b612382565b905060005b898110156105f15760008b8b838181106103f057634e487b7160e01b600052603260045260246000fd5b90506020020160208101906104059190613ea3565b905061052a8a8a8481811061042a57634e487b7160e01b600052603260045260246000fd5b905060200201358f6004018360ff168154811061045757634e487b7160e01b600052603260045260246000fd5b600091825260209182902060408051608081018252600290930290910180546001600160a01b03908116845260018201549081169484019490945260ff600160a01b8504811615159284019290925291926060840191600160a81b9091041660078111156104d557634e487b7160e01b600052602160045260246000fd5b60078111156104f457634e487b7160e01b600052602160045260246000fd5b81525050868460ff168151811061051b57634e487b7160e01b600052603260045260246000fd5b60200260200101518a876123ae565b6105598a8a8481811061054d57634e487b7160e01b600052603260045260246000fd5b9050602002013561266c565b848260ff168151811061057c57634e487b7160e01b600052603260045260246000fd5b60200260200101516020015161059291906141f4565b8e6005018260ff16815481106105b857634e487b7160e01b600052603260045260246000fd5b600091825260209091200180546001600160801b03928316600160801b02921691909117905550806105e98161425f565b9150506103c6565b5050509850989650505050505050565b600080600061060f876126d9565b915091506000610624838387602001516127ed565b905060006305f5e100898960ff168151811061065057634e487b7160e01b600052603260045260246000fd5b6020026020010151600001516001600160801b03168861067091906141d5565b61067a9190614084565b905080848960ff16815181106106a057634e487b7160e01b600052603260045260246000fd5b602002602001018181516106b49190614046565b9052506106c18184614046565b92506106d284848860400151612983565b6106ee5760405162461bcd60e51b815260040161037790613f0c565b6106fa84848489612a2d565b9998505050505050505050565b600080600089600501805480602002602001604051908101604052809291908181526020016000905b8282101561077957600084815260209081902060408051808201909152908401546001600160801b038082168352600160801b9091041681830152825260019092019101610730565b50929350600092506108b191505060048c0161079860208c018c613ea3565b60ff16815481106107b957634e487b7160e01b600052603260045260246000fd5b600091825260209182902060408051608081018252600290930290910180546001600160a01b03908116845260018201549081169484019490945260ff600160a01b8504811615159284019290925291926060840191600160a81b90910416600781111561083757634e487b7160e01b600052602160045260246000fd5b600781111561085657634e487b7160e01b600052602160045260246000fd5b9052508361086760208d018d613ea3565b60ff168151811061088857634e487b7160e01b600052603260045260246000fd5b6020026020010151600001516001600160801b0316896108ac8f8f60000135612382565b612abf565b90506108bc8161266c565b826108ca60208c018c613ea3565b60ff16815181106108eb57634e487b7160e01b600052603260045260246000fd5b602002602001015160200151610901919061401b565b60058c0161091260208c018c613ea3565b60ff168154811061093357634e487b7160e01b600052603260045260246000fd5b60009182526020918290200180546001600160801b03938416600160801b0293169290921790915561099190839061096d908c018c613ea3565b61097a60208c018c613ea3565b848f600001548f8036038101906101b29190613bae565b9094509250858410156109e65760405162461bcd60e51b815260206004820152601860248201527f4f757470757420717479203c206d696e696d756d2071747900000000000000006044820152606401610377565b60008411610a2d5760405162461bcd60e51b81526020600482015260146024820152735a65726f206f7574707574207175616e7469747960601b6044820152606401610377565b6000610a3a8c8c35612382565b9050610b508560048e01610a5160208d018d613ea3565b60ff1681548110610a7257634e487b7160e01b600052603260045260246000fd5b600091825260209182902060408051608081018252600290930290910180546001600160a01b03908116845260018201549081169484019490945260ff600160a01b8504811615159284019290925291926060840191600160a81b909104166007811115610af057634e487b7160e01b600052602160045260246000fd5b6007811115610b0f57634e487b7160e01b600052602160045260246000fd5b90525085610b2060208e018e613ea3565b60ff1681518110610b4157634e487b7160e01b600052603260045260246000fd5b602002602001015189856123ae565b610b598561266c565b83610b6760208c018c613ea3565b60ff1681518110610b8857634e487b7160e01b600052603260045260246000fd5b602002602001015160200151610b9e91906141f4565b60058d01610baf60208c018c613ea3565b60ff1681548110610bd057634e487b7160e01b600052603260045260246000fd5b6000918252602082200180546001600160801b03938416600160801b0293169290921790915560038d018054869290610c0a908490614046565b9250508190555050505097509795505050505050565b600080600088600501805480602002602001604051908101604052809291908181526020016000905b82821015610c9257600084815260209081902060408051808201909152908401546001600160801b038082168352600160801b9091041681830152825260019092019101610c49565b50929350610cc49250839150610cad905060208a018a613ea3565b88610cbd368d90038d018d613bae565b8d54610f45565b909350915084831015610d105760405162461bcd60e51b815260206004820152601460248201527362417373657420717479203c206d696e2071747960601b6044820152606401610377565b60008311610d4e5760405162461bcd60e51b815260206004820152600b60248201526a04f7574707574203d3d20360ac1b6044820152606401610377565b81896003016000828254610d629190614046565b9091555060009050610d7a8a846103b28a8d3561421c565b9050610e908460048c01610d9160208c018c613ea3565b60ff1681548110610db257634e487b7160e01b600052603260045260246000fd5b600091825260209182902060408051608081018252600290930290910180546001600160a01b03908116845260018201549081169484019490945260ff600160a01b8504811615159284019290925291926060840191600160a81b909104166007811115610e3057634e487b7160e01b600052602160045260246000fd5b6007811115610e4f57634e487b7160e01b600052602160045260246000fd5b90525084610e6060208d018d613ea3565b60ff1681518110610e8157634e487b7160e01b600052603260045260246000fd5b602002602001015188856123ae565b610e998461266c565b82610ea760208b018b613ea3565b60ff1681518110610ec857634e487b7160e01b600052603260045260246000fd5b602002602001015160200151610ede91906141f4565b60058b01610eef60208b018b613ea3565b60ff1681548110610f1057634e487b7160e01b600052603260045260246000fd5b600091825260209091200180546001600160801b03928316600160801b02921691909117905550919890975095505050505050565b600080600080610f54896126d9565b915091506000610f69838389602001516127ed565b90506000610f7989898985612cdb565b8951909650909150600090610f8e838261421c565b610f9890856141d5565b610fa29190614084565b610fad906001614046565b90506000610fc1868b602001518e85612d3a565b90506000600182888f60ff1681518110610feb57634e487b7160e01b600052603260045260246000fd5b6020026020010151610ffd919061421c565b611007919061421c565b90508d8d60ff168151811061102c57634e487b7160e01b600052603260045260246000fd5b6020026020010151600001516001600160801b0316816305f5e10061105191906141d5565b61105b9190614084565b985080878e60ff168151811061108157634e487b7160e01b600052603260045260246000fd5b60200260200101818151611095919061421c565b9052506110a2818761421c565b95506110b387878d60400151612983565b6110cf5760405162461bcd60e51b815260040161037790613f0c565b505050505050509550959350505050565b60008086600501805480602002602001604051908101604052809291908181526020016000905b8282101561115057600084815260209081902060408051808201909152908401546001600160801b038082168352600160801b9091041681830152825260019092019101611107565b50929350600092506112839150506004890161116f6020890189613ea3565b60ff168154811061119057634e487b7160e01b600052603260045260246000fd5b600091825260209182902060408051608081018252600290930290910180546001600160a01b03908116845260018201549081169484019490945260ff600160a01b8504811615159284019290925291926060840191600160a81b90910416600781111561120e57634e487b7160e01b600052602160045260246000fd5b600781111561122d57634e487b7160e01b600052602160045260246000fd5b9052508361123e60208a018a613ea3565b60ff168151811061125f57634e487b7160e01b600052603260045260246000fd5b6020026020010151600001516001600160801b0316876108ac8c8c60000135612382565b90506112a6826112966020890189613ea3565b8361010b368c90038c018c613bae565b9250838310156112f25760405162461bcd60e51b81526020600482015260176024820152764d696e74207175616e74697479203c206d696e2071747960481b6044820152606401610377565b6112fb8161266c565b826113096020890189613ea3565b60ff168151811061132a57634e487b7160e01b600052603260045260246000fd5b602002602001015160200151611340919061401b565b600589016113516020890189613ea3565b60ff168154811061137257634e487b7160e01b600052603260045260246000fd5b600091825260209091200180546001600160801b03928316600160801b02921691909117905550909695505050505050565b6000806000806113b3896126d9565b9150915060006113c8838389602001516127ed565b89519091506000805b828110156114fb576305f5e1008d8d83815181106113ff57634e487b7160e01b600052603260045260246000fd5b602002602001015160ff168151811061142857634e487b7160e01b600052603260045260246000fd5b6020026020010151600001516001600160801b03168c838151811061145d57634e487b7160e01b600052603260045260246000fd5b602002602001015161146f91906141d5565b6114799190614084565b915081868d838151811061149d57634e487b7160e01b600052603260045260246000fd5b602002602001015160ff16815181106114c657634e487b7160e01b600052603260045260246000fd5b602002602001018181516114da919061421c565b9052506114e7828661421c565b9450806114f38161425f565b9150506113d1565b5061150b85858b60400151612983565b6115275760405162461bcd60e51b815260040161037790613f0c565b600061153886868c602001516127ed565b9050600084611547838261421c565b8c5161155391906141d5565b61155d9190614084565b9050620f424081116115b15760405162461bcd60e51b815260206004820152601760248201527f4d7573742072656465656d203e2031653620756e6974730000000000000000006044820152606401610377565b6115cd6115c68b670de0b6b3a764000061421c565b8290612f8e565b98506115d9818a61421c565b97506115e660018a614046565b9850848b6000015111156110cf5760608b015161160b90670de0b6b3a764000061421c565b61161d8a670de0b6b3a76400006141d5565b6116279190614084565b9850505050505050509550959350505050565b6000806000806116498a6126d9565b91509150600061165e838388602001516127ed565b905060006305f5e1008c8c60ff168151811061168a57634e487b7160e01b600052603260045260246000fd5b6020026020010151600001516001600160801b03168a6116aa91906141d5565b6116b49190614084565b905080848c60ff16815181106116da57634e487b7160e01b600052603260045260246000fd5b602002602001018181516116ee9190614046565b9052506116fb8184614046565b925060006117198361171287878c602001516127ed565b8b8b612fa9565b80975081925050506000611733868a602001518e85612d3a565b9050858c60ff168151811061175857634e487b7160e01b600052603260045260246000fd5b602002602001015181106117a15760405162461bcd60e51b815260206004820152601060248201526f16995c9bc81cddd85c081bdd5d1c1d5d60821b6044820152606401610377565b6000600182888f60ff16815181106117c957634e487b7160e01b600052603260045260246000fd5b60200260200101516117db919061421c565b6117e5919061421c565b90508e8d60ff168151811061180a57634e487b7160e01b600052603260045260246000fd5b6020026020010151600001516001600160801b0316816305f5e10061182f91906141d5565b6118399190614084565b985080878e60ff168151811061185f57634e487b7160e01b600052603260045260246000fd5b60200260200101818151611873919061421c565b905250611880818761421c565b955061189187878c60400151612983565b6118ad5760405162461bcd60e51b815260040161037790613f0c565b50505050505050965096945050505050565b60008060006118cd876126d9565b9150915060006118e2838387602001516127ed565b8751909150600080805b838110156119f2578a818151811061191457634e487b7160e01b600052603260045260246000fd5b602002602001015192506305f5e1008c8460ff168151811061194657634e487b7160e01b600052603260045260246000fd5b6020026020010151600001516001600160801b03168b838151811061197b57634e487b7160e01b600052603260045260246000fd5b602002602001015161198d91906141d5565b6119979190614084565b915081878460ff16815181106119bd57634e487b7160e01b600052603260045260246000fd5b602002602001018181516119d19190614046565b9052506119de8287614046565b9550806119ea8161425f565b9150506118ec565b50611a0286868a60400151612983565b611a1e5760405162461bcd60e51b815260040161037790613f0c565b611a2a8686868b612a2d565b9b9a5050505050505050505050565b60008481816001600160401b03811115611a6357634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611a8c578160200160208202803683370190505b50905060008a600501805480602002602001604051908101604052809291908181526020016000905b82821015611afe57600084815260209081902060408051808201909152908401546001600160801b038082168352600160801b9091041681830152825260019092019101611ab5565b5050505090506000611b148c8c60000135612382565b905060005b84811015611d85576000898983818110611b4357634e487b7160e01b600052603260045260246000fd5b905060200201351115611d735760008b8b83818110611b7257634e487b7160e01b600052603260045260246000fd5b9050602002016020810190611b879190613ea3565b90506000848260ff1681518110611bae57634e487b7160e01b600052603260045260246000fd5b60200260200101519050611cb98f6004018360ff1681548110611be157634e487b7160e01b600052603260045260246000fd5b600091825260209182902060408051608081018252600290930290910180546001600160a01b03908116845260018201549081169484019490945260ff600160a01b8504811615159284019290925291926060840191600160a81b909104166007811115611c5f57634e487b7160e01b600052602160045260246000fd5b6007811115611c7e57634e487b7160e01b600052602160045260246000fd5b90525082516001600160801b03168d8d87818110611cac57634e487b7160e01b600052603260045260246000fd5b9050602002013587612abf565b868481518110611cd957634e487b7160e01b600052603260045260246000fd5b602002602001018181525050611d15868481518110611d0857634e487b7160e01b600052603260045260246000fd5b602002602001015161266c565b8160200151611d24919061401b565b8f6005018360ff1681548110611d4a57634e487b7160e01b600052603260045260246000fd5b600091825260209091200180546001600160801b03928316600160801b02921691909117905550505b80611d7d8161425f565b915050611b19565b50611dde828b8b80806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f82011690508083019250505050505050858e8036038101906101c59190613bae565b945085851015611e2a5760405162461bcd60e51b81526020600482015260176024820152764d696e74207175616e74697479203c206d696e2071747960481b6044820152606401610377565b60008511611e715760405162461bcd60e51b81526020600482015260146024820152735a65726f206d4173736574207175616e7469747960601b6044820152606401610377565b50505050979650505050505050565b600080600080611e8f866126d9565b91509150611ea2828287602001516127ed565b8551909350611eb984670de0b6b3a76400006141d5565b611ec39190614084565b935050509250929050565b6000606080600089600501805480602002602001604051908101604052809291908181526020016000905b82821015611f4257600084815260209081902060408051808201909152908401546001600160801b038082168352600160801b9091041681830152825260019092019101611ef9565b5050505090506000611f6a828b803603810190611f5f9190613bae565b8b8e60010154613050565b8096508192505050848b6003016000828254611f869190614046565b9091555060009050611f9e8c876103b28d8f3561421c565b8351909150806001600160401b03811115611fc957634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611ff2578160200160208202803683370190505b509550806001600160401b0381111561201b57634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015612044578160200160208202803683370190505b50945060005b818110156123715760008d600001358587848151811061207a57634e487b7160e01b600052603260045260246000fd5b6020026020010151602001516001600160801b031661209991906141d5565b6120a39190614084565b9050600181116120e35760405162461bcd60e51b815260206004820152600b60248201526a04f7574707574203d3d20360ac1b6044820152606401610377565b6120ee60018261421c565b90508b8b8381811061211057634e487b7160e01b600052603260045260246000fd5b9050602002013581101561215d5760405162461bcd60e51b815260206004820152601460248201527362417373657420717479203c206d696e2071747960601b6044820152606401610377565b6121668161266c565b86838151811061218657634e487b7160e01b600052603260045260246000fd5b60200260200101516020015161219c91906141f4565b8f60050183815481106121bf57634e487b7160e01b600052603260045260246000fd5b9060005260206000200160000160106101000a8154816001600160801b0302191690836001600160801b0316021790555060008f600401838154811061221557634e487b7160e01b600052603260045260246000fd5b600091825260209182902060408051608081018252600290930290910180546001600160a01b03908116845260018201549081169484019490945260ff600160a01b8504811615159284019290925291926060840191600160a81b90910416600781111561229357634e487b7160e01b600052602160045260246000fd5b60078111156122b257634e487b7160e01b600052602160045260246000fd5b8152505090508181600001518985815181106122de57634e487b7160e01b600052603260045260246000fd5b602002602001018b868151811061230557634e487b7160e01b600052603260045260246000fd5b60200260200101826001600160a01b03166001600160a01b031681525082815250505061235c828289868151811061234d57634e487b7160e01b600052603260045260246000fd5b60200260200101518e896123ae565b505080806123699061425f565b91505061204a565b505050505096509650969350505050565b6000670de0b6b3a764000083600201548361239d91906141d5565b6123a79190614084565b9392505050565b846123b857612665565b60208401516001600160a01b03166123e55783516123e0906001600160a01b031683876130c3565b612665565b836040015115612473576020840151845160405163c89fc72f60e01b81526001600160a01b038581166004830152918216602482015260448101889052606481018890526001608482015291169063c89fc72f9060a401600060405180830381600087803b15801561245657600080fd5b505af115801561246a573d6000803e3d6000fd5b50505050612665565b835160208501516040516370a0823160e01b81526001600160a01b03918216600482015260009291909116906370a082319060240160206040518083038186803b1580156124c057600080fd5b505afa1580156124d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124f89190613e8b565b9050858110612577576020850151855160405163a4e2859560e01b81526001600160a01b03868116600483015291821660248201526044810189905291169063a4e2859590606401600060405180830381600087803b15801561255a57600080fd5b505af115801561256e573d6000803e3d6000fd5b50505050612663565b83516000906002906125939085906001600160801b031661312b565b61259d9190614084565b905060006125df836125af8a85614046565b6125b9919061421c565b6125c28561266c565b88602001516125d191906141f4565b6001600160801b031661313c565b6020880151885160405163c89fc72f60e01b81526001600160a01b0389811660048301529182166024820152604481018c90526064810184905260006084820152929350169063c89fc72f9060a401600060405180830381600087803b15801561264857600080fd5b505af115801561265c573d6000803e3d6000fd5b5050505050505b505b5050505050565b6000600160801b82106126d15760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b6064820152608401610377565b50805b919050565b8051606090600090806001600160401b0381111561270757634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015612730578160200160208202803683370190505b5092506000805b828110156127e557600086828151811061276157634e487b7160e01b600052603260045260246000fd5b602002602001015190506305f5e1008160000151826020015161278491906141af565b61278e919061405e565b6001600160801b03169250828683815181106127ba57634e487b7160e01b600052603260045260246000fd5b60209081029190910101526127cf8386614046565b94505080806127dd9061425f565b915050612737565b505050915091565b8251600090836128015760009150506123a7565b600061280d82856141d5565b9050600085935060005b61010081101561293a578460005b8581101561288857858a828151811061284e57634e487b7160e01b600052603260045260246000fd5b602002602001015161286091906141d5565b61286a88846141d5565b6128749190614084565b9150806128808161425f565b915050612825565b5085925080612898866001614046565b6128a291906141d5565b6064876128af828861421c565b6128b991906141d5565b6128c39190614084565b6128cd9190614046565b866128d887846141d5565b60646128e48c896141d5565b6128ee9190614084565b6128f89190614046565b61290291906141d5565b61290c9190614084565b95506129188684613151565b156129275750505050506123a7565b50806129328161425f565b915050612817565b5060405162461bcd60e51b815260206004820152601a60248201527f496e76617269616e7420646964206e6f7420636f6e76657267650000000000006044820152606401610377565b82516001906000805b82811015612a2357858782815181106129b557634e487b7160e01b600052603260045260246000fd5b6020026020010151670de0b6b3a76400006129d091906141d5565b6129da9190614084565b915084602001516001600160801b0316821180612a00575084516001600160801b031682105b15612a1157600093505050506123a7565b80612a1b8161425f565b91505061298c565b5050509392505050565b600080612a3f868685602001516127ed565b8351909150612a5957612a52848261421c565b9150612a7d565b83612a64818361421c565b8451612a7091906141d5565b612a7a9190614084565b91505b8251841015612ab657670de0b6b3a7640000836060015183612a9f91906141d5565b612aa99190614084565b612ab3908361421c565b91505b50949350505050565b60208401516000906001600160a01b0316612af0576000612ae6333088600001518761317c565b509150612cd39050565b6000612b0633876020015188600001518761317c565b6040880151919350915015612bbf57602086015186516040516307dba22560e31b81526001600160a01b03918216600482015260248101859052600160448201526000929190911690633edd112890606401602060405180830381600087803b158015612b7257600080fd5b505af1158015612b86573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612baa9190613e8b565b9050612bb6818461313c565b92505050612cd3565b838214612c0e5760405162461bcd60e51b815260206004820152601b60248201527f4173736574206e6f742066756c6c79207472616e7366657272656400000000006044820152606401610377565b6000612c1a848761312b565b905080821115612cd0576000612c31600283614084565b612c3b908461421c565b602089015189516040516307dba22560e31b81526001600160a01b03918216600482015260248101849052600060448201529293501690633edd112890606401602060405180830381600087803b158015612c9557600080fd5b505af1158015612ca9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ccd9190613e8b565b50505b50505b949350505050565b82518490600090831015612d1957670de0b6b3a7640000856060015183612d0291906141d5565b612d0c9190614084565b612d16908361421c565b91505b612d238285613299565b9050612d2f818361421c565b915094509492505050565b8351600090808460ff1610612d815760405162461bcd60e51b815260206004820152600d60248201526c092dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610377565b6000808080612d90858a6141d5565b8792509250925060005b84811015612e3d578760ff168114612e2b57898181518110612dcc57634e487b7160e01b600052603260045260246000fd5b602002602001015184612ddf9190614046565b9350848a8281518110612e0257634e487b7160e01b600052603260045260246000fd5b6020026020010151612e1491906141d5565b612e1e88846141d5565b612e289190614084565b91505b80612e358161425f565b915050612d9a565b50600084836064612e4e8a866141d5565b612e5891906141d5565b612e629190614084565b612e6c9190614084565b9050600083612e7c60648261421c565b612e86908a6141d5565b612e909190614084565b9050600085821115612ef957612ea6868361421c565b9050600281612ed3612eb98660046141d5565b612ec46002866140de565b612ece9190614046565b6132ae565b612edd9190614046565b612ee79190614084565b612ef2906001614046565b9750612f38565b612f03828761421c565b9050600281612f16612eb98660046141d5565b612f20919061421c565b612f2a9190614084565b612f35906001614046565b97505b6305f5e100881015612f7f5760405162461bcd60e51b815260206004820152601060248201526f24b73b30b634b21039b7b63aba34b7b760811b6044820152606401610377565b50505050505050949350505050565b60008161239d670de0b6b3a7640000856141d5565b92915050565b60008080612fb7878761421c565b90508684600001511115612ff557670de0b6b3a7640000846060015182612fde91906141d5565b612fe89190614084565b612ff2908261421c565b90505b670de0b6b3a764000061300886836141d5565b6130129190614084565b91508161301f828861421c565b6130299190614046565b8451909350879061303a90846141d5565b6130449190614084565b91505094509492505050565b8160008061305e8787611e80565b509050670de0b6b3a76400008110156130a157670de0b6b3a764000086606001518661308a91906141d5565b6130949190614084565b61309e908461421c565b92505b6130ab8385613299565b91506130b7828461421c565b92505094509492505050565b6040516001600160a01b03831660248201526044810182905261312690849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261342d565b505050565b60008161239d6305f5e100856141d5565b600081831161314b57826123a7565b50919050565b600082821115613170576001613167848461421c565b11159050612fa3565b6001613167838561421c565b6040516370a0823160e01b81526001600160a01b03848116600483015260009182918291908616906370a082319060240160206040518083038186803b1580156131c557600080fd5b505afa1580156131d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131fd9190613e8b565b90506132146001600160a01b0386168888876134ff565b6040516370a0823160e01b81526001600160a01b0387811660048301528616906370a082319060240160206040518083038186803b15801561325557600080fd5b505afa158015613269573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061328d9190613e8b565b91506130b7818361421c565b60006123a78383670de0b6b3a764000061353d565b6000816132bd575060006126d4565b816001600160801b82106132d65760809190911c9060401b5b6801000000000000000082106132f15760409190911c9060201b5b64010000000082106133085760209190911c9060101b5b62010000821061331d5760109190911c9060081b5b61010082106133315760089190911c9060041b5b601082106133445760049190911c9060021b5b600882106133505760011b5b600161335c8286614084565b6133669083614046565b901c905060016133768286614084565b6133809083614046565b901c905060016133908286614084565b61339a9083614046565b901c905060016133aa8286614084565b6133b49083614046565b901c905060016133c48286614084565b6133ce9083614046565b901c905060016133de8286614084565b6133e89083614046565b901c905060016133f88286614084565b6134029083614046565b901c905060006134128286614084565b90508082106134215780613423565b815b93505050506126d4565b6000613482826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166135549092919063ffffffff16565b80519091501561312657808060200190518101906134a09190613b8e565b6131265760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610377565b6040516001600160a01b03808516602483015283166044820152606481018290526135379085906323b872dd60e01b906084016130ef565b50505050565b60008161354a84866141d5565b612cd39190614084565b6060612cd3848460008585843b6135ad5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610377565b600080866001600160a01b031685876040516135c99190613ebd565b60006040518083038185875af1925050503d8060008114613606576040519150601f19603f3d011682016040523d82523d6000602084013e61360b565b606091505b509150915061361b828286613626565b979650505050505050565b606083156136355750816123a7565b8251156136455782518084602001fd5b8160405162461bcd60e51b81526004016103779190613ed9565b80356001600160a01b03811681146126d457600080fd5b600082601f830112613686578081fd5b8135602061369b61369683613ff8565b613fc8565b828152818101908583016040808602880185018910156136b9578687fd5b865b868110156136df576136cd8a8461380e565b855293850193918101916001016136bb565b509198975050505050505050565b60008083601f8401126136fe578182fd5b5081356001600160401b03811115613714578182fd5b602083019150836020808302850101111561372e57600080fd5b9250929050565b600082601f830112613745578081fd5b8135602061375561369683613ff8565b8281528181019085830183850287018401881015613771578586fd5b855b8581101561378f57813584529284019290840190600101613773565b5090979650505050505050565b600082601f8301126137ac578081fd5b813560206137bc61369683613ff8565b82815281810190858301838502870184018810156137d8578586fd5b855b8581101561378f576137eb826138c2565b845292840192908401906001016137da565b60006060828403121561314b578081fd5b60006040828403121561381f578081fd5b6138296040613fc8565b9050613834826138ab565b8152613842602083016138ab565b602082015292915050565b600060a0828403121561314b578081fd5b600060a0828403121561386f578081fd5b6138796080613fc8565b90508135815260208201356020820152613896836040840161380e565b60408201526080820135606082015292915050565b80356001600160801b03811681146126d457600080fd5b803560ff811681146126d457600080fd5b60008060008061010085870312156138e9578384fd5b84356001600160401b03808211156138ff578586fd5b61390b88838901613676565b95506020870135915080821115613920578485fd5b61392c8883890161379c565b94506040870135915080821115613941578384fd5b5061394e87828801613735565b92505061395e866060870161385e565b905092959194509250565b60008060008060006101208688031215613981578081fd5b85356001600160401b0380821115613997578283fd5b6139a389838a01613676565b965060208801359150808211156139b8578283fd5b6139c489838a0161379c565b955060408801359150808211156139d9578283fd5b506139e688828901613735565b9350506139f6876060880161385e565b94979396509194610100013592915050565b60008060c08385031215613a1a578182fd5b82356001600160401b03811115613a2f578283fd5b613a3b85828601613676565b925050613a4b846020850161385e565b90509250929050565b6000806000806101008587031215613a6a578182fd5b84356001600160401b03811115613a7f578283fd5b613a8b87828801613676565b945050613a9a602086016138c2565b92506040850135915061395e866060870161385e565b60008060008060006101208688031215613ac8578283fd5b85356001600160401b03811115613add578384fd5b613ae988828901613676565b955050613af8602087016138c2565b9350604086013592506139f6876060880161385e565b6000806000806000806101408789031215613b27578384fd5b86356001600160401b03811115613b3c578485fd5b613b4889828a01613676565b965050613b57602088016138c2565b9450613b65604088016138c2565b93506060870135925060808701359150613b828860a0890161385e565b90509295509295509295565b600060208284031215613b9f578081fd5b815180151581146123a7578182fd5b600060a08284031215613bbf578081fd5b6123a7838361385e565b6000806000806000806000610120888a031215613be4578485fd5b87359650613bf58960208a0161384d565b955060c08801356001600160401b0380821115613c10578687fd5b613c1c8b838c016136ed565b909750955060e08a0135915080821115613c34578283fd5b50613c418a828b016136ed565b989b979a5095989497959661010090950135949350505050565b60008060008060008060006101e0888a031215613c76578081fd5b87359650613c878960208a0161384d565b9550613c968960c08a016137fd565b9450613ca6896101208a016137fd565b935061018088013592506101a08801359150613cc56101c0890161365f565b905092959891949750929550565b60008060008060006101608688031215613ceb578283fd5b85359450613cfc876020880161384d565b9350613d0b8760c088016137fd565b949793965093946101208101359450610140013592915050565b6000806000806000806101808789031215613d3e578384fd5b86359550613d4f886020890161384d565b9450613d5e8860c089016137fd565b935061012087013592506101408701359150613b82610160880161365f565b6000806000806000806101208789031215613d96578384fd5b86359550613da7886020890161384d565b945060c0870135935060e08701356001600160401b03811115613dc8578283fd5b613dd489828a016136ed565b9094509250613b829050610100880161365f565b600080600080600080600080610140898b031215613e04578182fd5b88359750613e158a60208b0161385e565b965060c08901356001600160401b0380821115613e30578384fd5b613e3c8c838d016136ed565b909850965060e08b0135915080821115613e54578384fd5b50613e618b828c016136ed565b9095509350506101008901359150613e7c6101208a0161365f565b90509295985092959890939650565b600060208284031215613e9c578081fd5b5051919050565b600060208284031215613eb4578081fd5b6123a7826138c2565b60008251613ecf818460208701614233565b9190910192915050565b6000602082528251806020840152613ef8816040850160208701614233565b601f01601f19169190910160400192915050565b6020808252601590820152744578636565647320776569676874206c696d69747360581b604082015260600190565b60006060820185835260206060818501528186518084526080860191508288019350845b81811015613f845784516001600160a01b031683529383019391830191600101613f5f565b505084810360408601528551808252908201925081860190845b81811015613fba57825185529383019391830191600101613f9e565b509298975050505050505050565b604051601f8201601f191681016001600160401b0381118282101715613ff057613ff06142a6565b604052919050565b60006001600160401b03821115614011576140116142a6565b5060209081020190565b60006001600160801b0380831681851680830382111561403d5761403d61427a565b01949350505050565b600082198211156140595761405961427a565b500190565b60006001600160801b038084168061407857614078614290565b92169190910492915050565b60008261409357614093614290565b500490565b80825b60018086116140aa57506140d5565b8187048211156140bc576140bc61427a565b808616156140c957918102915b9490941c93800261409b565b94509492505050565b60006123a760001960ff8516846000826140fa575060016123a7565b81614107575060006123a7565b816001811461411d576002811461412757614154565b60019150506123a7565b60ff8411156141385761413861427a565b6001841b91508482111561414e5761414e61427a565b506123a7565b5060208310610133831016604e8410600b8410161715614187575081810a838111156141825761418261427a565b6123a7565b6141948484846001614098565b8086048211156141a6576141a661427a565b02949350505050565b60006001600160801b03808316818516818304811182151516156141a6576141a661427a565b60008160001904831182151516156141ef576141ef61427a565b500290565b60006001600160801b03838116908316818110156142145761421461427a565b039392505050565b60008282101561422e5761422e61427a565b500390565b60005b8381101561424e578181015183820152602001614236565b838111156135375750506000910152565b60006000198214156142735761427361427a565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052604160045260246000fdfea2646970667358221220f78cb1fc5e5f9d3d51d2ceab0af6d29268e939f879fbfcba8b52c10ff7bbad2364736f6c63430008020033

Deployed Bytecode Sourcemap

33530:36362:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;47462:1483;;;;;;;;;;-1:-1:-1;47462:1483:0;;;;;:::i;:::-;;:::i;:::-;;;;25942:25:1;;;25998:2;25983:18;;25976:34;;;;25915:18;47462:1483:0;;;;;;;;54478:761;;;;;;:::i;:::-;;:::i;:::-;;;24457:25:1;;;24445:2;24430:18;54478:761:0;24412:76:1;38740:1881:0;;;;;;;;;;-1:-1:-1;38740:1881:0;;;;;:::i;:::-;;:::i;41607:1463::-;;;;;;;;;;-1:-1:-1;41607:1463:0;;;;;:::i;:::-;;:::i;59808:1083::-;;;;;;:::i;:::-;;:::i;34408:1171::-;;;;;;;;;;-1:-1:-1;34408:1171:0;;;;;:::i;:::-;;:::i;61893:1438::-;;;;;;:::i;:::-;;:::i;57344:1281::-;;;;;;:::i;:::-;;:::i;55690:980::-;;;;;;:::i;:::-;;:::i;36288:1510::-;;;;;;;;;;-1:-1:-1;36288:1510:0;;;;;:::i;:::-;;:::i;63640:330::-;;;;;;:::i;:::-;;:::i;43884:2030::-;;;;;;;;;;-1:-1:-1;43884:2030:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;:::i;47462:1483::-;47740:22;47764:11;47840:36;47879:5;:16;;47840:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;47840:55:0;;;;;-1:-1:-1;;;47840:55:0;;;;;;;;;;;;;;;;;;;;;;;;;47932:165;47965:16;47996:8;;47932:165;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;47932:165:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;48019:17:0;;-1:-1:-1;48019:17:0;;;;47932:165;;;48019:17;;47932:165;48019:17;47932:165;;;;;;;;;;;;;;;;;;;;;;;;;;48051:7;48073:5;:13;;;47932:18;:165::i;:::-;47908:189;;-1:-1:-1;47908:189:0;-1:-1:-1;48116:36:0;;;;48108:81;;;;-1:-1:-1;;;48108:81:0;;24144:2:1;48108:81:0;;;24126:21:1;;;24163:18;;;24156:30;24222:34;24202:18;;;24195:62;24274:18;;48108:81:0;;;;;;;;;48284:3;48267:5;:13;;;:20;;;;;;;:::i;:::-;;;;;;;;48363:16;48382:62;48399:5;48440:3;48423:14;48406:7;:14;;;:31;;;;:::i;:::-;:37;;;;:::i;:::-;48382:16;:62::i;:::-;48363:81;;48460:9;48455:483;48475:19;;;48455:483;;;48516:9;48528:8;;48537:1;48528:11;;;;;-1:-1:-1;;;48528:11:0;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;48516:23;;48554:209;48588:17;;48606:1;48588:20;;;;;-1:-1:-1;;;48588:20:0;;;;;;;;;;;;;;;48627:5;:20;;48648:3;48627:25;;;;;;;;-1:-1:-1;;;48627:25:0;;;;;;;;;;;;;;;;;;48554:209;;;;;;;;48627:25;;;;;;;48554:209;;-1:-1:-1;;;;;48554:209:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;48554:209:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;48554:209:0;;;;;;;;;;-1:-1:-1;;;48554:209:0;;;;;;;;;;;;;;;-1:-1:-1;;;48554:209:0;;;;;;;;;;;;;48671:16;48688:3;48671:21;;;;;;;;-1:-1:-1;;;48671:21:0;;;;;;;;;;;;;;;48711:10;48740:8;48554:15;:209::i;:::-;48886:40;48905:17;;48923:1;48905:20;;;;;-1:-1:-1;;;48905:20:0;;;;;;;;;;;;;;;48886:18;:40::i;:::-;48832:16;48849:3;48832:21;;;;;;;;-1:-1:-1;;;48832:21:0;;;;;;;;;;;;;;;:34;;;:94;;;;:::i;:::-;48778:5;:16;;48795:3;48778:21;;;;;;;;-1:-1:-1;;;48778:21:0;;;;;;;;;;;;;;;;;;:148;;-1:-1:-1;;;;;48778:148:0;;;-1:-1:-1;;;48778:148:0;;;;;;;;;-1:-1:-1;48496:3:0;;;;:::i;:::-;;;;48455:483;;;;47462:1483;;;;;;;;;;;;;:::o;54478:761::-;54654:18;54718;54738:11;54753:22;54766:8;54753:12;:22::i;:::-;54717:58;;;;54846:10;54859:29;54870:1;54873:3;54878:7;:9;;;54859:10;:29::i;:::-;54846:42;;54899:19;54956:3;54934:8;54943:2;54934:12;;;;;;;;-1:-1:-1;;;54934:12:0;;;;;;;;;;;;;;;:18;;;-1:-1:-1;;;;;54922:30:0;:9;:30;;;;:::i;:::-;54921:38;;;;:::i;:::-;54899:60;;55021:11;55012:1;55014:2;55012:5;;;;;;;;-1:-1:-1;;;55012:5:0;;;;;;;;;;;;;;:20;;;;;;;:::i;:::-;;;-1:-1:-1;55043:18:0;55050:11;55043:18;;:::i;:::-;;;55109:33;55119:1;55122:3;55127:7;:14;;;55109:9;:33::i;:::-;55101:67;;;;-1:-1:-1;;;55101:67:0;;;;;;;:::i;:::-;55192:39;55211:1;55214:3;55219:2;55223:7;55192:18;:39::i;:::-;55179:52;54478:761;-1:-1:-1;;;;;;;;;54478:761:0:o;38740:1881::-;39021:18;39041:17;39071:36;39110:5;:16;;39071:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;39071:55:0;;;;;-1:-1:-1;;;39071:55:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;39071:55:0;;-1:-1:-1;39177:25:0;;-1:-1:-1;39218:224:0;;-1:-1:-1;;39251:20:0;;;39272:10;;;;:6;:10;:::i;:::-;39251:32;;;;;;;;-1:-1:-1;;;39251:32:0;;;;;;;;;;;;;;;;;;39218:224;;;;;;;;39251:32;;;;;;;39218:224;;-1:-1:-1;;;;;39218:224:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;39218:224:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;39218:224:0;;;;;;;;;;-1:-1:-1;;;39218:224:0;;;;;;;;;;;;;;;-1:-1:-1;;;39218:224:0;;;;;;;;;;;-1:-1:-1;39302:16:0;39319:10;;;;:6;:10;:::i;:::-;39302:28;;;;;;;;-1:-1:-1;;;39302:28:0;;;;;;;;;;;;;;;:34;;;-1:-1:-1;;;;;39218:224:0;39355:14;39388:39;39405:5;39412:7;:14;;;39388:16;:39::i;:::-;39218:14;:224::i;:::-;39177:265;;39609:37;39628:17;39609:18;:37::i;:::-;39552:16;39569:10;;;;:6;:10;:::i;:::-;39552:28;;;;;;;;-1:-1:-1;;;39552:28:0;;;;;;;;;;;;;;;:41;;;:94;;;;:::i;:::-;39495:16;;;39512:10;;;;:6;:10;:::i;:::-;39495:28;;;;;;;;-1:-1:-1;;;39495:28:0;;;;;;;;;;;;;;;;;;;:151;;-1:-1:-1;;;;;39495:151:0;;;-1:-1:-1;;;39495:151:0;;;;;;;;;;39718:186;;39744:16;;39775:10;;;;:6;:10;:::i;:::-;39800:11;;;;:7;:11;:::i;:::-;39826:17;39858:5;:13;;;39886:7;39718:186;;;;;;;;;;:::i;:::-;39692:212;;-1:-1:-1;39692:212:0;-1:-1:-1;39923:32:0;;;;39915:69;;;;-1:-1:-1;;;39915:69:0;;20174:2:1;39915:69:0;;;20156:21:1;20213:2;20193:18;;;20186:30;20252:26;20232:18;;;20225:54;20296:18;;39915:69:0;20146:174:1;39915:69:0;40016:1;40003:10;:14;39995:47;;;;-1:-1:-1;;;39995:47:0;;23795:2:1;39995:47:0;;;23777:21:1;23834:2;23814:18;;;23807:30;-1:-1:-1;;;23853:18:1;;;23846:50;23913:18;;39995:47:0;23767:170:1;39995:47:0;40119:16;40138:39;40155:5;40162:14;;40138:16;:39::i;:::-;40119:58;-1:-1:-1;40188:191:0;40218:10;40243:20;;;40264:11;;;;:7;:11;:::i;:::-;40243:33;;;;;;;;-1:-1:-1;;;40243:33:0;;;;;;;;;;;;;;;;;;40188:191;;;;;;;;40243:33;;;;;;;40188:191;;-1:-1:-1;;;;;40188:191:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;40188:191:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;40188:191:0;;;;;;;;;;-1:-1:-1;;;40188:191:0;;;;;;;;;;;;;;;-1:-1:-1;;;40188:191:0;;;;;;;;;;;-1:-1:-1;40291:16:0;40308:11;;;;:7;:11;:::i;:::-;40291:29;;;;;;;;-1:-1:-1;;;40291:29:0;;;;;;;;;;;;;;;40335:10;40360:8;40188:15;:191::i;:::-;40506:30;40525:10;40506:18;:30::i;:::-;40448:16;40465:11;;;;:7;:11;:::i;:::-;40448:29;;;;;;;;-1:-1:-1;;;40448:29:0;;;;;;;;;;;;;;;:42;;;:88;;;;:::i;:::-;40390:16;;;40407:11;;;;:7;:11;:::i;:::-;40390:29;;;;;;;;-1:-1:-1;;;40390:29:0;;;;;;;;;;;;;;;;;:146;;-1:-1:-1;;;;;40390:146:0;;;-1:-1:-1;;;40390:146:0;;;;;;;;;;40587:13;;;:26;;40604:9;;40390:29;40587:26;;40604:9;;40587:26;:::i;:::-;;;;;;;;38740:1881;;;;;;;;;;;;;:::o;41607:1463::-;41858:22;41882:17;41970:36;42009:5;:16;;41970:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;41970:55:0;;;;;-1:-1:-1;;;41970:55:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;41970:55:0;;-1:-1:-1;42110:160:0;;-1:-1:-1;41970:55:0;;-1:-1:-1;42169:11:0;;-1:-1:-1;42169:11:0;;;:7;:11;:::i;:::-;42195:14;42110:160;;;;;;;42224:7;42110:160;:::i;:::-;42246:13;;42110;:160::i;:::-;42080:190;;-1:-1:-1;42080:190:0;-1:-1:-1;42289:36:0;;;;42281:69;;;;-1:-1:-1;;;42281:69:0;;19417:2:1;42281:69:0;;;19399:21:1;19456:2;19436:18;;;19429:30;-1:-1:-1;;;19475:18:1;;;19468:50;19535:18;;42281:69:0;19389:170:1;42281:69:0;42386:1;42369:14;:18;42361:42;;;;-1:-1:-1;;;42361:42:0;;21635:2:1;42361:42:0;;;21617:21:1;21674:2;21654:18;;;21647:30;-1:-1:-1;;;21693:18:1;;;21686:41;21744:18;;42361:42:0;21607:161:1;42361:42:0;42498:9;42481:5;:13;;;:26;;;;;;;:::i;:::-;;;;-1:-1:-1;42573:16:0;;-1:-1:-1;42592:68:0;42609:5;42650:9;42616:31;42633:14;42616;;:31;:::i;42592:68::-;42573:87;-1:-1:-1;42671:195:0;42701:14;42730:20;;;42751:11;;;;:7;:11;:::i;:::-;42730:33;;;;;;;;-1:-1:-1;;;42730:33:0;;;;;;;;;;;;;;;;;;42671:195;;;;;;;;42730:33;;;;;;;42671:195;;-1:-1:-1;;;;;42671:195:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;42671:195:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;42671:195:0;;;;;;;;;;-1:-1:-1;;;42671:195:0;;;;;;;;;;;;;;;-1:-1:-1;;;42671:195:0;;;;;;;;;;;-1:-1:-1;42778:16:0;42795:11;;;;:7;:11;:::i;:::-;42778:29;;;;;;;;-1:-1:-1;;;42778:29:0;;;;;;;;;;;;;;;42822:10;42847:8;42671:15;:195::i;:::-;43028:34;43047:14;43028:18;:34::i;:::-;42970:16;42987:11;;;;:7;:11;:::i;:::-;42970:29;;;;;;;;-1:-1:-1;;;42970:29:0;;;;;;;;;;;;;;;:42;;;:92;;;;:::i;:::-;42912:16;;;42929:11;;;;:7;:11;:::i;:::-;42912:29;;;;;;;;-1:-1:-1;;;42912:29:0;;;;;;;;;;;;;;;;;;:150;;-1:-1:-1;;;;;42912:150:0;;;-1:-1:-1;;;42912:150:0;;;;;;;;;-1:-1:-1;41607:1463:0;;;;-1:-1:-1;41607:1463:0;-1:-1:-1;;;;;;41607:1463:0:o;59808:1083::-;60024:22;60048:17;60111:18;60131:11;60146:22;60159:8;60146:12;:22::i;:::-;60110:58;;;;60239:10;60252:29;60263:1;60266:3;60271:7;:9;;;60252:10;:29::i;:::-;60239:42;;60292:18;60347:52;60355:20;60377:7;60386:8;60396:2;60347:7;:52::i;:::-;60466:14;;60321:78;;-1:-1:-1;60321:78:0;;-1:-1:-1;60410:14:0;;60434:27;60321:78;60466:14;60434:27;:::i;:::-;60428:34;;:2;:34;:::i;:::-;60427:53;;;;:::i;:::-;:57;;60483:1;60427:57;:::i;:::-;60410:74;;60532:24;60559:41;60575:1;60578:7;:9;;;60589:2;60593:6;60559:15;:41::i;:::-;60532:68;;60611:14;60655:1;60636:16;60628:1;60630:2;60628:5;;;;;;;;-1:-1:-1;;;60628:5:0;;;;;;;;;;;;;;;:24;;;;:::i;:::-;:28;;;;:::i;:::-;60611:45;;60701:8;60710:2;60701:12;;;;;;;;-1:-1:-1;;;60701:12:0;;;;;;;;;;;;;;;:18;;;-1:-1:-1;;;;;60684:35:0;60685:6;60694:3;60685:12;;;;:::i;:::-;60684:35;;;;:::i;:::-;60667:52;;60775:6;60766:1;60768:2;60766:5;;;;;;;;-1:-1:-1;;;60766:5:0;;;;;;;;;;;;;;:15;;;;;;;:::i;:::-;;;-1:-1:-1;60792:13:0;60799:6;60792:13;;:::i;:::-;;;60824:33;60834:1;60837:3;60842:7;:14;;;60824:9;:33::i;:::-;60816:67;;;;-1:-1:-1;;;60816:67:0;;;;;;;:::i;:::-;59808:1083;;;;;;;;;;;;;;;:::o;34408:1171::-;34627:18;34658:36;34697:5;:16;;34658:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;34658:55:0;;;;;-1:-1:-1;;;34658:55:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;34658:55:0;;-1:-1:-1;34809:25:0;;-1:-1:-1;34850:224:0;;-1:-1:-1;;34883:20:0;;;34904:10;;;;:6;:10;:::i;:::-;34883:32;;;;;;;;-1:-1:-1;;;34883:32:0;;;;;;;;;;;;;;;;;;34850:224;;;;;;;;34883:32;;;;;;;34850:224;;-1:-1:-1;;;;;34850:224:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;34850:224:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;34850:224:0;;;;;;;;;;-1:-1:-1;;;34850:224:0;;;;;;;;;;;;;;;-1:-1:-1;;;34850:224:0;;;;;;;;;;;-1:-1:-1;34934:16:0;34951:10;;;;:6;:10;:::i;:::-;34934:28;;;;;;;;-1:-1:-1;;;34934:28:0;;;;;;;;;;;;;;;:34;;;-1:-1:-1;;;;;34850:224:0;34987:14;35020:39;35037:5;35044:7;:14;;;35020:16;:39::i;34850:224::-;34809:265;-1:-1:-1;35184:69:0;35196:16;35214:10;;;;:6;:10;:::i;:::-;35226:17;35184:69;;;;;;;35245:7;35184:69;:::i;:::-;35171:82;;35286:18;35272:10;:32;;35264:68;;;;-1:-1:-1;;;35264:68:0;;18368:2:1;35264:68:0;;;18350:21:1;18407:2;18387:18;;;18380:30;-1:-1:-1;;;18426:18:1;;;18419:53;18489:18;;35264:68:0;18340:173:1;35264:68:0;35534:37;35553:17;35534:18;:37::i;:::-;35477:16;35494:10;;;;:6;:10;:::i;:::-;35477:28;;;;;;;;-1:-1:-1;;;35477:28:0;;;;;;;;;;;;;;;:41;;;:94;;;;:::i;:::-;35420:16;;;35437:10;;;;:6;:10;:::i;:::-;35420:28;;;;;;;;-1:-1:-1;;;35420:28:0;;;;;;;;;;;;;;;;;;:151;;-1:-1:-1;;;;;35420:151:0;;;-1:-1:-1;;;35420:151:0;;;;;;;;;-1:-1:-1;34408:1171:0;;;-1:-1:-1;;;;;;34408:1171:0:o;61893:1438::-;62129:19;62150:11;62207:18;62227:11;62242:22;62255:8;62242:12;:22::i;:::-;62206:58;;;;62335:10;62348:29;62359:1;62362:3;62367:7;:9;;;62348:10;:29::i;:::-;62445:15;;62335:42;;-1:-1:-1;62431:11:0;;62497:192;62521:3;62517:1;:7;62497:192;;;62605:3;62574:8;62583;62592:1;62583:11;;;;;;-1:-1:-1;;;62583:11:0;;;;;;;;;;;;;;;62574:21;;;;;;;;-1:-1:-1;;;62574:21:0;;;;;;;;;;;;;;;:27;;;-1:-1:-1;;;;;62557:44:0;:11;62569:1;62557:14;;;;;;-1:-1:-1;;;62557:14:0;;;;;;;;;;;;;;;:44;;;;:::i;:::-;62556:52;;;;:::i;:::-;62546:62;;62641:7;62623:1;62625:8;62634:1;62625:11;;;;;;-1:-1:-1;;;62625:11:0;;;;;;;;;;;;;;;62623:14;;;;;;;;-1:-1:-1;;;62623:14:0;;;;;;;;;;;;;;:25;;;;;;;:::i;:::-;;;-1:-1:-1;62663:14:0;62670:7;62663:14;;:::i;:::-;;-1:-1:-1;62526:3:0;;;;:::i;:::-;;;;62497:192;;;;62707:33;62717:1;62720:3;62725:7;:14;;;62707:9;:33::i;:::-;62699:67;;;;-1:-1:-1;;;62699:67:0;;;;;;;:::i;:::-;62841:10;62854:29;62865:1;62868:3;62873:7;:9;;;62854:10;:29::i;:::-;62841:42;-1:-1:-1;62955:16:0;63005:2;62993:7;62841:42;63005:2;62993:7;:::i;:::-;62975:14;;:26;;;;:::i;:::-;62974:33;;;;:::i;:::-;62955:52;;63037:3;63026:8;:14;63018:50;;;;-1:-1:-1;;;63018:50:0;;21975:2:1;63018:50:0;;;21957:21:1;22014:2;21994:18;;;21987:30;22053:25;22033:18;;;22026:53;22096:18;;63018:50:0;21947:173:1;63018:50:0;63093:38;63115:15;63122:8;63115:4;:15;:::i;:::-;63093:8;;:21;:38::i;:::-;63079:52;-1:-1:-1;63148:22:0;63162:8;63079:52;63148:22;:::i;:::-;63142:28;-1:-1:-1;63181:16:0;63196:1;63181:16;;:::i;:::-;;;63229:2;63212:7;:14;;;:19;63208:116;;;63294:16;;;;63287:23;;:4;:23;:::i;:::-;63264:18;:11;63278:4;63264:18;:::i;:::-;63263:48;;;;:::i;:::-;63248:64;;61893:1438;;;;;;;;;;;;;;;:::o;57344:1281::-;57566:28;57596:21;57663:18;57683:11;57698:22;57711:8;57698:12;:22::i;:::-;57662:58;;;;57791:10;57804:29;57815:1;57818:3;57823:7;:9;;;57804:10;:29::i;:::-;57791:42;;57885:19;57942:3;57920:8;57929:2;57920:12;;;;;;;;-1:-1:-1;;;57920:12:0;;;;;;;;;;;;;;;:18;;;-1:-1:-1;;;;;57908:30:0;:9;:30;;;;:::i;:::-;57907:38;;;;:::i;:::-;57885:60;;57965:11;57956:1;57958:2;57956:5;;;;;;;;-1:-1:-1;;;57956:5:0;;;;;;;;;;;;;;:20;;;;;;;:::i;:::-;;;-1:-1:-1;57987:18:0;57994:11;57987:18;;:::i;:::-;;;58051:10;58094:65;58106:2;58110:29;58121:1;58124:3;58129:7;:9;;;58110:10;:29::i;:::-;58141:8;58151:7;58094:11;:65::i;:::-;58072:87;;;;;;;;58204:24;58231:37;58247:1;58250:7;:9;;;58261:2;58265;58231:15;:37::i;:::-;58204:64;;58306:1;58308:2;58306:5;;;;;;;;-1:-1:-1;;;58306:5:0;;;;;;;;;;;;;;;58287:16;:24;58279:53;;;;-1:-1:-1;;;58279:53:0;;18023:2:1;58279:53:0;;;18005:21:1;18062:2;18042:18;;;18035:30;-1:-1:-1;;;18081:18:1;;;18074:46;18137:18;;58279:53:0;17995:166:1;58279:53:0;58343:14;58387:1;58368:16;58360:1;58362:2;58360:5;;;;;;;;-1:-1:-1;;;58360:5:0;;;;;;;;;;;;;;;:24;;;;:::i;:::-;:28;;;;:::i;:::-;58343:45;;58439:8;58448:2;58439:12;;;;;;;;-1:-1:-1;;;58439:12:0;;;;;;;;;;;;;;;:18;;;-1:-1:-1;;;;;58422:35:0;58423:6;58432:3;58423:12;;;;:::i;:::-;58422:35;;;;:::i;:::-;58399:58;;58509:6;58500:1;58502:2;58500:5;;;;;;;;-1:-1:-1;;;58500:5:0;;;;;;;;;;;;;;:15;;;;;;;:::i;:::-;;;-1:-1:-1;58526:13:0;58533:6;58526:13;;:::i;:::-;;;58558:33;58568:1;58571:3;58576:7;:14;;;58558:9;:33::i;:::-;58550:67;;;;-1:-1:-1;;;58550:67:0;;;;;;;:::i;:::-;57344:1281;;;;;;;;;;;;;;;;:::o;55690:980::-;55896:18;55960;55980:11;55995:22;56008:8;55995:12;:22::i;:::-;55959:58;;;;56088:10;56101:29;56112:1;56115:3;56120:7;:9;;;56101:10;:29::i;:::-;56198:15;;56088:42;;-1:-1:-1;56184:11:0;;;56274:219;56298:3;56294:1;:7;56274:219;;;56329:8;56338:1;56329:11;;;;;;-1:-1:-1;;;56329:11:0;;;;;;;;;;;;;;;56323:17;;56409:3;56386:8;56395:3;56386:13;;;;;;;;-1:-1:-1;;;56386:13:0;;;;;;;;;;;;;;;:19;;;-1:-1:-1;;;;;56370:35:0;:10;56381:1;56370:13;;;;;;-1:-1:-1;;;56370:13:0;;;;;;;;;;;;;;;:35;;;;:::i;:::-;56369:43;;;;:::i;:::-;56355:57;;56437:11;56427:1;56429:3;56427:6;;;;;;;;-1:-1:-1;;;56427:6:0;;;;;;;;;;;;;;:21;;;;;;;:::i;:::-;;;-1:-1:-1;56463:18:0;56470:11;56463:18;;:::i;:::-;;-1:-1:-1;56303:3:0;;;;:::i;:::-;;;;56274:219;;;;56540:33;56550:1;56553:3;56558:7;:14;;;56540:9;:33::i;:::-;56532:67;;;;-1:-1:-1;;;56532:67:0;;;;;;;:::i;:::-;56623:39;56642:1;56645:3;56650:2;56654:7;56623:18;:39::i;:::-;56610:52;55690:980;-1:-1:-1;;;;;;;;;;;55690:980:0:o;36288:1510::-;36529:18;36574:8;36529:18;36574:8;-1:-1:-1;;;;;36639:18:0;;;;;-1:-1:-1;;;36639:18:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;36639:18:0;;36600:57;;36668:36;36707:5;:16;;36668:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;36668:55:0;;;;;-1:-1:-1;;;36668:55:0;;;;;;;;;;;;;;;;;;;;;;;;;36734:16;36753:39;36770:5;36777:7;:14;;;36753:16;:39::i;:::-;36734:58;;36892:9;36887:608;36911:3;36907:1;:7;36887:608;;;36962:1;36940:16;;36957:1;36940:19;;;;;-1:-1:-1;;;36940:19:0;;;;;;;;;;;;;;;:23;36936:548;;;36984:9;36996:8;;37005:1;36996:11;;;;;-1:-1:-1;;;36996:11:0;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;36984:23;;37026;37052:16;37069:3;37052:21;;;;;;;;-1:-1:-1;;;37052:21:0;;;;;;;;;;;;;;;37026:47;;37117:188;37154:5;:20;;37175:3;37154:25;;;;;;;;-1:-1:-1;;;37154:25:0;;;;;;;;;;;;;;;;;;37117:188;;;;;;;;37154:25;;;;;;;37117:188;;-1:-1:-1;;;;;37117:188:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;37117:188:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;37117:188:0;;;;;;;;;;-1:-1:-1;;;37117:188:0;;;;;;;;;;;;;;;-1:-1:-1;;;37117:188:0;;;;;;;;;;;-1:-1:-1;37202:11:0;;-1:-1:-1;;;;;37117:188:0;37236:16;;37253:1;37236:19;;;;;-1:-1:-1;;;37236:19:0;;;;;;;;;;;;;;;37278:8;37117:14;:188::i;:::-;37092:19;37112:1;37092:22;;;;;;-1:-1:-1;;;37092:22:0;;;;;;;;;;;;;;:213;;;;;37426:42;37445:19;37465:1;37445:22;;;;;;-1:-1:-1;;;37445:22:0;;;;;;;;;;;;;;;37426:18;:42::i;:::-;37384:5;:18;;;:84;;;;:::i;:::-;37326:5;:16;;37343:3;37326:21;;;;;;;;-1:-1:-1;;;37326:21:0;;;;;;;;;;;;;;;;;;:142;;-1:-1:-1;;;;;37326:142:0;;;-1:-1:-1;;;37326:142:0;;;;;;;;;-1:-1:-1;;36936:548:0;36916:3;;;;:::i;:::-;;;;36887:608;;;;37579:74;37596:16;37614:8;;37579:74;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;37624:19;37645:7;37579:74;;;;;;;;;;:::i;:::-;37566:87;;37686:18;37672:10;:32;;37664:68;;;;-1:-1:-1;;;37664:68:0;;18368:2:1;37664:68:0;;;18350:21:1;18407:2;18387:18;;;18380:30;-1:-1:-1;;;18426:18:1;;;18419:53;18489:18;;37664:68:0;18340:173:1;37664:68:0;37764:1;37751:10;:14;37743:47;;;;-1:-1:-1;;;37743:47:0;;22327:2:1;37743:47:0;;;22309:21:1;22366:2;22346:18;;;22339:30;-1:-1:-1;;;22385:18:1;;;22378:50;22445:18;;37743:47:0;22299:170:1;37743:47:0;36288:1510;;;;;;;;;;;;;:::o;63640:330::-;63772:13;63787:9;63815:18;63835:11;63850:22;63863:8;63850:12;:22::i;:::-;63814:58;;;;63887:29;63898:1;63901:3;63906:7;:9;;;63887:10;:29::i;:::-;63948:14;;63883:33;;-1:-1:-1;63936:8:0;63883:33;63936:4;:8;:::i;:::-;63935:27;;;;:::i;:::-;63927:35;;63640:330;;;;;;;:::o;43884:2030::-;44162:17;44194:24;44233:33;44352:36;44391:5;:16;;44352:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;44352:55:0;;;;;-1:-1:-1;;;44352:55:0;;;;;;;;;;;;;;;;;;;;;;;;;44471:21;44532:139;44559:16;44590:7;44532:139;;;;;;;;;;:::i;:::-;44612:14;44641:5;:19;;;44532:12;:139::i;:::-;44503:168;;;;;;;;44701:9;44684:5;:13;;;:26;;;;;;;:::i;:::-;;;;-1:-1:-1;44775:16:0;;-1:-1:-1;44794:68:0;44811:5;44852:9;44818:31;44835:14;44818;;:31;:::i;44794:68::-;44889:23;;44775:87;;-1:-1:-1;44889:23:0;-1:-1:-1;;;;;44933:18:0;;;;;-1:-1:-1;;;44933:18:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;44933:18:0;;44923:28;;44995:3;-1:-1:-1;;;;;44981:18:0;;;;;-1:-1:-1;;;44981:18:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;44981:18:0;;44962:37;;45015:9;45010:897;45034:3;45030:1;:7;45010:897;;;45128:17;45201:7;:14;;;45184:13;45149:16;45166:1;45149:19;;;;;;-1:-1:-1;;;45149:19:0;;;;;;;;;;;;;;;:32;;;-1:-1:-1;;;;;45149:48:0;;;;;:::i;:::-;45148:67;;;;:::i;:::-;45128:87;;45250:1;45238:9;:13;45230:37;;;;-1:-1:-1;;;45230:37:0;;21635:2:1;45230:37:0;;;21617:21:1;21674:2;21654:18;;;21647:30;-1:-1:-1;;;21693:18:1;;;21686:41;21744:18;;45230:37:0;21607:161:1;45230:37:0;45282:14;45295:1;45282:14;;:::i;:::-;;;45332:20;;45353:1;45332:23;;;;;-1:-1:-1;;;45332:23:0;;;;;;;;;;;;;;;45319:9;:36;;45311:69;;;;-1:-1:-1;;;45311:69:0;;19417:2:1;45311:69:0;;;19399:21:1;19456:2;19436:18;;;19429:30;-1:-1:-1;;;19475:18:1;;;19468:50;19535:18;;45311:69:0;19389:170:1;45311:69:0;45535:29;45554:9;45535:18;:29::i;:::-;45483:16;45500:1;45483:19;;;;;;-1:-1:-1;;;45483:19:0;;;;;;;;;;;;;;;:32;;;:81;;;;:::i;:::-;45431:5;:16;;45448:1;45431:19;;;;;;-1:-1:-1;;;45431:19:0;;;;;;;;;;;;;;;;:32;;;:133;;;;;-1:-1:-1;;;;;45431:133:0;;;;;-1:-1:-1;;;;;45431:133:0;;;;;;45615:30;45648:5;:20;;45669:1;45648:23;;;;;;-1:-1:-1;;;45648:23:0;;;;;;;;;;;;;;;;;;45615:56;;;;;;;;45648:23;;;;;;;45615:56;;-1:-1:-1;;;;;45615:56:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;45615:56:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;45615:56:0;;;;;;;;;;-1:-1:-1;;;45615:56:0;;;;;;;;;;;;;;;-1:-1:-1;;;45615:56:0;;;;;;;;;;;;;;;45723:9;45734:8;:13;;;45687:16;45704:1;45687:19;;;;;;-1:-1:-1;;;45687:19:0;;;;;;;;;;;;;;45708:7;45716:1;45708:10;;;;;;-1:-1:-1;;;45708:10:0;;;;;;;;;;;;;;45686:62;-1:-1:-1;;;;;45686:62:0;-1:-1:-1;;;;;45686:62:0;;;;;;;;;;45816:79;45832:9;45843:8;45853:16;45870:1;45853:19;;;;;;-1:-1:-1;;;45853:19:0;;;;;;;;;;;;;;;45874:10;45886:8;45816:15;:79::i;:::-;45010:897;;45039:3;;;;;:::i;:::-;;;;45010:897;;;;43884:2030;;;;;;;;;;;;;;:::o;53688:206::-;53807:16;53882:4;53863:5;:15;;;53853:7;:25;;;;:::i;:::-;53852:34;;;;:::i;:::-;53841:45;53688:206;-1:-1:-1;;;53688:206:0:o;51446:2060::-;51663:14;51659:27;;51679:7;;51659:27;51760:20;;;;-1:-1:-1;;;;;51760:34:0;51756:1743;;51818:14;;51811:58;;-1:-1:-1;;;;;51811:35:0;51847:10;51859:9;51811:35;:58::i;:::-;51756:1743;;;51964:9;:18;;;51960:1539;;;52020:20;;;;52098:14;;51999:207;;-1:-1:-1;;;51999:207:0;;-1:-1:-1;;;;;16569:15:1;;;51999:207:0;;;16551:34:1;16621:15;;;16601:18;;;16594:43;16653:18;;;16646:34;;;16696:18;;;16689:34;;;52187:4:0;16739:19:1;;;16732:51;51999::0;;;;;16485:19:1;;51999:207:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;51960:1539;;;52338:14;;52364:20;;;;52331:54;;-1:-1:-1;;;52331:54:0;;-1:-1:-1;;;;;15836:32:1;;;52331:54:0;;;15818:51:1;52312:16:0;;52331:32;;;;;;;15791:18:1;;52331:54:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;52312:73;;52477:9;52465:8;:21;52461:1027;;52528:20;;;;52617:14;;52507:175;;-1:-1:-1;;;52507:175:0;;-1:-1:-1;;;;;16138:15:1;;;52507:175:0;;;16120:34:1;16190:15;;;16170:18;;;16163:43;16222:18;;;16215:34;;;52507:54:0;;;;;16055:18:1;;52507:175:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;52461:1027;;;52952:11;;52897:24;;52967:1;;52924:40;;:9;;-1:-1:-1;;;;;52924:40:0;:27;:40::i;:::-;:44;;;;:::i;:::-;52897:71;-1:-1:-1;52987:23:0;53034:179;53106:8;53075:28;53094:9;52897:71;53075:28;:::i;:::-;:39;;;;:::i;:::-;53162:28;53181:8;53162:18;:28::i;:::-;53141:5;:18;;;:49;;;;:::i;:::-;-1:-1:-1;;;;;53034:179:0;:14;:179::i;:::-;53255:20;;;;53341:14;;53234:238;;-1:-1:-1;;;53234:238:0;;-1:-1:-1;;;;;16569:15:1;;;53234:238:0;;;16551:34:1;16621:15;;;16601:18;;;16594:43;16653:18;;;16646:34;;;16696:18;;;16689:34;;;53341:14:0;16739:19:1;;;16732:51;52987:226:0;;-1:-1:-1;53234:51:0;;;;16485:19:1;;53234:238:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;52461:1027;;;51960:1539;;51446:2060;;;;;:::o;19117:184::-;19174:7;-1:-1:-1;;;19202:5:0;:14;19194:67;;;;-1:-1:-1;;;19194:67:0;;19766:2:1;19194:67:0;;;19748:21:1;19805:2;19785:18;;;19778:30;19844:34;19824:18;;;19817:62;-1:-1:-1;;;19895:18:1;;;19888:37;19942:19;;19194:67:0;19738:229:1;19194:67:0;-1:-1:-1;19287:5:0;19117:184;;;;:::o;65557:457::-;65722:15;;65659:18;;65679:11;;65722:15;-1:-1:-1;;;;;65752:18:0;;;;;-1:-1:-1;;;65752:18:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;65752:18:0;-1:-1:-1;65748:22:0;-1:-1:-1;65781:9:0;;65801:206;65825:3;65821:1;:7;65801:206;;;65850:24;65877:8;65886:1;65877:11;;;;;;-1:-1:-1;;;65877:11:0;;;;;;;;;;;;;;;65850:38;;65946:3;65930:6;:12;;;65908:6;:19;;;:34;;;;:::i;:::-;65907:42;;;;:::i;:::-;-1:-1:-1;;;;;65903:46:0;;;65971:1;65964;65966;65964:4;;;;;;-1:-1:-1;;;65964:4:0;;;;;;;;;;;;;;;;;;:8;65987;65994:1;65987:8;;:::i;:::-;;;65801:206;65830:3;;;;;:::i;:::-;;;;65801:206;;;;65557:457;;;;;:::o;67227:809::-;67387:9;;67351;;67413;67409:23;;67431:1;67424:8;;;;;67409:23;67445:10;67458:8;67463:3;67458:2;:8;:::i;:::-;67445:21;;67477:13;67505:4;67501:8;;67527:9;67522:458;67546:3;67542:1;:7;67522:458;;;67584:1;67571:10;67600:98;67624:3;67620:1;:7;67600:98;;;67678:3;67670:2;67673:1;67670:5;;;;;;-1:-1:-1;;;67670:5:0;;;;;;;;;;;;;;;:11;;;;:::i;:::-;67659:6;67664:1;67659:2;:6;:::i;:::-;67658:24;;;;:::i;:::-;67653:29;-1:-1:-1;67629:3:0;;;;:::i;:::-;;;;67600:98;;;-1:-1:-1;67720:1:0;;-1:-1:-1;67878:2:0;67867:7;:3;67873:1;67867:7;:::i;:::-;67866:14;;;;:::i;:::-;33667:3;67846:1;67826:16;33667:3;67826:2;:16;:::i;:::-;67825:22;;;;:::i;:::-;67824:38;;;;:::i;:::-;:57;;;;:::i;:::-;67801:1;67788:8;67793:3;67788:2;:8;:::i;:::-;33667:3;67760:9;67765:4;67760:2;:9;:::i;:::-;67759:25;;;;:::i;:::-;:38;;;;:::i;:::-;67758:44;;;;:::i;:::-;67757:125;;;;:::i;:::-;67736:146;;67901:23;67915:1;67918:5;67901:13;:23::i;:::-;67897:72;;;67945:8;;;;;;;67897:72;-1:-1:-1;67551:3:0;;;;:::i;:::-;;;;67522:458;;;-1:-1:-1;67992:36:0;;-1:-1:-1;;;67992:36:0;;19062:2:1;67992:36:0;;;19044:21:1;19101:2;19081:18;;;19074:30;19140:28;19120:18;;;19113:56;19186:18;;67992:36:0;19034:176:1;66351:406:0;66531:9;;66562:4;;66491:13;;66597:153;66621:3;66617:1;:7;66597:153;;;66667:4;66651:2;66654:1;66651:5;;;;;;-1:-1:-1;;;66651:5:0;;;;;;;;;;;;;;;66659:4;66651:12;;;;:::i;:::-;66650:21;;;;:::i;:::-;66646:25;;66694:7;:11;;;-1:-1:-1;;;;;66690:15:0;:1;:15;:34;;;-1:-1:-1;66713:11:0;;-1:-1:-1;;;;;66709:15:0;;;66690:34;66686:52;;;66733:5;66726:12;;;;;;;66686:52;66626:3;;;;:::i;:::-;;;;66597:153;;;;66351:406;;;;;;;:::o;64578:749::-;64751:18;64842:14;64859:31;64870:2;64874:4;64880:7;:9;;;64859:10;:31::i;:::-;64996:14;;64842:48;;-1:-1:-1;64992:159:0;;65045:11;65054:2;65045:6;:11;:::i;:::-;65032:24;;64992:159;;;65137:2;65121:11;65137:2;65121:6;:11;:::i;:::-;65103:14;;:30;;;;:::i;:::-;65102:37;;;;:::i;:::-;65089:50;;64992:159;65218:14;;:19;-1:-1:-1;65214:106:0;;;65303:4;65283:7;:16;;;65270:10;:29;;;;:::i;:::-;65269:38;;;;:::i;:::-;65254:54;;;;:::i;:::-;;;65214:106;64578:749;;;;;;;:::o;49336:1847::-;49604:18;;;;49512:25;;-1:-1:-1;;;;;49604:32:0;49600:325;;49654:16;49693:190;49751:10;49792:4;49820:7;:12;;;49855:9;49693:35;:190::i;:::-;-1:-1:-1;49653:230:0;-1:-1:-1;49898:15:0;;-1:-1:-1;49898:15:0;49600:325;50043:16;50102:155;50152:10;50177:7;:18;;;50210:7;:12;;;50237:9;50102:35;:155::i;:::-;50352:16;;;;50070:187;;-1:-1:-1;50070:187:0;-1:-1:-1;50348:323:0;;;50443:18;;;;50493:12;;50422:169;;-1:-1:-1;;;50422:169:0;;-1:-1:-1;;;;;17287:32:1;;;50422:169:0;;;17269:51:1;17336:18;;;17329:34;;;50568:4:0;17379:18:1;;;17372:50;50385:17:0;;50422:48;;;;;;;17242:18:1;;50422:169:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;50385:206;;50615:44;50630:9;50641:17;50615:14;:44::i;:::-;50608:51;;;;;;50348:323;50841:9;50820:17;:30;50812:70;;;;-1:-1:-1;;;50812:70:0;;21279:2:1;50812:70:0;;;21261:21:1;21318:2;21298:18;;;21291:30;21357:29;21337:18;;;21330:57;21404:18;;50812:70:0;21251:177:1;50812:70:0;50895:24;50922:41;:9;50950:12;50922:27;:41::i;:::-;50895:68;;50991:16;50980:8;:27;50976:200;;;51024:13;51052:20;51071:1;51052:16;:20;:::i;:::-;51040:33;;:8;:33;:::i;:::-;51109:18;;;;51137:12;;51088:76;;-1:-1:-1;;;51088:76:0;;-1:-1:-1;;;;;17287:32:1;;;51088:76:0;;;17269:51:1;17336:18;;;17329:34;;;51137:12:0;17379:18:1;;;17372:50;51024:49:0;;-1:-1:-1;51088:48:0;;;;17242:18:1;;51088:76:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;50976:200;;49336:1847;;;;;;;;;:::o;60899:473::-;61173:14;;61138:20;;61075:18;;61173:20;-1:-1:-1;61169:107:0;;;61259:4;61239:7;:16;;;61226:10;:29;;;;:::i;:::-;61225:38;;;;:::i;:::-;61210:54;;;;:::i;:::-;;;61169:107;61298:32;:10;61321:8;61298:22;:32::i;:::-;61286:44;-1:-1:-1;61341:23:0;61286:44;61341:23;;:::i;:::-;;;60899:473;;;;;;;:::o;68921:968::-;69111:9;;69075;;69159:3;69152:4;:10;;;69131:49;;;;-1:-1:-1;;;69131:49:0;;18720:2:1;69131:49:0;;;18702:21:1;18759:2;18739:18;;;18732:30;-1:-1:-1;;;18778:18:1;;;18771:43;18831:18;;69131:49:0;18692:163:1;69131:49:0;69194:12;;;;69238:8;69243:3;69238:2;:8;:::i;:::-;69248;69193:64;;;;;;69275:9;69270:178;69294:3;69290:1;:7;69270:178;;;69328:4;69323:9;;:1;:9;69319:118;;69361:2;69364:1;69361:5;;;;;;-1:-1:-1;;;69361:5:0;;;;;;;;;;;;;;;69353:13;;;;;:::i;:::-;;;69417:3;69409:2;69412:1;69409:5;;;;;;-1:-1:-1;;;69409:5:0;;;;;;;;;;;;;;;:11;;;;:::i;:::-;69391:13;69396:8;69391:2;:13;:::i;:::-;69390:31;;;;:::i;:::-;69385:36;;69319:118;69299:3;;;;:::i;:::-;;;;69270:178;;;-1:-1:-1;69460:9:0;69513:3;69507:2;33667:3;69475:13;69480:8;69475:2;:13;:::i;:::-;69474:29;;;;:::i;:::-;69473:36;;;;:::i;:::-;69472:44;;;;:::i;:::-;69460:56;-1:-1:-1;69527:9:0;69573:2;69552:16;33667:3;69573:2;69552:16;:::i;:::-;69540:29;;:8;:29;:::i;:::-;69539:36;;;;:::i;:::-;69527:48;;69586:9;69620:4;69616:1;:8;69612:218;;;69645:8;69649:4;69645:1;:8;:::i;:::-;69641:12;-1:-1:-1;69708:1:0;69641:12;69673:27;69693:5;69697:1;69693;:5;:::i;:::-;69684:4;69687:1;69684;:4;:::i;:::-;69683:16;;;;:::i;:::-;69673:9;:27::i;:::-;:31;;;;:::i;:::-;69672:37;;;;:::i;:::-;:41;;69712:1;69672:41;:::i;:::-;69668:45;;69612:218;;;69750:8;69757:1;69750:4;:8;:::i;:::-;69746:12;-1:-1:-1;69813:1:0;69746:12;69778:27;69798:5;69802:1;69798;:5;:::i;69778:27::-;:31;;;;:::i;:::-;69777:37;;;;:::i;:::-;:41;;69817:1;69777:41;:::i;:::-;69773:45;;69612:218;69850:3;69846:1;:7;69842:39;;;69855:26;;-1:-1:-1;;;69855:26:0;;20527:2:1;69855:26:0;;;20509:21:1;20566:2;20546:18;;;20539:30;-1:-1:-1;;;20585:18:1;;;20578:46;20641:18;;69855:26:0;20499:166:1;69842:39:0;68921:968;;;;;;;;;;;;;:::o;29450:195::-;29517:7;29636:1;29618:14;25694:4;29618:1;:14;:::i;29450:195::-;;;;;:::o;58718:612::-;58881:10;;;58944:9;58950:3;58944;:9;:::i;:::-;58927:26;;59019:3;59002:7;:14;;;:20;58998:99;;;59080:4;59060:7;:16;;;59051:6;:25;;;;:::i;:::-;59050:34;;;;:::i;:::-;59039:46;;;;:::i;:::-;;;58998:99;59171:4;59150:17;59159:8;59150:6;:17;:::i;:::-;59149:26;;;;:::i;:::-;59133:42;-1:-1:-1;59133:42:0;59191:12;59197:6;59191:3;:12;:::i;:::-;:28;;;;:::i;:::-;59301:14;;59186:33;;-1:-1:-1;59319:3:0;;59285:30;;:13;:30;:::i;:::-;59284:38;;;;:::i;:::-;59268:54;;58718:612;;;;;;;;:::o;46006:583::-;46263:6;46194:21;;46343:29;46356:6;46364:7;46343:12;:29::i;:::-;46323:49;;;46395:4;46387:5;:12;46383:98;;;46464:4;46444:7;:16;;;46435:6;:25;;;;:::i;:::-;46434:34;;;;:::i;:::-;46416:53;;;;:::i;:::-;;;46383:98;46503:41;:13;46529:14;46503:25;:41::i;:::-;46491:53;-1:-1:-1;46555:26:0;46491:53;46555:26;;:::i;:::-;;;46006:583;;;;;;;;:::o;15596:177::-;15706:58;;-1:-1:-1;;;;;16986:32:1;;15706:58:0;;;16968:51:1;17035:18;;;17028:34;;;15679:86:0;;15699:5;;-1:-1:-1;;;15729:23:0;16941:18:1;;15706:58:0;;;;-1:-1:-1;;15706:58:0;;;;;;;;;;;;;;-1:-1:-1;;;;;15706:58:0;-1:-1:-1;;;;;;15706:58:0;;;;;;;;;;15679:19;:86::i;:::-;15596:177;;;:::o;31542:211::-;31618:9;31740:5;31721:15;26102:3;31721:1;:15;:::i;32072:106::-;32130:7;32161:1;32157;:5;:13;;32169:1;32157:13;;;-1:-1:-1;32165:1:0;32072:106;-1:-1:-1;32072:106:0:o;68315:225::-;68389:4;68419:2;68410:6;:11;68406:127;;;68462:1;68446:11;68455:2;68446:6;:11;:::i;:::-;68445:18;;68438:25;;;;68406:127;68520:1;68504:11;68509:6;68504:2;:11;:::i;24819:473::-;25057:37;;-1:-1:-1;;;25057:37:0;;-1:-1:-1;;;;;15836:32:1;;;25057:37:0;;;15818:51:1;24979:19:0;;;;;;25057:25;;;;;;15791:18:1;;25057:37:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;25037:57;-1:-1:-1;25105:59:0;-1:-1:-1;;;;;25105:32:0;;25138:7;25147:10;25159:4;25105:32;:59::i;:::-;25194:37;;-1:-1:-1;;;25194:37:0;;-1:-1:-1;;;;;15836:32:1;;;25194:37:0;;;15818:51:1;25194:25:0;;;;;15791:18:1;;25194:37:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;25175:56;-1:-1:-1;25256:28:0;25275:9;25175:56;25256:28;:::i;27320:135::-;27386:7;27413:34;27430:1;27433;25694:4;27413:16;:34::i;3602:1273::-;3650:9;3676:6;3672:1196;;-1:-1:-1;3691:1:0;3684:8;;3672:1196;3736:1;3764;-1:-1:-1;;;3784:41:0;;3780:119;;3853:3;3846:10;;;;;3881:2;3875:8;3780:119;3923:19;3917:2;:25;3913:102;;3970:2;3963:9;;;;;3997:2;3991:8;3913:102;4039:11;4033:2;:17;4029:94;;4078:2;4071:9;;;;;4105:2;4099:8;4029:94;4147:7;4141:2;:13;4137:89;;4182:2;4175:9;;;;;4209:1;4203:7;4137:89;4250:5;4244:2;:11;4240:86;;4283:1;4276:8;;;;;4309:1;4303:7;4240:86;4350:4;4344:2;:10;4340:85;;4382:1;4375:8;;;;;4408:1;4402:7;4340:85;4449:3;4443:2;:9;4439:57;;4479:1;4473:7;4439:57;4529:1;4519:5;4523:1;4519;:5;:::i;:::-;4515:9;;:1;:9;:::i;:::-;4514:16;;;-1:-1:-1;4564:1:0;4554:5;4514:16;4554:1;:5;:::i;:::-;4550:9;;:1;:9;:::i;:::-;4549:16;;;-1:-1:-1;4599:1:0;4589:5;4549:16;4589:1;:5;:::i;:::-;4585:9;;:1;:9;:::i;:::-;4584:16;;;-1:-1:-1;4634:1:0;4624:5;4584:16;4624:1;:5;:::i;:::-;4620:9;;:1;:9;:::i;:::-;4619:16;;;-1:-1:-1;4669:1:0;4659:5;4619:16;4659:1;:5;:::i;:::-;4655:9;;:1;:9;:::i;:::-;4654:16;;;-1:-1:-1;4704:1:0;4694:5;4654:16;4694:1;:5;:::i;:::-;4690:9;;:1;:9;:::i;:::-;4689:16;;;-1:-1:-1;4739:1:0;4729:5;4689:16;4729:1;:5;:::i;:::-;4725:9;;:1;:9;:::i;:::-;4724:16;;;-1:-1:-1;4792:10:0;4805:5;4724:16;4805:1;:5;:::i;:::-;4792:18;;4844:2;4840:1;:6;:15;;4853:2;4840:15;;;4849:1;4840:15;4825:31;;;;;;;18030:761;18454:23;18480:69;18508:4;18480:69;;;;;;;;;;;;;;;;;18488:5;-1:-1:-1;;;;;18480:27:0;;;:69;;;;;:::i;:::-;18564:17;;18454:95;;-1:-1:-1;18564:21:0;18560:224;;18706:10;18695:30;;;;;;;;;;;;:::i;:::-;18687:85;;;;-1:-1:-1;;;18687:85:0;;23384:2:1;18687:85:0;;;23366:21:1;23423:2;23403:18;;;23396:30;23462:34;23442:18;;;23435:62;-1:-1:-1;;;23513:18:1;;;23506:40;23563:19;;18687:85:0;23356:232:1;15781:205:0;15909:68;;-1:-1:-1;;;;;16138:15:1;;;15909:68:0;;;16120:34:1;16190:15;;16170:18;;;16163:43;16222:18;;;16215:34;;;15882:96:0;;15902:5;;-1:-1:-1;;;15932:27:0;16055:18:1;;15909:68:0;16037:218:1;15882:96:0;15781:205;;;;:::o;27928:286::-;28048:7;28201:5;28192;28196:1;28192;:5;:::i;:::-;28191:15;;;;:::i;11196:195::-;11299:12;11331:52;11353:6;11361:4;11367:1;11370:12;11299;8645:20;;12492:60;;;;-1:-1:-1;;;12492:60:0;;23026:2:1;12492:60:0;;;23008:21:1;23065:2;23045:18;;;23038:30;23104:31;23084:18;;;23077:59;23153:18;;12492:60:0;22998:179:1;12492:60:0;12626:12;12640:23;12667:6;-1:-1:-1;;;;;12667:11:0;12687:5;12695:4;12667:33;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12625:75;;;;12718:52;12736:7;12745:10;12757:12;12718:17;:52::i;:::-;12711:59;12248:530;-1:-1:-1;;;;;;;12248:530:0:o;14788:742::-;14903:12;14932:7;14928:595;;;-1:-1:-1;14963:10:0;14956:17;;14928:595;15077:17;;:21;15073:439;;15340:10;15334:17;15401:15;15388:10;15384:2;15380:19;15373:44;15288:148;15483:12;15476:20;;-1:-1:-1;;;15476:20:0;;;;;;;;:::i;14:173:1:-;82:20;;-1:-1:-1;;;;;131:31:1;;121:42;;111:2;;177:1;174;167:12;192:758;;309:3;302:4;294:6;290:17;286:27;276:2;;331:5;324;317:20;276:2;371:6;358:20;397:4;421:70;437:53;487:2;437:53;:::i;:::-;421:70;:::i;:::-;525:15;;;556:12;;;;588:15;;;622:4;657:11;;;645:24;;641:33;;638:42;-1:-1:-1;635:2:1;;;697:5;690;683:20;635:2;723:5;737:184;751:2;748:1;745:9;737:184;;;808:38;842:3;837;808:38;:::i;:::-;796:51;;867:12;;;;899;;;;769:1;762:9;737:184;;;-1:-1:-1;939:5:1;;266:684;-1:-1:-1;;;;;;;;266:684:1:o;955:398::-;;;1082:3;1075:4;1067:6;1063:17;1059:27;1049:2;;1107:8;1097;1090:26;1049:2;-1:-1:-1;1137:20:1;;-1:-1:-1;;;;;1169:30:1;;1166:2;;;1219:8;1209;1202:26;1166:2;1263:4;1255:6;1251:17;1239:29;;1326:3;1319:4;1311;1303:6;1299:17;1291:6;1287:30;1283:41;1280:50;1277:2;;;1343:1;1340;1333:12;1277:2;1039:314;;;;;:::o;1358:704::-;;1465:3;1458:4;1450:6;1446:17;1442:27;1432:2;;1487:5;1480;1473:20;1432:2;1527:6;1514:20;1553:4;1577:70;1593:53;1643:2;1593:53;:::i;1577:70::-;1681:15;;;1712:12;;;;1744:15;;;1790:11;;;1778:24;;1774:33;;1771:42;-1:-1:-1;1768:2:1;;;1830:5;1823;1816:20;1768:2;1856:5;1870:163;1884:2;1881:1;1878:9;1870:163;;;1941:17;;1929:30;;1979:12;;;;2011;;;;1902:1;1895:9;1870:163;;;-1:-1:-1;2051:5:1;;1422:640;-1:-1:-1;;;;;;;1422:640:1:o;2067:706::-;;2172:3;2165:4;2157:6;2153:17;2149:27;2139:2;;2194:5;2187;2180:20;2139:2;2234:6;2221:20;2260:4;2284:70;2300:53;2350:2;2300:53;:::i;2284:70::-;2388:15;;;2419:12;;;;2451:15;;;2497:11;;;2485:24;;2481:33;;2478:42;-1:-1:-1;2475:2:1;;;2537:5;2530;2523:20;2475:2;2563:5;2577:167;2591:2;2588:1;2585:9;2577:167;;;2648:21;2665:3;2648:21;:::i;:::-;2636:34;;2690:12;;;;2722;;;;2609:1;2602:9;2577:167;;2778:161;;2881:2;2872:6;2867:3;2863:16;2859:25;2856:2;;;2901:5;2894;2887:20;2944:304;;3049:4;3037:9;3032:3;3028:19;3024:30;3021:2;;;3071:5;3064;3057:20;3021:2;3097:21;3113:4;3097:21;:::i;:::-;3088:30;;3141:29;3160:9;3141:29;:::i;:::-;3134:5;3127:44;3203:38;3237:2;3226:9;3222:18;3203:38;:::i;:::-;3198:2;3191:5;3187:14;3180:62;3011:237;;;;:::o;3253:172::-;;3366:3;3357:6;3352:3;3348:16;3344:26;3341:2;;;3387:5;3380;3373:20;3430:452;;3540:4;3528:9;3523:3;3519:19;3515:30;3512:2;;;3562:5;3555;3548:20;3512:2;3588:21;3604:4;3588:21;:::i;:::-;3579:30;;3645:9;3632:23;3625:5;3618:38;3716:2;3705:9;3701:18;3688:32;3683:2;3676:5;3672:14;3665:56;3753:53;3802:3;3797:2;3786:9;3782:18;3753:53;:::i;:::-;3748:2;3741:5;3737:14;3730:77;3869:4;3858:9;3854:20;3841:34;3834:4;3827:5;3823:16;3816:60;3502:380;;;;:::o;3887:188::-;3955:20;;-1:-1:-1;;;;;4004:46:1;;3994:57;;3984:2;;4065:1;4062;4055:12;4080:156;4146:20;;4206:4;4195:16;;4185:27;;4175:2;;4226:1;4223;4216:12;4241:1024;;;;;4535:3;4523:9;4514:7;4510:23;4506:33;4503:2;;;4557:6;4549;4542:22;4503:2;4602:9;4589:23;-1:-1:-1;;;;;4672:2:1;4664:6;4661:14;4658:2;;;4693:6;4685;4678:22;4658:2;4721:71;4784:7;4775:6;4764:9;4760:22;4721:71;:::i;:::-;4711:81;;4845:2;4834:9;4830:18;4817:32;4801:48;;4874:2;4864:8;4861:16;4858:2;;;4895:6;4887;4880:22;4858:2;4923:61;4976:7;4965:8;4954:9;4950:24;4923:61;:::i;:::-;4913:71;;5037:2;5026:9;5022:18;5009:32;4993:48;;5066:2;5056:8;5053:16;5050:2;;;5087:6;5079;5072:22;5050:2;;5115:63;5170:7;5159:8;5148:9;5144:24;5115:63;:::i;:::-;5105:73;;;5197:62;5251:7;5246:2;5235:9;5231:18;5197:62;:::i;:::-;5187:72;;4493:772;;;;;;;:::o;5270:1093::-;;;;;;5581:3;5569:9;5560:7;5556:23;5552:33;5549:2;;;5603:6;5595;5588:22;5549:2;5648:9;5635:23;-1:-1:-1;;;;;5718:2:1;5710:6;5707:14;5704:2;;;5739:6;5731;5724:22;5704:2;5767:71;5830:7;5821:6;5810:9;5806:22;5767:71;:::i;:::-;5757:81;;5891:2;5880:9;5876:18;5863:32;5847:48;;5920:2;5910:8;5907:16;5904:2;;;5941:6;5933;5926:22;5904:2;5969:61;6022:7;6011:8;6000:9;5996:24;5969:61;:::i;:::-;5959:71;;6083:2;6072:9;6068:18;6055:32;6039:48;;6112:2;6102:8;6099:16;6096:2;;;6133:6;6125;6118:22;6096:2;;6161:63;6216:7;6205:8;6194:9;6190:24;6161:63;:::i;:::-;6151:73;;;6243:62;6297:7;6292:2;6281:9;6277:18;6243:62;:::i;:::-;5539:824;;;;-1:-1:-1;5539:824:1;;6352:3;6337:19;6324:33;;5539:824;-1:-1:-1;;5539:824:1:o;6368:535::-;;;6580:3;6568:9;6559:7;6555:23;6551:33;6548:2;;;6602:6;6594;6587:22;6548:2;6647:9;6634:23;-1:-1:-1;;;;;6672:6:1;6669:30;6666:2;;;6717:6;6709;6702:22;6666:2;6745:71;6808:7;6799:6;6788:9;6784:22;6745:71;:::i;:::-;6735:81;;;6835:62;6889:7;6884:2;6873:9;6869:18;6835:62;:::i;:::-;6825:72;;6538:365;;;;;:::o;6908:673::-;;;;;7152:3;7140:9;7131:7;7127:23;7123:33;7120:2;;;7174:6;7166;7159:22;7120:2;7219:9;7206:23;-1:-1:-1;;;;;7244:6:1;7241:30;7238:2;;;7289:6;7281;7274:22;7238:2;7317:71;7380:7;7371:6;7360:9;7356:22;7317:71;:::i;:::-;7307:81;;;7407:36;7439:2;7428:9;7424:18;7407:36;:::i;:::-;7397:46;;7490:2;7479:9;7475:18;7462:32;7452:42;;7513:62;7567:7;7562:2;7551:9;7547:18;7513:62;:::i;7586:742::-;;;;;;7847:3;7835:9;7826:7;7822:23;7818:33;7815:2;;;7869:6;7861;7854:22;7815:2;7914:9;7901:23;-1:-1:-1;;;;;7939:6:1;7936:30;7933:2;;;7984:6;7976;7969:22;7933:2;8012:71;8075:7;8066:6;8055:9;8051:22;8012:71;:::i;:::-;8002:81;;;8102:36;8134:2;8123:9;8119:18;8102:36;:::i;:::-;8092:46;;8185:2;8174:9;8170:18;8157:32;8147:42;;8208:62;8262:7;8257:2;8246:9;8242:18;8208:62;:::i;8333:813::-;;;;;;;8609:3;8597:9;8588:7;8584:23;8580:33;8577:2;;;8631:6;8623;8616:22;8577:2;8676:9;8663:23;-1:-1:-1;;;;;8701:6:1;8698:30;8695:2;;;8746:6;8738;8731:22;8695:2;8774:71;8837:7;8828:6;8817:9;8813:22;8774:71;:::i;:::-;8764:81;;;8864:36;8896:2;8885:9;8881:18;8864:36;:::i;:::-;8854:46;;8919:36;8951:2;8940:9;8936:18;8919:36;:::i;:::-;8909:46;;9002:2;8991:9;8987:18;8974:32;8964:42;;9053:3;9042:9;9038:19;9025:33;9015:43;;9077:63;9132:7;9126:3;9115:9;9111:19;9077:63;:::i;:::-;9067:73;;8567:579;;;;;;;;:::o;9151:297::-;;9271:2;9259:9;9250:7;9246:23;9242:32;9239:2;;;9292:6;9284;9277:22;9239:2;9329:9;9323:16;9382:5;9375:13;9368:21;9361:5;9358:32;9348:2;;9409:6;9401;9394:22;9453:253;;9597:3;9585:9;9576:7;9572:23;9568:33;9565:2;;;9619:6;9611;9604:22;9565:2;9647:53;9692:7;9681:9;9647:53;:::i;9711:1110::-;;;;;;;;10021:3;10009:9;10000:7;9996:23;9992:33;9989:2;;;10043:6;10035;10028:22;9989:2;10084:9;10071:23;10061:33;;10113:71;10176:7;10171:2;10160:9;10156:18;10113:71;:::i;:::-;10103:81;;10235:3;10224:9;10220:19;10207:33;-1:-1:-1;;;;;10300:2:1;10292:6;10289:14;10286:2;;;10321:6;10313;10306:22;10286:2;10365:70;10427:7;10418:6;10407:9;10403:22;10365:70;:::i;:::-;10454:8;;-1:-1:-1;10339:96:1;-1:-1:-1;10542:3:1;10527:19;;10514:33;;-1:-1:-1;10559:16:1;;;10556:2;;;10593:6;10585;10578:22;10556:2;;10637:72;10701:7;10690:8;10679:9;10675:24;10637:72;:::i;:::-;9979:842;;;;-1:-1:-1;9979:842:1;;;;;;10810:3;10795:19;;;10782:33;;9979:842;-1:-1:-1;;;;9979:842:1:o;10826:817::-;;;;;;;;11150:3;11138:9;11129:7;11125:23;11121:33;11118:2;;;11172:6;11164;11157:22;11118:2;11213:9;11200:23;11190:33;;11242:71;11305:7;11300:2;11289:9;11285:18;11242:71;:::i;:::-;11232:81;;11332:62;11386:7;11380:3;11369:9;11365:19;11332:62;:::i;:::-;11322:72;;11413:62;11467:7;11461:3;11450:9;11446:19;11413:62;:::i;:::-;11403:72;;11522:3;11511:9;11507:19;11494:33;11484:43;;11574:3;11563:9;11559:19;11546:33;11536:43;;11598:39;11632:3;11621:9;11617:19;11598:39;:::i;:::-;11588:49;;11108:535;;;;;;;;;;:::o;11648:620::-;;;;;;11914:3;11902:9;11893:7;11889:23;11885:33;11882:2;;;11936:6;11928;11921:22;11882:2;11977:9;11964:23;11954:33;;12006:71;12069:7;12064:2;12053:9;12049:18;12006:71;:::i;:::-;11996:81;;12096:62;12150:7;12144:3;12133:9;12129:19;12096:62;:::i;:::-;11872:396;;;;-1:-1:-1;12086:72:1;;12205:3;12190:19;;12177:33;;-1:-1:-1;12257:3:1;12242:19;12229:33;;11872:396;-1:-1:-1;;11872:396:1:o;12273:695::-;;;;;;;12556:3;12544:9;12535:7;12531:23;12527:33;12524:2;;;12578:6;12570;12563:22;12524:2;12619:9;12606:23;12596:33;;12648:71;12711:7;12706:2;12695:9;12691:18;12648:71;:::i;:::-;12638:81;;12738:62;12792:7;12786:3;12775:9;12771:19;12738:62;:::i;:::-;12728:72;;12847:3;12836:9;12832:19;12819:33;12809:43;;12899:3;12888:9;12884:19;12871:33;12861:43;;12923:39;12957:3;12946:9;12942:19;12923:39;:::i;12973:840::-;;;;;;;13250:3;13238:9;13229:7;13225:23;13221:33;13218:2;;;13272:6;13264;13257:22;13218:2;13313:9;13300:23;13290:33;;13342:71;13405:7;13400:2;13389:9;13385:18;13342:71;:::i;:::-;13332:81;;13460:3;13449:9;13445:19;13432:33;13422:43;;13516:3;13505:9;13501:19;13488:33;-1:-1:-1;;;;;13536:6:1;13533:30;13530:2;;;13581:6;13573;13566:22;13530:2;13625:70;13687:7;13678:6;13667:9;13663:22;13625:70;:::i;:::-;13714:8;;-1:-1:-1;13599:96:1;-1:-1:-1;13768:39:1;;-1:-1:-1;13802:3:1;13787:19;;13768:39;:::i;13818:1174::-;;;;;;;;;14143:3;14131:9;14122:7;14118:23;14114:33;14111:2;;;14165:6;14157;14150:22;14111:2;14206:9;14193:23;14183:33;;14235:62;14289:7;14284:2;14273:9;14269:18;14235:62;:::i;:::-;14225:72;;14348:3;14337:9;14333:19;14320:33;-1:-1:-1;;;;;14413:2:1;14405:6;14402:14;14399:2;;;14434:6;14426;14419:22;14399:2;14478:70;14540:7;14531:6;14520:9;14516:22;14478:70;:::i;:::-;14567:8;;-1:-1:-1;14452:96:1;-1:-1:-1;14655:3:1;14640:19;;14627:33;;-1:-1:-1;14672:16:1;;;14669:2;;;14706:6;14698;14691:22;14669:2;;14750:72;14814:7;14803:8;14792:9;14788:24;14750:72;:::i;:::-;14841:8;;-1:-1:-1;14724:98:1;-1:-1:-1;;14923:3:1;14908:19;;14895:33;;-1:-1:-1;14947:39:1;14981:3;14966:19;;14947:39;:::i;:::-;14937:49;;14101:891;;;;;;;;;;;:::o;14997:194::-;;15120:2;15108:9;15099:7;15095:23;15091:32;15088:2;;;15141:6;15133;15126:22;15088:2;-1:-1:-1;15169:16:1;;15078:113;-1:-1:-1;15078:113:1:o;15196:192::-;;15306:2;15294:9;15285:7;15281:23;15277:32;15274:2;;;15327:6;15319;15312:22;15274:2;15355:27;15372:9;15355:27;:::i;15393:274::-;;15560:6;15554:13;15576:53;15622:6;15617:3;15610:4;15602:6;15598:17;15576:53;:::i;:::-;15645:16;;;;;15530:137;-1:-1:-1;;15530:137:1:o;17433:383::-;;17582:2;17571:9;17564:21;17614:6;17608:13;17657:6;17652:2;17641:9;17637:18;17630:34;17673:66;17732:6;17727:2;17716:9;17712:18;17707:2;17699:6;17695:15;17673:66;:::i;:::-;17800:2;17779:15;-1:-1:-1;;17775:29:1;17760:45;;;;17807:2;17756:54;;17554:262;-1:-1:-1;;17554:262:1:o;22474:345::-;22676:2;22658:21;;;22715:2;22695:18;;;22688:30;-1:-1:-1;;;22749:2:1;22734:18;;22727:51;22810:2;22795:18;;22648:171::o;24493:1262::-;;24797:2;24786:9;24782:18;24827:6;24816:9;24809:25;24853:2;24891;24886;24875:9;24871:18;24864:30;24914:6;24949;24943:13;24980:6;24972;24965:22;25018:3;25007:9;25003:19;24996:26;;25057:2;25049:6;25045:15;25031:29;;25078:4;25091:195;25105:6;25102:1;25099:13;25091:195;;;25170:13;;-1:-1:-1;;;;;25166:39:1;25154:52;;25261:15;;;;25226:12;;;;25202:1;25120:9;25091:195;;;-1:-1:-1;;25322:19:1;;;25317:2;25302:18;;25295:47;25392:13;;25414:21;;;25453:12;;;;-1:-1:-1;25490:15:1;;;;25525:4;25538:189;25554:8;25549:3;25546:17;25538:189;;;25623:15;;25609:30;;25661:14;;;;25700:17;;;;25582:1;25573:11;25538:189;;;-1:-1:-1;25744:5:1;;24758:997;-1:-1:-1;;;;;;;;24758:997:1:o;26021:275::-;26092:2;26086:9;26157:2;26138:13;;-1:-1:-1;;26134:27:1;26122:40;;-1:-1:-1;;;;;26177:34:1;;26213:22;;;26174:62;26171:2;;;26239:18;;:::i;:::-;26275:2;26268:22;26066:230;;-1:-1:-1;26066:230:1:o;26301:196::-;;-1:-1:-1;;;;;26396:6:1;26393:30;26390:2;;;26426:18;;:::i;:::-;-1:-1:-1;26486:4:1;26467:17;;;26463:28;;26380:117::o;26502:253::-;;-1:-1:-1;;;;;26631:2:1;26628:1;26624:10;26661:2;26658:1;26654:10;26692:3;26688:2;26684:12;26679:3;26676:21;26673:2;;;26700:18;;:::i;:::-;26736:13;;26550:205;-1:-1:-1;;;;26550:205:1:o;26760:128::-;;26831:1;26827:6;26824:1;26821:13;26818:2;;;26837:18;;:::i;:::-;-1:-1:-1;26873:9:1;;26808:80::o;26893:216::-;;-1:-1:-1;;;;;27020:2:1;27017:1;27013:10;27042:3;27032:2;;27049:18;;:::i;:::-;27087:10;;27083:20;;;;;26939:170;-1:-1:-1;;26939:170:1:o;27114:120::-;;27180:1;27170:2;;27185:18;;:::i;:::-;-1:-1:-1;27219:9:1;;27160:74::o;27239:453::-;27335:6;27358:5;27372:314;27421:1;27458:2;27448:8;27445:16;27435:2;;27465:5;;;27435:2;27506:4;27501:3;27497:14;27491:4;27488:24;27485:2;;;27515:18;;:::i;:::-;27565:2;27555:8;27551:17;27548:2;;;27580:16;;;;27548:2;27659:17;;;;;27619:15;;27372:314;;;27316:376;;;;;;;:::o;27697:148::-;;27784:55;-1:-1:-1;;27825:4:1;27811:19;;27805:4;27850:922;27934:8;27924:2;;-1:-1:-1;27975:1:1;27989:5;;27924:2;28023:4;28013:2;;-1:-1:-1;28060:1:1;28074:5;;28013:2;28105:4;28123:1;28118:59;;;;28191:1;28186:183;;;;28098:271;;28118:59;28148:1;28139:10;;28162:5;;;28186:183;28223:3;28213:8;28210:17;28207:2;;;28230:18;;:::i;:::-;28286:1;28276:8;28272:16;28263:25;;28314:3;28307:5;28304:14;28301:2;;;28321:18;;:::i;:::-;28354:5;;;28098:271;;28453:2;28443:8;28440:16;28434:3;28428:4;28425:13;28421:36;28415:2;28405:8;28402:16;28397:2;28391:4;28388:12;28384:35;28381:77;28378:2;;;-1:-1:-1;28490:19:1;;;28525:14;;;28522:2;;;28542:18;;:::i;:::-;28575:5;;28378:2;28622:42;28660:3;28650:8;28644:4;28641:1;28622:42;:::i;:::-;28697:6;28692:3;28688:16;28679:7;28676:29;28673:2;;;28708:18;;:::i;:::-;28746:20;;27914:858;-1:-1:-1;;;;27914:858:1:o;28777:287::-;;-1:-1:-1;;;;;28910:2:1;28907:1;28903:10;28940:2;28937:1;28933:10;28996:3;28992:2;28988:12;28983:3;28980:21;28973:3;28966:11;28959:19;28955:47;28952:2;;;29005:18;;:::i;29069:168::-;;29175:1;29171;29167:6;29163:14;29160:1;29157:21;29152:1;29145:9;29138:17;29134:45;29131:2;;;29182:18;;:::i;:::-;-1:-1:-1;29222:9:1;;29121:116::o;29242:246::-;;-1:-1:-1;;;;;29395:10:1;;;;29365;;29417:12;;;29414:2;;;29432:18;;:::i;:::-;29469:13;;29291:197;-1:-1:-1;;;29291:197:1:o;29493:125::-;;29561:1;29558;29555:8;29552:2;;;29566:18;;:::i;:::-;-1:-1:-1;29603:9:1;;29542:76::o;29623:258::-;29695:1;29705:113;29719:6;29716:1;29713:13;29705:113;;;29795:11;;;29789:18;29776:11;;;29769:39;29741:2;29734:10;29705:113;;;29836:6;29833:1;29830:13;29827:2;;;-1:-1:-1;;29871:1:1;29853:16;;29846:27;29676:205::o;29886:135::-;;-1:-1:-1;;29946:17:1;;29943:2;;;29966:18;;:::i;:::-;-1:-1:-1;30013:1:1;30002:13;;29933:88::o;30026:127::-;30087:10;30082:3;30078:20;30075:1;30068:31;30118:4;30115:1;30108:15;30142:4;30139:1;30132:15;30158:127;30219:10;30214:3;30210:20;30207:1;30200:31;30250:4;30247:1;30240:15;30274:4;30271:1;30264:15;30290:127;30351:10;30346:3;30342:20;30339:1;30332:31;30382:4;30379:1;30372:15;30406:4;30403:1;30396:15

Swarm Source

ipfs://f78cb1fc5e5f9d3d51d2ceab0af6d29268e939f879fbfcba8b52c10ff7bbad23

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

Txn Hash Block Value Eth2 PubKey Valid
View All Deposits
[ 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.